/// <summary> /// Joins a list of video files. /// </summary> /// <param name="output">Output video file.</param> /// <param name="videos">List of vides that need to be joined together.</param> /// <returns>Output video information.</returns> public VideoInfo Join(FileInfo output, params VideoInfo[] videos) { FFMpegHelper.OutputExistsExceptionCheck(output); FFMpegHelper.InputsExistExceptionCheck(videos.Select(video => video.ToFileInfo()).ToArray()); var temporaryVideoParts = videos.Select(video => { FFMpegHelper.ConversionSizeExceptionCheck(video); var destinationPath = video.FullName.Replace(video.Extension, FileExtension.Ts); Convert( video, new FileInfo(destinationPath), VideoType.Ts ); return(destinationPath); }).ToList(); var args = Arguments.InputConcat(temporaryVideoParts) + Arguments.Copy() + Arguments.BitStreamFilter(Channel.Audio, Filter.Aac_AdtstoAsc) + Arguments.Output(output); try { if (!RunProcess(args, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not join the provided video files."); } return(new VideoInfo(output)); } finally { Cleanup(temporaryVideoParts); } }
/// <summary> /// Converts a source video to TS format. /// </summary> /// <param name="source">Source video file.</param> /// <param name="IntendedOutput">Output video file.</param> /// <returns>Success state.</returns> public bool ToTS(VideoInfo source, string IntendedOutput, out string ActualOutput) { int i = 0; ActualOutput = IntendedOutput; while (File.Exists(ActualOutput) && FFMpegHelper.IsFileLocked(ActualOutput)) { ActualOutput = Path.Combine(Path.GetDirectoryName(IntendedOutput), Path.GetFileNameWithoutExtension(IntendedOutput) + $"({i}){Path.GetExtension(IntendedOutput)}"); i++; } _probe.SetVideoInfo(ref source); _totalVideoTime = source.Duration; IsConverting = true; if (File.Exists(IntendedOutput) && !FFMpegHelper.IsFileLocked(IntendedOutput)) { return(true); } FFMpegHelper.ConversionExceptionCheck(source, IntendedOutput); FFMpegHelper.ExtensionExceptionCheck(IntendedOutput, ".ts"); string conversionArgs = string.Format("-i \"{0}\" -c copy -bsf:v h264_mp4toannexb -f mpegts \"{1}\"", source.Path, IntendedOutput); return(_RunProcess(conversionArgs)); }
/// <summary> /// Converts an image sequence to a video. /// </summary> /// <param name="output">Output video file.</param> /// <param name="frameRate">FPS</param> /// <param name="images">Image sequence collection</param> /// <returns>Output video information.</returns> public VideoInfo JoinImageSequence(FileInfo output, double frameRate = 30, params ImageInfo[] images) { var temporaryImageFiles = images.Select((image, index) => { FFMpegHelper.ConversionSizeExceptionCheck(Image.FromFile(image.FullName)); var destinationPath = image.FullName.Replace(image.Name, $"{index.ToString().PadLeft(9, '0')}{image.Extension}"); File.Copy(image.FullName, destinationPath); return(destinationPath); }).ToList(); var firstImage = images.First(); var args = Arguments.FrameRate(frameRate) + Arguments.Size(new Size(firstImage.Width, firstImage.Height)) + Arguments.StartNumber(0) + Arguments.Input($"{firstImage.Directory}\\%09d.png") + Arguments.FrameOutputCount(images.Length) + Arguments.Video(VideoCodec.LibX264) + Arguments.Output(output); try { if (!RunProcess(args, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not join the provided image sequence."); } return(new VideoInfo(output)); } finally { Cleanup(temporaryImageFiles); } }
/// <summary> /// Joins a list of video files. /// </summary> /// <param name="output">Output video file.</param> /// <param name="videos">List of vides that need to be joined together.</param> /// <returns>Success state.</returns> public bool Join(string output, params VideoInfo[] videos) { string[] pathList = new string[videos.Length]; for (int i = 0; i < pathList.Length; i++) { ToTS(videos[i].Path, videos[i].Path.Replace("mp4", "ts"), out string ActualPath); pathList[i] = ActualPath; } string conversionArgs = string.Format("-i \"concat:{0}\" -c copy -bsf:a aac_adtstoasc \"{1}\"", string.Join(@"|", (object[])pathList), output); bool result = _RunProcess(conversionArgs); if (result) { foreach (string path in pathList) { if (File.Exists(path)) { FFMpegHelper.TryDelete(path); } } } return(result); }
/// <summary> /// Builds parameters string from <see cref="ArgumentsContainer"/> that would be passed to ffmpeg process /// </summary> /// <param name="container">Container of arguments</param> /// <param name="input">Input file</param> /// <param name="output">Output file</param> /// <returns>Parameters string</returns> public string BuildArguments(ArgumentsContainer container, FileInfo input, FileInfo output) { CheckContainerException(container); CheckExtensionOfOutputExtension(container, output); FFMpegHelper.ConversionExceptionCheck(input, output); StringBuilder sb = new StringBuilder(); var inputA = new InputArgument(input); var outputA = new OutputArgument(); sb.Append(inputA.GetStringValue().Trim() + " "); foreach (var a in container) { if (!IsInputOrOutput(a.Key)) { sb.Append(a.Value.GetStringValue().Trim() + " "); } } sb.Append(outputA.GetStringValue().Trim()); var overrideArg = container.Find <OverrideArgument>(); if (overrideArg != null) { sb.Append(" " + overrideArg.GetStringValue().Trim()); } return(sb.ToString()); }
/// <summary> /// Records M3U8 streams to the specified output. /// </summary> /// <param name="httpStream">URI to pointing towards stream.</param> /// <param name="output">Output file</param> /// <returns>Success state.</returns> public bool SaveM3U8Stream(string httpStream, string output) { FFMpegHelper.ExtensionExceptionCheck(output, ".mp4"); string conversionArgs = string.Format("-i \"{0}\" \"{1}\"", httpStream, output); return(_RunProcess(conversionArgs)); }
private void CheckExtensionOfOutputExtension(ArgumentContainer container, FileInfo output) { if (container.ContainsKey(typeof(VideoCodecArgument))) { var codec = (VideoCodecArgument)container[typeof(VideoCodecArgument)]; FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.ForCodec(codec.Value)); } }
/// <summary> /// Intializes the FFMPEG encoder. /// </summary> public FFMpeg() : base() { FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); _ffmpegPath = FFMpegOptions.Options.FFmpegBinary; ArgumentBuilder = new FFArgumentBuilder(); }
/// <summary> /// Adds a poster image to an audio file. /// </summary> /// <param name="image">Source image file.</param> /// <param name="audio">Source audio file.</param> /// <param name="output">Output video file.</param> /// <returns></returns> public bool AddPosterToAudio(string image, string audio, string output) { FFMpegHelper.InputFilesExistExceptionCheck(image, audio); FFMpegHelper.ExtensionExceptionCheck(output, ".mp4"); string args = string.Format("-loop 1 -i \"{0}\" -i \"{1}\" -b:v 2000k -vcodec libx264 -c:a aac -strict experimental -shortest \"{2}\"", image, audio, output); return(_RunProcess(args)); }
/// <summary> /// Intializes the FFMPEG encoder. /// </summary> public FFMpeg() { FFMpegHelper.RootExceptionCheck(ConfiguredRoot); FFProbeHelper.RootExceptionCheck(ConfiguredRoot); var target = Environment.Is64BitProcess ? "x64" : "x86"; _ffmpegPath = ConfiguredRoot + $"\\{target}\\ffmpeg.exe"; }
public static T UseFFMpeg <T>(this AppBuilderBase <T> b, FFOptions fFMpegOptions) where T : AppBuilderBase <T>, new() { return(b.AfterSetup(_ => { GlobalFFOptions.Configure(fFMpegOptions); FFMpegHelper.VerifyFFMpegExists(fFMpegOptions); })); }
/// <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 VideoInfo Convert( VideoInfo source, FileInfo output, VideoType type = VideoType.Mp4, Speed speed = Speed.SuperFast, VideoSize size = VideoSize.Original, AudioQuality audioQuality = AudioQuality.Normal, bool multithreaded = false) { FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.ForType(type)); FFMpegHelper.ConversionSizeExceptionCheck(source); string args = ""; var height = source.Height * (source.Width / (int)size); switch (type) { case VideoType.Mp4: args = Arguments.Input(source) + Arguments.Threads(multithreaded) + Arguments.Scale(size, height) + Arguments.Video(VideoCodec.LibX264, 2400) + Arguments.Speed(speed) + Arguments.Audio(AudioCodec.Aac, audioQuality) + Arguments.Output(output); break; case VideoType.Ogv: args = Arguments.Input(source) + Arguments.Threads(multithreaded) + Arguments.Scale(size, height) + Arguments.Video(VideoCodec.LibTheora, 2400) + Arguments.Speed(16) + Arguments.Audio(AudioCodec.LibVorbis, audioQuality) + Arguments.Output(output); break; case VideoType.Ts: args = Arguments.Input(source) + Arguments.Copy() + Arguments.BitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB) + Arguments.ForceFormat(VideoCodec.MpegTs) + Arguments.Output(output); break; } if (!RunProcess(args, output)) { throw new FFMpegException(FFMpegExceptionType.Conversion, $"The video could not be converted to {Enum.GetName(typeof(VideoType), type)}"); } return(new VideoInfo(output)); }
/// <summary> /// Intializes the FFMPEG encoder. /// </summary> public FFMpeg() : base() { FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); var target = Environment.Is64BitProcess ? "x64" : "x86"; _ffmpegPath = $"{FFMpegOptions.Options.RootDirectory}\\{target}\\ffmpeg.exe"; ArgumentBuilder = new FFArgumentBuilder(); }
/// <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 VideoInfo Convert( VideoInfo source, FileInfo output, VideoType type = VideoType.Mp4, Speed speed = Speed.SuperFast, VideoSize size = VideoSize.Original, AudioQuality audioQuality = AudioQuality.Normal, bool multithreaded = false) { FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.ForType(type)); FFMpegHelper.ConversionSizeExceptionCheck(source); var scale = VideoSize.Original == size ? 1 : (double)source.Height / (int)size; var outputSize = new Size((int)(source.Width / scale), (int)(source.Height / scale)); if (outputSize.Width % 2 != 0) { outputSize.Width += 1; } return(type switch { VideoType.Mp4 => Convert(new ArgumentContainer( new InputArgument(source), new ThreadsArgument(multithreaded), new ScaleArgument(outputSize), new VideoCodecArgument(VideoCodec.LibX264, 2400), new SpeedArgument(speed), new AudioCodecArgument(AudioCodec.Aac, audioQuality), new OutputArgument(output))), VideoType.Ogv => Convert(new ArgumentContainer( new InputArgument(source), new ThreadsArgument(multithreaded), new ScaleArgument(outputSize), new VideoCodecArgument(VideoCodec.LibTheora, 2400), new SpeedArgument(speed), new AudioCodecArgument(AudioCodec.LibVorbis, audioQuality), new OutputArgument(output))), VideoType.Ts => Convert(new ArgumentContainer( new InputArgument(source), new CopyArgument(), new BitStreamFilterArgument(Channel.Video, Filter.H264_Mp4ToAnnexB), new ForceFormatArgument(VideoCodec.MpegTs), new OutputArgument(output))), VideoType.WebM => Convert(new ArgumentContainer( new InputArgument(source), new ThreadsArgument(multithreaded), new ScaleArgument(outputSize), new VideoCodecArgument(VideoCodec.LibVpx, 2400), new SpeedArgument(speed), new AudioCodecArgument(AudioCodec.LibVorbis, audioQuality), new OutputArgument(output))), _ => throw new ArgumentOutOfRangeException(nameof(type)) });
/// <summary> /// Strips a video file of audio. /// </summary> /// <param name="source">Source video file.</param> /// <param name="output">Output video file.</param> /// <returns></returns> public bool Mute(VideoInfo source, string output) { _probe.SetVideoInfo(ref source); FFMpegHelper.ConversionExceptionCheck(source, output); FFMpegHelper.ExtensionExceptionCheck(output, source.Extension); string args = string.Format("-i \"{0}\" -c copy -an \"{1}\"", source.Path, output); return(_RunProcess(args)); }
/// <summary> /// Saves audio from a specific video file to disk. /// </summary> /// <param name="source">Source video file.</param> /// <param name="output">Output audio file.</param> /// <returns>Success state.</returns> public bool SaveAudio(VideoInfo source, string output) { _probe.SetVideoInfo(ref source); FFMpegHelper.ConversionExceptionCheck(source, output); FFMpegHelper.ExtensionExceptionCheck(output, ".mp3"); string args = string.Format("-i \"{0}\" -vn -ab 256 \"{1}\"", source.Path, output); return(_RunProcess(args)); }
/// <summary> /// Adds audio to a video file. /// </summary> /// <param name="source">Source video file.</param> /// <param name="audio">Source audio file.</param> /// <param name="output">Output video file.</param> /// <param name="stopAtShortest">Indicates if the encoding should stop at the shortest input file.</param> /// <returns>Success state</returns> public bool AddAudio(VideoInfo source, string audio, string output, bool stopAtShortest = false) { _probe.SetVideoInfo(ref source); FFMpegHelper.ConversionExceptionCheck(source, output); FFMpegHelper.InputFilesExistExceptionCheck(audio); FFMpegHelper.ExtensionExceptionCheck(output, source.Extension); string args = string.Format("-i \"{0}\" -i \"{1}\" -c:v copy -c:a aac -strict experimental {3} \"{2}\"", source.Path, audio, output, stopAtShortest ? "-shortest" : ""); return(_RunProcess(args)); }
/// <summary> /// Intializes the FFMPEG encoder. /// </summary> /// <param name="rootPath">Directory root where ffmpeg.exe can be found. If not specified, root will be loaded from config.</param> public FFMpeg(string rootPath = null) { if (rootPath == null) { rootPath = Environment.CurrentDirectory; } FFMpegHelper.RootExceptionCheck(rootPath); FFProbeHelper.RootExceptionCheck(rootPath); _ffmpegPath = rootPath + "\\ffmpeg.exe"; _probe = new FFProbe(rootPath); }
/// <summary> /// Intializes the FFMPEG encoder. /// </summary> /// <param name="rootPath">Directory root where ffmpeg.exe can be found. If not specified, root will be loaded from config.</param> public FFMpeg(string rootPath = null) { if (rootPath == null) { rootPath = ConfigurationManager.AppSettings["ffmpegRoot"]; } FFMpegHelper.RootExceptionCheck(rootPath); FFProbeHelper.RootExceptionCheck(rootPath); _ffmpegPath = rootPath + "\\ffmpeg.exe"; _probe = new FFProbe(rootPath); }
private Instance PrepareInstance(out CancellationTokenSource cancellationTokenSource) { FFMpegHelper.RootExceptionCheck(); FFMpegHelper.VerifyFFMpegExists(); var instance = new Instance(FFMpegOptions.Options.FFmpegBinary(), _ffMpegArguments.Text); cancellationTokenSource = new CancellationTokenSource(); if (_onTimeProgress != null || (_onPercentageProgress != null && _totalTimespan != null)) { instance.DataReceived += OutputData; } return(instance); }
/// <summary> /// The OnExportChart. /// </summary> internal async void ExportChart() { if (!FFMpegHelper.IsFFMpegLibExist) { var title = $"FFMpeg Library {FFMpegHelper.FFMpegLib} Not Found"; var message = $"Please download {FFMpegHelper.FFMpegLib} from https://ffbinaries.com/downloads," + $" extract and copy to the application path."; await this.GlobalData.ShowMessageAsync(title, message); return; } var fileName = $"{this.BarChartViewModel.Title}.mp4"; var dialog = new VistaSaveFileDialog { InitialDirectory = this.InitialDirectory, FileName = fileName, Filter = "MPEG4 files (*.mp4)|*.mp4" }; if (!(bool)dialog.ShowDialog()) { return; } var filePath = dialog.FileName; if (!filePath.ToLower().Contains(".mp4")) { filePath += ".mp4"; } this.RenderCancellationTokenSource?.Cancel(); this.RenderCancellationTokenSource = new CancellationTokenSource(); var token = this.RenderCancellationTokenSource.Token; await Task.Run(async() => { try { FFMpegHelper.Record(filePath, this.BarChartView, this.OnDrawChart, this.BarAnimationModel.FrameCount, token); } catch (Exception e) { await this.GlobalData.ShowMessageAsync($"Export Failed", $"Error: {e.Message}\r\n{e.StackTrace}"); } }, token); }
private Instance PrepareInstance(out CancellationTokenSource cancellationTokenSource, out int errorCode) { FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); var instance = new Instance(FFMpegOptions.Options.FFmpegBinary(), _ffMpegArguments.Text); instance.DataReceived += OutputData; cancellationTokenSource = new CancellationTokenSource(); if (_onTimeProgress != null || (_onPercentageProgress != null && _totalTimespan != null)) { instance.DataReceived += OutputData; } errorCode = -1; return(instance); }
/// <summary> /// Saves audio from a specific video file to disk. /// </summary> /// <param name="source">Source video file.</param> /// <param name="output">Output audio file.</param> /// <returns>Success state.</returns> public FileInfo ExtractAudio(VideoInfo source, FileInfo output) { FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp3); var args = Arguments.Input(source) + Arguments.Disable(Channel.Video) + Arguments.Output(output); if (!RunProcess(args, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not extract the audio from the requested video."); } output.Refresh(); return(output); }
/// <summary> /// Strips a video file of audio. /// </summary> /// <param name="source">Source video file.</param> /// <param name="output">Output video file.</param> /// <returns></returns> public VideoInfo Mute(VideoInfo source, FileInfo output) { FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); FFMpegHelper.ConversionSizeExceptionCheck(source); FFMpegHelper.ExtensionExceptionCheck(output, source.Extension); var args = Arguments.Input(source) + Arguments.Copy() + Arguments.Disable(Channel.Audio) + Arguments.Output(output); if (!RunProcess(args, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not mute the requested video."); } return(new VideoInfo(output)); }
/// <summary> /// Records M3U8 streams to the specified output. /// </summary> /// <param name="uri">URI to pointing towards stream.</param> /// <param name="output">Output file</param> /// <returns>Success state.</returns> public VideoInfo SaveM3U8Stream(Uri uri, FileInfo output) { FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4); if (uri.Scheme == "http" || uri.Scheme == "https") { var args = Arguments.Input(uri) + Arguments.Output(output); if (!RunProcess(args, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, $"Saving the ${uri.AbsoluteUri} stream failed."); } return(new VideoInfo(output)); } throw new ArgumentException($"Uri: {uri.AbsoluteUri}, does not point to a valid http(s) stream."); }
/// <summary> /// Strips a video file of audio. /// </summary> /// <param name="source">Source video file.</param> /// <param name="output">Output video file.</param> /// <returns></returns> public VideoInfo Mute(VideoInfo source, FileInfo output) { FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); FFMpegHelper.ConversionSizeExceptionCheck(source); FFMpegHelper.ExtensionExceptionCheck(output, source.Extension); var container = new ArgumentContainer( new InputArgument(source), new CopyArgument(), new DisableChannelArgument(Channel.Audio), new OutputArgument(output) ); if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not mute the requested video."); } return(new VideoInfo(output)); }
/// <summary> /// Saves audio from a specific video file to disk. /// </summary> /// <param name="source">Source video file.</param> /// <param name="output">Output audio file.</param> /// <returns>Success state.</returns> public FileInfo ExtractAudio(VideoInfo source, FileInfo output) { FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp3); var container = new ArgumentContainer( new InputArgument(source), new DisableChannelArgument(Channel.Video), new OutputArgument(output) ); if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not extract the audio from the requested video."); } output.Refresh(); return(output); }
/// <summary> /// Converts a source video to OGV format. /// </summary> /// <param name="source">Source video file.</param> /// <param name="output">Output video file.</param> /// <param name="size">Output video size.</param> /// <param name="multithread">Use multithreading for conversion.</param> /// <returns>Success state.</returns> public bool ToOGV(VideoInfo source, string output, VideoSize size = VideoSize.Original, bool multithread = false) { _probe.SetVideoInfo(ref source); _totalVideoTime = source.Duration; IsConverting = true; string threadCount = multithread ? Environment.ProcessorCount.ToString() : "1", scale = FFMpegHelper.GetScale(size); FFMpegHelper.ConversionExceptionCheck(source, output); FFMpegHelper.ExtensionExceptionCheck(output, ".ogv"); string conversionArgs = string.Format("-i \"{0}\" -threads {1} {2} -codec:v libtheora -qscale:v 7 -codec:a libvorbis -qscale:a 5 \"{3}\"", source.Path, threadCount, scale, output); return(_RunProcess(conversionArgs)); }
/// <summary> /// Converts a source video to WebM format. /// </summary> /// <param name="source">Source video file.</param> /// <param name="output">Output video file.</param> /// <param name="size">Output video size.</param> /// <param name="multithread">Use multithreading for conversion.</param> /// <returns>Success state.</returns> public bool ToWebM(VideoInfo source, string output, VideoSize size = VideoSize.Original, bool multithread = false) { _probe.SetVideoInfo(ref source); _totalVideoTime = source.Duration; IsConverting = true; string threadCount = multithread ? Environment.ProcessorCount.ToString() : "1", scale = FFMpegHelper.GetScale(size); FFMpegHelper.ConversionExceptionCheck(source, output); FFMpegHelper.ExtensionExceptionCheck(output, ".webm"); string conversionArgs = string.Format("-i \"{0}\" -threads {1} {2} -vcodec libvpx -quality good -cpu-used 0 -b:v 1500k -qmin 10 -qmax 42 -maxrate 500k -bufsize 1000k -codec:a libvorbis -b:a 128k \"{3}\"", source.Path, threadCount, scale, output); return(_RunProcess(conversionArgs)); }
/// <summary> /// Adds audio to a video file. /// </summary> /// <param name="source">Source video file.</param> /// <param name="audio">Source audio file.</param> /// <param name="output">Output video file.</param> /// <param name="stopAtShortest">Indicates if the encoding should stop at the shortest input file.</param> /// <returns>Success state</returns> public VideoInfo ReplaceAudio(VideoInfo source, FileInfo audio, FileInfo output, bool stopAtShortest = false) { FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); FFMpegHelper.InputsExistExceptionCheck(audio); FFMpegHelper.ConversionSizeExceptionCheck(source); FFMpegHelper.ExtensionExceptionCheck(output, source.Extension); var args = Arguments.Input(source) + Arguments.Input(audio) + Arguments.Copy(Channel.Video) + Arguments.Audio(AudioCodec.Aac, AudioQuality.Hd) + Arguments.FinalizeAtShortestInput(stopAtShortest) + Arguments.Output(output); if (!RunProcess(args, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not replace the video audio."); } return(new VideoInfo(output)); }