示例#1
0
        /// <summary>
        /// Concatenates (merges) all specified files.
        /// </summary>
        /// <param name="files">The files to merge.</param>
        /// <param name="destination">The destination file.</param>
        /// <param name="options">The options for starting the process.</param>
        /// <param name="callback">A method that will be called after the process has been started.</param>
        /// <returns>The process completion status.</returns>
        public CompletionStatus Concatenate(IEnumerable <string> files, string destination, ProcessOptionsFFmpeg options = null, ProcessStartedEventHandler callback = null)
        {
            if (files == null || !files.Any())
            {
                throw new ArgumentException("Files cannot be null or empty.", nameof(files));
            }
            if (string.IsNullOrEmpty(destination))
            {
                throw new ArgumentException("Destination cannot be null or empty.", nameof(destination));
            }
            CompletionStatus Result = CompletionStatus.None;

            // Write temp file.
            string        TempFile    = fileSystem.GetTempFile();
            StringBuilder TempContent = new StringBuilder();

            foreach (string item in files)
            {
                TempContent.AppendFormat("file '{0}'", item).AppendLine();
            }
            fileSystem.WriteAllText(TempFile, TempContent.ToString());

            string Query = string.Format(@"-y -f concat -fflags +genpts -async 1 -safe 0 -i ""{0}"" -c copy ""{1}""", TempFile, destination);

            IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options, callback);

            Result = Worker.RunFFmpeg(Query.ToString());

            fileSystem.Delete(TempFile);
            return(Result);
        }
示例#2
0
        /// <summary>
        /// Returns the version information from FFmpeg.
        /// </summary>
        /// <param name="options">The options for starting the process.</param>
        /// <param name="callback">A method that will be called after the process has been started.</param>
        /// <returns>A IFFmpegProcess object containing the version information.</returns>
        public IProcessManagerFFmpeg GetVersion(ProcessOptionsFFmpeg options = null, ProcessStartedEventHandler callback = null)
        {
            IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options, callback);

            Worker.OutputType = ProcessOutput.Output;
            Worker.RunFFmpeg("-version");
            return(Worker);
        }
示例#3
0
        public void GetVersion_Valid_ReturnsProcessManager()
        {
            var Info = SetupInfo();

            IProcessManagerFFmpeg Result = Info.GetVersion();

            AssertSingleInstance();
        }
示例#4
0
        public void GetVersion_ParamCallback_CallbackCalled()
        {
            var Info           = SetupInfo();
            int CallbackCalled = 0;

            IProcessManagerFFmpeg Result = Info.GetVersion(null, (s, e) => CallbackCalled++);

            Assert.Equal(1, CallbackCalled);
        }
示例#5
0
        /// <summary>
        /// Gets file streams information of specified file via FFmpeg.
        /// </summary>
        /// <param name="source">The file to get information about.</param>
        /// <param name="options">The options for starting the process.</param>
        /// <param name="callback">A method that will be called after the process has been started.</param>
        /// <returns>A IFFmpegProcess object containing the file information.</returns>
        public IProcessManagerFFmpeg GetFileInfo(string source, ProcessOptionsFFmpeg options = null, ProcessStartedEventHandler callback = null)
        {
            if (string.IsNullOrEmpty(source))
            {
                throw new ArgumentException("Source cannot be null or empty.", nameof(source));
            }
            IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options, callback);

            Worker.RunFFmpeg(string.Format(@"-i ""{0}""", source));
            return(Worker);
        }
示例#6
0
        /// <summary>
        /// Returns the exact frame count of specified video file.
        /// </summary>
        /// <param name="source">The file to get information about.</param>
        /// <param name="options">The options for starting the process.</param>
        /// <param name="callback">A method that will be called after the process has been started.</param>
        /// <returns>The number of frames in the video.</returns>
        public long GetFrameCount(string source, ProcessOptionsFFmpeg options = null, ProcessStartedEventHandler callback = null)
        {
            if (string.IsNullOrEmpty(source))
            {
                throw new ArgumentException("Source cannot be null or empty.", nameof(source));
            }
            long Result = 0;
            IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options, callback);

            Worker.StatusUpdated += (sender, e) => {
                Result = e.Status.Frame;
            };
            Worker.RunFFmpeg(string.Format(@"-i ""{0}"" -f null /dev/null", source));
            return(Result);
        }
示例#7
0
        /// <summary>
        /// Extracts an audio or video stream from specified file.
        /// </summary>
        /// <param name="args">The arguments string that will be passed to FFmpeg.</param>
        /// <param name="source">The media file to extract from.</param>
        /// <param name="destination">The destination file.</param>
        /// <param name="options">The options for starting the process.</param>
        /// <param name="callback">A method that will be called after the process has been started.</param>
        /// <returns>The process completion status.</returns>
        private CompletionStatus ExtractStream(string args, string source, string destination, ProcessOptionsFFmpeg options = null, ProcessStartedEventHandler callback = null)
        {
            if (string.IsNullOrEmpty(source))
            {
                throw new ArgumentException("Source cannot be empty.", nameof(source));
            }
            if (string.IsNullOrEmpty(destination))
            {
                throw new ArgumentException("Destination cannot be empty.", nameof(destination));
            }
            fileSystem.Delete(destination);
            IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options, callback);

            return(Worker.RunFFmpeg(string.Format(args, source, destination)));
        }
示例#8
0
        /// <summary>
        /// Truncates a media file from specified start position with specified duration.
        /// </summary>
        /// <param name="source">The source file to truncate.</param>
        /// <param name="destination">The output file to write.</param>
        /// <param name="startPos">The position where to start copying. Anything before this position will be ignored. TimeSpan.Zero or null to start from beginning.</param>
        /// <param name="duration">The duration after which to stop copying. Anything after this duration will be ignored. TimeSpan.Zero or null to copy until the end.</param>
        /// <param name="options">The options for starting the process.</param>
        /// <param name="callback">A method that will be called after the process has been started.</param>
        /// <returns>The process completion status.</returns>
        public CompletionStatus Truncate(string source, string destination, TimeSpan?startPos, TimeSpan?duration = null, ProcessOptionsFFmpeg options = null, ProcessStartedEventHandler callback = null)
        {
            if (string.IsNullOrEmpty(source))
            {
                throw new ArgumentException("Source cannot be empty.", nameof(source));
            }
            if (string.IsNullOrEmpty(destination))
            {
                throw new ArgumentException("Destination cannot be empty.", nameof(destination));
            }
            fileSystem.Delete(destination);
            IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options, callback);
            string Args = string.Format(@"-i ""{0}"" -vcodec copy -acodec copy {1}{2}""{3}""", source,
                                        startPos.HasValue && startPos > TimeSpan.Zero ? string.Format("-ss {0:c} ", startPos) : "",
                                        duration.HasValue && duration > TimeSpan.Zero ? string.Format("-t {0:c} ", duration) : "",
                                        destination);

            return(Worker.RunFFmpeg(Args));
        }
示例#9
0
        /// <summary>
        /// Returns stream information as FFmpegStream about specified media file that can be used to call a muxing operation.
        /// </summary>
        /// <param name="path">The path of the media file to query.</param>
        /// <param name="streamType">The type of media stream to query.</param>
        /// <param name="options">The options for starting the process.</param>
        /// <returns>A FFmpegStream object.</returns>
        private FFmpegStream GetStreamInfo(string path, FFmpegStreamType streamType, ProcessOptionsFFmpeg options)
        {
            IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options);

            Worker.RunFFmpeg(string.Format(@"-i ""{0}""", path));
            FFmpegStreamInfo StreamInfo = Worker.FileStreams?.FirstOrDefault(x => x.StreamType == streamType);

            if (StreamInfo != null)
            {
                return(new FFmpegStream()
                {
                    Path = path,
                    Index = StreamInfo.Index,
                    Format = StreamInfo.Format,
                    Type = streamType
                });
            }
            else
            {
                return(null);
            }
        }
示例#10
0
 public void DisplayTask(IProcessManager taskArg)
 {
     Dispatcher.Invoke(() => {
         if (taskArg.Options.IsMainTask)
         {
             host       = taskArg;
             hostFFmpeg = host as IProcessManagerFFmpeg;
             if (hostFFmpeg != null)
             {
                 hostFFmpeg.InfoUpdated   += FFmpeg_InfoUpdated;
                 hostFFmpeg.StatusUpdated += FFmpeg_StatusUpdated;
             }
             host.ProcessCompleted += FFmpeg_Completed;
             PercentText.Text       = 0.ToString("p1");
             SetPageTitle(PercentText.Text);
         }
         else
         {
             task = taskArg;
             TaskStatusText.Text    = task.Options.Title;
             task.ProcessCompleted += (sender, e) => {
                 ProcessManager Proc = (ProcessManager)sender;
                 Dispatcher.Invoke(() => {
                     if (e.Status == CompletionStatus.Failed && !Proc.WorkProcess.StartInfo.FileName.EndsWith("avs2yuv.exe"))
                     {
                         FFmpegErrorWindow.Instance(Owner, Proc);
                     }
                     TaskStatusText.Text = "";
                     task = null;
                     if (autoClose)
                     {
                         this.Close();
                     }
                 });
             };
         }
     });
 }
示例#11
0
        /// <summary>
        /// Encodes a media file with specified arguments.
        /// </summary>
        /// <param name="source">The file to convert.</param>
        /// <param name="videoCodec">The codec(s) to use to encode the video stream(s).</param>
        /// <param name="audioCodec">The codec(s) to use to encode the audio stream(s).</param>
        /// <param name="encodeArgs">Additional arguments to pass to FFmpeg.</param>
        /// <param name="destination">The destination file.</param>
        /// <param name="options">The options for starting the process.</param>
        /// <param name="callback">A method that will be called after the process has been started.</param>
        /// <returns>The process completion status.</returns>
        public CompletionStatus Encode(string source, string[] videoCodec, string[] audioCodec, string encodeArgs, string destination, ProcessOptionsFFmpeg options = null, ProcessStartedEventHandler callback = null)
        {
            File.Delete(destination);
            StringBuilder Query = new StringBuilder();

            Query.Append("-y -i ");
            // AviSynth source will pipe through Avs2Yuv into FFmpeg.
            bool SourceAvisynth = source.ToLower().EndsWith(".avs");

            if (SourceAvisynth)
            {
                Query.Append("-"); // Pipe source
            }
            else
            {
                Query.Append("\"");
                Query.Append(source);
                Query.Append("\"");
            }

            // Add video codec.
            if (videoCodec == null || videoCodec.Length == 0)
            {
                Query.Append(" -vn");
            }
            else if (videoCodec.Length == 1)
            {
                Query.Append(" -vcodec ");
                Query.Append(videoCodec[0]);
            }
            else
            {
                for (int i = 0; i < videoCodec.Length; i++)
                {
                    Query.Append(" -vcodec:");
                    Query.Append(i);
                    Query.Append(" ");
                    Query.Append(videoCodec[i]);
                }
            }

            // Add audio codec.
            if (audioCodec == null || audioCodec.Length == 0)
            {
                Query.Append(" -an");
            }
            else if (audioCodec.Length == 1)
            {
                Query.Append(" -acodec ");
                Query.Append(audioCodec[0]);
            }
            else
            {
                for (int i = 0; i < audioCodec.Length; i++)
                {
                    Query.Append(" -acodec:");
                    Query.Append(i);
                    Query.Append(" ");
                    Query.Append(audioCodec[i]);
                }
            }

            if (!string.IsNullOrEmpty(encodeArgs))
            {
                Query.Append(" ");
                Query.Append(encodeArgs);
            }

            Query.Append(" \"");
            Query.Append(destination);
            Query.Append("\"");

            // Run FFmpeg with query.
            IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options, callback);
            CompletionStatus      Result = SourceAvisynth ?
                                           Worker.RunAvisynthToEncoder(source, Query.ToString()) :
                                           Worker.RunFFmpeg(Query.ToString());

            return(Result);
        }
示例#12
0
        /// <summary>
        /// Merges the specified list of file streams.
        /// </summary>
        /// <param name="fileStreams">The list of file streams to include in the output.</param>
        /// <param name="destination">The destination file.</param>
        /// <param name="options">The options for starting the process.</param>
        /// <param name="callback">A method that will be called after the process has been started.</param>
        /// <returns>The process completion status.</returns>
        public CompletionStatus Muxe(IEnumerable <FFmpegStream> fileStreams, string destination, ProcessOptionsFFmpeg options = null, ProcessStartedEventHandler callback = null)
        {
            if (fileStreams == null || !fileStreams.Any())
            {
                throw new ArgumentException("FileStreams cannot be null or empty.", nameof(fileStreams));
            }
            if (string.IsNullOrEmpty(destination))
            {
                throw new ArgumentException("Destination cannot be null or empty.", nameof(destination));
            }

            CompletionStatus Result    = CompletionStatus.Success;
            List <string>    TempFiles = new List <string>();

            fileSystem.Delete(destination);

            // FFMPEG fails to muxe H264 into MKV container. Converting to MP4 and then muxing with the audio, however, works.
            foreach (FFmpegStream item in fileStreams)
            {
                if (string.IsNullOrEmpty(item.Path) && item.Type != FFmpegStreamType.None)
                {
                    throw new ArgumentException("FFmpegStream.Path cannot be null or empty.", nameof(item.Path));
                }
                if (item.Type == FFmpegStreamType.Video && (item.Format == "h264" || item.Format == "h265") && destination.EndsWith(".mkv"))
                {
                    string NewFile = item.Path.Substring(0, item.Path.LastIndexOf('.')) + ".mp4";
                    Result = Muxe(new List <FFmpegStream>()
                    {
                        item
                    }, NewFile, options);
                    TempFiles.Add(NewFile);
                    if (Result != CompletionStatus.Success)
                    {
                        break;
                    }
                }
            }

            if (Result == CompletionStatus.Success)
            {
                // Join audio and video files.
                StringBuilder Query = new StringBuilder();
                StringBuilder Map   = new StringBuilder();
                Query.Append("-y ");
                int           StreamIndex = 0;
                bool          HasVideo = false, HasAudio = false, HasPcmDvdAudio = false;
                StringBuilder AacFix             = new StringBuilder();
                var           FileStreamsOrdered = fileStreams.OrderBy(f => f.Type);
                foreach (FFmpegStream item in FileStreamsOrdered)
                {
                    if (item.Type == FFmpegStreamType.Video)
                    {
                        HasVideo = true;
                    }
                    if (item.Type == FFmpegStreamType.Audio)
                    {
                        HasAudio = true;
                        if (item.Format == "aac")
                        {
                            AacFix.AppendFormat("-bsf:{0} aac_adtstoasc ", StreamIndex);
                        }
                        if (item.Format == "pcm_dvd")
                        {
                            HasPcmDvdAudio = true;
                        }
                    }
                    Query.Append("-i \"");
                    Query.Append(item.Path);
                    Query.Append("\" ");
                    Map.Append("-map ");
                    Map.Append(StreamIndex++);
                    Map.Append(":");
                    Map.Append(item.Index);
                    Map.Append(" ");
                }
                if (!HasVideo && !HasAudio)
                {
                    throw new ArgumentException("FileStreams cannot be empty.", nameof(fileStreams));
                }
                if (HasVideo)
                {
                    Query.Append("-vcodec copy ");
                }
                if (HasAudio)
                {
                    Query.Append(HasPcmDvdAudio ? "-acodec pcm_s16le " : "-acodec copy ");
                }
                Query.Append(Map);
                // FFMPEG-encoded AAC streams are invalid and require an extra flag to join.
                if (AacFix.Length > 0 && HasVideo)
                {
                    Query.Append(AacFix);
                }
                Query.Append("\"");
                Query.Append(destination);
                Query.Append("\"");
                IProcessManagerFFmpeg Worker = factory.CreateFFmpeg(options, callback);
                Result = Worker.RunFFmpeg(Query.ToString());
            }

            // Delete temp file.
            foreach (string item in TempFiles)
            {
                fileSystem.Delete(item);
            }
            return(Result);
        }