diff --git a/Application/FileConverter/ConversionJobs/ConversionJob_FFMPEG.Converters.cs b/Application/FileConverter/ConversionJobs/ConversionJob_FFMPEG.Converters.cs
index 35d46b16..279c90ed 100644
--- a/Application/FileConverter/ConversionJobs/ConversionJob_FFMPEG.Converters.cs
+++ b/Application/FileConverter/ConversionJobs/ConversionJob_FFMPEG.Converters.cs
@@ -45,14 +45,14 @@ private static string ComputeTransformArgs(ConversionPreset conversionPreset, He
if (conversionPreset.OutputType == OutputType.Mkv || conversionPreset.OutputType == OutputType.Mp4)
{
// This presets use h264 codec, the size of the video need to be divisible by 2.
- switch (hwAccel)
- {
- case Helpers.HardwareAccelerationMode.CUDA:
- scaleArgs = string.Format("scale_cuda=trunc(iw*{0}/2)*2:trunc(ih*{0}/2)*2:format=yuv420p", scaleFactor.ToString("#.##", CultureInfo.InvariantCulture));
- break;
- default:
- scaleArgs = string.Format("scale=trunc(iw*{0}/2)*2:trunc(ih*{0}/2)*2", scaleFactor.ToString("#.##", CultureInfo.InvariantCulture));
- break;
+ switch (hwAccel)
+ {
+ case Helpers.HardwareAccelerationMode.CUDA:
+ scaleArgs = string.Format("scale_cuda=trunc(iw*{0}/2)*2:trunc(ih*{0}/2)*2:format=yuv420p", scaleFactor.ToString("#.##", CultureInfo.InvariantCulture));
+ break;
+ default:
+ scaleArgs = string.Format("scale=trunc(iw*{0}/2)*2:trunc(ih*{0}/2)*2", scaleFactor.ToString("#.##", CultureInfo.InvariantCulture));
+ break;
}
}
else if (Math.Abs(scaleFactor - 1f) >= 0.005f)
@@ -104,10 +104,12 @@ private static string ComputeTransformArgs(ConversionPreset conversionPreset, He
transformArgs += rotationArgs;
}
- if (hwAccel == Helpers.HardwareAccelerationMode.Off && (conversionPreset.OutputType == OutputType.Mkv || conversionPreset.OutputType == OutputType.Mp4))
+ if (hwAccel != Helpers.HardwareAccelerationMode.CUDA && (conversionPreset.OutputType == OutputType.Mkv || conversionPreset.OutputType == OutputType.Mp4))
{
+ // For H.264 in MP4/MKV, force yuv420p for broad player compatibility:
// http://trac.ffmpeg.org/wiki/Encode/H.264#Encodingfordumbplayers
- // YUV planar color space with 4:2:0 chroma subsampling
+ // - Software encoding and non-CUDA hardware (e.g., AMF) come through this path.
+ // - CUDA is excluded here because the scale_cuda path above already sets format=yuv420p.
transformArgs += (transformArgs.Length > 0 ? "," : string.Empty) + "format=yuv420p";
//// TODO: maybe there should be an option for this on the settings?
}
@@ -324,7 +326,71 @@ private string H264EncodingSpeedToPreset(VideoEncodingSpeed encodingSpeed)
return "veryslow";
}
- throw new Exception("Unknown H264 encoding speed.");
+ throw new ArgumentOutOfRangeException(nameof(encodingSpeed), encodingSpeed, "Unknown H264 encoding speed.");
+ }
+
+ ///
+ /// Convert video encoding speed to NVENC preset.
+ ///
+ /// The encoding speed.
+ /// The NVENC preset.
+ private string H264EncodingSpeedToNVENCPreset(VideoEncodingSpeed encodingSpeed)
+ {
+ switch (encodingSpeed)
+ {
+ case VideoEncodingSpeed.UltraFast:
+ return "p1";
+
+ case VideoEncodingSpeed.SuperFast:
+ return "p2";
+
+ case VideoEncodingSpeed.VeryFast:
+ return "p3";
+
+ case VideoEncodingSpeed.Faster:
+ case VideoEncodingSpeed.Fast:
+ case VideoEncodingSpeed.Medium:
+ return "p4";
+
+ case VideoEncodingSpeed.Slow:
+ return "p5";
+
+ case VideoEncodingSpeed.Slower:
+ return "p6";
+
+ case VideoEncodingSpeed.VerySlow:
+ return "p7";
+ }
+
+ throw new ArgumentOutOfRangeException(nameof(encodingSpeed), encodingSpeed, "Unknown H264 encoding speed.");
+ }
+
+ ///
+ /// Convert video encoding speed to AMF quality mode.
+ ///
+ /// The encoding speed.
+ /// The AMF quality mode.
+ private string H264EncodingSpeedToAMFQuality(VideoEncodingSpeed encodingSpeed)
+ {
+ switch (encodingSpeed)
+ {
+ case VideoEncodingSpeed.UltraFast:
+ case VideoEncodingSpeed.SuperFast:
+ case VideoEncodingSpeed.VeryFast:
+ case VideoEncodingSpeed.Faster:
+ case VideoEncodingSpeed.Fast:
+ return "speed";
+
+ case VideoEncodingSpeed.Medium:
+ case VideoEncodingSpeed.Slow:
+ return "balanced";
+
+ case VideoEncodingSpeed.Slower:
+ case VideoEncodingSpeed.VerySlow:
+ return "quality";
+ }
+
+ throw new ArgumentOutOfRangeException(nameof(encodingSpeed), encodingSpeed, "Unknown H264 encoding speed.");
}
///
diff --git a/Application/FileConverter/ConversionJobs/ConversionJob_FFMPEG.cs b/Application/FileConverter/ConversionJobs/ConversionJob_FFMPEG.cs
index 99c9e93a..74214086 100644
--- a/Application/FileConverter/ConversionJobs/ConversionJob_FFMPEG.cs
+++ b/Application/FileConverter/ConversionJobs/ConversionJob_FFMPEG.cs
@@ -7,11 +7,11 @@ namespace FileConverter.ConversionJobs
using System.Diagnostics;
using System.Globalization;
using System.IO;
- using System.Text.RegularExpressions;
- using CommunityToolkit.Mvvm.DependencyInjection;
- using FileConverter.Controls;
- using FileConverter.Services;
-
+ using System.Text.RegularExpressions;
+ using CommunityToolkit.Mvvm.DependencyInjection;
+ using FileConverter.Controls;
+ using FileConverter.Services;
+
public partial class ConversionJob_FFMPEG : ConversionJob
{
private readonly Regex durationRegex = new Regex(@"Duration:\s*([0-9][0-9]):([0-9][0-9]):([0-9][0-9])\.([0-9][0-9]),.*bitrate:\s*([0-9]+) kb\/s");
@@ -269,20 +269,43 @@ protected virtual void FillFFMpegArgumentsList()
audioArgs = $"-c:a aac -qscale:a {this.AACBitrateToQualityIndex(audioEncodingBitrate)}";
}
- string videoCodec = "libx264";
- string hwAccelArg = "";
- if (hwAccel == Helpers.HardwareAccelerationMode.CUDA)
- {
- videoCodec = "h264_nvenc";
- hwAccelArg = "-hwaccel cuda -hwaccel_output_format cuda";
- }
-
+ string videoCodec = "libx264";
+ string videoCodecArgs = string.Format(
+ "-preset {0} -crf {1}",
+ this.H264EncodingSpeedToPreset(videoEncodingSpeed),
+ this.H264QualityToCRF(videoEncodingQuality));
+ string hwAccelArg = string.Empty;
+
+ switch (hwAccel)
+ {
+ case Helpers.HardwareAccelerationMode.CUDA:
+ videoCodec = "h264_nvenc";
+ int nvencQP = this.H264QualityToCRF(videoEncodingQuality);
+ videoCodecArgs = string.Format(
+ "-preset {0} -rc constqp -qp {1}",
+ this.H264EncodingSpeedToNVENCPreset(videoEncodingSpeed),
+ nvencQP);
+
+ hwAccelArg = "-hwaccel cuda -hwaccel_output_format cuda";
+ break;
+
+ case Helpers.HardwareAccelerationMode.AMF:
+ int amfQP = this.H264QualityToCRF(videoEncodingQuality);
+ int amfBFrameQP = Math.Min(51, amfQP + 2);
+ videoCodec = "h264_amf";
+ videoCodecArgs = string.Format(
+ "-usage transcoding -quality {0} -qp_i {1} -qp_p {1} -qp_b {2}",
+ this.H264EncodingSpeedToAMFQuality(videoEncodingSpeed),
+ amfQP,
+ amfBFrameQP);
+ break;
+ }
+
string encoderArgs = string.Format(
- "-c:v {0} -preset {1} -crf {2} {3} {4}",
- videoCodec,
- this.H264EncodingSpeedToPreset(videoEncodingSpeed),
- this.H264QualityToCRF(videoEncodingQuality),
- audioArgs,
+ "-c:v {0} {1} {2} {3}",
+ videoCodec,
+ videoCodecArgs,
+ audioArgs,
videoFilteringArgs);
string arguments = string.Format("-n -stats {3} -i \"{0}\" {2} \"{1}\"", this.InputFilePath, this.OutputFilePath, encoderArgs, hwAccelArg);
diff --git a/Application/FileConverter/Helpers.cs b/Application/FileConverter/Helpers.cs
index 6387f336..1112e10f 100644
--- a/Application/FileConverter/Helpers.cs
+++ b/Application/FileConverter/Helpers.cs
@@ -352,10 +352,11 @@ public static class InputCategoryNames
public const string Misc = "Misc";
}
- public enum HardwareAccelerationMode
- {
- Off,
- CUDA
- }
- }
-}
\ No newline at end of file
+ public enum HardwareAccelerationMode
+ {
+ Off,
+ CUDA,
+ AMF
+ }
+ }
+}
diff --git a/Application/FileConverter/ValueConverters/HardwareAccelerationModeToString.cs b/Application/FileConverter/ValueConverters/HardwareAccelerationModeToString.cs
index e2742ba7..970d80c7 100644
--- a/Application/FileConverter/ValueConverters/HardwareAccelerationModeToString.cs
+++ b/Application/FileConverter/ValueConverters/HardwareAccelerationModeToString.cs
@@ -10,13 +10,15 @@ public class HardwareAccelerationModeToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
- switch (value) {
- case Helpers.HardwareAccelerationMode.Off:
- return Properties.Resources.HardwareAccelerationModeOffName;
- case Helpers.HardwareAccelerationMode.CUDA:
- return Properties.Resources.HardwareAccelerationModeCUDAName;
+ switch (value) {
+ case Helpers.HardwareAccelerationMode.Off:
+ return Properties.Resources.HardwareAccelerationModeOffName;
+ case Helpers.HardwareAccelerationMode.CUDA:
+ return Properties.Resources.HardwareAccelerationModeCUDAName;
+ case Helpers.HardwareAccelerationMode.AMF:
+ return Properties.Resources.HardwareAccelerationModeAMFName;
}
- return "Unknown";
+ return value?.ToString() ?? string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
@@ -24,4 +26,4 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu
throw new NotImplementedException();
}
}
-}
\ No newline at end of file
+}
diff --git a/Application/FileConverter/ViewModels/SettingsViewModel.cs b/Application/FileConverter/ViewModels/SettingsViewModel.cs
index 0b201e5d..15d33c87 100644
--- a/Application/FileConverter/ViewModels/SettingsViewModel.cs
+++ b/Application/FileConverter/ViewModels/SettingsViewModel.cs
@@ -47,7 +47,7 @@ public class SettingsViewModel : ObservableRecipient, IDataErrorInfo
private ListCollectionView outputTypes;
private CultureInfo[] supportedCultures;
- private Helpers.HardwareAccelerationMode[] hardwareAccelerationModes = { Helpers.HardwareAccelerationMode.Off, Helpers.HardwareAccelerationMode.CUDA };
+ private Helpers.HardwareAccelerationMode[] hardwareAccelerationModes = { Helpers.HardwareAccelerationMode.Off, Helpers.HardwareAccelerationMode.CUDA, Helpers.HardwareAccelerationMode.AMF };
public event Action OnPresetCreated;
public event Action OnFolderCreated;