From 1b2af5fd1f8f9347a8cda058fe3eb9ac5cace1a7 Mon Sep 17 00:00:00 2001 From: Jonas Kamsker Date: Tue, 11 Jan 2022 22:42:31 +0100 Subject: [PATCH 1/9] Using correct map_metadata dynamically --- FFMpegCore.Test/MetaDataBuilderTests.cs | 26 ++++++++++ FFMpegCore/Extend/StringExtensions.cs | 49 ++++++++++++++++++- .../FFMpeg/Arguments/IDynamicArgument.cs | 14 ++++++ .../FFMpeg/Arguments/MetaDataArgument.cs | 17 +++++-- FFMpegCore/FFMpeg/FFMpegArguments.cs | 24 +++++++-- 5 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs diff --git a/FFMpegCore.Test/MetaDataBuilderTests.cs b/FFMpegCore.Test/MetaDataBuilderTests.cs index 5f0a144..747fd9e 100644 --- a/FFMpegCore.Test/MetaDataBuilderTests.cs +++ b/FFMpegCore.Test/MetaDataBuilderTests.cs @@ -4,8 +4,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace FFMpegCore.Test @@ -50,5 +52,29 @@ public void TestMetaDataBuilderIntegrity() Assert.IsTrue(serialized.Contains("title=Chapter 01", StringComparison.OrdinalIgnoreCase)); Assert.IsTrue(serialized.Contains("album_artist=Pachelbel", StringComparison.OrdinalIgnoreCase)); } + + [TestMethod] + public void TestMapMetadata() + { + //-i "whaterver0" // index: 0 + //-f concat -safe 0 + //-i "\AppData\Local\Temp\concat_b511f2bf-c4af-4f71-b9bd-24d706bf4861.txt" // index: 1 + //-i "\AppData\Local\Temp\metadata_210d3259-3d5c-43c8-9786-54b5c414fa70.txt" // index: 2 + //-map_metadata 2 + + var text0 = FFMpegArguments.FromFileInput("whaterver0") + .AddMetaData("WhatEver3") + .Text; + + var text1 = FFMpegArguments.FromFileInput("whaterver0") + .AddDemuxConcatInput(new[] { "whaterver", "whaterver1" }) + .AddMetaData("WhatEver3") + .Text; + + + + Assert.IsTrue(Regex.IsMatch(text0, "metadata_[0-9a-f-]+\\.txt\" -map_metadata 1"), "map_metadata index is calculated incorrectly."); + Assert.IsTrue(Regex.IsMatch(text1, "metadata_[0-9a-f-]+\\.txt\" -map_metadata 2"), "map_metadata index is calculated incorrectly."); + } } } diff --git a/FFMpegCore/Extend/StringExtensions.cs b/FFMpegCore/Extend/StringExtensions.cs index 29c8d42..d07ad1e 100644 --- a/FFMpegCore/Extend/StringExtensions.cs +++ b/FFMpegCore/Extend/StringExtensions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Text; namespace FFMpegCore.Extend @@ -66,5 +67,51 @@ public static string Replace(this string str, Dictionary replaceLi return parsedString.ToString(); } + + /// + /// Counts the number of occurrences of the specified substring within + /// the current string. + /// + /// The current string. + /// The substring we are searching for. + /// Indicates whether or not the algorithm + /// should be aggressive in its search behavior (see Remarks). Default + /// behavior is non-aggressive. + /// This algorithm has two search modes - aggressive and + /// non-aggressive. When in aggressive search mode (aggressiveSearch = + /// true), the algorithm will try to match at every possible starting + /// character index within the string. When false, all subsequent + /// character indexes within a substring match will not be evaluated. + /// For example, if the string was 'abbbc' and we were searching for + /// the substring 'bb', then aggressive search would find 2 matches + /// with starting indexes of 1 and 2. Non aggressive search would find + /// just 1 match with starting index at 1. After the match was made, + /// the non aggressive search would attempt to make it's next match + /// starting at index 3 instead of 2. + /// The count of occurrences of the substring within the string. + public static int CountOccurrences(this string s, string substring, + bool aggressiveSearch = false) + { + // if s or substring is null or empty, substring cannot be found in s + if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(substring)) + return 0; + + // if the length of substring is greater than the length of s, + // substring cannot be found in s + if (substring.Length > s.Length) + return 0; + + int count = 0, n = 0; + while ((n = s.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1) + { + if (aggressiveSearch) + n++; + else + n += substring.Length; + count++; + } + + return count; + } } } \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs b/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs new file mode 100644 index 0000000..1213630 --- /dev/null +++ b/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs @@ -0,0 +1,14 @@ +using System.Text; + +namespace FFMpegCore.Arguments +{ + public interface IDynamicArgument + { + /// + /// Same as , but this receives the arguments generated before as parameter + /// + /// + /// + public string GetText(StringBuilder context); + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs b/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs index 7e9ffc6..c34257e 100644 --- a/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs @@ -1,11 +1,15 @@ -using System; +using FFMpegCore.Extend; + +using System; using System.IO; +using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; namespace FFMpegCore.Arguments { - public class MetaDataArgument : IInputArgument + public class MetaDataArgument : IInputArgument, IDynamicArgument { private readonly string _metaDataContent; private readonly string _tempFileName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"metadata_{Guid.NewGuid()}.txt"); @@ -15,7 +19,7 @@ public MetaDataArgument(string metaDataContent) _metaDataContent = metaDataContent; } - public string Text => $"-i \"{_tempFileName}\" -map_metadata 1"; + public string Text => GetText(null); public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask; @@ -23,5 +27,12 @@ public MetaDataArgument(string metaDataContent) public void Pre() => File.WriteAllText(_tempFileName, _metaDataContent); public void Post() => File.Delete(_tempFileName); + + public string GetText(StringBuilder context) + { + var index = context.ToString().CountOccurrences("-i"); + + return $"-i \"{_tempFileName}\" -map_metadata {index}"; + } } } diff --git a/FFMpegCore/FFMpeg/FFMpegArguments.cs b/FFMpegCore/FFMpeg/FFMpegArguments.cs index 6c9784d..edc2606 100644 --- a/FFMpegCore/FFMpeg/FFMpegArguments.cs +++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; + using FFMpegCore.Arguments; using FFMpegCore.Builders.MetaData; using FFMpegCore.Pipes; @@ -13,10 +15,26 @@ namespace FFMpegCore public sealed class FFMpegArguments : FFMpegArgumentsBase { private readonly FFMpegGlobalArguments _globalArguments = new FFMpegGlobalArguments(); - + private FFMpegArguments() { } - public string Text => string.Join(" ", _globalArguments.Arguments.Concat(Arguments).Select(arg => arg.Text)); + public string Text => GetText(); + + private string GetText() + { + var sb = new StringBuilder(); + + foreach (var arg in _globalArguments.Arguments.Concat(Arguments)) + { + if (sb.Length != 0) + { + sb.Append(' '); + } + sb.Append(arg is IDynamicArgument dynArg ? dynArg.GetText(sb) : arg.Text); + } + + return sb.ToString(); + } public static FFMpegArguments FromConcatInput(IEnumerable filePaths, Action? addArguments = null) => new FFMpegArguments().WithInput(new ConcatArgument(filePaths), addArguments); public static FFMpegArguments FromDemuxConcatInput(IEnumerable filePaths, Action? addArguments = null) => new FFMpegArguments().WithInput(new DemuxConcatArgument(filePaths), addArguments); @@ -26,7 +44,7 @@ private FFMpegArguments() { } public static FFMpegArguments FromDeviceInput(string device, Action? addArguments = null) => new FFMpegArguments().WithInput(new InputDeviceArgument(device), addArguments); public static FFMpegArguments FromPipeInput(IPipeSource sourcePipe, Action? addArguments = null) => new FFMpegArguments().WithInput(new InputPipeArgument(sourcePipe), addArguments); - + public FFMpegArguments WithGlobalOptions(Action configureOptions) { configureOptions(_globalArguments); From bfd2f4a908dfc398e5a6fa0d37513cea5dc41c7e Mon Sep 17 00:00:00 2001 From: Jonas Kamsker Date: Tue, 11 Jan 2022 22:46:33 +0100 Subject: [PATCH 2/9] Fixed possible nullreference --- FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs b/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs index c34257e..6e9f77f 100644 --- a/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs @@ -30,7 +30,7 @@ public MetaDataArgument(string metaDataContent) public string GetText(StringBuilder context) { - var index = context.ToString().CountOccurrences("-i"); + var index = context?.ToString().CountOccurrences("-i") ?? 0; return $"-i \"{_tempFileName}\" -map_metadata {index}"; } From 2626b3796b1d37dee945dd0e9a63a29bd5d55664 Mon Sep 17 00:00:00 2001 From: Jonas Kamsker Date: Wed, 12 Jan 2022 00:15:32 +0100 Subject: [PATCH 3/9] Added support for aaxc decryption --- .../Arguments/AudibleEncryptionKeyArgument.cs | 16 +++++++ .../FFMpeg/Arguments/ID3V2VersionArgument.cs | 14 ++++++ .../FFMpeg/Arguments/MapMetadataArgument.cs | 44 +++++++++++++++++++ FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs | 5 +++ FFMpegCore/FFMpeg/FFMpegArguments.cs | 7 +++ 5 files changed, 86 insertions(+) create mode 100644 FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs create mode 100644 FFMpegCore/FFMpeg/Arguments/ID3V2VersionArgument.cs create mode 100644 FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs diff --git a/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs b/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs new file mode 100644 index 0000000..9f1a325 --- /dev/null +++ b/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs @@ -0,0 +1,16 @@ +namespace FFMpegCore.Arguments +{ + public class AudibleEncryptionKeyArgument : IArgument + { + private readonly string _key; + private readonly string _iv; + + public AudibleEncryptionKeyArgument(string key, string iv) + { + _key = key; + _iv = iv; + } + + public string Text => $"-audible_key {_key} -audible_iv {_iv}"; + } +} 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..01b661c --- /dev/null +++ b/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs @@ -0,0 +1,44 @@ +using FFMpegCore.Extend; + +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace FFMpegCore.Arguments +{ + public class MapMetadataArgument : IInputArgument, IDynamicArgument + { + private readonly int? _inputIndex; + + /// + /// Null means it takes the last input used befroe this argument + /// + /// + public MapMetadataArgument(int? inputIndex = null) + { + _inputIndex = inputIndex; + } + + public string Text => GetText(null); + + public string GetText(StringBuilder context) + { + var index = _inputIndex ?? context?.ToString().CountOccurrences("-i") -1 ?? 0; + 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..b4f5111 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,10 @@ 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 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 edc2606..a628867 100644 --- a/FFMpegCore/FFMpeg/FFMpegArguments.cs +++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs @@ -60,6 +60,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(); From c05337562cb98eb1c08a68147c2ed88e230c8203 Mon Sep 17 00:00:00 2001 From: Jonas Kamsker <11245306+JKamsker@users.noreply.github.com> Date: Wed, 12 Jan 2022 00:31:47 +0100 Subject: [PATCH 4/9] Fixed GetText to pleasure the unit test --- FFMpegCore/FFMpeg/FFMpegArguments.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/FFMpegCore/FFMpeg/FFMpegArguments.cs b/FFMpegCore/FFMpeg/FFMpegArguments.cs index edc2606..4546dbe 100644 --- a/FFMpegCore/FFMpeg/FFMpegArguments.cs +++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs @@ -23,13 +23,19 @@ private FFMpegArguments() { } private string GetText() { var sb = new StringBuilder(); + var appendSpace = false; foreach (var arg in _globalArguments.Arguments.Concat(Arguments)) { - if (sb.Length != 0) + if (appendSpace) { sb.Append(' '); } + else + { + appendSpace = true; + } + sb.Append(arg is IDynamicArgument dynArg ? dynArg.GetText(sb) : arg.Text); } @@ -99,4 +105,4 @@ internal void Post() argument.Post(); } } -} \ No newline at end of file +} From d6bc6c92a5a8a3457b77618832f8bde83429ad4b Mon Sep 17 00:00:00 2001 From: Jonas Kamsker Date: Wed, 12 Jan 2022 00:34:52 +0100 Subject: [PATCH 5/9] Added unit tests --- FFMpegCore.Test/ArgumentBuilderTest.cs | 15 +++++++++++++-- FFMpegCore.Test/FFMpegArgumentProcessorTest.cs | 7 +++++++ 2 files changed, 20 insertions(+), 2 deletions(-) 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..c0a565e 100644 --- a/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs +++ b/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs @@ -94,5 +94,12 @@ 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"); + } } } \ No newline at end of file From 5b0d3d21c9946fb8095559faf3a4ef139115a2ef Mon Sep 17 00:00:00 2001 From: Jonas Kamsker <11245306+JKamsker@users.noreply.github.com> Date: Sun, 20 Mar 2022 19:31:15 +0100 Subject: [PATCH 6/9] Applied reqested changes --- FFMpegCore/Extend/StringExtensions.cs | 5 +-- .../FFMpeg/Arguments/IDynamicArgument.cs | 6 ++-- .../FFMpeg/Arguments/MetaDataArgument.cs | 10 ++++-- FFMpegCore/FFMpeg/FFMpegArguments.cs | 33 ++++++++++--------- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/FFMpegCore/Extend/StringExtensions.cs b/FFMpegCore/Extend/StringExtensions.cs index d07ad1e..35f2e84 100644 --- a/FFMpegCore/Extend/StringExtensions.cs +++ b/FFMpegCore/Extend/StringExtensions.cs @@ -93,12 +93,9 @@ public static int CountOccurrences(this string s, string substring, bool aggressiveSearch = false) { // if s or substring is null or empty, substring cannot be found in s - if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(substring)) - return 0; - // if the length of substring is greater than the length of s, // substring cannot be found in s - if (substring.Length > s.Length) + if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(substring) || substring.Length > s.Length) return 0; int count = 0, n = 0; diff --git a/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs b/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs index 1213630..36a504e 100644 --- a/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs @@ -1,4 +1,5 @@ -using System.Text; +using System.Collections.Generic; +using System.Text; namespace FFMpegCore.Arguments { @@ -9,6 +10,7 @@ public interface IDynamicArgument /// /// /// - public string GetText(StringBuilder context); + //public string GetText(StringBuilder context); + public string GetText(IEnumerable context); } } \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs b/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs index c34257e..89bb1fe 100644 --- a/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs @@ -1,6 +1,7 @@ using FFMpegCore.Extend; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; @@ -28,9 +29,14 @@ public MetaDataArgument(string metaDataContent) public void Post() => File.Delete(_tempFileName); - public string GetText(StringBuilder context) + public string GetText(IEnumerable? arguments) { - var index = context.ToString().CountOccurrences("-i"); + arguments ??= Enumerable.Empty(); + + var index = arguments + .TakeWhile(x => x != this) + .OfType() + .Count(); return $"-i \"{_tempFileName}\" -map_metadata {index}"; } diff --git a/FFMpegCore/FFMpeg/FFMpegArguments.cs b/FFMpegCore/FFMpeg/FFMpegArguments.cs index 4546dbe..e7a5940 100644 --- a/FFMpegCore/FFMpeg/FFMpegArguments.cs +++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs @@ -22,24 +22,27 @@ private FFMpegArguments() { } private string GetText() { - var sb = new StringBuilder(); - var appendSpace = false; + //var sb = new StringBuilder(); + //var appendSpace = false; - foreach (var arg in _globalArguments.Arguments.Concat(Arguments)) - { - if (appendSpace) - { - sb.Append(' '); - } - else - { - appendSpace = true; - } + //foreach (var arg in _globalArguments.Arguments.Concat(Arguments)) + //{ + // if (appendSpace) + // { + // sb.Append(' '); + // } + // else + // { + // appendSpace = true; + // } - sb.Append(arg is IDynamicArgument dynArg ? dynArg.GetText(sb) : arg.Text); - } + // sb.Append(arg is IDynamicArgument dynArg ? dynArg.GetText(sb) : arg.Text); + //} - return sb.ToString(); + //return sb.ToString(); + + var allArguments = _globalArguments.Arguments.Concat(Arguments).ToArray(); + return string.Join(" ", allArguments.Select(arg => arg is IDynamicArgument dynArg ? dynArg.GetText(allArguments) : arg.Text)); } public static FFMpegArguments FromConcatInput(IEnumerable filePaths, Action? addArguments = null) => new FFMpegArguments().WithInput(new ConcatArgument(filePaths), addArguments); From 373c604a11b4050846d88a15f57b919e16dd7e1e Mon Sep 17 00:00:00 2001 From: Jonas Kamsker <11245306+JKamsker@users.noreply.github.com> Date: Sun, 20 Mar 2022 19:32:48 +0100 Subject: [PATCH 7/9] Removed string count extension --- FFMpegCore/Extend/StringExtensions.cs | 43 --------------------------- 1 file changed, 43 deletions(-) diff --git a/FFMpegCore/Extend/StringExtensions.cs b/FFMpegCore/Extend/StringExtensions.cs index 35f2e84..7b02089 100644 --- a/FFMpegCore/Extend/StringExtensions.cs +++ b/FFMpegCore/Extend/StringExtensions.cs @@ -67,48 +67,5 @@ public static string Replace(this string str, Dictionary replaceLi return parsedString.ToString(); } - - /// - /// Counts the number of occurrences of the specified substring within - /// the current string. - /// - /// The current string. - /// The substring we are searching for. - /// Indicates whether or not the algorithm - /// should be aggressive in its search behavior (see Remarks). Default - /// behavior is non-aggressive. - /// This algorithm has two search modes - aggressive and - /// non-aggressive. When in aggressive search mode (aggressiveSearch = - /// true), the algorithm will try to match at every possible starting - /// character index within the string. When false, all subsequent - /// character indexes within a substring match will not be evaluated. - /// For example, if the string was 'abbbc' and we were searching for - /// the substring 'bb', then aggressive search would find 2 matches - /// with starting indexes of 1 and 2. Non aggressive search would find - /// just 1 match with starting index at 1. After the match was made, - /// the non aggressive search would attempt to make it's next match - /// starting at index 3 instead of 2. - /// The count of occurrences of the substring within the string. - public static int CountOccurrences(this string s, string substring, - bool aggressiveSearch = false) - { - // if s or substring is null or empty, substring cannot be found in s - // if the length of substring is greater than the length of s, - // substring cannot be found in s - if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(substring) || substring.Length > s.Length) - return 0; - - int count = 0, n = 0; - while ((n = s.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1) - { - if (aggressiveSearch) - n++; - else - n += substring.Length; - count++; - } - - return count; - } } } \ No newline at end of file From 353bbff1b883ebeaf2412977ae581bb548585e68 Mon Sep 17 00:00:00 2001 From: Jonas Kamsker <11245306+JKamsker@users.noreply.github.com> Date: Sun, 20 Mar 2022 19:34:01 +0100 Subject: [PATCH 8/9] Removed comment --- FFMpegCore/FFMpeg/FFMpegArguments.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/FFMpegCore/FFMpeg/FFMpegArguments.cs b/FFMpegCore/FFMpeg/FFMpegArguments.cs index e7a5940..a93f1bd 100644 --- a/FFMpegCore/FFMpeg/FFMpegArguments.cs +++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs @@ -22,25 +22,6 @@ private FFMpegArguments() { } private string GetText() { - //var sb = new StringBuilder(); - //var appendSpace = false; - - //foreach (var arg in _globalArguments.Arguments.Concat(Arguments)) - //{ - // if (appendSpace) - // { - // sb.Append(' '); - // } - // else - // { - // appendSpace = true; - // } - - // sb.Append(arg is IDynamicArgument dynArg ? dynArg.GetText(sb) : arg.Text); - //} - - //return sb.ToString(); - var allArguments = _globalArguments.Arguments.Concat(Arguments).ToArray(); return string.Join(" ", allArguments.Select(arg => arg is IDynamicArgument dynArg ? dynArg.GetText(allArguments) : arg.Text)); } From f42faa4f264b8ee84016c1386400a05545c5be1b Mon Sep 17 00:00:00 2001 From: Jonas Kamsker <11245306+JKamsker@users.noreply.github.com> Date: Sun, 20 Mar 2022 19:56:17 +0100 Subject: [PATCH 9/9] Fixed merge & implemented aax mode --- .../FFMpegArgumentProcessorTest.cs | 8 +++++ .../Arguments/AudibleEncryptionKeyArgument.cs | 14 +++++++- .../FFMpeg/Arguments/MapMetadataArgument.cs | 32 +++++++++++++++---- FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs | 1 + 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs b/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs index c0a565e..6e30999 100644 --- a/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs +++ b/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs @@ -101,5 +101,13 @@ 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 index 9f1a325..0f514dc 100644 --- a/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs @@ -2,15 +2,27 @@ { 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 => $"-audible_key {_key} -audible_iv {_iv}"; + public string Text => _aaxcMode ? $"-audible_key {_key} -audible_iv {_iv}" : $"-activation_bytes {_activationBytes}"; } } diff --git a/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs b/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs index 01b661c..afec731 100644 --- a/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs @@ -1,5 +1,8 @@ using FFMpegCore.Extend; +using System; +using System.Collections.Generic; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -10,8 +13,10 @@ public class MapMetadataArgument : IInputArgument, IDynamicArgument { private readonly int? _inputIndex; + public string Text => GetText(null); + /// - /// Null means it takes the last input used befroe this argument + /// Null means it takes the last input used before this argument /// /// public MapMetadataArgument(int? inputIndex = null) @@ -19,15 +24,28 @@ public MapMetadataArgument(int? inputIndex = null) _inputIndex = inputIndex; } - public string Text => GetText(null); - - public string GetText(StringBuilder context) + public string GetText(IEnumerable? arguments) { - var index = _inputIndex ?? context?.ToString().CountOccurrences("-i") -1 ?? 0; + 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; @@ -40,5 +58,7 @@ public void Post() public void Pre() { } + + } } diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs b/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs index b4f5111..7b3da7a 100644 --- a/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs +++ b/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs @@ -68,6 +68,7 @@ public FFMpegArgumentOptions WithAudioFilters(Action audioFi 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));