Merge branch 'develop'

# Conflicts:
#	VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_MetadataTests.cs
This commit is contained in:
John Andrews
2022-05-06 08:45:53 +12:00
12 changed files with 619 additions and 80 deletions

View File

@@ -97,27 +97,32 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
var audio = new FfmpegAudioStream();
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
var bestAudio = Model.AudioStreams.Where(x => System.Text.Json.JsonSerializer.Serialize(x.Stream).ToLower().Contains("commentary") == false)
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
.OrderBy(x =>
var bestAudio = GetBestAudioTrack(args, Model.AudioStreams.Select(x => x.Stream));
if (bestAudio == null)
{
if (Language != string.Empty)
{
args.Logger?.ILog("Language: " + x.Stream.Language, x);
if (string.IsNullOrEmpty(x.Stream.Language))
return 50; // no language specified
if (x.Stream.Language?.ToLower() != Language)
return 100; // low priority not the desired language
}
return 0;
})
.ThenByDescending(x => x.Stream.Channels)
.ThenBy(x => x.Index)
.FirstOrDefault();
audio.Stream = bestAudio.Stream;
args.Logger.WLog("No source audio track found");
return -1;
}
audio.EncodingParameters.AddRange(GetNewAudioTrackParameters("0:a:" + (bestAudio.Stream.TypeIndex)));
audio.Stream = bestAudio;
bool directCopy = false;
if(bestAudio.Codec.ToLower() == this.Codec.ToLower())
{
if(this.Channels == 0 || this.Channels == bestAudio.Channels)
{
directCopy = true;
}
}
if (directCopy)
{
args.Logger?.ILog($"Source audio is already in appropriate format, just copying that track: {bestAudio.IndexString}, Channels: {bestAudio.Channels}, Codec: {bestAudio.Codec}");
}
else
{
audio.EncodingParameters.AddRange(GetNewAudioTrackParameters("0:a:" + (bestAudio.TypeIndex)));
}
if (Index > Model.AudioStreams.Count - 1)
Model.AudioStreams.Add(audio);
else
@@ -126,6 +131,54 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return 1;
}
internal AudioStream GetBestAudioTrack(NodeParameters args, IEnumerable<AudioStream> streams)
{
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
var bestAudio = streams.Where(x => System.Text.Json.JsonSerializer.Serialize(x).ToLower().Contains("commentary") == false)
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
.OrderBy(x =>
{
if (Language != string.Empty)
{
args.Logger?.ILog("Language: " + x.Language, x);
if (string.IsNullOrEmpty(x.Language))
return 50; // no language specified
if (x.Language.ToLower() != Language)
return 100; // low priority not the desired language
}
return 0;
})
.ThenByDescending(x => {
if(this.Channels == 2)
{
if (x.Channels == 2)
return 1_000_000_000;
// compare codecs
if (x.Codec?.ToLower() == this.Codec?.ToLower())
return 1_000_000;
}
if(this.Channels == 1)
{
if (x.Channels == 1)
return 1_000_000_000;
if (x.Channels <= 2.1f)
return 5_000_000;
if (x.Codec?.ToLower() == this.Codec?.ToLower())
return 1_000_000;
}
// now we want best channels, but to prefer matching codec
if (x.Codec?.ToLower() == this.Codec?.ToLower())
{
return 1_000 + x.Channels;
}
return x.Channels;
})
.ThenBy(x => x.Index)
.FirstOrDefault();
return bestAudio;
}
private string[] GetNewAudioTrackParameters(string source)
{

View File

@@ -10,6 +10,12 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
public override int Outputs => 2;
public override FlowElementType Type => FlowElementType.BuildEnd;
public override bool NoEditorOnAdd => true;
[DefaultValue(true)]
[Boolean(1)]
public bool HardwareDecoding { get; set; }
public override int Execute(NodeParameters args)
{
this.Init(args);
@@ -56,7 +62,16 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
else
model.InputFiles[0] = args.WorkingFile;
foreach(string file in model.InputFiles)
startArgs.AddRange(new[] {
"-probesize", VideoInfoHelper.ProbeSize + "M"
});
if (HardwareDecoding)
{
startArgs.AddRange(GetHardwareDecodingArgs());
}
foreach (string file in model.InputFiles)
{
startArgs.Add("-i");
startArgs.Add(file);
@@ -70,5 +85,39 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
return 1;
}
internal string[] GetHardwareDecodingArgs()
{
string testFile = Path.Combine(args.TempPath, Guid.NewGuid() + ".hwtest.mkv");
foreach(var hw in new [] { "cuda", "dxva2", "qsv", "d3d11va", "opencl" })
{
// ffmpeg -y -hwaccel qsvf -f lavfi -i color=color=red -frames:v 10 test.mkv
try
{
var result = args.Execute(new ExecuteArgs
{
Command = ffmpegExe,
ArgumentList = new[]
{
"-y",
"-hwaccel", hw,
"-f", "lavfi",
"-i", "color=color=red",
"-frames:v", "10",
testFile
}
});
if (result.ExitCode == 0)
{
args.Logger?.ILog("Supported hardware decoding detected: " + hw);
return new[] { "-hwaccel", hw };
}
}
catch (Exception) { }
}
args.Logger?.ILog("No hardware decoding availble");
return new string[] { };
}
}
}

View File

@@ -50,7 +50,17 @@
_OptionalEncodingParameters = value ?? new List<string>();
}
}
public override bool HasChange => EncodingParameters.Any() || Filter.Any();
private List<string> _AdditionalParameters = new List<string>();
public List<string> AdditionalParameters
{
get => _AdditionalParameters;
set
{
_AdditionalParameters = value ?? new List<string>();
}
}
public override bool HasChange => EncodingParameters.Any() || Filter.Any() || AdditionalParameters.Any();
public override string[] GetParameters(int outputIndex)
{
@@ -58,7 +68,7 @@
return new string[] { };
var results = new List<string> { "-map", "0:v:" + outputIndex };
if (Filter.Any() == false && EncodingParameters.Any() == false)
if (Filter.Any() == false && EncodingParameters.Any() == false && AdditionalParameters.Any() == false)
{
results.Add("-c:v:" + Stream.TypeIndex);
results.Add("copy");
@@ -78,6 +88,8 @@
// we need to set this codec since a filter will be applied, so we cant copy it.
//results.Add("copy");
}
if (AdditionalParameters.Any())
results.AddRange(AdditionalParameters.Select(x => x.Replace("{index}", outputIndex.ToString())));
if (Filter.Any() || OptionalFilter.Any())
{

View File

@@ -0,0 +1,54 @@
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
public class FfmpegBuilderVideoBitrate : FfmpegBuilderNode
{
public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-Video-Bitrate";
/// <summary>
/// Gets or sets the bitrate in K
/// </summary>
[NumberInt(1)]
[DefaultValue(3000)]
public float Bitrate { get; set; }
public override int Execute(NodeParameters args)
{
base.Init(args);
var video = Model.VideoStreams?.Where(x => x.Deleted == false)?.FirstOrDefault();
if (video?.Stream == null)
{
args.Logger?.ELog("No video stream found");
return -1;
}
if(Bitrate < 0)
{
args.Logger?.ELog("Minimum birate not set");
return -1;
}
int minimum = (int)(Bitrate * 0.75f);
int maximum = (int)(Bitrate * 1.25f);
float currentBitrate = (int)(video.Stream.Bitrate / 1024f);
if(currentBitrate <= 0)
{
// need to work it out
currentBitrate = (float)(args.WorkingFileSize / video.Stream.Duration.TotalSeconds);
// rough estimate of 75% of the file is video
currentBitrate *= 0.75f;
}
video.AdditionalParameters.AddRange(new[]
{
"-b:v:{index}", Bitrate + "k",
"-minrate", minimum + "k",
"-maxrate", maximum + "k",
"-bufsize", currentBitrate + "k"
});
return 1;
}
}

View File

@@ -9,6 +9,13 @@ namespace FileFlows.VideoNodes
public override int Outputs => 1;
public override FlowElementType Type => FlowElementType.Input;
public override bool NoEditorOnAdd => true;
[DefaultValue(25)]
[NumberInt(1)]
[Range(5, 1000)]
public int ProbeSize { get; set; }
private Dictionary<string, object> _Variables;
public override Dictionary<string, object> Variables => _Variables;
public VideoFile()
@@ -48,6 +55,8 @@ namespace FileFlows.VideoNodes
if (string.IsNullOrEmpty(ffmpegExe))
return -1;
VideoInfoHelper.ProbeSize = this.ProbeSize;
try
{

View File

@@ -0,0 +1,170 @@
#if(DEBUG)
using FileFlows.VideoNodes.FfmpegBuilderNodes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using VideoNodes.Tests;
namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests;
[TestClass]
public class FfmpegBuilder_AddAudioTests
{
VideoInfo vii;
NodeParameters args;
private void Prepare()
{
const string file = @"D:\videos\unprocessed\basic.mkv";
var logger = new TestLogger();
const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe";
var vi = new VideoInfoHelper(ffmpeg, logger);
vii = vi.Read(file);
vii.AudioStreams = new List<AudioStream>
{
new AudioStream
{
Index = 2,
IndexString = "0:a:0",
Language = "en",
Codec = "AC3",
Channels = 5.1f
},
new AudioStream
{
Index = 3,
IndexString = "0:a:1",
Language = "en",
Codec = "AAC",
Channels = 2
},
new AudioStream
{
Index = 4,
IndexString = "0:a:3",
Language = "en",
Codec = "AAC",
Channels = 2
},
new AudioStream
{
Index = 5,
IndexString = "0:a:4",
Language = "en",
Codec = "AAC",
Channels = 5.1f
}
};
args = new NodeParameters(file, logger, false, string.Empty);
args.GetToolPathActual = (string tool) => ffmpeg;
args.TempPath = @"D:\videos\temp";
args.Parameters.Add("VideoInfo", vii);
FfmpegBuilderStart ffStart = new();
Assert.AreEqual(1, ffStart.Execute(args));
}
[TestMethod]
public void FfmpegBuilder_AddAudio_AacStereo()
{
Prepare();
FfmpegBuilderAudioAddTrack ffAddAudio = new();
ffAddAudio.Codec = "aac";
ffAddAudio.Channels = 2;
var best = ffAddAudio.GetBestAudioTrack(args, vii.AudioStreams);
Assert.IsNotNull(best);
Assert.AreEqual(3, best.Index);
Assert.AreEqual("AAC", best.Codec);
Assert.AreEqual(2f, best.Channels);
}
[TestMethod]
public void FfmpegBuilder_AddAudio_AacSameAsSource()
{
Prepare();
FfmpegBuilderAudioAddTrack ffAddAudio = new();
ffAddAudio.Codec = "aac";
ffAddAudio.Channels = 0;
var best = ffAddAudio.GetBestAudioTrack(args, vii.AudioStreams);
Assert.IsNotNull(best);
Assert.AreEqual(5, best.Index);
Assert.AreEqual("AAC", best.Codec);
Assert.AreEqual(5.1f, best.Channels);
}
[TestMethod]
public void FfmpegBuilder_AddAudio_Ac3SameAsSource()
{
Prepare();
FfmpegBuilderAudioAddTrack ffAddAudio = new();
ffAddAudio.Codec = "ac3";
ffAddAudio.Channels = 0;
ffAddAudio.Index = 1;
var best = ffAddAudio.GetBestAudioTrack(args, vii.AudioStreams);
Assert.IsNotNull(best);
Assert.AreEqual(2, best.Index);
Assert.AreEqual("AC3", best.Codec);
Assert.AreEqual(5.1f, best.Channels);
}
[TestMethod]
public void FfmpegBuilder_AddAudio_DtsSame()
{
Prepare();
FfmpegBuilderAudioAddTrack ffAddAudio = new();
ffAddAudio.Codec = "dts";
ffAddAudio.Channels = 0;
var best = ffAddAudio.GetBestAudioTrack(args, vii.AudioStreams);
Assert.IsNotNull(best);
Assert.AreEqual(2, best.Index);
Assert.AreEqual("AC3", best.Codec);
Assert.AreEqual(5.1f, best.Channels);
}
[TestMethod]
public void FfmpegBuilder_AddAudio_DtsStereo()
{
Prepare();
FfmpegBuilderAudioAddTrack ffAddAudio = new();
ffAddAudio.Codec = "dts";
ffAddAudio.Channels = 2;
var best = ffAddAudio.GetBestAudioTrack(args, vii.AudioStreams);
Assert.IsNotNull(best);
Assert.AreEqual(3, best.Index);
Assert.AreEqual("AAC", best.Codec);
Assert.AreEqual(2f, best.Channels);
}
[TestMethod]
public void FfmpegBuilder_AddAudio_DtsMono()
{
Prepare();
FfmpegBuilderAudioAddTrack ffAddAudio = new();
ffAddAudio.Codec = "dts";
ffAddAudio.Channels = 1;
var best = ffAddAudio.GetBestAudioTrack(args, vii.AudioStreams);
Assert.IsNotNull(best);
Assert.AreEqual(3, best.Index);
Assert.AreEqual("AAC", best.Codec);
Assert.AreEqual(2f, best.Channels);
}
}
#endif

View File

@@ -776,6 +776,144 @@ namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests
string log = logger.ToString();
Assert.AreEqual(1, result);
}
[TestMethod]
public void FfmpegBuilder_HardwareDecoding()
{
const string file = @"D:\videos\unprocessed\basic.mkv";
var logger = new TestLogger();
const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe";
var vi = new VideoInfoHelper(ffmpeg, logger);
var vii = vi.Read(file);
var args = new NodeParameters(file, logger, false, string.Empty);
args.GetToolPathActual = (string tool) => ffmpeg;
args.TempPath = @"D:\videos\temp";
args.Parameters.Add("VideoInfo", vii);
FfmpegBuilderStart ffStart = new();
Assert.AreEqual(1, ffStart.Execute(args));
FfmpegBuilderVideoCodec ffEncode = new();
ffEncode.VideoCodec = "h264";
ffEncode.Execute(args);
FfmpegBuilderAudioAddTrack ffAddAudio = new();
ffAddAudio.Codec = "ac3";
ffAddAudio.Index = 0;
ffAddAudio.Execute(args);
FfmpegBuilderExecutor ffExecutor = new();
ffExecutor.HardwareDecoding = true;
int result = ffExecutor.Execute(args);
string log = logger.ToString();
Assert.AreEqual(1, result);
}
[TestMethod]
public void FfmpegBuilder_VideoBitrate()
{
const string file = @"D:\videos\unprocessed\basic.mkv";
var logger = new TestLogger();
const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe";
var vi = new VideoInfoHelper(ffmpeg, logger);
var vii = vi.Read(file);
var args = new NodeParameters(file, logger, false, string.Empty);
args.GetToolPathActual = (string tool) => ffmpeg;
args.TempPath = @"D:\videos\temp";
args.Parameters.Add("VideoInfo", vii);
FfmpegBuilderStart ffStart = new();
Assert.AreEqual(1, ffStart.Execute(args));
FfmpegBuilderVideoBitrate ffBitrate = new();
ffBitrate.Bitrate = 1_000;
ffBitrate.Execute(args);
FfmpegBuilderExecutor ffExecutor = new();
ffExecutor.HardwareDecoding = true;
int result = ffExecutor.Execute(args);
string log = logger.ToString();
Assert.AreEqual(1, result);
}
[TestMethod]
public void FfmpegBuilder_VideoCodecAndBitrate()
{
const string file = @"D:\videos\unprocessed\basic.mkv";
var logger = new TestLogger();
const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe";
var vi = new VideoInfoHelper(ffmpeg, logger);
var vii = vi.Read(file);
var args = new NodeParameters(file, logger, false, string.Empty);
args.GetToolPathActual = (string tool) => ffmpeg;
args.TempPath = @"D:\videos\temp";
args.Parameters.Add("VideoInfo", vii);
FfmpegBuilderStart ffStart = new();
Assert.AreEqual(1, ffStart.Execute(args));
FfmpegBuilderVideoCodec ffEncode = new();
ffEncode.VideoCodec = "h264";
ffEncode.Force = true;
ffEncode.Execute(args);
FfmpegBuilderVideoBitrate ffBitrate = new();
ffBitrate.Bitrate = 1_000;
ffBitrate.Execute(args);
FfmpegBuilderExecutor ffExecutor = new();
ffExecutor.HardwareDecoding = true;
int result = ffExecutor.Execute(args);
string log = logger.ToString();
Assert.AreEqual(1, result);
}
[TestMethod]
public void FfmpegBuilder_FF43()
{
const string file = @"D:\videos\testfiles\ff-43.ts";
var logger = new TestLogger();
const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe";
var vi = new VideoInfoHelper(ffmpeg, logger);
var vii = vi.Read(file);
var args = new NodeParameters(file, logger, false, string.Empty);
args.GetToolPathActual = (string tool) => ffmpeg;
args.TempPath = @"D:\videos\temp";
args.Parameters.Add("VideoInfo", vii);
FfmpegBuilderStart ffStart = new();
Assert.AreEqual(1, ffStart.Execute(args));
FfmpegBuilderAudioTrackRemover ffRemoveAudio = new();
ffRemoveAudio.RemoveAll = true;
ffRemoveAudio.Execute(args);
FfmpegBuilderAudioAddTrack ffAddAudio = new();
ffAddAudio.Codec = "ac3";
ffAddAudio.Index = 0;
ffAddAudio.Execute(args);
FfmpegBuilderAudioAddTrack ffAddAudio2 = new();
ffAddAudio2.Codec = "aac";
ffAddAudio2.Index = 1;
ffAddAudio2.Execute(args);
FfmpegBuilderExecutor ffExecutor = new();
int result = ffExecutor.Execute(args);
string log = logger.ToString();
Assert.AreEqual(1, result);
}
}
}

View File

@@ -1,44 +1,44 @@
// #if(DEBUG)
//
// using FileFlows.VideoNodes.FfmpegBuilderNodes;
// using Microsoft.VisualStudio.TestTools.UnitTesting;
// using VideoNodes.Tests;
//
// namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests
// {
// [TestClass]
// public class FfmpegBuilder_MetadataTests
// {
// [TestMethod]
// public void FfmpegBuilder_MetadataJson()
// {
// const string file = @"D:\videos\unprocessed\basic.mkv";
// var logger = new TestLogger();
// const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe";
// var vi = new VideoInfoHelper(ffmpeg, logger);
// var vii = vi.Read(file);
// var args = new NodeParameters(file, logger, false, string.Empty);
// VideoMetadata md = System.Text.Json.JsonSerializer.Deserialize<VideoMetadata>(File.ReadAllText(@"D:\videos\metadata.json"));
// args.Variables.Add("VideoMetadata", md);
// args.GetToolPathActual = (string tool) => ffmpeg;
// args.TempPath = @"D:\videos\temp";
// args.Parameters.Add("VideoInfo", vii);
//
//
// FfmpegBuilderStart ffStart = new ();
// Assert.AreEqual(1, ffStart.Execute(args));
//
//
// FfmpegBuilderVideoMetadata ffMetadata = new();
// Assert.AreEqual(1, ffMetadata.Execute(args));
//
// FfmpegBuilderExecutor ffExecutor = new();
// int result = ffExecutor.Execute(args);
//
// string log = logger.ToString();
// Assert.AreEqual(1, result);
// }
// }
// }
//
// #endif
//#if(DEBUG)
//using FileFlows.VideoNodes.FfmpegBuilderNodes;
//using Microsoft.VisualStudio.TestTools.UnitTesting;
//using VideoNodes.Tests;
//namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests
//{
// [TestClass]
// public class FfmpegBuilder_MetadataTests
// {
// [TestMethod]
// public void FfmpegBuilder_MetadataJson()
// {
// const string file = @"D:\videos\unprocessed\basic.mkv";
// var logger = new TestLogger();
// const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe";
// var vi = new VideoInfoHelper(ffmpeg, logger);
// var vii = vi.Read(file);
// var args = new NodeParameters(file, logger, false, string.Empty);
// VideoMetadata md = System.Text.Json.JsonSerializer.Deserialize<VideoMetadata>(File.ReadAllText(@"D:\videos\metadata.json"));
// args.Variables.Add("VideoMetadata", md);
// args.GetToolPathActual = (string tool) => ffmpeg;
// args.TempPath = @"D:\videos\temp";
// args.Parameters.Add("VideoInfo", vii);
// FfmpegBuilderStart ffStart = new ();
// Assert.AreEqual(1, ffStart.Execute(args));
// FfmpegBuilderVideoMetadata ffMetadata = new();
// Assert.AreEqual(1, ffMetadata.Execute(args));
// FfmpegBuilderExecutor ffExecutor = new();
// int result = ffExecutor.Execute(args);
// string log = logger.ToString();
// Assert.AreEqual(1, result);
// }
// }
//}
//#endif

View File

@@ -16,6 +16,21 @@ namespace FileFlows.VideoNodes
static Regex rgxDuration2 = new Regex(@"(?<=((^[\s]+Duration:[\s])))([\d]+:?)+\.[\d]{1,7}", RegexOptions.Multiline);
static Regex rgxAudioSampleRate = new Regex(@"(?<=((,|\s)))[\d]+(?=([\s]?hz))", RegexOptions.IgnoreCase);
static int _ProbeSize = 25;
internal static int ProbeSize
{
get => _ProbeSize;
set
{
if (value < 5)
_ProbeSize = 5;
else if (value > 1000)
_ProbeSize = 1000;
else
_ProbeSize = value;
}
}
public VideoInfoHelper(string ffMpegExe, ILogger logger)
{
this.ffMpegExe = ffMpegExe;
@@ -48,9 +63,16 @@ namespace FileFlows.VideoNodes
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.ArgumentList.Add("-hide_banner");
process.StartInfo.ArgumentList.Add("-i");
process.StartInfo.ArgumentList.Add(filename);
foreach (var arg in new[]
{
"-hide_banner",
"-probesize", ProbeSize + "M",
"-i",
filename,
})
{
process.StartInfo.ArgumentList.Add(arg);
}
process.Start();
string output = process.StandardError.ReadToEnd();
output = output.Replace("At least one output file must be specified", string.Empty).Trim();
@@ -243,14 +265,25 @@ namespace FileFlows.VideoNodes
audio.TypeIndex = int.Parse(Regex.Match(line, @"#([\d]+):([\d]+)").Groups[2].Value) - 1;
audio.Codec = parts[0].Substring(parts[0].IndexOf("Audio: ") + "Audio: ".Length).Trim().Split(' ').First().ToLower() ?? "";
audio.Language = Regex.Match(line, @"(?<=(Stream\s#[\d]+:[\d]+)\()[^\)]+").Value?.ToLower() ?? "";
//Logger.ILog("codec: " + vs.Codec);
if (parts[2] == "stereo")
audio.Channels = 2;
else if (parts[2] == "mono")
audio.Channels = 1;
else if (Regex.IsMatch(parts[2], @"^[\d]+(\.[\d]+)?"))
if (info.IndexOf("0 channels") >= 0)
{
audio.Channels = float.Parse(Regex.Match(parts[2], @"^[\d]+(\.[\d]+)?").Value);
audio.Channels = 0;
}
else
{
try
{
//Logger.ILog("codec: " + vs.Codec);
if (parts[2] == "stereo")
audio.Channels = 2;
else if (parts[2] == "mono")
audio.Channels = 1;
else if (Regex.IsMatch(parts[2], @"^[\d]+(\.[\d]+)?"))
{
audio.Channels = float.Parse(Regex.Match(parts[2], @"^[\d]+(\.[\d]+)?").Value);
}
}
catch (Exception) { }
}
var match = rgxAudioSampleRate.Match(info);

View File

@@ -119,6 +119,11 @@
"Description": "An input video file that has had its VideoInformation read and can be processed",
"Outputs": {
"1": "Video file from library"
},
"Fields": {
"ProbeSize": "Probe Size",
"ProbeSize-Suffix": "MB",
"ProbeSize-Help": "The probe size to use in FFMPEG when executing."
}
},
"DetectBlackBars": {
@@ -157,7 +162,11 @@
"1": "FFMPEG Builder ran successfully and created new temporary file",
"2": "No changes detected in FFMPEG Builder, file not created"
},
"Description": "Executes a FFMPEG Builder command created by other FFMPEG Builder nodes."
"Description": "Executes a FFMPEG Builder command created by other FFMPEG Builder nodes.",
"Fields": {
"HardwareDecoding": "Hardware Decoding",
"HardwareDecoding-Help": "If the executor should attempt to use hardware decoding. If not available the execution will proceed just without hardware decoding enabled."
}
},
"FfmpegBuilderAudioAddTrack": {
"Label": "FFMPEG Builder: Audio Add Track",
@@ -369,6 +378,18 @@
"1": "FFMPEG Builder video streams set to encode in 10 Bit"
}
},
"FfmpegBuilderVideoBitrate": {
"Label": "FFMPEG Builder: Video Bitrate",
"Description": "Sets FFMPEG Builder to encode the video given the bitrate",
"Outputs": {
"1": "FFMPEG Builder video streams updated"
},
"Fields": {
"Bitrate": "Bitrate",
"Bitrate-Suffix": "KB",
"Bitrate-Help": "The target bitrate of the video in kilobytes"
}
},
"FfmpegBuilderVideoCodec": {
"Label": "FFMPEG Builder: Video Codec",
"Description": "Sets FFMPEG Builder to encode the video streams in the specified codec",

View File

@@ -101,7 +101,7 @@ namespace FileFlows.VideoNodes
if(vidparams.ToLower() == "hevc" || vidparams.ToLower() == "h265")
{
// try find best hevc encoder
foreach(string vidparam in new [] { "hevc_nvenc -preset hq", "hevc_qsv -load_plugin hevc_hw", "hevc_amf", "hevc_vaapi" })
foreach(string vidparam in new [] { "hevc_nvenc -preset hq", "hevc_qsv -global_quality 28 -load_plugin hevc_hw", "hevc_amf", "hevc_vaapi" })
{
bool canProcess = CanProcessEncoder(ffmpeg, vidparam);
if (canProcess)
@@ -185,7 +185,7 @@ namespace FileFlows.VideoNodes
}).Result;
if (cmd.ExitCode != 0 || string.IsNullOrWhiteSpace(cmd.Output) == false)
{
args.Logger?.WLog($"Cant prcoess '{encodingParams}': {cmd.Output ?? ""}");
args.Logger?.WLog($"Cant process '{encodingParams}': {cmd.Output ?? ""}");
return false;
}
return true;

View File

@@ -23,7 +23,7 @@ $output = $output | Resolve-Path
Remove-Item Builds -Recurse -ErrorAction SilentlyContinue
$revision = (git rev-list --count --first-parent HEAD) -join "`n"
$version = "0.5.3.$revision"
$version = "0.5.4.$revision"
$json = "[`n"