diff --git a/FFMpegCore.Test/ArgumentBuilderTest.cs b/FFMpegCore.Test/ArgumentBuilderTest.cs
index 54620a5..9cf7e39 100644
--- a/FFMpegCore.Test/ArgumentBuilderTest.cs
+++ b/FFMpegCore.Test/ArgumentBuilderTest.cs
@@ -334,7 +334,7 @@ public void Builder_BuildString_SubtitleHardBurnFilter()
.HardBurnSubtitle(SubtitleHardBurnOptions
.Create(subtitlePath: "sample.srt")
.SetCharacterEncoding("UTF-8")
- .SetOriginalSize(1366,768)
+ .SetOriginalSize(1366, 768)
.SetSubtitleIndex(0)
.WithStyle(StyleOptions.Create()
.WithParameter("FontName", "DejaVu Serif")
@@ -479,10 +479,21 @@ public void Builder_BuildString_DynamicAudioNormalizerWithValuesFormat()
{
var str = FFMpegArguments.FromFileInput("input.mp4")
.OutputToFile("output.mp4", false,
- opt => opt.WithAudioFilters(filterOptions => filterOptions.DynamicNormalizer(125, 13, 0.9215, 5.124, 0.5458,false,true,true, 0.3333333)))
+ opt => opt.WithAudioFilters(filterOptions => filterOptions.DynamicNormalizer(125, 13, 0.9215, 5.124, 0.5458, false, true, true, 0.3333333)))
.Arguments;
Assert.AreEqual("-i \"input.mp4\" -af \"dynaudnorm=f=125:g=13:p=0.92:m=5.1:r=0.5:n=0:c=1:b=1:s=0.3\" \"output.mp4\"", str);
}
+
+ [TestMethod]
+ public void Builder_BuildString_Audible_AAXC_Decryption()
+ {
+ var str = FFMpegArguments.FromFileInput("input.aaxc", false, x => x.WithAudibleEncryptionKeys("123", "456"))
+ .MapMetaData()
+ .OutputToFile("output.m4b", true, x => x.WithTagVersion(3).DisableChannel(Channel.Video).CopyChannel(Channel.Audio))
+ .Arguments;
+
+ Assert.AreEqual("-audible_key 123 -audible_iv 456 -i \"input.aaxc\" -map_metadata 0 -id3v2_version 3 -vn -c:a copy \"output.m4b\" -y", str);
+ }
}
}
\ No newline at end of file
diff --git a/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs b/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs
index 8443d0d..6e30999 100644
--- a/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs
+++ b/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs
@@ -94,5 +94,20 @@ public void Concat_Escape()
var arg = new DemuxConcatArgument(new[] { @"Heaven's River\05 - Investigation.m4b" });
arg.Values.Should().BeEquivalentTo(new[] { @"file 'Heaven'\''s River\05 - Investigation.m4b'" });
}
+
+ [TestMethod]
+ public void Audible_Aaxc_Test()
+ {
+ var arg = new AudibleEncryptionKeyArgument("123", "456");
+ arg.Text.Should().Be($"-audible_key 123 -audible_iv 456");
+ }
+
+
+ [TestMethod]
+ public void Audible_Aax_Test()
+ {
+ var arg = new AudibleEncryptionKeyArgument("62689101");
+ arg.Text.Should().Be($"-activation_bytes 62689101");
+ }
}
}
\ No newline at end of file
diff --git a/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs b/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs
new file mode 100644
index 0000000..0f514dc
--- /dev/null
+++ b/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs
@@ -0,0 +1,28 @@
+namespace FFMpegCore.Arguments
+{
+ public class AudibleEncryptionKeyArgument : IArgument
+ {
+ private readonly bool _aaxcMode;
+
+ private readonly string _key;
+ private readonly string _iv;
+
+ private readonly string _activationBytes;
+
+
+ public AudibleEncryptionKeyArgument(string activationBytes)
+ {
+ _activationBytes = activationBytes;
+ }
+
+ public AudibleEncryptionKeyArgument(string key, string iv)
+ {
+ _aaxcMode = true;
+
+ _key = key;
+ _iv = iv;
+ }
+
+ public string Text => _aaxcMode ? $"-audible_key {_key} -audible_iv {_iv}" : $"-activation_bytes {_activationBytes}";
+ }
+}
diff --git a/FFMpegCore/FFMpeg/Arguments/ID3V2VersionArgument.cs b/FFMpegCore/FFMpeg/Arguments/ID3V2VersionArgument.cs
new file mode 100644
index 0000000..e18d93b
--- /dev/null
+++ b/FFMpegCore/FFMpeg/Arguments/ID3V2VersionArgument.cs
@@ -0,0 +1,14 @@
+namespace FFMpegCore.Arguments
+{
+ public class ID3V2VersionArgument : IArgument
+ {
+ private readonly int _version;
+
+ public ID3V2VersionArgument(int version)
+ {
+ _version = version;
+ }
+
+ public string Text => $"-id3v2_version {_version}";
+ }
+}
diff --git a/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs b/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs
new file mode 100644
index 0000000..afec731
--- /dev/null
+++ b/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs
@@ -0,0 +1,64 @@
+using FFMpegCore.Extend;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FFMpegCore.Arguments
+{
+ public class MapMetadataArgument : IInputArgument, IDynamicArgument
+ {
+ private readonly int? _inputIndex;
+
+ public string Text => GetText(null);
+
+ ///
+ /// Null means it takes the last input used before this argument
+ ///
+ ///
+ public MapMetadataArgument(int? inputIndex = null)
+ {
+ _inputIndex = inputIndex;
+ }
+
+ public string GetText(IEnumerable? arguments)
+ {
+ arguments ??= Enumerable.Empty();
+
+ var index = 0;
+ if (_inputIndex is null)
+ {
+ index = arguments
+ .TakeWhile(x => x != this)
+ .OfType()
+ .Count();
+
+ index = Math.Max(index - 1, 0);
+ }
+ else
+ {
+ index = _inputIndex.Value;
+ }
+
+ return $"-map_metadata {index}";
+ }
+
+ public Task During(CancellationToken cancellationToken = default)
+ {
+ return Task.CompletedTask;
+ }
+
+ public void Post()
+ {
+ }
+
+ public void Pre()
+ {
+ }
+
+
+ }
+}
diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs b/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
index ca6628a..7b3da7a 100644
--- a/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
+++ b/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
@@ -1,5 +1,6 @@
using System;
using System.Drawing;
+
using FFMpegCore.Arguments;
using FFMpegCore.Enums;
@@ -66,6 +67,11 @@ public FFMpegArgumentOptions WithAudioFilters(Action audioFi
public FFMpegArgumentOptions ForcePixelFormat(string pixelFormat) => WithArgument(new ForcePixelFormat(pixelFormat));
public FFMpegArgumentOptions ForcePixelFormat(PixelFormat pixelFormat) => WithArgument(new ForcePixelFormat(pixelFormat));
+ public FFMpegArgumentOptions WithAudibleEncryptionKeys(string key, string iv) => WithArgument(new AudibleEncryptionKeyArgument(key, iv));
+ public FFMpegArgumentOptions WithAudibleActivationBytes(string activationBytes) => WithArgument(new AudibleEncryptionKeyArgument(activationBytes));
+ public FFMpegArgumentOptions WithTagVersion(int id3v2Version = 3) => WithArgument(new ID3V2VersionArgument(id3v2Version));
+
+
public FFMpegArgumentOptions WithArgument(IArgument argument)
{
Arguments.Add(argument);
diff --git a/FFMpegCore/FFMpeg/FFMpegArguments.cs b/FFMpegCore/FFMpeg/FFMpegArguments.cs
index a93f1bd..c100c85 100644
--- a/FFMpegCore/FFMpeg/FFMpegArguments.cs
+++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs
@@ -50,6 +50,13 @@ public FFMpegArguments WithGlobalOptions(Action configure
public FFMpegArguments AddMetaData(string content, Action? addArguments = null) => WithInput(new MetaDataArgument(content), addArguments);
public FFMpegArguments AddMetaData(IReadOnlyMetaData metaData, Action? addArguments = null) => WithInput(new MetaDataArgument(MetaDataSerializer.Instance.Serialize(metaData)), addArguments);
+
+ ///
+ /// Maps the metadata of the given stream
+ ///
+ /// null means, the previous input will be used
+ public FFMpegArguments MapMetaData(int? inputIndex = null, Action? addArguments = null) => WithInput(new MapMetadataArgument(inputIndex), addArguments);
+
private FFMpegArguments WithInput(IInputArgument inputArgument, Action? addArguments)
{
var arguments = new FFMpegArgumentOptions();