FF-1008 - fixing ordering of newly created tracks

This commit is contained in:
John Andrews
2023-07-14 06:24:38 +12:00
parent 477260685d
commit 8033daef3b
6 changed files with 206 additions and 22 deletions

View File

@@ -2,23 +2,37 @@
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
/// <summary>
/// FFmpeg Builder: Add Audio Track
/// </summary>
public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
{
/// <summary>
/// Gets the icon for this flow element
/// </summary>
public override string Icon => "fas fa-volume-off";
/// <summary>
/// Gets the help URL for this flow element
/// </summary>
public override string HelpUrl => "https://fileflows.com/docs/plugins/video-nodes/ffmpeg-builder/add-audio-track";
/// <summary>
/// Gets or sets the index to insert this track
/// </summary>
[NumberInt(1)]
[Range(0, 100)]
[DefaultValue(1)]
public int Index { get; set; }
/// <summary>
/// Gets or sets the codec to to use
/// </summary>
[DefaultValue("aac")]
[Select(nameof(CodecOptions), 1)]
public string Codec { get; set; }
private static List<ListOption> _CodecOptions;
/// <summary>
/// Gets the codec options
/// </summary>
public static List<ListOption> CodecOptions
{
get
@@ -37,12 +51,17 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return _CodecOptions;
}
}
/// <summary>
/// Gets or sets the audio channels for the new track
/// </summary>
[DefaultValue(2f)]
[Select(nameof(ChannelsOptions), 2)]
public float Channels { get; set; }
private static List<ListOption> _ChannelsOptions;
/// <summary>
/// Gets the channel options
/// </summary>
public static List<ListOption> ChannelsOptions
{
get
@@ -61,11 +80,16 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return _ChannelsOptions;
}
}
/// <summary>
/// Gets or sets the bitrate
/// </summary>
[Select(nameof(BitrateOptions), 3)]
public int Bitrate { get; set; }
private static List<ListOption> _BitrateOptions;
/// <summary>
/// Gets the background bitrate options
/// </summary>
public static List<ListOption> BitrateOptions
{
get
@@ -84,18 +108,29 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
return _BitrateOptions;
}
}
/// <summary>
/// Gets or sets the language of the nee track
/// </summary>
[DefaultValue("eng")]
[TextVariable(4)]
public string Language { get; set; }
/// <summary>
/// Gets or sets if the title of the new track should be removed
/// </summary>
[Boolean(5)]
public bool RemoveTitle { get; set; }
/// <summary>
/// Gets or sets the title of the new track
/// </summary>
[TextVariable(6)]
[ConditionEquals(nameof(RemoveTitle), false)]
public string NewTitle { get; set; }
/// <summary>
/// Executes the flow element
/// </summary>
/// <param name="args">the node parameters</param>
/// <returns>the output node to execute next</returns>
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;
}
/// <summary>
/// Gets the best audio track
/// </summary>
/// <param name="args">the node parameters</param>
/// <param name="streams">the possible audio streams</param>
/// <returns>the best stream</returns>
internal AudioStream GetBestAudioTrack(NodeParameters args, IEnumerable<AudioStream> 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)
/// <summary>
/// Gets hte new audio track parameters
/// </summary>
/// <param name="codec">the codec of the new track</param>
/// <param name="channels">the channels of the new track</param>
/// <param name="bitrate">the bitrate of the new track</param>
/// <returns>the new track parameters</returns>
internal static string[] GetNewAudioTrackParameters(string codec, float channels, int bitrate)
{
if (codec == "opus")
codec = "libopus";

View File

@@ -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;
}
}

View File

@@ -3,29 +3,49 @@ using System.Text;
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
/// <summary>
/// FFmpeg Builder: Audio Track Reorder
/// </summary>
public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
{
/// <summary>
/// Gets the number of output nodes
/// </summary>
public override int Outputs => 2;
/// <summary>
/// Gets the icon
/// </summary>
public override string Icon => "fas fa-sort-alpha-down";
/// <summary>
/// Gets the help URL
/// </summary>
public override string HelpUrl => "https://fileflows.com/docs/plugins/video-nodes/ffmpeg-builder/track-reorder";
/// <summary>
/// Gets or sets the stream type
/// </summary>
[Select(nameof(StreamTypeOptions), 1)]
public string StreamType { get; set; }
/// <summary>
/// Gets or sets the languages
/// </summary>
[StringArray(2)]
public List<string> Languages { get; set; }
/// <summary>
/// Gets or sets the ordered tracks
/// </summary>
[StringArray(3)]
public List<string> OrderedTracks { get; set; }
/// <summary>
/// Gets or sets the channels
/// </summary>
[StringArray(4)]
[ConditionEquals(nameof(StreamType), "Subtitle", inverse: true)]
public List<string> Channels { get; set; }
private static List<ListOption> _StreamTypeOptions;
/// <summary>
/// Gets or sets the stream type options
/// </summary>
public static List<ListOption> StreamTypeOptions
{
get
@@ -42,6 +62,11 @@ public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
}
}
/// <summary>
/// Executes the flow element
/// </summary>
/// <param name="args">the node parameters</param>
/// <returns>the next output node</returns>
public override int Execute(NodeParameters args)
{
OrderedTracks = OrderedTracks?.Select(x => x.ToLower())?.ToList() ?? new();
@@ -92,6 +117,12 @@ public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
}
}
/// <summary>
/// Reorders the tracks
/// </summary>
/// <param name="input">the inputs to reorder</param>
/// <typeparam name="T">the type to reorder</typeparam>
/// <returns>the reordered tracks</returns>
public List<T> Reorder<T>(List<T> input) where T : FfmpegStream
{
Languages ??= new List<string>();
@@ -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;
}
/// <summary>
/// Tests if two lists are the same
/// </summary>
/// <param name="original">the original list</param>
/// <param name="reordered">the reordered list</param>
/// <typeparam name="T">the type of items</typeparam>
/// <returns>true if the lists are the same, otherwise false</returns>
public bool AreSame<T>(List<T> original, List<T> reordered) where T: FfmpegStream
{
for (int i = 0; i < reordered.Count; i++)

View File

@@ -4,6 +4,13 @@
{
public AudioStream Stream { get; set; }
public override bool HasChange => EncodingParameters.Any() || Filter.Any();
/// <summary>
/// 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
/// </summary>
public float Channels { get; set; }
private List<string> _EncodingParameters = new List<string>();
public List<string> EncodingParameters

View File

@@ -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)))

View File

@@ -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;
/// <summary>
/// Tests for track reorders
/// </summary>
[TestClass]
public class FFmpegBuilder_TrackReorderTests
{
/// <summary>
/// Basic test
/// </summary>
[TestMethod]
public void Basic()
{
var element = new FfmpegBuilderAudioTrackReorder();
List<FfmpegAudioStream> 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);
}
/// <summary>
/// Basic test 2
/// </summary>
[TestMethod]
public void Basic_2()
{
var element = new FfmpegBuilderAudioTrackReorder();
List<FfmpegAudioStream> 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);
}
/// <summary>
/// Basic test 3
/// </summary>
[TestMethod]
public void Basic_3()
{
var element = new FfmpegBuilderAudioTrackReorder();
List<FfmpegAudioStream> 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