Merge branch 'master' into bugfix/fixes

Former-commit-id: eb0f6ca44a
This commit is contained in:
Malte Rosenbjerg 2022-03-24 21:15:59 +01:00 committed by GitHub
commit d5d2c18af7
11 changed files with 223 additions and 10 deletions

View file

@ -484,5 +484,16 @@ public void Builder_BuildString_DynamicAudioNormalizerWithValuesFormat()
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); 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);
}
} }
} }

View file

@ -94,5 +94,20 @@ public void Concat_Escape()
var arg = new DemuxConcatArgument(new[] { @"Heaven's River\05 - Investigation.m4b" }); var arg = new DemuxConcatArgument(new[] { @"Heaven's River\05 - Investigation.m4b" });
arg.Values.Should().BeEquivalentTo(new[] { @"file '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");
}
} }
} }

View file

@ -4,8 +4,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FFMpegCore.Test namespace FFMpegCore.Test
@ -50,5 +52,29 @@ public void TestMetaDataBuilderIntegrity()
Assert.IsTrue(serialized.Contains("title=Chapter 01", StringComparison.OrdinalIgnoreCase)); Assert.IsTrue(serialized.Contains("title=Chapter 01", StringComparison.OrdinalIgnoreCase));
Assert.IsTrue(serialized.Contains("album_artist=Pachelbel", 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.");
}
} }
} }

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Text; using System.Text;
namespace FFMpegCore.Extend namespace FFMpegCore.Extend

View file

@ -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}";
}
}

View file

@ -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}";
}
}

View file

@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Text;
namespace FFMpegCore.Arguments
{
public interface IDynamicArgument
{
/// <summary>
/// Same as <see cref="IArgument.Text"/>, but this receives the arguments generated before as parameter
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
//public string GetText(StringBuilder context);
public string GetText(IEnumerable<IArgument> context);
}
}

View file

@ -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);
/// <summary>
/// Null means it takes the last input used before this argument
/// </summary>
/// <param name="inputIndex"></param>
public MapMetadataArgument(int? inputIndex = null)
{
_inputIndex = inputIndex;
}
public string GetText(IEnumerable<IArgument>? arguments)
{
arguments ??= Enumerable.Empty<IArgument>();
var index = 0;
if (_inputIndex is null)
{
index = arguments
.TakeWhile(x => x != this)
.OfType<IInputArgument>()
.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()
{
}
}
}

View file

@ -1,11 +1,16 @@
using System; using FFMpegCore.Extend;
using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FFMpegCore.Arguments namespace FFMpegCore.Arguments
{ {
public class MetaDataArgument : IInputArgument public class MetaDataArgument : IInputArgument, IDynamicArgument
{ {
private readonly string _metaDataContent; private readonly string _metaDataContent;
private readonly string _tempFileName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"metadata_{Guid.NewGuid()}.txt"); private readonly string _tempFileName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"metadata_{Guid.NewGuid()}.txt");
@ -15,7 +20,7 @@ public MetaDataArgument(string metaDataContent)
_metaDataContent = metaDataContent; _metaDataContent = metaDataContent;
} }
public string Text => $"-i \"{_tempFileName}\" -map_metadata 1"; public string Text => GetText(null);
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask; public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
@ -23,5 +28,17 @@ public MetaDataArgument(string metaDataContent)
public void Pre() => File.WriteAllText(_tempFileName, _metaDataContent); public void Pre() => File.WriteAllText(_tempFileName, _metaDataContent);
public void Post() => File.Delete(_tempFileName); public void Post() => File.Delete(_tempFileName);
public string GetText(IEnumerable<IArgument>? arguments)
{
arguments ??= Enumerable.Empty<IArgument>();
var index = arguments
.TakeWhile(x => x != this)
.OfType<IInputArgument>()
.Count();
return $"-i \"{_tempFileName}\" -map_metadata {index}";
}
} }
} }

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Drawing; using System.Drawing;
using FFMpegCore.Arguments; using FFMpegCore.Arguments;
using FFMpegCore.Enums; using FFMpegCore.Enums;
@ -66,6 +67,11 @@ public FFMpegArgumentOptions WithAudioFilters(Action<AudioFilterOptions> audioFi
public FFMpegArgumentOptions ForcePixelFormat(string pixelFormat) => WithArgument(new ForcePixelFormat(pixelFormat)); public FFMpegArgumentOptions ForcePixelFormat(string pixelFormat) => WithArgument(new ForcePixelFormat(pixelFormat));
public FFMpegArgumentOptions ForcePixelFormat(PixelFormat 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) public FFMpegArgumentOptions WithArgument(IArgument argument)
{ {
Arguments.Add(argument); Arguments.Add(argument);

View file

@ -2,8 +2,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFMpegCore.Arguments; using FFMpegCore.Arguments;
using FFMpegCore.Builders.MetaData; using FFMpegCore.Builders.MetaData;
using FFMpegCore.Pipes; using FFMpegCore.Pipes;
@ -16,7 +18,13 @@ public sealed class FFMpegArguments : FFMpegArgumentsBase
private FFMpegArguments() { } private FFMpegArguments() { }
public string Text => string.Join(" ", _globalArguments.Arguments.Concat(Arguments).Select(arg => arg.Text)); public string Text => GetText();
private string GetText()
{
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<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new ConcatArgument(filePaths), addArguments); public static FFMpegArguments FromConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new ConcatArgument(filePaths), addArguments);
public static FFMpegArguments FromDemuxConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new DemuxConcatArgument(filePaths), addArguments); public static FFMpegArguments FromDemuxConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new DemuxConcatArgument(filePaths), addArguments);
@ -42,6 +50,13 @@ public FFMpegArguments WithGlobalOptions(Action<FFMpegGlobalArguments> configure
public FFMpegArguments AddMetaData(string content, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new MetaDataArgument(content), addArguments); public FFMpegArguments AddMetaData(string content, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new MetaDataArgument(content), addArguments);
public FFMpegArguments AddMetaData(IReadOnlyMetaData metaData, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new MetaDataArgument(MetaDataSerializer.Instance.Serialize(metaData)), addArguments); public FFMpegArguments AddMetaData(IReadOnlyMetaData metaData, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new MetaDataArgument(MetaDataSerializer.Instance.Serialize(metaData)), addArguments);
/// <summary>
/// Maps the metadata of the given stream
/// </summary>
/// <param name="inputIndex">null means, the previous input will be used</param>
public FFMpegArguments MapMetaData(int? inputIndex = null, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new MapMetadataArgument(inputIndex), addArguments);
private FFMpegArguments WithInput(IInputArgument inputArgument, Action<FFMpegArgumentOptions>? addArguments) private FFMpegArguments WithInput(IInputArgument inputArgument, Action<FFMpegArgumentOptions>? addArguments)
{ {
var arguments = new FFMpegArgumentOptions(); var arguments = new FFMpegArgumentOptions();