mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-01-04 03:49:28 -06:00
added Audio Add Track node
This commit is contained in:
46
VideoNodes/Tests/AudioAddTrackTests.cs
Normal file
46
VideoNodes/Tests/AudioAddTrackTests.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
#if(DEBUG)
|
||||
|
||||
namespace VideoNodes.Tests
|
||||
{
|
||||
using FileFlows.VideoNodes;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[TestClass]
|
||||
public class AudioAddTrackTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void AudioAddTrackTests_Mono_First()
|
||||
{
|
||||
const string file = @"D:\videos\unprocessed\The Witcher - S02E05 - Turn Your Back.mkv";
|
||||
var logger = new TestLogger();
|
||||
var vi = new VideoInfoHelper(@"C:\utils\ffmpeg\ffmpeg.exe", logger);
|
||||
var vii = vi.Read(file);
|
||||
|
||||
const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe";
|
||||
|
||||
AudioAddTrack node = new();
|
||||
var args = new FileFlows.Plugin.NodeParameters(file, logger, false, string.Empty);
|
||||
args.GetToolPathActual = (string tool) => ffmpeg;
|
||||
args.TempPath = @"D:\videos\temp";
|
||||
|
||||
new VideoFile().Execute(args);
|
||||
node.Bitrate = 128;
|
||||
node.Channels = 2;
|
||||
node.Index = 2;
|
||||
node.Codec = "aac";
|
||||
|
||||
int output = node.Execute(args);
|
||||
string log = logger.ToString();
|
||||
Assert.AreEqual(1, output);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,21 @@
|
||||
{
|
||||
"Flow":{
|
||||
"Parts": {
|
||||
"AudioAddTrack": {
|
||||
"Outputs": {
|
||||
"1": "Audio track adde and saved to temporary file"
|
||||
},
|
||||
"Description": "Adds a new audio track to ta video file, all other audio tracks will remain. This will use the first audio track of the file as the source audio track to convert.",
|
||||
"Fields": {
|
||||
"Index": "Index",
|
||||
"Index-Help": "The index where to insert the new audio track. 1 based, so to insert the new audio track as the first track set this to 1.",
|
||||
"Channels": "Channels",
|
||||
"Channels-Help": "The number of channels to convert this audio track to.",
|
||||
"Bitrate": "Bitrate",
|
||||
"Bitrate-Help": "Bitrate of the new audio track"
|
||||
}
|
||||
|
||||
},
|
||||
"AudioAdjustVolume": {
|
||||
"Outputs": {
|
||||
"1": "Audio tracks volume was adjusted and saved to temporary file",
|
||||
|
||||
179
VideoNodes/VideoNodes/AudioAddTrack.cs
Normal file
179
VideoNodes/VideoNodes/AudioAddTrack.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
namespace FileFlows.VideoNodes
|
||||
{
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
public class AudioAddTrack: EncodingNode
|
||||
{
|
||||
public override int Outputs => 1;
|
||||
|
||||
public override string Icon => "fas fa-volume-down";
|
||||
|
||||
[NumberInt(1)]
|
||||
[Range(1, 100)]
|
||||
public int Index { get; set; }
|
||||
|
||||
|
||||
[Select(nameof(CodecOptions), 1)]
|
||||
public string Codec { get; set; }
|
||||
|
||||
private static List<ListOption> _CodecOptions;
|
||||
public static List<ListOption> CodecOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_CodecOptions == null)
|
||||
{
|
||||
_CodecOptions = new List<ListOption>
|
||||
{
|
||||
new ListOption { Label = "AAC", Value = "aac"},
|
||||
new ListOption { Label = "AC3", Value = "ac3"},
|
||||
new ListOption { Label = "EAC3", Value = "eac3" },
|
||||
new ListOption { Label = "MP3", Value = "mp3"},
|
||||
};
|
||||
}
|
||||
return _CodecOptions;
|
||||
}
|
||||
}
|
||||
|
||||
[Select(nameof(ChannelsOptions), 2)]
|
||||
public float Channels { get; set; }
|
||||
|
||||
private static List<ListOption> _ChannelsOptions;
|
||||
public static List<ListOption> ChannelsOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_ChannelsOptions == null)
|
||||
{
|
||||
_ChannelsOptions = new List<ListOption>
|
||||
{
|
||||
new ListOption { Label = "Same as source", Value = 0},
|
||||
new ListOption { Label = "Mono", Value = 1f},
|
||||
new ListOption { Label = "Stereo", Value = 2f}
|
||||
};
|
||||
}
|
||||
return _ChannelsOptions;
|
||||
}
|
||||
}
|
||||
|
||||
[Select(nameof(BitrateOptions), 3)]
|
||||
public int Bitrate { get; set; }
|
||||
|
||||
private static List<ListOption> _BitrateOptions;
|
||||
public static List<ListOption> BitrateOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_BitrateOptions == null)
|
||||
{
|
||||
_BitrateOptions = new List<ListOption>
|
||||
{
|
||||
new ListOption { Label = "64 Kbps", Value = 64},
|
||||
new ListOption { Label = "96 Kbps", Value = 96},
|
||||
new ListOption { Label = "128 Kbps", Value = 128},
|
||||
new ListOption { Label = "160 Kbps", Value = 160},
|
||||
new ListOption { Label = "192 Kbps", Value = 192},
|
||||
new ListOption { Label = "224 Kbps", Value = 224},
|
||||
new ListOption { Label = "256 Kbps", Value = 256},
|
||||
new ListOption { Label = "288 Kbps", Value = 288},
|
||||
new ListOption { Label = "320 Kbps", Value = 320},
|
||||
};
|
||||
}
|
||||
return _BitrateOptions;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
try
|
||||
{
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
List<string> ffArgs = new List<string>
|
||||
{
|
||||
"-c", "copy",
|
||||
"-map", "0:v",
|
||||
};
|
||||
|
||||
bool added = false;
|
||||
int audioIndex = 0;
|
||||
for(int i = 0; i < videoInfo.AudioStreams.Count; i++)
|
||||
{
|
||||
if((i + 1) == Index)
|
||||
{
|
||||
ffArgs.AddRange(GetNewAudioTrackParameters(videoInfo, audioIndex));
|
||||
added = true;
|
||||
++audioIndex;
|
||||
}
|
||||
ffArgs.AddRange(new[]
|
||||
{
|
||||
"-map", videoInfo.AudioStreams[i].IndexString,
|
||||
"-c:a:" + audioIndex, "copy"
|
||||
});
|
||||
++audioIndex;
|
||||
}
|
||||
|
||||
if(added == false) // incase the index is greater than the number of tracks this file has
|
||||
ffArgs.AddRange(GetNewAudioTrackParameters(videoInfo, audioIndex));
|
||||
|
||||
if (videoInfo.SubtitleStreams?.Any() == true)
|
||||
ffArgs.AddRange(new[] { "-map", "0:s" });
|
||||
|
||||
if (Index < 2)
|
||||
{
|
||||
// this makes the first audio track now the default track
|
||||
ffArgs.AddRange(new[] { "-disposition:a:0", "default" });
|
||||
}
|
||||
|
||||
string extension = new FileInfo(args.WorkingFile).Extension;
|
||||
if(extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Logger?.ELog("Failed processing VideoFile: " + ex.Message);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private string[] GetNewAudioTrackParameters(VideoInfo videoInfo, int index)
|
||||
{
|
||||
if (Channels == 0)
|
||||
{
|
||||
// same as source
|
||||
return new[]
|
||||
{
|
||||
"-map", videoInfo.AudioStreams[0].IndexString,
|
||||
"-c:a:" + index, Codec,
|
||||
"-b:a:" + index, Bitrate + "k"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
"-map", videoInfo.AudioStreams[0].IndexString,
|
||||
"-c:a:" + index, Codec,
|
||||
"-ac", Channels.ToString(),
|
||||
"-b:a:" + index, Bitrate + "k"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,6 @@
|
||||
args.Logger?.ELog("Failed processing VideoFile: " + ex.Message);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user