mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-02-14 07:18:27 -06:00
FF-1227 - added pixel format detection to hw decoding
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -192,7 +192,7 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
|
||||
|
||||
var video = this.Model.VideoStreams.FirstOrDefault(x => x.Stream.IsImage == false);
|
||||
startArgs.AddRange(GetHardwareDecodingArgs(args, localFile, FFMPEG, video?.Stream?.Codec));
|
||||
startArgs.AddRange(GetHardwareDecodingArgs(args, localFile, FFMPEG, video?.Stream?.Codec, video?.Stream?.PixelFormat));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
return 1;
|
||||
}
|
||||
|
||||
internal static string[] GetHardwareDecodingArgs(NodeParameters args, string localFile, string ffmpeg, string codec)
|
||||
internal static string[] GetHardwareDecodingArgs(NodeParameters args, string localFile, string ffmpeg, string codec, string pixelFormat)
|
||||
{
|
||||
string testFile = FileHelper.Combine(args.TempPath, Guid.NewGuid() + ".hwtest.mkv");
|
||||
if (string.IsNullOrWhiteSpace(codec))
|
||||
@@ -270,10 +270,13 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
Decoders_Default(args);
|
||||
try
|
||||
{
|
||||
List<string> tested = new List<string>();
|
||||
foreach (var hw in decoders)
|
||||
{
|
||||
if (hw == null)
|
||||
continue;
|
||||
if (hw.Contains("#FORMAT#") && string.IsNullOrWhiteSpace(pixelFormat))
|
||||
continue;
|
||||
if (CanUseHardwareEncoding.DisabledByVariables(args, hw))
|
||||
{
|
||||
args.Logger?.ILog("HW disabled by variables: " + string.Join(", ", hw));
|
||||
@@ -286,7 +289,8 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
{
|
||||
"-y",
|
||||
};
|
||||
arguments.AddRange(hw);
|
||||
foreach(var hwarg in hw)
|
||||
arguments.Add(hwarg.Replace("#FORMAT#", pixelFormat));
|
||||
arguments.AddRange(new[]
|
||||
{
|
||||
"-i", localFile,
|
||||
@@ -296,6 +300,11 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
//"-f", "null", "-",
|
||||
testFile
|
||||
});
|
||||
string line = string.Join("", arguments);
|
||||
if (tested.Contains(line))
|
||||
continue; // avoids testing twice if the #FORMAT# already tested one
|
||||
|
||||
tested.Add(line);
|
||||
|
||||
DateTime dtStart = DateTime.Now;
|
||||
const int timeout = 20;
|
||||
@@ -361,18 +370,20 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "novideotoolbox" && x.Value as bool? == true);
|
||||
bool noVulkan =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "novulkan" && x.Value as bool? == true);
|
||||
bool noDxva2 =
|
||||
bool noDxva2 = OperatingSystem.IsWindows() == false ||
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nodxva2" && x.Value as bool? == true);
|
||||
bool noD3d11va =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nod3d11va" && x.Value as bool? == true);
|
||||
bool noD3d11va = OperatingSystem.IsWindows() == false ||
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nod3d11va" && x.Value as bool? == true);
|
||||
bool noOpencl =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "noopencl" && x.Value as bool? == true);
|
||||
|
||||
return new[]
|
||||
{
|
||||
noVideoToolbox == false && IsMac ? new [] { "-hwaccel", "videotoolbox" } : null,
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "#FORMAT#" },
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda" },
|
||||
noNvidia ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "#FORMAT#" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "p010le" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv" },
|
||||
@@ -401,17 +412,19 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
bool noVulkan =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "novulkan" && x.Value as bool? == true);
|
||||
bool noDxva2 =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nodxva2" && x.Value as bool? == true);
|
||||
OperatingSystem.IsWindows() == false || args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nodxva2" && x.Value as bool? == true);
|
||||
bool noD3d11va =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nod3d11va" && x.Value as bool? == true);
|
||||
OperatingSystem.IsWindows() == false || args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nod3d11va" && x.Value as bool? == true);
|
||||
bool noOpencl =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "noopencl" && x.Value as bool? == true);
|
||||
|
||||
return new[]
|
||||
{
|
||||
noVideoToolbox == false && IsMac ? new [] { "-hwaccel", "videotoolbox" } : null,
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "#FORMAT#" },
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda" },
|
||||
noNvidia ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "#FORMAT#" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "p010le" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv" },
|
||||
@@ -440,17 +453,19 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
bool noVulkan =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "novulkan" && x.Value as bool? == true);
|
||||
bool noDxva2 =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nodxva2" && x.Value as bool? == true);
|
||||
OperatingSystem.IsWindows() == false || args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nodxva2" && x.Value as bool? == true);
|
||||
bool noD3d11va =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nod3d11va" && x.Value as bool? == true);
|
||||
OperatingSystem.IsWindows() == false || args.Variables.Any(x => x.Key?.ToLowerInvariant() == "nod3d11va" && x.Value as bool? == true);
|
||||
bool noOpencl =
|
||||
args.Variables.Any(x => x.Key?.ToLowerInvariant() == "noopencl" && x.Value as bool? == true);
|
||||
|
||||
|
||||
return new[]
|
||||
{
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "#FORMAT#" },
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
noNvidia ? null : new [] { "-hwaccel", "cuda" },
|
||||
noNvidia ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "#FORMAT#" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "p010le" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
noQsv ? null : new [] { "-hwaccel", "qsv" },
|
||||
|
||||
@@ -95,7 +95,7 @@ public class VideoHasErrors: VideoNode
|
||||
{
|
||||
var hardwareDecodingArgs =
|
||||
FfmpegBuilderNodes.FfmpegBuilderExecutor.GetHardwareDecodingArgs(args, filename, ffmpegPath,
|
||||
video?.Codec);
|
||||
video?.Codec, video?.PixelFormat);
|
||||
if (hardwareDecodingArgs?.Any() == true)
|
||||
{
|
||||
foreach (var hwArg in hardwareDecodingArgs)
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace VideoNodes.Tests
|
||||
public void VideoInfoTest_AC1()
|
||||
{
|
||||
string ffmpegOutput =
|
||||
@"Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/media/Videos/#-Test Tdarr/Input3/input file.mp4':
|
||||
@"Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/media/Videos/Input3/input file.mp4':
|
||||
Metadata:
|
||||
major_brand : mp42
|
||||
minor_version : 512
|
||||
@@ -92,6 +92,7 @@ namespace VideoNodes.Tests
|
||||
var vi = VideoInfoHelper.ParseOutput(null, ffmpegOutput);
|
||||
Assert.AreEqual(1920, vi.VideoStreams[0].Width);
|
||||
Assert.AreEqual(1080, vi.VideoStreams[0].Height);
|
||||
Assert.AreEqual("yuv420p", vi.VideoStreams[0].PixelFormat);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -88,6 +88,11 @@ public class VideoFileStream
|
||||
/// Gets or sets the input file index
|
||||
/// </summary>
|
||||
public int InputFileIndex { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pixel format that should be used to decode this stream
|
||||
/// </summary>
|
||||
public string PixelFormat { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -256,6 +256,7 @@ public class VideoInfoHelper
|
||||
}
|
||||
|
||||
vs.Codec = line.Substring(line.IndexOf("Video: ") + "Video: ".Length).Replace(",", "").Trim().Split(' ').First().ToLower();
|
||||
vs.PixelFormat = GetDecoderPixelFormat(line);
|
||||
var dimensions = Regex.Match(line, @"([\d]{3,})x([\d]{3,})");
|
||||
if (int.TryParse(dimensions.Groups[1].Value, out int width))
|
||||
vs.Width = width;
|
||||
@@ -265,7 +266,7 @@ public class VideoInfoHelper
|
||||
if (Regex.IsMatch(line, @"([\d]+(\.[\d]+)?)\sfps") &&
|
||||
float.TryParse(Regex.Match(line, @"([\d]+(\.[\d]+)?)\sfps").Groups[1].Value, out float fps))
|
||||
{
|
||||
logger.ILog("Frames Per Second: " + fps);
|
||||
logger?.ILog("Frames Per Second: " + fps);
|
||||
vs.FramesPerSecond = fps;
|
||||
}
|
||||
|
||||
@@ -441,4 +442,26 @@ public class VideoInfoHelper
|
||||
return string.Empty;
|
||||
return lang;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the supported pixel format from an FFmpeg output line for hardware decoding.
|
||||
/// </summary>
|
||||
/// <param name="line">The FFmpeg output line containing video stream information.</param>
|
||||
/// <returns>The supported pixel format (e.g., "yuv420p" or "p010le"), or an empty string if not found or not supported.</returns>
|
||||
/// <remarks>
|
||||
/// Supports "yuv420p" and "p010le" formats. Handles cases where "p010le" has no additional specifiers, defaulting to "yuv420p".
|
||||
/// Adjust the regular expression or default behavior based on specific hardware and FFmpeg output format.
|
||||
/// </remarks>
|
||||
static string GetDecoderPixelFormat(string line)
|
||||
{
|
||||
if(line.IndexOf("yuv420p", StringComparison.Ordinal) > 0)
|
||||
return "yuv420p";
|
||||
if(line.IndexOf("p010le", StringComparison.Ordinal) > 0)
|
||||
return "p010le";
|
||||
if (line.IndexOf("nv12", StringComparison.Ordinal) >= 0)
|
||||
return "nv12";
|
||||
if (line.IndexOf("yuv444p", StringComparison.Ordinal) >= 0)
|
||||
return "yuv444p";
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user