protected async Task CreateOutput(Action <double> progress, IReadOnlyList <Video> videos, string outputFile) { await Task.WhenAll(videos.Select(this.CreateOutput)); FFMpegCore.FFMpegArguments ffmpeg = null; foreach (var video in videos) { if (ffmpeg == null) { ffmpeg = FFMpegCore.FFMpegArguments.FromFileInput(GetCombineVideoPath(video)); } else { ffmpeg = ffmpeg.AddFileInput(GetCombineVideoPath(video)); } } try { var duration = (await FFProbe.AnalyseAsync(GetCombineVideoPath(videos[0]))).Duration; await ffmpeg.OutputToFile(outputFile, true, _ => this.ApplyOption(videos, _)) .NotifyOnProgress(progress, duration) .ProcessAsynchronously(); } catch (Exception e) { Console.Error.WriteLine(e.ToString()); } }
/// <summary> /// Saves a 'png' thumbnail to an in-memory bitmap /// </summary> /// <param name="source">Source video file.</param> /// <param name="captureTime">Seek position where the thumbnail should be taken.</param> /// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param> /// <returns>Bitmap with the requested snapshot.</returns> public static Bitmap Snapshot(MediaAnalysis source, Size?size = null, TimeSpan?captureTime = null) { captureTime ??= TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3); size = PrepareSnapshotSize(source, size); using var ms = new MemoryStream(); FFMpegArguments .FromInputFiles(source.Path) .WithVideoCodec(VideoCodec.Png) .WithFrameOutputCount(1) .Resize(size) .Seek(captureTime) .ForceFormat("rawvideo") .OutputToPipe(new StreamPipeSink(ms)) .ProcessSynchronously(); ms.Position = 0; return(new Bitmap(ms)); }
/// <summary> /// Saves a 'png' thumbnail from the input video to drive /// </summary> /// <param name="source">Source video analysis</param> /// <param name="output">Output video file path</param> /// <param name="captureTime">Seek position where the thumbnail should be taken.</param> /// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param> /// <returns>Bitmap with the requested snapshot.</returns> public static bool Snapshot(MediaAnalysis source, string output, Size?size = null, TimeSpan?captureTime = null) { captureTime ??= TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3); if (Path.GetExtension(output) != FileExtension.Png) { output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png; } size = PrepareSnapshotSize(source, size); return(FFMpegArguments .FromInputFiles(source.Path) .WithVideoCodec(VideoCodec.Png) .WithFrameOutputCount(1) .Resize(size) .Seek(captureTime) .OutputToFile(output) .ProcessSynchronously()); }
private static (FFMpegArguments, Action <FFMpegArgumentOptions> outputOptions) BuildSnapshotArguments( string input, IMediaAnalysis source, Size?size = null, TimeSpan?captureTime = null, int?streamIndex = null, int inputFileIndex = 0) { captureTime ??= TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3); size = PrepareSnapshotSize(source, size); streamIndex = streamIndex == null ? 0 : source.VideoStreams.FirstOrDefault(videoStream => videoStream.Index == streamIndex).Index; return(FFMpegArguments .FromFileInput(input, false, options => options .Seek(captureTime)), options => options .SelectStream((int)streamIndex, inputFileIndex) .WithVideoCodec(VideoCodec.Png) .WithFrameOutputCount(1) .Resize(size)); }
/// <summary> /// Convert a video do a different format. /// </summary> /// <param name="source">Input video source.</param> /// <param name="output">Output information.</param> /// <param name="type">Target conversion video type.</param> /// <param name="speed">Conversion target speed/quality (faster speed = lower quality).</param> /// <param name="size">Video size.</param> /// <param name="audioQuality">Conversion target audio quality.</param> /// <param name="multithreaded">Is encoding multithreaded.</param> /// <returns>Output video information.</returns> public static bool Convert( string input, string output, ContainerFormat format, Speed speed = Speed.SuperFast, VideoSize size = VideoSize.Original, AudioQuality audioQuality = AudioQuality.Normal, bool multithreaded = false) { FFMpegHelper.ExtensionExceptionCheck(output, format.Extension); var source = FFProbe.Analyse(input); FFMpegHelper.ConversionSizeExceptionCheck(source); var scale = VideoSize.Original == size ? 1 : (double)source.PrimaryVideoStream !.Height / (int)size; var outputSize = new Size((int)(source.PrimaryVideoStream !.Width / scale), (int)(source.PrimaryVideoStream.Height / scale)); if (outputSize.Width % 2 != 0) { outputSize.Width += 1; } return(format.Name switch { "mp4" => FFMpegArguments .FromFileInput(input) .OutputToFile(output, true, options => options .UsingMultithreading(multithreaded) .WithVideoCodec(VideoCodec.LibX264) .WithVideoBitrate(2400) .WithVideoFilters(filterOptions => filterOptions .Scale(outputSize)) .WithSpeedPreset(speed) .WithAudioCodec(AudioCodec.Aac) .WithAudioBitrate(audioQuality)) .ProcessSynchronously(), "ogv" => FFMpegArguments .FromFileInput(input) .OutputToFile(output, true, options => options .UsingMultithreading(multithreaded) .WithVideoCodec(VideoCodec.LibTheora) .WithVideoBitrate(2400) .WithVideoFilters(filterOptions => filterOptions .Scale(outputSize)) .WithSpeedPreset(speed) .WithAudioCodec(AudioCodec.LibVorbis) .WithAudioBitrate(audioQuality)) .ProcessSynchronously(), "mpegts" => FFMpegArguments .FromFileInput(input) .OutputToFile(output, true, options => options .CopyChannel() .WithBitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB) .ForceFormat(VideoType.Ts)) .ProcessSynchronously(), "webm" => FFMpegArguments .FromFileInput(input) .OutputToFile(output, true, options => options .UsingMultithreading(multithreaded) .WithVideoCodec(VideoCodec.LibVpx) .WithVideoBitrate(2400) .WithVideoFilters(filterOptions => filterOptions .Scale(outputSize)) .WithSpeedPreset(speed) .WithAudioCodec(AudioCodec.LibVorbis) .WithAudioBitrate(audioQuality)) .ProcessSynchronously(), _ => throw new ArgumentOutOfRangeException(nameof(format)) });
internal FFMpegArgumentProcessor(FFMpegArguments ffMpegArguments) { _ffMpegArguments = ffMpegArguments; }