diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs
index 441ce13b..a43647c3 100644
--- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs
+++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs
@@ -2,23 +2,37 @@
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
+///
+/// FFmpeg Builder: Add Audio Track
+///
public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
{
+ ///
+ /// Gets the icon for this flow element
+ ///
public override string Icon => "fas fa-volume-off";
-
+ ///
+ /// Gets the help URL for this flow element
+ ///
public override string HelpUrl => "https://fileflows.com/docs/plugins/video-nodes/ffmpeg-builder/add-audio-track";
-
+ ///
+ /// Gets or sets the index to insert this track
+ ///
[NumberInt(1)]
[Range(0, 100)]
[DefaultValue(1)]
public int Index { get; set; }
-
-
+ ///
+ /// Gets or sets the codec to to use
+ ///
[DefaultValue("aac")]
[Select(nameof(CodecOptions), 1)]
public string Codec { get; set; }
private static List _CodecOptions;
+ ///
+ /// Gets the codec options
+ ///
public static List CodecOptions
{
get
@@ -37,12 +51,17 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return _CodecOptions;
}
}
-
+ ///
+ /// Gets or sets the audio channels for the new track
+ ///
[DefaultValue(2f)]
[Select(nameof(ChannelsOptions), 2)]
public float Channels { get; set; }
private static List _ChannelsOptions;
+ ///
+ /// Gets the channel options
+ ///
public static List ChannelsOptions
{
get
@@ -61,11 +80,16 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return _ChannelsOptions;
}
}
-
+ ///
+ /// Gets or sets the bitrate
+ ///
[Select(nameof(BitrateOptions), 3)]
public int Bitrate { get; set; }
private static List _BitrateOptions;
+ ///
+ /// Gets the background bitrate options
+ ///
public static List BitrateOptions
{
get
@@ -84,18 +108,29 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return _BitrateOptions;
}
}
-
+ ///
+ /// Gets or sets the language of the nee track
+ ///
[DefaultValue("eng")]
[TextVariable(4)]
public string Language { get; set; }
-
+ ///
+ /// Gets or sets if the title of the new track should be removed
+ ///
[Boolean(5)]
public bool RemoveTitle { get; set; }
-
+ ///
+ /// Gets or sets the title of the new track
+ ///
[TextVariable(6)]
[ConditionEquals(nameof(RemoveTitle), false)]
public string NewTitle { get; set; }
-
+
+ ///
+ /// Executes the flow element
+ ///
+ /// the node parameters
+ /// the output node to execute next
public override int Execute(NodeParameters args)
{
if (string.IsNullOrEmpty(Codec) || Codec == "ORIGINAL")
@@ -113,6 +148,7 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
}
audio.Stream = bestAudio;
+ audio.Channels = audio.Stream.Channels;
bool directCopy = false;
if(bestAudio.Codec.ToLower() == this.Codec.ToLower())
@@ -129,7 +165,9 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
}
else
{
- audio.EncodingParameters.AddRange(GetNewAudioTrackParameters("0:a:" + (bestAudio.TypeIndex), Codec, Channels, Bitrate));
+ audio.EncodingParameters.AddRange(GetNewAudioTrackParameters(Codec, Channels, Bitrate));
+ if (this.Channels > 0)
+ audio.Channels = this.Channels;
}
if (RemoveTitle)
@@ -145,6 +183,12 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return 1;
}
+ ///
+ /// Gets the best audio track
+ ///
+ /// the node parameters
+ /// the possible audio streams
+ /// the best stream
internal AudioStream GetBestAudioTrack(NodeParameters args, IEnumerable streams)
{
Regex? rgxLanguage = null;
@@ -202,8 +246,14 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return bestAudio;
}
-
- internal static string[] GetNewAudioTrackParameters(string source, string codec, float channels, int bitrate)
+ ///
+ /// Gets hte new audio track parameters
+ ///
+ /// the codec of the new track
+ /// the channels of the new track
+ /// the bitrate of the new track
+ /// the new track parameters
+ internal static string[] GetNewAudioTrackParameters(string codec, float channels, int bitrate)
{
if (codec == "opus")
codec = "libopus";
diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioConvert.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioConvert.cs
index d1a43f5f..3732cdb8 100644
--- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioConvert.cs
+++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioConvert.cs
@@ -136,7 +136,7 @@ public class FfmpegBuilderAudioConverter : FfmpegBuilderNode
if (codecSame && channelsSame && bitrateSame)
return false;
- stream.EncodingParameters.AddRange(FfmpegBuilderAudioAddTrack.GetNewAudioTrackParameters("0:a:" + (stream.Stream.TypeIndex), Codec, Channels, Bitrate));
+ stream.EncodingParameters.AddRange(FfmpegBuilderAudioAddTrack.GetNewAudioTrackParameters(Codec, Channels, Bitrate));
return true;
}
}
diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs
index 86c3de00..9bd836c9 100644
--- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs
+++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs
@@ -3,29 +3,49 @@ using System.Text;
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
+///
+/// FFmpeg Builder: Audio Track Reorder
+///
public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
{
+ ///
+ /// Gets the number of output nodes
+ ///
public override int Outputs => 2;
-
+ ///
+ /// Gets the icon
+ ///
public override string Icon => "fas fa-sort-alpha-down";
-
+ ///
+ /// Gets the help URL
+ ///
public override string HelpUrl => "https://fileflows.com/docs/plugins/video-nodes/ffmpeg-builder/track-reorder";
-
-
+ ///
+ /// Gets or sets the stream type
+ ///
[Select(nameof(StreamTypeOptions), 1)]
public string StreamType { get; set; }
-
+ ///
+ /// Gets or sets the languages
+ ///
[StringArray(2)]
public List Languages { get; set; }
-
+ ///
+ /// Gets or sets the ordered tracks
+ ///
[StringArray(3)]
public List OrderedTracks { get; set; }
-
+ ///
+ /// Gets or sets the channels
+ ///
[StringArray(4)]
[ConditionEquals(nameof(StreamType), "Subtitle", inverse: true)]
public List Channels { get; set; }
private static List _StreamTypeOptions;
+ ///
+ /// Gets or sets the stream type options
+ ///
public static List StreamTypeOptions
{
get
@@ -42,6 +62,11 @@ public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
}
}
+ ///
+ /// Executes the flow element
+ ///
+ /// the node parameters
+ /// the next output node
public override int Execute(NodeParameters args)
{
OrderedTracks = OrderedTracks?.Select(x => x.ToLower())?.ToList() ?? new();
@@ -92,6 +117,12 @@ public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
}
}
+ ///
+ /// Reorders the tracks
+ ///
+ /// the inputs to reorder
+ /// the type to reorder
+ /// the reordered tracks
public List Reorder(List input) where T : FfmpegStream
{
Languages ??= new List();
@@ -124,7 +155,8 @@ public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
{
langIndex = Languages.IndexOf(audioStream.Stream.Language?.ToLower() ?? String.Empty);
codecIndex = OrderedTracks.IndexOf(audioStream.Stream.Codec?.ToLower() ?? String.Empty);
- channelIndex = actualChannels.IndexOf(audioStream.Stream.Channels);
+ float channels = audioStream.Channels > 0 ? audioStream.Channels : audioStream.Stream.Channels;
+ channelIndex = actualChannels.IndexOf(channels);
}
else if (x is FfmpegSubtitleStream subStream)
{
@@ -152,6 +184,14 @@ public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
return data;
}
+
+ ///
+ /// Tests if two lists are the same
+ ///
+ /// the original list
+ /// the reordered list
+ /// the type of items
+ /// true if the lists are the same, otherwise false
public bool AreSame(List original, List reordered) where T: FfmpegStream
{
for (int i = 0; i < reordered.Count; i++)
diff --git a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegAudioStream.cs b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegAudioStream.cs
index b8b34c7f..b1b687b4 100644
--- a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegAudioStream.cs
+++ b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegAudioStream.cs
@@ -4,6 +4,13 @@
{
public AudioStream Stream { get; set; }
public override bool HasChange => EncodingParameters.Any() || Filter.Any();
+
+ ///
+ /// Gets or sets the channels for this stream
+ /// Note: changing this will not magically change the channels for processing, you must change manually
+ /// down-mix or up-mix then update this channel count, this is intended for sorting only
+ ///
+ public float Channels { get; set; }
private List _EncodingParameters = new List();
public List EncodingParameters
diff --git a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegModel.cs b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegModel.cs
index 81b509f0..805eb434 100644
--- a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegModel.cs
+++ b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegModel.cs
@@ -90,6 +90,7 @@
Title = item.stream.Title,
Language = item.stream.Language,
Stream = item.stream,
+ Channels = item.stream.Channels
});
}
foreach (var item in info.SubtitleStreams.Select((stream, index) => (stream, index)))
diff --git a/VideoNodes/Tests/FfmpegBuilderTests/FFmpegBuilder_TrackReorderTests.cs b/VideoNodes/Tests/FfmpegBuilderTests/FFmpegBuilder_TrackReorderTests.cs
new file mode 100644
index 00000000..bcdd6f3b
--- /dev/null
+++ b/VideoNodes/Tests/FfmpegBuilderTests/FFmpegBuilder_TrackReorderTests.cs
@@ -0,0 +1,86 @@
+#if(DEBUG)
+
+using FileFlows.VideoNodes.FfmpegBuilderNodes;
+using FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests;
+
+///
+/// Tests for track reorders
+///
+[TestClass]
+public class FFmpegBuilder_TrackReorderTests
+{
+ ///
+ /// Basic test
+ ///
+ [TestMethod]
+ public void Basic()
+ {
+ var element = new FfmpegBuilderAudioTrackReorder();
+ List original = new()
+ {
+ new() { Index = 1, Channels = 2, Stream = new() { Language = "en", Codec = "ac3", Channels = 5.1f } },
+ new() { Index = 2, Channels = 0, Stream = new() { Language = "en", Codec = "ac3", Channels = 5.1f } },
+ new() { Index = 3, Channels = 5.1f, Stream = new() { Language = "fr", Codec = "ac3", Channels = 5.1f } },
+ new() { Index = 4, Channels = 5.1f, Stream = new() { Language = "en", Codec = "aac", Channels = 2 } },
+ };
+ element.Channels = new() { "5.1" };
+ var reordered = element.Reorder(original);
+ Assert.IsFalse(element.AreSame(original, reordered));
+ Assert.AreEqual(2, reordered[0].Index);
+ Assert.AreEqual(3, reordered[1].Index);
+ Assert.AreEqual(4, reordered[2].Index);
+ Assert.AreEqual(1, reordered[3].Index);
+ }
+
+ ///
+ /// Basic test 2
+ ///
+ [TestMethod]
+ public void Basic_2()
+ {
+ var element = new FfmpegBuilderAudioTrackReorder();
+ List original = new()
+ {
+ new() { Index = 1, Channels = 2, Stream = new() { Language = "en", Codec = "ac3", Channels = 5.1f } },
+ new() { Index = 2, Channels = 0, Stream = new() { Language = "en", Codec = "ac3", Channels = 5.1f } },
+ new() { Index = 3, Channels = 5.1f, Stream = new() { Language = "fr", Codec = "ac3", Channels = 7.1f } },
+ new() { Index = 4, Channels = 5.1f, Stream = new() { Language = "en", Codec = "aac", Channels = 2 } },
+ };
+ element.Channels = new() { "5.1" };
+ var reordered = element.Reorder(original);
+ Assert.IsFalse(element.AreSame(original, reordered));
+ Assert.AreEqual(2, reordered[0].Index);
+ Assert.AreEqual(3, reordered[1].Index);
+ Assert.AreEqual(4, reordered[2].Index);
+ Assert.AreEqual(1, reordered[3].Index);
+ }
+
+ ///
+ /// Basic test 3
+ ///
+ [TestMethod]
+ public void Basic_3()
+ {
+ var element = new FfmpegBuilderAudioTrackReorder();
+ List original = new()
+ {
+ new() { Index = 1, Channels = 2, Stream = new() { Language = "en", Codec = "ac3", Channels = 5.1f } },
+ new() { Index = 2, Channels = 0, Stream = new() { Language = "en", Codec = "ac3", Channels = 5.1f } },
+ new() { Index = 3, Channels = 5.1f, Stream = new() { Language = "fr", Codec = "ac3", Channels = 7.1f } },
+ new() { Index = 4, Channels = 5.1f, Stream = new() { Language = "en", Codec = "aac", Channels = 2 } },
+ };
+ element.Channels = new() { "5.1" };
+ element.OrderedTracks = new() { "aac", "ac3" };
+ var reordered = element.Reorder(original);
+ Assert.IsFalse(element.AreSame(original, reordered));
+ Assert.AreEqual(4, reordered[0].Index);
+ Assert.AreEqual(2, reordered[1].Index);
+ Assert.AreEqual(3, reordered[2].Index);
+ Assert.AreEqual(1, reordered[3].Index);
+ }
+}
+
+#endif
\ No newline at end of file