Esempio n. 1
0
        /// <summary>
        /// Convert video encoding speed to H264 preset.
        /// </summary>
        /// <param name="encodingSpeed">The encoding speed.</param>
        /// <returns>The H264 preset.</returns>
        private string H264EncodingSpeedToPreset(VideoEncodingSpeed encodingSpeed)
        {
            switch (encodingSpeed)
            {
            case VideoEncodingSpeed.UltraFast:
                return("ultrafast");

            case VideoEncodingSpeed.SuperFast:
                return("superfast");

            case VideoEncodingSpeed.VeryFast:
                return("veryfast");

            case VideoEncodingSpeed.Faster:
                return("faster");

            case VideoEncodingSpeed.Fast:
                return("fast");

            case VideoEncodingSpeed.Medium:
                return("medium");

            case VideoEncodingSpeed.Slow:
                return("slow");

            case VideoEncodingSpeed.Slower:
                return("slower");

            case VideoEncodingSpeed.VerySlow:
                return("veryslow");
            }

            throw new Exception("Unknown H264 encoding speed.");
        }
Esempio n. 2
0
        protected virtual void FillFFMpegArgumentsList()
        {
            // This option are necessary to be able to read metadata on Windows. src: http://jonhall.info/how_to/create_id3_tags_using_ffmpeg
            const string mp3MetadataArgs = "-id3v2_version 3 -write_id3v1 1";
            // AAC have no standard tag system, use ApeV2 (that are compatible). src: http://eolindel.free.fr/foobar/tags.shtml
            const string aacMetadataArgs = "-write_apetag 1";

            switch (this.ConversionPreset.OutputType)
            {
            case OutputType.Aac:
            {
                string channelArgs = ConversionJob_FFMPEG.ComputeAudioChannelArgs(this.ConversionPreset);

                // https://trac.ffmpeg.org/wiki/Encode/AAC
                int    audioEncodingBitrate = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.AudioBitrate);
                string encoderArgs          = $"-c:a aac -q:a {this.AACBitrateToQualityIndex(audioEncodingBitrate)} {channelArgs} {aacMetadataArgs}";

                string arguments = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Avi:
            {
                // https://trac.ffmpeg.org/wiki/Encode/MPEG-4
                int videoEncodingQuality = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.VideoQuality);
                int audioEncodingBitrate = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.AudioBitrate);

                string transformArgs = ConversionJob_FFMPEG.ComputeTransformArgs(this.ConversionPreset);

                string audioArgs = "-an";
                if (this.ConversionPreset.GetSettingsValue <bool>(ConversionPreset.ConversionSettingKeys.EnableAudio))
                {
                    audioArgs = string.Format("-c:a libmp3lame -qscale:a {0}", this.MP3VBRBitrateToQualityIndex(audioEncodingBitrate));
                }

                // Compute final arguments.
                string videoFilteringArgs = ConversionJob_FFMPEG.Encapsulate("-vf", transformArgs);
                string encoderArgs        = $"-c:v mpeg4 -vtag xvid -qscale:v {this.MPEG4QualityToQualityIndex(videoEncodingQuality)} {audioArgs} {videoFilteringArgs} {mp3MetadataArgs}";
                string arguments          = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Flac:
            {
                string channelArgs = ConversionJob_FFMPEG.ComputeAudioChannelArgs(this.ConversionPreset);

                // http://taer-naguur.blogspot.fr/2013/11/flac-audio-encoding-with-ffmpeg.html
                string encoderArgs = $"-compression_level 12 {channelArgs}";
                string arguments   = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Gif:
            {
                // http://blog.pkh.me/p/21-high-quality-gif-with-ffmpeg.html
                string fileName        = Path.GetFileName(this.InputFilePath);
                string tempPath        = Path.GetTempPath();
                string paletteFilePath = PathHelpers.GenerateUniquePath(tempPath + fileName + " - palette.png");

                string transformArgs = ConversionJob_FFMPEG.ComputeTransformArgs(this.ConversionPreset);

                // fps.
                int framesPerSecond = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.VideoFramesPerSecond);
                if (!string.IsNullOrEmpty(transformArgs))
                {
                    transformArgs += ",";
                }

                transformArgs += string.Format("fps={0}", framesPerSecond);

                // Generate palette.
                string encoderArgs = string.Format("-vf \"{0},palettegen\"", transformArgs);
                string arguments   = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, paletteFilePath, encoderArgs);
                this.ffmpegArgumentStringByPass.Add(new FFMpegPass("Indexing colors", arguments, paletteFilePath));

                // Create gif.
                encoderArgs = string.Format("-i \"{0}\" -lavfi \"{1},paletteuse\"", paletteFilePath, transformArgs);
                arguments   = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);
                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Ico:
            {
                string encoderArgs = string.Empty;
                string arguments   = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Jpg:
            {
                int encodingQuality = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.ImageQuality);

                float  scaleFactor = this.ConversionPreset.GetSettingsValue <float>(ConversionPreset.ConversionSettingKeys.ImageScale);
                string scaleArgs   = string.Empty;
                if (Math.Abs(scaleFactor - 1f) >= 0.005f)
                {
                    scaleArgs = string.Format("-vf scale=iw*{0}:ih*{0}", scaleFactor.ToString("#.##", CultureInfo.InvariantCulture));
                }

                string encoderArgs = string.Format("-q:v {0} {1}", this.JPGQualityToQualityIndex(encodingQuality), scaleArgs);

                string arguments = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Mp3:
            {
                string channelArgs = ConversionJob_FFMPEG.ComputeAudioChannelArgs(this.ConversionPreset);

                string       encoderArgs     = string.Empty;
                EncodingMode encodingMode    = this.ConversionPreset.GetSettingsValue <EncodingMode>(ConversionPreset.ConversionSettingKeys.AudioEncodingMode);
                int          encodingQuality = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.AudioBitrate);
                switch (encodingMode)
                {
                case EncodingMode.Mp3VBR:
                    encoderArgs = $"-codec:a libmp3lame -q:a {this.MP3VBRBitrateToQualityIndex(encodingQuality)} {channelArgs} {mp3MetadataArgs}";
                    break;

                case EncodingMode.Mp3CBR:
                    encoderArgs = $"-codec:a libmp3lame -b:a {encodingQuality}k {channelArgs} {mp3MetadataArgs}";
                    break;

                default:
                    break;
                }

                string arguments = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Mkv:
            case OutputType.Mp4:
            {
                // https://trac.ffmpeg.org/wiki/Encode/H.264
                // https://trac.ffmpeg.org/wiki/Encode/AAC
                int videoEncodingQuality = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.VideoQuality);
                VideoEncodingSpeed videoEncodingSpeed = this.ConversionPreset.GetSettingsValue <VideoEncodingSpeed>(ConversionPreset.ConversionSettingKeys.VideoEncodingSpeed);
                int audioEncodingBitrate = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.AudioBitrate);

                string transformArgs      = ConversionJob_FFMPEG.ComputeTransformArgs(this.ConversionPreset);
                string videoFilteringArgs = ConversionJob_FFMPEG.Encapsulate("-vf", transformArgs);

                string audioArgs = "-an";
                if (this.ConversionPreset.GetSettingsValue <bool>(ConversionPreset.ConversionSettingKeys.EnableAudio))
                {
                    audioArgs = $"-c:a aac -qscale:a {this.AACBitrateToQualityIndex(audioEncodingBitrate)}";
                }

                string encoderArgs = string.Format(
                    "-c:v libx264 -preset {0} -crf {1} {2} {3}",
                    this.H264EncodingSpeedToPreset(videoEncodingSpeed),
                    this.H264QualityToCRF(videoEncodingQuality),
                    audioArgs,
                    videoFilteringArgs);

                string arguments = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Ogg:
            {
                string channelArgs = ConversionJob_FFMPEG.ComputeAudioChannelArgs(this.ConversionPreset);

                int    encodingQuality = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.AudioBitrate);
                string encoderArgs     = $"-vn -codec:a libvorbis -qscale:a {this.OGGVBRBitrateToQualityIndex(encodingQuality)} {channelArgs}";
                string arguments       = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Ogv:
            {
                // https://trac.ffmpeg.org/wiki/TheoraVorbisEncodingGuide
                int videoEncodingQuality = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.VideoQuality);
                int audioEncodingBitrate = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.AudioBitrate);

                string transformArgs      = ConversionJob_FFMPEG.ComputeTransformArgs(this.ConversionPreset);
                string videoFilteringArgs = ConversionJob_FFMPEG.Encapsulate("-vf", transformArgs);

                string audioArgs = "-an";
                if (this.ConversionPreset.GetSettingsValue <bool>(ConversionPreset.ConversionSettingKeys.EnableAudio))
                {
                    audioArgs = $"-codec:a libvorbis -qscale:a {this.OGGVBRBitrateToQualityIndex(audioEncodingBitrate)}";
                }

                string encoderArgs = $"-codec:v libtheora -qscale:v {this.OGVTheoraQualityToQualityIndex(videoEncodingQuality)} {audioArgs} {videoFilteringArgs}";

                string arguments = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Png:
            {
                float  scaleFactor = this.ConversionPreset.GetSettingsValue <float>(ConversionPreset.ConversionSettingKeys.ImageScale);
                string scaleArgs   = string.Empty;
                if (Math.Abs(scaleFactor - 1f) >= 0.005f)
                {
                    scaleArgs = string.Format("-vf scale=iw*{0}:ih*{0}", scaleFactor.ToString("#.##", CultureInfo.InvariantCulture));
                }

                // http://www.howtogeek.com/203979/is-the-png-format-lossless-since-it-has-a-compression-parameter/
                string encoderArgs = string.Format("-compression_level 100 {0}", scaleArgs);

                string arguments = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Wav:
            {
                string channelArgs = ConversionJob_FFMPEG.ComputeAudioChannelArgs(this.ConversionPreset);

                EncodingMode encodingMode = this.ConversionPreset.GetSettingsValue <EncodingMode>(ConversionPreset.ConversionSettingKeys.AudioEncodingMode);
                string       encoderArgs  = $"-acodec {this.WAVEncodingToCodecArgument(encodingMode)} {channelArgs}";
                string       arguments    = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            case OutputType.Webm:
            {
                // https://trac.ffmpeg.org/wiki/Encode/VP9
                int videoEncodingQuality = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.VideoQuality);
                int audioEncodingQuality = this.ConversionPreset.GetSettingsValue <int>(ConversionPreset.ConversionSettingKeys.AudioBitrate);

                string encodingArgs = string.Empty;
                if (videoEncodingQuality == 63)
                {
                    // Replace maximum quality settings by lossless compression.
                    encodingArgs = $"-lossless 1";
                }
                else
                {
                    encodingArgs = $"-crf {this.WebmQualityToCRF(videoEncodingQuality)} -b:v 0";
                }

                string transformArgs      = ConversionJob_FFMPEG.ComputeTransformArgs(this.ConversionPreset);
                string videoFilteringArgs = ConversionJob_FFMPEG.Encapsulate("-vf", transformArgs);

                string audioArgs = "-an";
                if (this.ConversionPreset.GetSettingsValue <bool>(ConversionPreset.ConversionSettingKeys.EnableAudio))
                {
                    audioArgs = string.Format("-c:a libvorbis -qscale:a {0}", this.OGGVBRBitrateToQualityIndex(audioEncodingQuality));
                }

                string encoderArgs = string.Format(
                    "-c:v libvpx-vp9 {0} {1} {2}",
                    encodingArgs,
                    audioArgs,
                    videoFilteringArgs);

                string arguments = string.Format("-n -stats -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs);

                this.ffmpegArgumentStringByPass.Add(new FFMpegPass(arguments));
            }

            break;

            default:
                throw new NotImplementedException("Converter not implemented for output file type " +
                                                  this.ConversionPreset.OutputType);
            }

            if (this.ffmpegArgumentStringByPass.Count == 0)
            {
                throw new Exception("No ffmpeg arguments generated.");
            }

            for (int index = 0; index < this.ffmpegArgumentStringByPass.Count; index++)
            {
                if (string.IsNullOrEmpty(this.ffmpegArgumentStringByPass[index].Arguments))
                {
                    throw new Exception("Invalid ffmpeg process arguments.");
                }
            }
        }