Files
FileFlowsPlugins/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs
T
2024-02-02 11:31:54 +13:00

218 lines
6.8 KiB
C#

using FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
using System.Text;
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
/// <summary>
/// FFmpeg Builder: Audio Track Reorder
/// </summary>
public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
{
/// <summary>
/// Gets that this node is obsolete
/// </summary>
public override bool Obsolete => true;
/// <summary>
/// Gets the obsolete message
/// </summary>
public override string ObsoleteMessage => "This has been replaced with the Track Sorter flow element.\n\nUse that instead.";
/// <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
{
if (_StreamTypeOptions == null)
{
_StreamTypeOptions = new List<ListOption>
{
new ListOption { Label = "Audio", Value = "Audio" },
new ListOption { Label = "Subtitle", Value = "Subtitle" }
};
}
return _StreamTypeOptions;
}
}
/// <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();
if (StreamType == "Subtitle")
{
var reordered = Reorder(Model.SubtitleStreams);
bool same = AreSame(Model.SubtitleStreams, reordered);
for(int i = 0; i < reordered.Count; i++)
{
reordered[i].IsDefault = i == 0;
}
if (same)
{
args.Logger?.ILog("No subtitle tracks need reordering");
return 2;
}
Model.SubtitleStreams = reordered;
return 1;
}
else
{
var reordered = Reorder(Model.AudioStreams);
bool same = AreSame(Model.AudioStreams, reordered);
for(int i = 0; i < reordered.Count; i++)
{
reordered[i].IsDefault = i == 0;
}
if (same)
{
args.Logger?.ILog("No audio tracks need reordering");
return 2;
}
Model.AudioStreams = reordered;
Model.ForceEncode = true;
return 1;
}
}
/// <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
=> Reorder(Languages, OrderedTracks, Channels, input);
public static List<T> Reorder<T>(List<string> languages, List<string> orderedTracks, List<string> channels, List<T> input) where T : FfmpegStream
{
languages ??= new List<string>();
orderedTracks ??= new List<string>();
channels ??= new List<string>();
List<float> actualChannels = channels.Select(x =>
{
if (float.TryParse(x, out float value))
return value;
return -1f;
}).Where(x => x > 0f).ToList();
if (languages.Any() == false && orderedTracks.Any() == false && actualChannels.Any() == false)
return input; // nothing to do
languages.Reverse();
orderedTracks.Reverse();
actualChannels.Reverse();
const int base_number = 1_000_000_000;
int count = base_number;
var debug = new StringBuilder();
var data = input.OrderBy(x =>
{
int langIndex = 0;
int codecIndex = 0;
int channelIndex = 0;
if (x is FfmpegAudioStream audioStream)
{
langIndex = languages.IndexOf(audioStream.Stream.Language?.ToLower() ?? String.Empty);
codecIndex = orderedTracks.IndexOf(audioStream.Stream.Codec?.ToLower() ?? String.Empty);
float asChannels = audioStream.Channels > 0 ? audioStream.Channels : audioStream.Stream.Channels;
channelIndex = actualChannels.IndexOf(asChannels);
}
else if (x is FfmpegSubtitleStream subStream)
{
langIndex = languages.IndexOf(subStream.Stream.Language?.ToLower() ?? String.Empty);
codecIndex = orderedTracks.IndexOf(subStream.Stream.Codec?.ToLower() ?? String.Empty);
}
int result = base_number;
if (langIndex >= 0)
{
result -= ((langIndex + 1) * 10_000_000);
}
if (codecIndex >= 0)
{
result -= ((codecIndex + 1) * 100_000);
}
if (channelIndex >= 0)
{
result -= ((channelIndex + 1) * 1_000);
}
if (result == base_number)
result = ++count;
return result;
}).ToList();
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++)
{
if (reordered[i] != original[i])
{
return false;
}
}
return true;
}
}