mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-01-03 19:39:29 -06:00
FF-1008 - fixing ordering of newly created tracks
This commit is contained in:
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user