namespace FileFlows.VideoNodes;
///
/// Flow element to test if a video is interlaced
///
public class VideoIsInterlaced : VideoNode
{
///
/// Gets the number of inputs
///
public override int Inputs => 1;
///
/// Gets the number of outputs
///
public override int Outputs => 2;
///
/// Gets the type of flow element
///
public override FlowElementType Type => FlowElementType.Logic;
///
/// Gets the icon
///
public override string Icon => "fas fa-question";
///
/// Gets the help URL
///
public override string HelpUrl => "https://fileflows.com/docs/plugins/video-nodes/logical-nodes/video-is-interlaced";
///
/// Gets or sets the threshold
///
[Range(1, 100)]
[Slider(1)]
[DefaultValue(10)]
public int Threshold { get; set; }
///
/// Executes the flow element
///
/// the arguments
/// the output to call next
public override int Execute(NodeParameters args)
{
string ffmpeg = args.GetToolPath("FFmpeg");
if (string.IsNullOrEmpty(ffmpeg))
{
args.Logger?.ELog("FFmpeg tool not found.");
return 2;
}
var localFile = args.FileService.GetLocalPath(args.WorkingFile);
if (localFile.Failed(out string error))
{
args.FailureReason = "Failed to get local file: " + error;
args.Logger?.ELog(args.FailureReason);
return -1;
}
var ffOutput = args.Execute(new()
{
Command = ffmpeg,
Silent = true,
ArgumentList = new[]
{
"-hide_banner",
"-i", localFile.Value,
"-vf", "idet",
"-f", "null", "-"
}
});
if (string.IsNullOrEmpty(ffOutput.StandardOutput))
{
args.Logger?.ELog("Failed to get standard output from FFmpeg");
return 2;
}
bool isInterlaced = IsVideoInterlaced(args.Logger, ffOutput.StandardOutput, Math.Max(Threshold, 1));
args.Logger?.ILog("Is interlaced: " + isInterlaced);
return isInterlaced ? 1 : 2;
}
///
/// Determines if a video is interlaced based on FFmpeg output.
///
/// The FFmpeg output as a string.
/// An optional threshold for the number of interlaced frames to consider.
/// True if the video is interlaced, false if it's not.
public static bool IsVideoInterlaced(ILogger logger, string ffmpegOutput, int interlaceThreshold = 10)
{
// Define regular expressions to match interlaced and progressive frame counts
Regex tffRegex = new Regex(@"TFF:[\s]*(\d+)");
Regex bffRegex = new Regex(@"BFF:[\s]*(\d+)");
Regex progressiveRegex = new Regex(@"Progressive:[\s]*(\d+)");
int tffCount = 0;
int bffCount = 0;
int progressiveCount = 0;
// Use regular expressions to extract counts of interlaced and progressive frames
MatchCollection tffMatches = tffRegex.Matches(ffmpegOutput);
MatchCollection bffMatches = bffRegex.Matches(ffmpegOutput);
MatchCollection progressiveMatches = progressiveRegex.Matches(ffmpegOutput);
foreach (Match match in tffMatches)
{
tffCount += int.Parse(match.Groups[1].Value);
}
foreach (Match match in bffMatches)
{
bffCount += int.Parse(match.Groups[1].Value);
}
foreach (Match match in progressiveMatches)
{
progressiveCount += int.Parse(match.Groups[1].Value);
}
// Calculate the total count of interlaced frames
int totalInterlacedCount = tffCount + bffCount;
int totalFrames = totalInterlacedCount + progressiveCount;
float percent = ((float)totalInterlacedCount) / totalFrames * 100f;
logger?.ILog("Interlaced threshold percentage: " + interlaceThreshold);
logger?.ILog("Total Interlaced Frames: " + totalInterlacedCount);
logger?.ILog("Total Progressive Frames: " + progressiveCount);
logger?.ILog("Total Frames: " + totalFrames);
logger?.ILog("Interlaced Percent: " + percent);
// Check if the total count of interlaced frames exceeds the threshold
return percent >= interlaceThreshold;
}
}