Merge pull request #347 from qe201020335/master

Add Stream mapping of multiple streams and negative mapping of streams (deselect)
This commit is contained in:
Malte Rosenbjerg 2023-01-31 20:56:00 +01:00 committed by GitHub
commit 1ad13e069a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 11 deletions

View file

@ -114,7 +114,7 @@ public void Builder_BuildString_Copy_Both()
{ {
var str = FFMpegArguments.FromFileInput("input.mp4") var str = FFMpegArguments.FromFileInput("input.mp4")
.OutputToFile("output.mp4", false, opt => opt.CopyChannel()).Arguments; .OutputToFile("output.mp4", false, opt => opt.CopyChannel()).Arguments;
Assert.AreEqual("-i \"input.mp4\" -c copy \"output.mp4\"", str); Assert.AreEqual("-i \"input.mp4\" -c:a copy -c:v copy \"output.mp4\"", str);
} }
[TestMethod] [TestMethod]

View file

@ -16,9 +16,8 @@ public CopyArgument(Channel channel = Channel.Both)
public string Text => Channel switch public string Text => Channel switch
{ {
Channel.Audio => "-c:a copy", Channel.Both => "-c:a copy -c:v copy",
Channel.Video => "-c:v copy", _ => $"-c{Channel.StreamType()} copy"
_ => "-c copy"
}; };
} }
} }

View file

@ -1,19 +1,30 @@
namespace FFMpegCore.Arguments using FFMpegCore.Enums;
namespace FFMpegCore.Arguments
{ {
/// <summary> /// <summary>
/// Represents choice of video stream /// Represents choice of stream by the stream specifier
/// </summary> /// </summary>
public class MapStreamArgument : IArgument public class MapStreamArgument : IArgument
{ {
private readonly int _inputFileIndex; private readonly int _inputFileIndex;
private readonly int _streamIndex; private readonly int _streamIndex;
private readonly Channel _channel;
private readonly bool _negativeMap;
public MapStreamArgument(int streamIndex, int inputFileIndex) public MapStreamArgument(int streamIndex, int inputFileIndex, Channel channel = Channel.All, bool negativeMap = false)
{ {
if (channel == Channel.Both)
{
// "Both" is not valid in this case and probably means all stream types
channel = Channel.All;
}
_inputFileIndex = inputFileIndex; _inputFileIndex = inputFileIndex;
_streamIndex = streamIndex; _streamIndex = streamIndex;
_channel = channel;
_negativeMap = negativeMap;
} }
public string Text => $"-map {_inputFileIndex}:{_streamIndex}"; public string Text => $"-map {(_negativeMap?"-":"")}{_inputFileIndex}{_channel.StreamType()}:{_streamIndex}";
} }
} }

View file

@ -46,10 +46,43 @@ public enum Filter
Aac_AdtstoAsc Aac_AdtstoAsc
} }
/// <summary>
/// https://ffmpeg.org/ffmpeg.html#Stream-specifiers-1
/// v or V for video, a for audio, s for subtitle, d for data, and t for attachments
/// V only matches video streams which are not attached pictures, video thumbnails or cover arts.
/// Both for audio + video
/// All for all types
/// </summary>
public enum Channel public enum Channel
{ {
Audio, Audio,
Video, Video,
Both Both,
VideoNoAttachedPic,
Subtitle,
Data,
Attachments,
All
}
internal static class ChannelMethods
{
/// <summary>
/// <see cref="Channel.Both"/> is left as empty because it cannot be in a single stream specifier
/// </summary>
/// <returns>The stream_type used in stream specifiers</returns>
public static string StreamType(this Channel channel)
{
return channel switch
{
Channel.Audio => ":a",
Channel.Video => ":v",
Channel.VideoNoAttachedPic => ":V",
Channel.Subtitle => ":s",
Channel.Data => ":d",
Channel.Attachments => ":t",
_ => string.Empty
};
} }
} }
}

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq;
using FFMpegCore.Arguments; using FFMpegCore.Arguments;
using FFMpegCore.Enums; using FFMpegCore.Enums;
@ -60,7 +61,16 @@ public FFMpegArgumentOptions WithAudioFilters(Action<AudioFilterOptions> audioFi
public FFMpegArgumentOptions Seek(TimeSpan? seekTo) => WithArgument(new SeekArgument(seekTo)); public FFMpegArgumentOptions Seek(TimeSpan? seekTo) => WithArgument(new SeekArgument(seekTo));
public FFMpegArgumentOptions Loop(int times) => WithArgument(new LoopArgument(times)); public FFMpegArgumentOptions Loop(int times) => WithArgument(new LoopArgument(times));
public FFMpegArgumentOptions OverwriteExisting() => WithArgument(new OverwriteArgument()); public FFMpegArgumentOptions OverwriteExisting() => WithArgument(new OverwriteArgument());
public FFMpegArgumentOptions SelectStream(int streamIndex, int inputFileIndex = 0) => WithArgument(new MapStreamArgument(streamIndex, inputFileIndex)); public FFMpegArgumentOptions SelectStream(int streamIndex, int inputFileIndex = 0,
Channel channel = Channel.All) => WithArgument(new MapStreamArgument(streamIndex, inputFileIndex, channel));
public FFMpegArgumentOptions SelectStreams(IEnumerable<int> streamIndices, int inputFileIndex = 0,
Channel channel = Channel.All) => streamIndices.Aggregate(this,
(options, streamIndex) => options.SelectStream(streamIndex, inputFileIndex, channel));
public FFMpegArgumentOptions DeselectStream(int streamIndex, int inputFileIndex = 0,
Channel channel = Channel.All) => WithArgument(new MapStreamArgument(streamIndex, inputFileIndex, channel, true));
public FFMpegArgumentOptions DeselectStreams(IEnumerable<int> streamIndices, int inputFileIndex = 0,
Channel channel = Channel.All) => streamIndices.Aggregate(this,
(options, streamIndex) => options.DeselectStream(streamIndex, inputFileIndex, channel));
public FFMpegArgumentOptions ForceFormat(ContainerFormat format) => WithArgument(new ForceFormatArgument(format)); public FFMpegArgumentOptions ForceFormat(ContainerFormat format) => WithArgument(new ForceFormatArgument(format));
public FFMpegArgumentOptions ForceFormat(string format) => WithArgument(new ForceFormatArgument(format)); public FFMpegArgumentOptions ForceFormat(string format) => WithArgument(new ForceFormatArgument(format));