Exemple #1
0
        private async void ButtonOpen_Click(object sender, RoutedEventArgs e)
        {
            if (String.IsNullOrEmpty(textBoxURL.Text))
            {
                return;
            }

            buttonOpen.IsEnabled = false;
            if (buttonOpen.Content.ToString() == "Open URL")
            {
                string url = textBoxURL.Text;
                if (url.StartsWith("http"))
                {
                    if (!url.Contains("reddit") && !url.Contains("youtu") && !url.Contains("twitter") && !url.Contains("facebook") && !url.Contains("instagram"))
                    {
                        labelTitle.Content = "Opening network stream...";
                        try
                        {
                            MediaStream = await MediaInfo.Open(url);
                        }
                        catch (Exception)
                        {
                            new MessageBoxWindow("Failed to open media from the url\n" + url, "Error opening url").ShowDialog();
                            MediaStream = null;
                        }
                        Close();
                    }
                    else
                    {
                        VideoUrlParser videoUrlParser = null;

                        if (url.Contains("reddit"))
                        {
                            host = "Reddit";
                            labelTitle.Content = "Fetching Reddit post info...";
                            videoUrlParser     = new RedditParser();
                        }
                        else if (url.Contains("youtu"))
                        {
                            host = "Youtube";
                            labelTitle.Content = "Fetching Youtube video info...";
                            videoUrlParser     = new YouTubeParser();
                        }
                        else if (url.Contains("twitter"))
                        {
                            host = "Twitter";
                            labelTitle.Content = "Fetching Twitter status info...";
                            videoUrlParser     = new TwitterParser();
                            comboBoxAudioQuality.Visibility  = Visibility.Hidden;
                            textBlockAudioQuality.Visibility = Visibility.Hidden;
                        }
                        else if (url.Contains("facebook"))
                        {
                            host = "Facebook";
                            labelTitle.Content = "Fetching Facebook post info...";
                            videoUrlParser     = new FacebookParser();
                            comboBoxAudioQuality.Visibility  = Visibility.Hidden;
                            textBlockAudioQuality.Visibility = Visibility.Hidden;
                        }
                        else if (url.Contains("instagram"))
                        {
                            host = "Instagram";
                            labelTitle.Content = "Fetching Instagram post info...";
                            videoUrlParser     = new InstagramParser();
                        }

                        try
                        {
                            foreach (var item in await videoUrlParser.GetVideoList(url))
                            {
                                if (!item.IsAudio)
                                {
                                    comboBoxQuality.Items.Add(item);
                                }
                                else
                                {
                                    comboBoxAudioQuality.Items.Add(item);
                                }
                                labelTitle.Content = item.Title;
                            }
                        }
                        catch (Exception)
                        {
                            new MessageBoxWindow("Failed to retreive media info from the url\n" + url, "Error parsing url").ShowDialog();
                            buttonOpen.IsEnabled = true;
                            return;
                        }

                        comboBoxAudioQuality.Items.Add("[No Audio]");
                        comboBoxQuality.SelectedIndex      = 0;
                        comboBoxAudioQuality.SelectedIndex = 0;
                        buttonOpen.Content = "Open selected quality";
                        if (comboBoxQuality.Items.Count == 1 && comboBoxAudioQuality.Items.Count == 1) //Only one option -> automatically select that option
                        {
                            ButtonOpen_Click(null, null);
                        }
                        else
                        {
                            buttonOpen.IsEnabled = true;
                            Storyboard storyboard = FindResource("ChoseQualityAnimation") as Storyboard;
                            storyboard.Begin();
                        }
                    }
                }
            }
            else
            {
                buttonOpen.IsEnabled = false;
                labelTitle.Content   = $"Loading {host} video...";
                StreamInfo selectedVideo = (StreamInfo)comboBoxQuality.SelectedItem;
                MediaStream = await MediaInfo.Open(selectedVideo.Url);

                if (comboBoxAudioQuality.SelectedItem.ToString() != "[No Audio]")
                {
                    StreamInfo selectedAudio = (StreamInfo)comboBoxAudioQuality.SelectedItem;
                    MediaStream.AudioSource = selectedAudio.Url;
                    MediaStream.AudioCodec  = selectedAudio.Codec;
                }
                MediaStream.Title = selectedVideo.Title;
                Close();
            }
        }
Exemple #2
0
        public async void Convert(MediaInfo sourceInfo, string destination, ConversionOptions conversionOptions)
        {
            progressData           = new ProgressData();
            progressData.IsFastCut = false;
            if (conversionOptions.End != TimeSpan.Zero)
            {
                progressData.TotalTime = conversionOptions.End - conversionOptions.Start;
            }
            else
            {
                progressData.TotalTime = sourceInfo.Duration - conversionOptions.Start;
            }

            string filters = "";

            if (conversionOptions.Resolution.HasValue() && conversionOptions.CropData.HasValue())
            {
                filters = $" -vf \"scale={conversionOptions.Resolution.Width}:{conversionOptions.Resolution.Height}," +
                          $" crop=in_w-{conversionOptions.CropData.Left + conversionOptions.CropData.Right}:in_h-{conversionOptions.CropData.Top + conversionOptions.CropData.Bottom}:{conversionOptions.CropData.Left}:{conversionOptions.CropData.Top}\"";
            }
            else if (conversionOptions.Resolution.HasValue())
            {
                filters = $" -vf \"scale={conversionOptions.Resolution.Width}:{conversionOptions.Resolution.Height}\"";
            }
            else if (conversionOptions.CropData.HasValue())
            {
                filters = $" -vf \"crop=in_w-{conversionOptions.CropData.Left + conversionOptions.CropData.Right}:in_h-{conversionOptions.CropData.Top + conversionOptions.CropData.Bottom}:{conversionOptions.CropData.Left}:{conversionOptions.CropData.Top}\"";
            }

            StringBuilder sb = new StringBuilder("-y");

            sb.Append($" -ss {conversionOptions.Start} ");
            sb.Append($" -i \"{sourceInfo.Source}\"");
            if (!String.IsNullOrEmpty(sourceInfo.AudioSource))
            {
                sb.Append($" -i \"{sourceInfo.AudioSource}\"");
            }
            if (conversionOptions.End != TimeSpan.Zero)
            {
                sb.Append($" -t {conversionOptions.End - conversionOptions.Start}");
            }
            sb.Append(" -c:v " + (conversionOptions.Encoder == Encoder.H264 ? "libx264" : "libx265"));
            sb.Append(" -movflags faststart -preset " + PRESETS[conversionOptions.Preset]);
            sb.Append(" -crf " + conversionOptions.Crf);
            if (conversionOptions.Framerate > 0)
            {
                sb.Append(" -r" + conversionOptions.Framerate);
            }
            sb.Append(filters);
            sb.Append(conversionOptions.SkipAudio ? " -an" : " -c:a copy");
            sb.Append($" \"{destination}\" -hide_banner");

            convertProcess.StartInfo.Arguments = sb.ToString();
            convertProcess.Start();
            convertProcess.BeginErrorReadLine();

            await Task.Run(() =>
            {
                convertProcess.WaitForExit();
                errorWaitHandle.WaitOne();
            });

            convertProcess.CancelErrorRead();

            int exitCode = convertProcess.ExitCode;

            if (exitCode == 0) //conversion not aborted
            {
                ConversionCompleted?.Invoke(progressData);
            }
        }
        public async void Convert(MediaInfo sourceInfo, string outputPath, ConversionOptions conversionOptions)
        {
            progressData         = new ProgressData();
            previousProgressData = new ProgressData();

            //Capture the Synchronization Context of the caller, in order to invoke the events in its original thread
            synchronizationContext = SynchronizationContext.Current;

            //Duration
            if (conversionOptions.EncodeSections.Count > 0)
            {
                progressData.TotalTime = conversionOptions.EncodeSections.TotalDuration;
            }
            else
            {
                progressData.TotalTime = sourceInfo.Duration;
            }

            progressData.EncodingMode = conversionOptions.EncodingMode;
            partialProgress           = false;

            //2-pass mode
            if (conversionOptions.EncodingMode == EncodingMode.AverageBitrate_FirstPass)
            {
                await RunConversionProcess(BuildArgumentsString(sourceInfo, outputPath, conversionOptions), false).ConfigureAwait(false);

                if (!stopped)
                {
                    progressData.EncodingMode      = EncodingMode.AverageBitrate_SecondPass;
                    conversionOptions.EncodingMode = EncodingMode.AverageBitrate_SecondPass;
                    await RunConversionProcess(BuildArgumentsString(sourceInfo, outputPath, conversionOptions)).ConfigureAwait(false);
                }
                //Remove 2pass log files
                foreach (var file in Directory.GetFiles(Environment.CurrentDirectory).Where(x => x.Contains("log")))
                {
                    File.Delete(file);
                }
            }
            //Single pass mode
            else
            {
                if (conversionOptions.EncodeSections.Count == 0)
                {
                    await RunConversionProcess(BuildArgumentsString(sourceInfo, outputPath, conversionOptions)).ConfigureAwait(false);
                }
                else if (conversionOptions.EncodeSections.Count == 1)
                {
                    await RunConversionProcess(BuildArgumentsString(sourceInfo, outputPath, conversionOptions, conversionOptions.EncodeSections.ActualStart, conversionOptions.EncodeSections.ActualEnd, conversionOptions.FadeEffect, conversionOptions.FadeEffect)).ConfigureAwait(false);
                }
                else
                {
                    partialProgress = true;
                    string outputDirectory = Path.GetDirectoryName(outputPath);
                    string outputFileName  = Path.GetFileNameWithoutExtension(outputPath);
                    for (int i = 0; i < conversionOptions.EncodeSections.Count; i++)
                    {
                        bool   fadeStart   = conversionOptions.FadeEffect && i != 0;
                        bool   fadeEnd     = conversionOptions.FadeEffect && i < conversionOptions.EncodeSections.Count - 1;
                        string destination = $"{outputDirectory}\\{outputFileName}_part_{i}.mp4";
                        string arguments   = BuildArgumentsString(sourceInfo, destination, conversionOptions, conversionOptions.EncodeSections[i].Start, conversionOptions.EncodeSections[i].End, fadeStart, fadeEnd);
                        await RunConversionProcess(arguments, false).ConfigureAwait(false);

                        if (stopped)
                        {
                            break;
                        }
                        previousProgressData = progressData;
                        File.AppendAllText("concat.txt", $"file '{destination}'\n");
                    }
                    if (!stopped)
                    {
                        await RunConversionProcess($"-y -f concat -safe 0 -i concat.txt -c copy \"{outputPath}\"", false).ConfigureAwait(false);
                    }
                    File.Delete("concat.txt");
                    for (int i = 0; i < conversionOptions.EncodeSections.Count; i++)
                    {
                        File.Delete($"{outputDirectory}\\{outputFileName}_part_{i}.mp4");
                    }
                    if (!stopped)
                    {
                        synchronizationContext.Post(new SendOrPostCallback((o) =>
                        {
                            ConversionCompleted?.Invoke(progressData);
                        }), null);
                    }
                }
            }
        }
        private async void ButtonOpen_Click(object sender, RoutedEventArgs e)
        {
            if (String.IsNullOrEmpty(textBoxURL.Text))
            {
                return;
            }

            buttonOpen.IsEnabled = false;
            if (buttonOpen.Content.ToString() == "Open URL")
            {
                string url = textBoxURL.Text;
                if (url.StartsWith("http"))
                {
                    if (!url.Contains("reddit") && !url.Contains("youtu") && !url.Contains("twitter") && !url.Contains("facebook") && !url.Contains("instagram"))
                    {
                        labelTitle.Content = "Opening network stream...";
                        try
                        {
                            MediaStream = await MediaInfo.Open(url);
                        }
                        catch (Exception)
                        {
                            new MessageBoxWindow("Failed to open media from the url\n" + url, "Error opening url").ShowDialog();
                            MediaStream = null;
                        }
                        Close();
                    }
                    else
                    {
                        VideoUrlParser videoUrlParser = null;

                        if (url.Contains("reddit"))
                        {
                            host = "Reddit";
                            labelTitle.Content = "Fetching Reddit post info...";
                            videoUrlParser     = new RedditParser();
                        }
                        else if (url.Contains("youtu"))
                        {
                            host = "Youtube";
                            labelTitle.Content = "Fetching Youtube video info...";
                            videoUrlParser     = new YouTubeParser();
                        }
                        else if (url.Contains("twitter"))
                        {
                            host = "Twitter";
                            labelTitle.Content = "Fetching Twitter status info...";
                            videoUrlParser     = new TwitterParser();
                            comboBoxAudioQuality.Visibility  = Visibility.Hidden;
                            textBlockAudioQuality.Visibility = Visibility.Hidden;
                        }
                        else if (url.Contains("facebook"))
                        {
                            host = "Facebook";
                            labelTitle.Content = "Fetching Facebook post info...";
                            videoUrlParser     = new FacebookParser();
                            comboBoxAudioQuality.Visibility  = Visibility.Hidden;
                            textBlockAudioQuality.Visibility = Visibility.Hidden;
                        }
                        else if (url.Contains("instagram"))
                        {
                            host = "Instagram";
                            labelTitle.Content = "Fetching Instagram post info...";
                            videoUrlParser     = new InstagramParser();
                        }

                        try
                        {
                            foreach (var item in await videoUrlParser.GetVideoList(url))
                            {
                                if (!item.IsAudio)
                                {
                                    comboBoxQuality.Items.Add(item);
                                }
                                else
                                {
                                    comboBoxAudioQuality.Items.Add(item);
                                }
                                labelTitle.Content = item.Title;
                            }
                            if (videoUrlParser is YouTubeParser)
                            {
                                PlayerSource = await((YouTubeParser)videoUrlParser).GetMuxedSource(url);
                            }
                        }
                        catch (Exception)
                        {
                            new MessageBoxWindow("Failed to retreive media info from the url\n" + url, "Error parsing url").ShowDialog();
                            buttonOpen.IsEnabled = true;
                            return;
                        }

                        comboBoxQuality.SelectedIndex = 0;
                        if (comboBoxAudioQuality.Items.Count > 0)
                        {
                            comboBoxAudioQuality.SelectedIndex = 0;
                            comboBoxAudioQuality.Visibility    = Visibility.Visible;
                        }
                        else
                        {
                            comboBoxAudioQuality.Visibility = Visibility.Hidden;
                        }
                        buttonOpen.Content = "Open selected quality";
                        if (comboBoxQuality.Items.Count == 1 && comboBoxAudioQuality.Items.Count == 1) //Only one option -> automatically select that option
                        {
                            ButtonOpen_Click(null, null);
                        }
                        else
                        {
                            buttonOpen.IsEnabled = true;
                            Storyboard storyboard = FindResource("ChoseQualityAnimation") as Storyboard;
                            storyboard.Begin();
                        }
                    }
                }
                else
                {
                    new MessageBoxWindow("Enter a valid url", "FF Video Converter").ShowDialog();
                }
            }
            else
            {
                buttonOpen.IsEnabled = false;
                labelTitle.Content   = $"Loading {host} video...";
                StreamInfo selectedVideo = (StreamInfo)comboBoxQuality.SelectedItem;
                try
                {
                    if (comboBoxAudioQuality.Items.Count > 0)
                    {
                        StreamInfo selectedAudio = (StreamInfo)comboBoxAudioQuality.SelectedItem;
                        MediaStream = await MediaInfo.Open(selectedVideo.Url, selectedAudio.Url);

                        //new MessageBoxWindow("The audio stream relative to this video is separate, therefore the integrated player will play the video without audio.\nWhen converting or downloading this video however, audio and video will be muxed toghether", "Info").ShowDialog();
                    }
                    else
                    {
                        PlayerSource = null;
                        MediaStream  = await MediaInfo.Open(selectedVideo.Url);
                    }
                }
                catch (Exception ex)
                {
                    new MessageBoxWindow(ex.Message, "Error opening selected url").ShowDialog();
                    Close();
                    return;
                }
                MediaStream.Title = selectedVideo.Title;
                Close();
            }
        }
 public string BuildArgumentsString(MediaInfo sourceInfo, string destination, ConversionOptions conversionOptions)
 {
     return(BuildArgumentsString(sourceInfo, destination, conversionOptions, TimeSpan.Zero, TimeSpan.Zero));
 }
        public string BuildArgumentsString(MediaInfo sourceInfo, string destination, ConversionOptions conversionOptions, TimeSpan start, TimeSpan end, bool fadeStart = false, bool fadeEnd = false)
        {
            StringBuilder sb           = new StringBuilder("-y -progress -");
            bool          changeVolume = false;

            //Start time
            if (start != TimeSpan.Zero)
            {
                sb.Append($" -ss {start}");
            }

            //Input path
            sb.Append($" -i \"{sourceInfo.Source}\"");

            //External audio source
            if (sourceInfo.HasExternalAudio && conversionOptions.EncodingMode != EncodingMode.AverageBitrate_FirstPass)
            {
                if (start != TimeSpan.Zero)
                {
                    sb.Append($" -ss {start}");
                }
                sb.Append($" -i \"{sourceInfo.ExternalAudioSource}\"");
            }

            //Duration
            if (end != TimeSpan.Zero)
            {
                sb.Append($" -t {end - start}");
            }

            //Main video track
            sb.Append($" -map 0:v:0");

            //Add or skip audio tracks
            if (!conversionOptions.SkipAudio && conversionOptions.EncodingMode != EncodingMode.AverageBitrate_FirstPass)
            {
                foreach (var audioTrack in sourceInfo.AudioTracks)
                {
                    if (audioTrack.Enabled)
                    {
                        sb.Append($" -map {(sourceInfo.HasExternalAudio ? "1" : "0")}:{audioTrack.StreamIndex}");
                        sb.Append($" -disposition:{audioTrack.StreamIndex} {(audioTrack.Default ? "default" : "none")}");
                    }
                    if (audioTrack.Volume != 100)
                    {
                        changeVolume = true;
                    }
                }
            }

            //Subtitles
            sb.Append(" -map 0:s?");

            //Encoder command line
            sb.Append(" -movflags faststart -c:v " + conversionOptions.Encoder.GetFFMpegCommand(conversionOptions.EncodingMode));

            //Framerate and filters
            if (conversionOptions.EncodingMode != EncodingMode.AverageBitrate_FirstPass)
            {
                if (conversionOptions.Framerate > 0)
                {
                    sb.Append(" -r " + conversionOptions.Framerate);
                }

                //Video filters
                if (conversionOptions.Resolution.HasValue() || conversionOptions.CropData.HasValue() || conversionOptions.Rotation.HasValue() || fadeStart || fadeEnd)
                {
                    string fadeStartFilter = fadeStart ? "fade=t=in:d=0.5" : "";
                    string fadeEndFilter   = fadeEnd ? $"fade=t=out:d=0.5:st={(end.TotalSeconds - start.TotalSeconds - 0.5).ToString(CultureInfo.InvariantCulture)}" : "";
                    sb.Append(" -vf " + ConcatFilters(conversionOptions.Resolution.FilterString, conversionOptions.CropData.FilterString, conversionOptions.Rotation.FilterString, fadeStartFilter, fadeEndFilter));
                }
                //Audio filters
                if (changeVolume)
                {
                    var volumeFilters = sourceInfo.AudioTracks.Where(x => x.Volume != 100).Select(x => "volume=" + (x.Volume / 100).ToString("0.##", CultureInfo.InvariantCulture));
                    sb.Append(" -af " + ConcatFilters(volumeFilters.ToArray()));
                }
            }

            //Audio encoder
            if (conversionOptions.SkipAudio || conversionOptions.EncodingMode == EncodingMode.AverageBitrate_FirstPass)
            {
                sb.Append(" -an");
            }
            else if (changeVolume)
            {
                sb.Append($" -c:a aac -b:a 192k");
            }
            else
            {
                sb.Append(" -c:a copy");
            }

            //When cutting without encoding, this flag allows to cut at the nearest keyframe before the start position; without this flag audio would be cut at the start position, but video would start playing only after the next keyframe
            if (conversionOptions.Encoder is NativeEncoder)
            {
                sb.Append($" -avoid_negative_ts make_zero");
            }

            //Output path
            if (conversionOptions.EncodingMode != EncodingMode.AverageBitrate_FirstPass)
            {
                sb.Append($" \"{destination}\" -hide_banner");
            }
            else
            {
                sb.Append($" -f null NUL -hide_banner");
            }

            return(sb.ToString());
        }
Exemple #7
0
        private async void ButtonOpen_Click(object sender, RoutedEventArgs e)
        {
            if (String.IsNullOrEmpty(textBoxURL.Text))
            {
                return;
            }

            buttonOpen.IsEnabled = false;
            if (buttonOpen.Content.ToString() == "Open URL")
            {
                string url = textBoxURL.Text;
                if (url.StartsWith("http"))
                {
                    if (!url.Contains("reddit") && !url.Contains("youtu") && !url.Contains("twitter") && !url.Contains("facebook") && !url.Contains("instagram"))
                    {
                        titleBar.Text = "Opening network stream...";
                        try
                        {
                            MediaStream = await MediaInfo.Open(url);
                        }
                        catch (Exception)
                        {
                            new MessageBoxWindow("Failed to open media from the url\n" + url, "Error opening url").ShowDialog();
                            MediaStream = null;
                        }
                        Close();
                    }
                    else
                    {
                        VideoUrlParser videoUrlParser = null;

                        if (url.Contains("reddit"))
                        {
                            host           = "Reddit";
                            titleBar.Text  = "Fetching Reddit post info...";
                            videoUrlParser = new RedditParser();
                        }
                        else if (url.Contains("youtu"))
                        {
                            host           = "Youtube";
                            titleBar.Text  = "Fetching Youtube video info...";
                            videoUrlParser = new YouTubeParser();
                        }
                        else if (url.Contains("twitter"))
                        {
                            host           = "Twitter";
                            titleBar.Text  = "Fetching Twitter status info...";
                            videoUrlParser = new TwitterParser();
                            comboBoxAudioQuality.Visibility  = Visibility.Hidden;
                            textBlockAudioQuality.Visibility = Visibility.Hidden;
                        }
                        else if (url.Contains("facebook"))
                        {
                            host           = "Facebook";
                            titleBar.Text  = "Fetching Facebook post info...";
                            videoUrlParser = new FacebookParser();
                            comboBoxAudioQuality.Visibility  = Visibility.Hidden;
                            textBlockAudioQuality.Visibility = Visibility.Hidden;
                        }
                        else if (url.Contains("instagram"))
                        {
                            host           = "Instagram";
                            titleBar.Text  = "Fetching Instagram post info...";
                            videoUrlParser = new InstagramParser();
                        }

                        GetVideoList(videoUrlParser, url);
                    }
                }
                else
                {
                    new MessageBoxWindow("Enter a valid url", "FF Video Converter").ShowDialog();
                }
            }
            else
            {
                OpenVideo((StreamInfo)comboBoxQuality.SelectedItem);
            }
        }
        public async void Convert(MediaInfo sourceInfo, string destination, ConversionOptions conversionOptions)
        {
            progressData = new ProgressData();

            //Captures the Synchronization Context of the caller, in order to invoke the events on its original thread
            synchronizationContext = SynchronizationContext.Current;

            //Duration
            if (conversionOptions.End != TimeSpan.Zero)
            {
                progressData.TotalTime = conversionOptions.End - conversionOptions.Start;
            }
            else
            {
                progressData.TotalTime = sourceInfo.Duration - conversionOptions.Start;
            }

            //Filters
            string filters = "";

            if (conversionOptions.Resolution.HasValue() || conversionOptions.CropData.HasValue() || conversionOptions.Rotation.HasValue())
            {
                filters = " -vf " + ConcatFilters(conversionOptions.Resolution.FilterString, conversionOptions.CropData.FilterString, conversionOptions.Rotation.FilterString);
            }

            //Get nearest before keyframe
            var keyframes = await sourceInfo.GetNearestBeforeAndAfterKeyFrames(conversionOptions.Start.TotalSeconds).ConfigureAwait(false);

            TimeSpan startTime = TimeSpan.FromSeconds(keyframes.before);

            //FFMpeg command string
            StringBuilder sb = new StringBuilder("-y");

            sb.Append($" -ss {startTime}");
            sb.Append($" -i \"{sourceInfo.Source}\"");
            if (sourceInfo.HasExternalAudio)
            {
                sb.Append($" -ss {startTime}");
                sb.Append($" -i \"{sourceInfo.ExternalAudioSource}\"");
            }
            if (conversionOptions.End != TimeSpan.Zero)
            {
                sb.Append($" -t {conversionOptions.End - conversionOptions.Start}");
            }
            sb.Append($" -map 0:v:0");
            if (!conversionOptions.SkipAudio)
            {
                foreach (var audioTrack in sourceInfo.AudioTracks)
                {
                    if (audioTrack.Enabled)
                    {
                        sb.Append($" -map {(sourceInfo.HasExternalAudio ? "1" : "0")}:{audioTrack.StreamIndex}");
                        sb.Append($" -disposition:{audioTrack.StreamIndex} {(audioTrack.Default ? "default" : "none")}");
                    }
                }
            }
            sb.Append(" -map 0:s?");
            sb.Append(" -movflags faststart -c:v " + conversionOptions.Encoder.GetFFMpegCommand());
            if (conversionOptions.Framerate > 0)
            {
                sb.Append(" -r " + conversionOptions.Framerate);
            }
            sb.Append(filters);
            sb.Append(conversionOptions.SkipAudio ? " -an" : " -c:a copy");
            sb.Append($" -ss {conversionOptions.Start - startTime}");
            sb.Append($" -avoid_negative_ts 1 \"{destination}\" -hide_banner");

            StartConversionProcess(sb.ToString());
        }
Exemple #9
0
        public void Convert(MediaInfo sourceInfo, string outputPath, ConversionOptions conversionOptions)
        {
            progressData         = new ProgressData();
            previousProgressData = new ProgressData();
            errorLine            = "";

            // Capture the Synchronization Context of the caller, in order to invoke the events in its original thread
            synchronizationContext = SynchronizationContext.Current;

            // Duration
            if (conversionOptions.EncodeSections.Count > 0)
            {
                progressData.TotalTime = conversionOptions.EncodeSections.TotalDuration;
            }
            else
            {
                progressData.TotalTime = sourceInfo.Duration;
            }

            // Gets the total number of output frames
            Filters.FpsFilter fpsFilter = conversionOptions.Filters.FirstOrDefault(f => f is Filters.FpsFilter) as Filters.FpsFilter;
            double            outputFps = fpsFilter?.Framerate ?? sourceInfo.Framerate;

            progressData.TotalFrames = System.Convert.ToInt32(progressData.TotalTime.TotalSeconds * outputFps);

            // Get the total output file size (if using constant bitrate)
            if (conversionOptions.EncodingMode == EncodingMode.AverageBitrate_FirstPass || conversionOptions.EncodingMode == EncodingMode.AverageBitrate_SinglePass)
            {
                progressData.TotalByteSize = conversionOptions.Encoder.Bitrate.Bps / 8 * System.Convert.ToInt64(progressData.TotalTime.TotalSeconds);
                foreach (var audioTrack in sourceInfo.AudioTracks)
                {
                    if (conversionOptions.AudioConversionOptions.ContainsKey(audioTrack.StreamIndex))
                    {
                        progressData.TotalByteSize += conversionOptions.AudioConversionOptions[audioTrack.StreamIndex].Encoder.Bitrate.Bps / 8 * System.Convert.ToInt64(progressData.TotalTime.TotalSeconds);
                    }
                    else
                    {
                        progressData.TotalByteSize += audioTrack.Bitrate.Bps / 8 * System.Convert.ToInt64(progressData.TotalTime.TotalSeconds);
                    }
                }
            }

            partialProgress           = false;
            progressData.EncodingMode = conversionOptions.EncodingMode;
            stopped = false;

            // Starts the conversion task
            Task <bool> conversionTask;

            if (conversionOptions.EncodeSections.Count == 0)
            {
                conversionTask = Convert_SingleSegment(sourceInfo, outputPath, conversionOptions, TimeSpan.Zero, TimeSpan.Zero);
            }
            else if (conversionOptions.EncodeSections.Count == 1)
            {
                conversionTask = Convert_SingleSegment(sourceInfo, outputPath, conversionOptions, conversionOptions.EncodeSections.ActualStart, conversionOptions.EncodeSections.ActualEnd);
            }
            else
            {
                conversionTask = Convert_MultipleSegments(sourceInfo, outputPath, conversionOptions);
            }

            // Reports the conversion result to the original caller
            conversionTask.ContinueWith(result => ReportCompletition(result.Result));
        }
Exemple #10
0
        private string BuildArgumentsString(MediaInfo sourceInfo, string destination, ConversionOptions conversionOptions, TimeSpan start, TimeSpan end, string twopasslogfile = "", bool fadeStart = false, bool fadeEnd = false)
        {
            StringBuilder sb = new StringBuilder("-y -progress -");

            // Start time
            if (start != TimeSpan.Zero)
            {
                sb.Append($" -ss {start}");
            }

            // Input path
            sb.Append($" -i \"{sourceInfo.Source}\"");

            // Duration
            if (end != TimeSpan.Zero)
            {
                sb.Append($" -t {end - start}");
            }

            // External audio source
            if (sourceInfo.HasExternalAudio && !conversionOptions.NoAudio && conversionOptions.EncodingMode != EncodingMode.AverageBitrate_FirstPass)
            {
                if (start != TimeSpan.Zero)
                {
                    sb.Append($" -ss {start}");
                }
                sb.Append($" -i \"{sourceInfo.ExternalAudioSource}\"");
                if (end != TimeSpan.Zero)
                {
                    sb.Append($" -t {end - start}");
                }
            }

            // Main video track
            sb.Append($" -map 0:v:0");

            // Add or skip audio tracks
            var audioTracks = sourceInfo.AudioTracks.Where(at => at.Enabled == true).ToList();

            if (!conversionOptions.NoAudio && conversionOptions.EncodingMode != EncodingMode.AverageBitrate_FirstPass)
            {
                foreach (var audioTrack in audioTracks)
                {
                    sb.Append($" -map {(sourceInfo.HasExternalAudio ? "1" : $"0:{audioTrack.StreamIndex}")}");
                    sb.Append($" -disposition:{(sourceInfo.HasExternalAudio ? "1" : audioTrack.StreamIndex)} {(audioTrack.Default ? "default" : "none")}");
                    if (conversionOptions.AudioConversionOptions.ContainsKey(audioTrack.StreamIndex))
                    {
                        sb.Append($" -metadata:s:{(sourceInfo.HasExternalAudio ? "1" : audioTrack.StreamIndex)} title=\"{conversionOptions.AudioConversionOptions[audioTrack.StreamIndex].Title}\"");
                        sb.Append($" -metadata:s:{(sourceInfo.HasExternalAudio ? "1" : audioTrack.StreamIndex)} handler_name=\"{conversionOptions.AudioConversionOptions[audioTrack.StreamIndex].Title}\"");
                    }
                }
            }

            // Subtitles
            if (conversionOptions.EncodingMode != EncodingMode.NoEncoding)
            {
                sb.Append(" -map 0:s?");
            }

            // Filters
            if (conversionOptions.EncodingMode != EncodingMode.AverageBitrate_FirstPass)
            {
                Filtergraph filtergraph = new Filtergraph();

                // Video filters
                if (conversionOptions.Filters.Count > 0)
                {
                    filtergraph.AddFilters(conversionOptions.Filters, 0, 0);
                }
                if (fadeStart)
                {
                    filtergraph.AddFilter(new Filters.FadeFilter(Filters.FadeMode.In, 0.2), 0, 0);
                }
                if (fadeEnd)
                {
                    TimeSpan actualEnd = end != TimeSpan.Zero ? end : sourceInfo.Duration;
                    filtergraph.AddFilter(new Filters.FadeFilter(Filters.FadeMode.Out, 0.2, actualEnd.TotalSeconds - start.TotalSeconds - 0.2), 0, 0);
                }

                // Audio filters

                /* Currently disabled as it requires dedicated mapping which is not supported
                 * foreach (var item in conversionOptions.AudioConversionOptions)
                 * {
                 *  if (item.Value.Filters.Count > 0)
                 *  {
                 *      filtergraph.AddFilters(item.Value.Filters, sourceInfo.HasExternalAudio ? 1 : 0, item.Key);
                 *  }
                 * }*/

                if (filtergraph.Count > 0)
                {
                    sb.Append($" -filter_complex \"{filtergraph.GenerateFiltergraph()}\"");
                }
            }

            // Video encoder
            if (conversionOptions.EncodingMode != EncodingMode.NoEncoding)
            {
                sb.Append("  -c:v " + conversionOptions.Encoder.GetFFMpegCommand(conversionOptions.EncodingMode));
                if ((conversionOptions.EncodingMode == EncodingMode.AverageBitrate_FirstPass || conversionOptions.EncodingMode == EncodingMode.AverageBitrate_SecondPass) && twopasslogfile != "")
                {
                    sb.Append(" -passlogfile " + twopasslogfile);
                }
                // When cutting without encoding, "-avoid_negative_ts make_zero" allows to cut at the nearest keyframe before the start position
                // Without this flag audio would be cut at the start position, but video would start playing only after the next keyframe
                sb.Append(" -avoid_negative_ts make_zero");
            }

            // Audio encoders
            if (conversionOptions.NoAudio || conversionOptions.EncodingMode == EncodingMode.AverageBitrate_FirstPass)
            {
                sb.Append(" -an");
            }
            else
            {
                foreach (var audioTrack in audioTracks)
                {
                    if (conversionOptions.AudioConversionOptions.ContainsKey(audioTrack.StreamIndex))
                    {
                        AudioConversionOptions audioConversionOptions = conversionOptions.AudioConversionOptions[audioTrack.StreamIndex];
                        sb.Append($" -c:{(sourceInfo.HasExternalAudio ? "1" : audioTrack.StreamIndex)} {audioConversionOptions.Encoder.GetFFMpegCommand(sourceInfo.HasExternalAudio ? 1 : audioTrack.StreamIndex)}");
                        sb.Append($" -ac:{(sourceInfo.HasExternalAudio ? "1" : audioTrack.StreamIndex)} {audioConversionOptions.Channels}");
                    }
                    else
                    {
                        sb.Append($" -c:{(sourceInfo.HasExternalAudio ? "1" : audioTrack.StreamIndex)} copy");
                    }
                }
            }

            // MP4 specific stuff
            if (Path.GetExtension(destination) == "mp4")
            {
                // Subtitle encoder (necessary to convert mkv subtitles to mp4 format)
                sb.Append(" -c:s mov_text");
                // Moves moov atom to the beginning of the file; ignored by the mkv muxer (does it do the same thing automatically? No answer on the web...)
                sb.Append(" -movflags +faststart");
            }


            // Output path
            if (conversionOptions.EncodingMode != EncodingMode.AverageBitrate_FirstPass)
            {
                // max_muxing_queue_size is necessary to allow ffmpeg to allocate more memory to muxing, so that it's enough for very big streams
                sb.Append($" -max_muxing_queue_size 2048 \"{destination}\" -loglevel error -stats");
            }
            else
            {
                sb.Append($" -f null NUL -loglevel error -stats");
            }

#if DEBUG
            Thread thread = new Thread(() => System.Windows.Clipboard.SetText(sb.ToString()));
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            thread.Join();
#endif

            return(sb.ToString());
        }
Exemple #11
0
        private async Task <bool> Convert_MultipleSegments(MediaInfo sourceInfo, string outputPath, ConversionOptions conversionOptions)
        {
            bool success = false;

            partialProgress = true;
            string outputDirectory = Path.GetDirectoryName(outputPath);
            string outputFileName  = Path.GetFileNameWithoutExtension(outputPath);

            if (conversionOptions.EncodingMode == EncodingMode.AverageBitrate_FirstPass)
            {
                for (int i = 0; i < conversionOptions.EncodeSections.Count; i++)
                {
                    string arguments = BuildArgumentsString(sourceInfo, outputPath, conversionOptions, conversionOptions.EncodeSections[i].Start, conversionOptions.EncodeSections[i].End, "segment" + i.ToString());
                    success = await RunConversionProcess(arguments).ConfigureAwait(false);

                    if (stopped || !success)
                    {
                        return(success);
                    }
                }

                progressData.EncodingMode          = EncodingMode.AverageBitrate_SecondPass;
                conversionOptions.EncodingMode     = EncodingMode.AverageBitrate_SecondPass;
                previousProgressData.CurrentTime   = TimeSpan.Zero;
                previousProgressData.CurrentFrames = 0;
            }

            for (int i = 0; i < conversionOptions.EncodeSections.Count; i++)
            {
                bool   fadeStart   = conversionOptions.FadeEffect && i != 0;
                bool   fadeEnd     = conversionOptions.FadeEffect && i < conversionOptions.EncodeSections.Count - 1;
                string destination = $"{outputDirectory}\\{outputFileName}_part_{i}.mp4";
                string arguments   = BuildArgumentsString(sourceInfo, destination, conversionOptions, conversionOptions.EncodeSections[i].Start, conversionOptions.EncodeSections[i].End, "segment" + i.ToString(), fadeStart, fadeEnd);
                success = await RunConversionProcess(arguments).ConfigureAwait(false);

                if (stopped || !success)
                {
                    break;
                }
                File.AppendAllText("concat.txt", $"file '{destination}'\n");
            }

            // Joins all segments toghether
            if (!stopped && success)
            {
                success = await RunConversionProcess($"-y -f concat -safe 0 -i concat.txt -c copy \"{outputPath}\"").ConfigureAwait(false);

                File.Delete("concat.txt");
            }

            // Removes segments
            for (int i = 0; i < conversionOptions.EncodeSections.Count; i++)
            {
                string partName = $"{outputDirectory}\\{outputFileName}_part_{i}.mp4";
                if (File.Exists(partName))
                {
                    File.Delete(partName);
                }
            }

            // Removes 2pass log files, if they exist
            foreach (var file in Directory.GetFiles(Environment.CurrentDirectory).Where(x => x.Contains("log")))
            {
                File.Delete(file);
            }

            return(success);
        }