diff --git a/FFMpegCore.Test/ArgumentBuilderTest.cs b/FFMpegCore.Test/ArgumentBuilderTest.cs
index 9cf7e39..906a87b 100644
--- a/FFMpegCore.Test/ArgumentBuilderTest.cs
+++ b/FFMpegCore.Test/ArgumentBuilderTest.cs
@@ -114,7 +114,7 @@ public void Builder_BuildString_Copy_Both()
{
var str = FFMpegArguments.FromFileInput("input.mp4")
.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]
diff --git a/FFMpegCore/FFMpeg/Arguments/CopyArgument.cs b/FFMpegCore/FFMpeg/Arguments/CopyArgument.cs
index 91419d5..eeac4c8 100644
--- a/FFMpegCore/FFMpeg/Arguments/CopyArgument.cs
+++ b/FFMpegCore/FFMpeg/Arguments/CopyArgument.cs
@@ -16,9 +16,8 @@ public CopyArgument(Channel channel = Channel.Both)
public string Text => Channel switch
{
- Channel.Audio => "-c:a copy",
- Channel.Video => "-c:v copy",
- _ => "-c copy"
+ Channel.Both => "-c:a copy -c:v copy",
+ _ => $"-c{Channel.StreamType()} copy"
};
}
}
diff --git a/FFMpegCore/FFMpeg/Arguments/MapStreamArgument.cs b/FFMpegCore/FFMpeg/Arguments/MapStreamArgument.cs
index b904be5..a9813c7 100644
--- a/FFMpegCore/FFMpeg/Arguments/MapStreamArgument.cs
+++ b/FFMpegCore/FFMpeg/Arguments/MapStreamArgument.cs
@@ -1,19 +1,30 @@
-namespace FFMpegCore.Arguments
+using FFMpegCore.Enums;
+
+namespace FFMpegCore.Arguments
{
///
- /// Represents choice of video stream
+ /// Represents choice of stream by the stream specifier
///
public class MapStreamArgument : IArgument
{
private readonly int _inputFileIndex;
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;
_streamIndex = streamIndex;
+ _channel = channel;
+ _negativeMap = negativeMap;
}
- public string Text => $"-map {_inputFileIndex}:{_streamIndex}";
+ public string Text => $"-map {(_negativeMap?"-":"")}{_inputFileIndex}{_channel.StreamType()}:{_streamIndex}";
}
}
\ No newline at end of file
diff --git a/FFMpegCore/FFMpeg/Enums/Enums.cs b/FFMpegCore/FFMpeg/Enums/Enums.cs
index 7520fea..a6eb413 100644
--- a/FFMpegCore/FFMpeg/Enums/Enums.cs
+++ b/FFMpegCore/FFMpeg/Enums/Enums.cs
@@ -46,10 +46,43 @@ public enum Filter
Aac_AdtstoAsc
}
+ ///
+ /// 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
+ ///
public enum Channel
{
Audio,
Video,
- Both
+ Both,
+ VideoNoAttachedPic,
+ Subtitle,
+ Data,
+ Attachments,
+ All
}
+ internal static class ChannelMethods
+ {
+ ///
+ /// is left as empty because it cannot be in a single stream specifier
+ ///
+ /// The stream_type used in stream specifiers
+ 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
+ };
+ }
+ }
+
}
\ No newline at end of file
diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs b/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
index 7b3da7a..1ff892a 100644
--- a/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
+++ b/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
@@ -1,6 +1,7 @@
using System;
+using System.Collections.Generic;
using System.Drawing;
-
+using System.Linq;
using FFMpegCore.Arguments;
using FFMpegCore.Enums;
@@ -60,7 +61,16 @@ public FFMpegArgumentOptions WithAudioFilters(Action audioFi
public FFMpegArgumentOptions Seek(TimeSpan? seekTo) => WithArgument(new SeekArgument(seekTo));
public FFMpegArgumentOptions Loop(int times) => WithArgument(new LoopArgument(times));
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 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 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(string format) => WithArgument(new ForceFormatArgument(format));