public async Task RtpStream(string rtpurl, CancellationToken cancellationToken) { this.Response.StatusCode = 200; this.Response.Headers.Add(HeaderNames.ContentDisposition, $"attachment; filename=\"stream\""); this.Response.Headers.Add(HeaderNames.ContentType, "application/octet-stream"); var pipe = new StreamPipeSink(this.Response.Body); var arg = FFMpegCore.FFMpegArguments.FromFileInput($"rtp://{rtpurl}", false).OutputToPipe(pipe, options => { options.ForceFormat("mpegts"); options.WithAudioCodec("aac"); options.WithVideoCodec("copy"); options.WithFastStart(); options.UsingMultithreading(true); options.WithCustomArgument("-analyzeduration 500000"); options.WithCustomArgument("-fflags nobuffer"); options.WithCustomArgument("-flags low_delay"); options.WithCustomArgument("-max_delay 250000"); options.WithCustomArgument("-max_interleave_delta 1"); // see https://github.com/l3tnun/EPGStation/issues/433 }); arg.CancellableThrough(out var cancel); cancellationToken.Register(cancel); await arg.ProcessAsynchronously(); }
public static Stream ConvertToWav(Stream inputStream, string mimeType) { if (mimeType.EndsWith("/wav")) { return(inputStream); } var outputStream = new MemoryStream(); var outputPipe = new StreamPipeSink(outputStream); outputPipe.Format = "wav"; // pcm_s16le or pcm_s32le var ffargs = FFMpegArguments .FromPipeInput(new StreamPipeSource(inputStream)) .OutputToPipe(outputPipe, options => options.WithCustomArgument("-ar 8000 -c:a pcm_s16le") .ForceFormat("wav") ); ffargs.ProcessAsynchronously().Wait(); return(outputStream); }
// Old solution using FFmpeg public void GetColors(Action <Color4[]> callback, int time) { Task.Run(() => { if (videoFile == null) { return; } Stream stream; var sink = new StreamPipeSink(stream = new MemoryStream()); var path = store.Storage.GetFullPath(videoFile); FFMpegArguments .FromFileInput(path, true, opt => opt.Seek(TimeSpan.FromMilliseconds(time))) .OutputToPipe(sink, opt => opt.WithFrameOutputCount(1) .WithArgument(new CustomArgument("-s 16x16")) .ForceFormat("image2")) .ProcessSynchronously(); stream.Seek(0, SeekOrigin.Begin); using Image <Rgb24> image = SixLabors.ImageSharp.Image.Load <Rgb24>(stream); callback(getImageColors(image)); }); }
public async Task Produce(IBoundedQueue <MutableByteImage> sourceQueue) { try { if (!string.IsNullOrWhiteSpace(_arguments.PathToFfmpeg)) { FFMpegOptions.Configure(new FFMpegOptions { RootDirectory = _arguments.PathToFfmpeg }); } var result = await FFProbe.AnalyseAsync(_arguments.InputFile).ConfigureAwait(false); var width = result.PrimaryVideoStream.Width; var height = result.PrimaryVideoStream.Height; var bpp = Image.GetPixelFormatSize(System.Drawing.Imaging.PixelFormat.Format24bppRgb) / 8; var pixelsPerFrame = width * height; var frameSizeInBytes = pixelsPerFrame * bpp; _logger.WriteLine("Input from ffmpeg currently only supports rgb24-convertable input", Verbosity.Warning); var chunksQueue = BoundedQueueFactory.Get <byte[]>(4, "In-ChuQ"); using var memoryStream = new ChunkedSimpleMemoryStream(frameSizeInBytes, chunksQueue); // new MemoryStream(frameSizeInBytes); StreamPipeSink sink = new StreamPipeSink(memoryStream); var args = FFMpegArguments .FromFileInput(_arguments.InputFile).OutputToPipe(sink, options => options.DisableChannel(FFMpegCore.Enums.Channel.Audio) .UsingMultithreading(true) .ForceFormat("rawvideo") .WithCustomArgument(_arguments.CustomArgs ?? string.Empty) .ForcePixelFormat("bgr24")) .NotifyOnProgress( percent => _logger.NotifyFillstate(Convert.ToInt32(percent), "InputVideoParsing"), TimeSpan.FromSeconds(1)); var produceTask = args.ProcessAsynchronously(true).ContinueWith((_) => { chunksQueue.CompleteAdding(); sourceQueue.CompleteAdding(); }); var consumeTask = ParseInputStream(sourceQueue, chunksQueue, width, height, memoryStream) .ContinueWith((_) => _logger.WriteLine("finished reading", Verbosity.Info)); await Task.WhenAll(produceTask, consumeTask); _logger.WriteLine("finished reading", Verbosity.Info); } catch (System.ComponentModel.Win32Exception) { _logger.WriteLine("Couldn't find ffmpeg", Verbosity.Error); } catch (Exception e) { _logger.LogException(e); } }
public async Task Video_ToMP4_Args_StreamOutputPipe_Async() { await using var ms = new MemoryStream(); var pipeSource = new StreamPipeSink(ms); await FFMpegArguments .FromFileInput(TestResources.Mp4Video) .OutputToPipe(pipeSource, opt => opt .WithVideoCodec(VideoCodec.LibX264) .ForceFormat("matroska")) .ProcessAsynchronously(); }
public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure() { await Assert.ThrowsExceptionAsync <FFMpegException>(async() => { await using var ms = new MemoryStream(); var pipeSource = new StreamPipeSink(ms); await FFMpegArguments .FromFileInput(TestResources.Mp4Video) .OutputToPipe(pipeSource, opt => opt.ForceFormat("mkv")) .ProcessAsynchronously(); }); }
public void Video_ToMP4_Args_StreamOutputPipe_Async() { using var ms = new MemoryStream(); var pipeSource = new StreamPipeSink(ms); FFMpegArguments .FromFileInput(VideoLibrary.LocalVideo) .OutputToPipe(pipeSource, opt => opt .WithVideoCodec(VideoCodec.LibX264) .ForceFormat("matroska")) .ProcessAsynchronously() .WaitForResult(); }
// [TestMethod, Timeout(10000)] public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure() { await Assert.ThrowsExceptionAsync <FFMpegException>(async() => { await using var ms = new MemoryStream(); var pipeSource = new StreamPipeSink(ms); await FFMpegArguments .FromInputFiles(VideoLibrary.LocalVideo) .ForceFormat("mkv") .OutputToPipe(pipeSource) .ProcessAsynchronously(); }); }
private void ConvertToStreamPipe(params IArgument[] inputArguments) { using var ms = new MemoryStream(); var arguments = FFMpegArguments.FromInputFiles(VideoLibrary.LocalVideo); foreach (var arg in inputArguments) { arguments.WithArgument(arg); } var streamPipeDataReader = new StreamPipeSink(ms); var processor = arguments.OutputToPipe(streamPipeDataReader); var scaling = arguments.Find <ScaleArgument>(); processor.ProcessSynchronously(); ms.Position = 0; var outputVideo = FFProbe.Analyse(ms); var input = FFProbe.Analyse(VideoLibrary.LocalVideo.FullName); // Assert.IsTrue(Math.Abs((outputVideo.Duration - input.Duration).TotalMilliseconds) < 1000.0 / input.PrimaryVideoStream.FrameRate); if (scaling?.Size == null) { Assert.AreEqual(outputVideo.PrimaryVideoStream.Width, input.PrimaryVideoStream.Width); Assert.AreEqual(outputVideo.PrimaryVideoStream.Height, input.PrimaryVideoStream.Height); } else { if (scaling.Size.Value.Width != -1) { Assert.AreEqual(outputVideo.PrimaryVideoStream.Width, scaling.Size.Value.Width); } if (scaling.Size.Value.Height != -1) { Assert.AreEqual(outputVideo.PrimaryVideoStream.Height, scaling.Size.Value.Height); } Assert.AreNotEqual(outputVideo.PrimaryVideoStream.Width, input.PrimaryVideoStream.Width); Assert.AreNotEqual(outputVideo.PrimaryVideoStream.Height, input.PrimaryVideoStream.Height); } }
public void Video_TranscodeInMemory() { using var resStream = new MemoryStream(); var reader = new StreamPipeSink(resStream); var writer = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, System.Drawing.Imaging.PixelFormat.Format24bppRgb, 128, 128)); FFMpegArguments .FromPipeInput(writer) .OutputToPipe(reader, opt => opt .WithVideoCodec("vp9") .ForceFormat("webm")) .ProcessSynchronously(); resStream.Position = 0; var vi = FFProbe.Analyse(resStream); Assert.AreEqual(vi.PrimaryVideoStream.Width, 128); Assert.AreEqual(vi.PrimaryVideoStream.Height, 128); }
public async Task Video_Cancel_Async() { await using var resStream = new MemoryStream(); var reader = new StreamPipeSink(resStream); var writer = new RawVideoPipeSource(BitmapSource.CreateBitmaps(512, System.Drawing.Imaging.PixelFormat.Format24bppRgb, 128, 128)); var task = FFMpegArguments .FromPipe(writer) .WithVideoCodec("vp9") .ForceFormat("webm") .OutputToPipe(reader) .CancellableThrough(out var cancel) .ProcessAsynchronously(false); await Task.Delay(300); cancel(); var result = await task; Assert.IsFalse(result); }
public async Task Produce(ConcurrentQueue <MutableByteImage> queue) { try { FFMpegOptions.Configure(new FFMpegOptions { RootDirectory = _arguments.PathToFfmpeg }); var result = await FFProbe.AnalyseAsync(_arguments.InputFiles.First()).ConfigureAwait(false); var width = result.PrimaryVideoStream.Width; var height = result.PrimaryVideoStream.Height; var bpp = Image.GetPixelFormatSize(System.Drawing.Imaging.PixelFormat.Format24bppRgb) / 8; var pixelsPerFrame = width * height; var frameSizeInBytes = pixelsPerFrame * bpp; _logger.WriteLine("Input from ffmpeg currently only supports rgb24-convertable input", Verbosity.Warning); var chunksQueue = new ConcurrentQueue <byte[]>(); using var memoryStream = new ChunkedMemoryStream(frameSizeInBytes, chunksQueue); // new MemoryStream(frameSizeInBytes); StreamPipeSink sink = new StreamPipeSink(memoryStream); var args = FFMpegArguments .FromInputFiles(_arguments.InputFiles) .UsingMultithreading(true) .ForceFormat("rawvideo") .ForcePixelFormat("bgr24") .OutputToPipe(sink) .NotifyOnProgress( percent => _logger.NotifyFillstate(Convert.ToInt32(percent), "InputVideoParsing"), TimeSpan.FromSeconds(1)); var produceTask = args.ProcessAsynchronously(true).ContinueWith((_) => parsingFinished.Cancel()); var consumeTask = ParseInputStream(queue, chunksQueue, width, height, frameSizeInBytes, memoryStream); await Task.WhenAll(produceTask, consumeTask); // await Task.WhenAny(produceTask, consumeTask).ConfigureAwait(false); } catch (Exception e) { } async Task ParseInputStream(ConcurrentQueue <MutableByteImage> queue, ConcurrentQueue <byte[]> chunksQueue, int width, int height, int frameSizeInBytes, ChunkedMemoryStream memoryStream) { int count = 0; while (true) //while ((memoryStream.HasUnwrittenData || chunksQueue.Count > 0) && !parsingFinished.IsCancellationRequested) { try { var foo = await chunksQueue.TryDequeueOrWait(parsingFinished); if (foo.cancelled) { break; } _logger.NotifyFillstate(++count, "ParsedImages"); _logger.NotifyFillstate(chunksQueue.Count, "ChunkedQueue"); queue.Enqueue(_factory.FromBytes(width, height, foo.item)); } catch (Exception e) { _logger.LogException(e); } await queue.WaitForBufferSpace(24); } Console.WriteLine(memoryStream.HasUnwrittenData); } }