diff --git a/FFMpegCore.Test/ArgumentBuilderTest.cs b/FFMpegCore.Test/ArgumentBuilderTest.cs
index f676a447..2c550c92 100644
--- a/FFMpegCore.Test/ArgumentBuilderTest.cs
+++ b/FFMpegCore.Test/ArgumentBuilderTest.cs
@@ -258,6 +258,13 @@ public void Builder_BuildString_Seek()
Assert.AreEqual("-ss 00:00:10.000 -i \"input.mp4\" -ss 00:00:10.000 \"output.mp4\"", str);
}
+ [TestMethod]
+ public void Builder_BuildString_EndSeek()
+ {
+ var str = FFMpegArguments.FromFileInput("input.mp4", false, opt => opt.EndSeek(TimeSpan.FromSeconds(10))).OutputToFile("output.mp4", false, opt => opt.EndSeek(TimeSpan.FromSeconds(10))).Arguments;
+ Assert.AreEqual("-to 00:00:10.000 -i \"input.mp4\" -to 00:00:10.000 \"output.mp4\"", str);
+ }
+
[TestMethod]
public void Builder_BuildString_Shortest()
{
diff --git a/FFMpegCore/FFMpeg/Arguments/EndSeekArgument.cs b/FFMpegCore/FFMpeg/Arguments/EndSeekArgument.cs
new file mode 100644
index 00000000..ea57339f
--- /dev/null
+++ b/FFMpegCore/FFMpeg/Arguments/EndSeekArgument.cs
@@ -0,0 +1,36 @@
+namespace FFMpegCore.Arguments
+{
+ ///
+ /// Represents seek parameter
+ ///
+ public class EndSeekArgument : IArgument
+ {
+ public readonly TimeSpan? SeekTo;
+
+ public EndSeekArgument(TimeSpan? seekTo)
+ {
+ SeekTo = seekTo;
+ }
+
+ public string Text
+ {
+ get
+ {
+ if (SeekTo.HasValue)
+ {
+ var hours = SeekTo.Value.Hours;
+ if (SeekTo.Value.Days > 0)
+ {
+ hours += SeekTo.Value.Days * 24;
+ }
+
+ return $"-to {hours.ToString("00")}:{SeekTo.Value.Minutes.ToString("00")}:{SeekTo.Value.Seconds.ToString("00")}.{SeekTo.Value.Milliseconds.ToString("000")}";
+ }
+ else
+ {
+ return string.Empty;
+ }
+ }
+ }
+ }
+}
diff --git a/FFMpegCore/FFMpeg/FFMpeg.cs b/FFMpegCore/FFMpeg/FFMpeg.cs
index 94f35c07..362a865b 100644
--- a/FFMpegCore/FFMpeg/FFMpeg.cs
+++ b/FFMpegCore/FFMpeg/FFMpeg.cs
@@ -247,6 +247,46 @@ public static bool Join(string output, params string[] videos)
}
}
+ private static FFMpegArgumentProcessor BaseSubVideo(string input, string output, TimeSpan startTime, TimeSpan endTime)
+ {
+ if (Path.GetExtension(input) != Path.GetExtension(output))
+ {
+ output = Path.Combine(Path.GetDirectoryName(output), Path.GetFileNameWithoutExtension(output), Path.GetExtension(input));
+ }
+
+ return FFMpegArguments
+ .FromFileInput(input, true, options => options.Seek(startTime).EndSeek(endTime))
+ .OutputToFile(output, true, options => options.CopyChannel());
+ }
+
+ ///
+ /// Creates a new video starting and ending at the specified times
+ ///
+ /// Input video file.
+ /// Output video file.
+ /// The start time of when the sub video needs to start
+ /// The end time of where the sub video needs to end
+ /// Output video information.
+ public static bool SubVideo(string input, string output, TimeSpan startTime, TimeSpan endTime)
+ {
+ return BaseSubVideo(input, output, startTime, endTime)
+ .ProcessSynchronously();
+ }
+
+ ///
+ /// Creates a new video starting and ending at the specified times
+ ///
+ /// Input video file.
+ /// Output video file.
+ /// The start time of when the sub video needs to start
+ /// The end time of where the sub video needs to end
+ /// Output video information.
+ public static async Task SubVideoAsync(string input, string output, TimeSpan startTime, TimeSpan endTime)
+ {
+ return await BaseSubVideo(input, output, startTime, endTime)
+ .ProcessAsynchronously();
+ }
+
///
/// Records M3U8 streams to the specified output.
///
diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs b/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
index 0f54b8cd..cc49c5f3 100644
--- a/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
+++ b/FFMpegCore/FFMpeg/FFMpegArgumentOptions.cs
@@ -54,6 +54,7 @@ public FFMpegArgumentOptions WithAudioFilters(Action audioFi
public FFMpegArgumentOptions WithCustomArgument(string argument) => WithArgument(new CustomArgument(argument));
public FFMpegArgumentOptions Seek(TimeSpan? seekTo) => WithArgument(new SeekArgument(seekTo));
+ public FFMpegArgumentOptions EndSeek(TimeSpan? seekTo) => WithArgument(new EndSeekArgument(seekTo));
public FFMpegArgumentOptions Loop(int times) => WithArgument(new LoopArgument(times));
public FFMpegArgumentOptions OverwriteExisting() => WithArgument(new OverwriteArgument());
public FFMpegArgumentOptions SelectStream(int streamIndex, int inputFileIndex = 0,
diff --git a/README.md b/README.md
index 990361e8..d2a96339 100644
--- a/README.md
+++ b/README.md
@@ -72,6 +72,15 @@ FFMpeg.Join(@"..\joined_video.mp4",
);
```
+### Create a sub video
+``` csharp
+FFMpeg.SubVideo(inputPath,
+ outputPath,
+ TimeSpan.FromSeconds(0)
+ TimeSpan.FromSeconds(30)
+);
+```
+
### Join images into a video:
```csharp
FFMpeg.JoinImageSequence(@"..\joined_video.mp4", frameRate: 1,