diff --git a/FFMpegCore.Test/FFMpegCore.Test.csproj b/FFMpegCore.Test/FFMpegCore.Test.csproj
index 2e6adf74..e7ff13be 100644
--- a/FFMpegCore.Test/FFMpegCore.Test.csproj
+++ b/FFMpegCore.Test/FFMpegCore.Test.csproj
@@ -93,6 +93,9 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/FFMpegCore.Test/FFProbeTests.cs b/FFMpegCore.Test/FFProbeTests.cs
index 4b1e519c..63ff3539 100644
--- a/FFMpegCore.Test/FFProbeTests.cs
+++ b/FFMpegCore.Test/FFProbeTests.cs
@@ -164,6 +164,39 @@ public void Probe_Success()
Assert.AreEqual("0x31637661", info.PrimaryVideoStream.CodecTag);
}
+ [TestMethod]
+ public void Probe_BrdiskISO()
+ {
+ var info = FFProbe.Analyse(TestResources.BrdiskISO);
+ Assert.AreEqual(3, info.Duration.Minutes);
+
+ Assert.AreEqual("mono", info.PrimaryAudioStream!.ChannelLayout);
+ Assert.AreEqual(1, info.PrimaryAudioStream.Channels);
+ Assert.AreEqual("ATSC A/52A (AC-3)", info.PrimaryAudioStream.CodecLongName);
+ Assert.AreEqual("ac3", info.PrimaryAudioStream.CodecName);
+ Assert.AreEqual(32000, info.PrimaryAudioStream.BitRate);
+ Assert.AreEqual(44100, info.PrimaryAudioStream.SampleRateHz);
+ Assert.AreEqual("AC-3", info.PrimaryAudioStream.CodecTagString);
+ Assert.AreEqual("0x332d4341", info.PrimaryAudioStream.CodecTag);
+
+ Assert.AreEqual(30000/1001m, info.PrimaryVideoStream.FrameRate);
+ Assert.AreEqual(30000/1001m, info.PrimaryVideoStream.AvgFrameRate);
+ Assert.AreEqual(20, info.PrimaryVideoStream.DisplayAspectRatio.Width);
+ Assert.AreEqual(11, info.PrimaryVideoStream.DisplayAspectRatio.Height);
+ Assert.AreEqual("yuv420p", info.PrimaryVideoStream.PixelFormat);
+ Assert.AreEqual("smpte170m", info.PrimaryVideoStream.ColorSpace);
+ Assert.AreEqual("smpte170m", info.PrimaryVideoStream.ColorPrimaries);
+ Assert.AreEqual("smpte170m", info.PrimaryVideoStream.ColorTransfer);
+ Assert.AreEqual(720, info.PrimaryVideoStream.Width);
+ Assert.AreEqual(480, info.PrimaryVideoStream.Height);
+ Assert.AreEqual("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", info.PrimaryVideoStream.CodecLongName);
+ Assert.AreEqual("h264", info.PrimaryVideoStream.CodecName);
+ Assert.AreEqual(8, info.PrimaryVideoStream.BitsPerRawSample);
+ Assert.AreEqual("High", info.PrimaryVideoStream.Profile);
+ Assert.AreEqual("HDMV", info.PrimaryVideoStream.CodecTagString);
+ Assert.AreEqual("0x564d4448", info.PrimaryVideoStream.CodecTag);
+ }
+
[TestMethod]
public void Probe_Dolby_Vision()
{
diff --git a/FFMpegCore.Test/Resources/TestResources.cs b/FFMpegCore.Test/Resources/TestResources.cs
index 77580c79..0ad7c79a 100644
--- a/FFMpegCore.Test/Resources/TestResources.cs
+++ b/FFMpegCore.Test/Resources/TestResources.cs
@@ -1,4 +1,6 @@
-namespace FFMpegCore.Test.Resources
+using System;
+
+namespace FFMpegCore.Test.Resources
{
public enum AudioType
{
@@ -23,5 +25,6 @@ public static class TestResources
public static readonly string SrtSubtitle = "./Resources/sample.srt";
public static readonly string Dovi = "./Resources/dovi.mp4";
public static readonly string Interlaced = "./Resources/interlaced.mkv";
+ public static readonly Uri BrdiskISO = new Uri("bluray:./Resources/brdisk.iso");
}
}
diff --git a/FFMpegCore.Test/Resources/brdisk.iso b/FFMpegCore.Test/Resources/brdisk.iso
new file mode 100644
index 00000000..8d0b90e6
Binary files /dev/null and b/FFMpegCore.Test/Resources/brdisk.iso differ
diff --git a/FFMpegCore/FFProbe/FFProbe.cs b/FFMpegCore/FFProbe/FFProbe.cs
index 9af9a88a..9c4ff5c8 100644
--- a/FFMpegCore/FFProbe/FFProbe.cs
+++ b/FFMpegCore/FFProbe/FFProbe.cs
@@ -29,10 +29,15 @@ public static class FFProbe
public static string GetStreamJson(string filePath, int outputCapacity = int.MaxValue,
FFOptions? ffOptions = null)
{
- if (!File.Exists(filePath))
- throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
+ return GetStreamJson(FileUri(filePath), outputCapacity, ffOptions);
+ }
+ public static string GetStreamJson(Uri uri, int outputCapacity = int.MaxValue,
+ FFOptions? ffOptions = null)
+ {
+ if (IsLocalFile(uri) && !File.Exists(uri.LocalPath))
+ throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{uri.LocalPath}'");
- using var instance = PrepareStreamAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
+ using var instance = PrepareStreamAnalysisInstance(InputArgument(uri), outputCapacity, ffOptions ?? GlobalFFOptions.Current);
var exitCode = instance.BlockUntilFinished();
if (exitCode != 0)
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
@@ -49,10 +54,14 @@ public static IMediaAnalysis AnalyseStreamJson(string json)
}
public static IMediaAnalysis Analyse(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
- if (!File.Exists(filePath))
- throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
+ return Analyse(FileUri(filePath), outputCapacity, ffOptions);
+ }
+ public static IMediaAnalysis Analyse(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
+ {
+ if (IsLocalFile(uri) && !File.Exists(uri.LocalPath))
+ throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{uri.LocalPath}'");
- using var instance = PrepareStreamAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
+ using var instance = PrepareStreamAnalysisInstance(InputArgument(uri), outputCapacity, ffOptions ?? GlobalFFOptions.Current);
var exitCode = instance.BlockUntilFinished();
if (exitCode != 0)
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
@@ -62,10 +71,15 @@ public static IMediaAnalysis Analyse(string filePath, int outputCapacity = int.M
public static string GetFrameJson(string filePath, int outputCapacity = int.MaxValue,
FFOptions? ffOptions = null)
{
- if (!File.Exists(filePath))
- throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
+ return GetFrameJson(FileUri(filePath), outputCapacity, ffOptions);
+ }
+ public static string GetFrameJson(Uri uri, int outputCapacity = int.MaxValue,
+ FFOptions? ffOptions = null)
+ {
+ if (IsLocalFile(uri) && !File.Exists(uri.LocalPath))
+ throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{uri.LocalPath}'");
- using var instance = PrepareFrameAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
+ using var instance = PrepareFrameAnalysisInstance(InputArgument(uri), outputCapacity, ffOptions ?? GlobalFFOptions.Current);
var exitCode = instance.BlockUntilFinished();
if (exitCode != 0)
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
@@ -78,10 +92,14 @@ public static FFProbeFrames AnalyseFrameJson(string json)
}
public static FFProbeFrames GetFrames(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
- if (!File.Exists(filePath))
- throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
+ return GetFrames(FileUri(filePath), outputCapacity, ffOptions);
+ }
+ public static FFProbeFrames GetFrames(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
+ {
+ if (IsLocalFile(uri) && !File.Exists(uri.LocalPath))
+ throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{uri.LocalPath}'");
- using var instance = PrepareFrameAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
+ using var instance = PrepareFrameAnalysisInstance(InputArgument(uri), outputCapacity, ffOptions ?? GlobalFFOptions.Current);
var exitCode = instance.BlockUntilFinished();
if (exitCode != 0)
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
@@ -91,10 +109,14 @@ public static FFProbeFrames GetFrames(string filePath, int outputCapacity = int.
public static FFProbePackets GetPackets(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
- if (!File.Exists(filePath))
- throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
+ return GetPackets(FileUri(filePath), outputCapacity, ffOptions);
+ }
+ public static FFProbePackets GetPackets(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
+ {
+ if (IsLocalFile(uri) && !File.Exists(uri.LocalPath))
+ throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{uri.LocalPath}'");
- using var instance = PreparePacketAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
+ using var instance = PreparePacketAnalysisInstance(InputArgument(uri), outputCapacity, ffOptions ?? GlobalFFOptions.Current);
var exitCode = instance.BlockUntilFinished();
if (exitCode != 0)
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
@@ -102,15 +124,6 @@ public static FFProbePackets GetPackets(string filePath, int outputCapacity = in
return ParsePacketsOutput(instance);
}
- public static IMediaAnalysis Analyse(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
- {
- using var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
- var exitCode = instance.BlockUntilFinished();
- if (exitCode != 0)
- throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
-
- return ParseOutput(instance);
- }
public static IMediaAnalysis Analyse(Stream stream, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
var streamPipeSource = new StreamPipeSource(stream);
@@ -136,10 +149,14 @@ public static IMediaAnalysis Analyse(Stream stream, int outputCapacity = int.Max
}
public static async Task AnalyseAsync(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
- if (!File.Exists(filePath))
- throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
+ return await AnalyseAsync(FileUri(filePath), outputCapacity, ffOptions);
+ }
+ public static async Task AnalyseAsync(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
+ {
+ if (IsLocalFile(uri) && !File.Exists(uri.LocalPath))
+ throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{uri.LocalPath}'");
- using var instance = PrepareStreamAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
+ using var instance = PrepareStreamAnalysisInstance(InputArgument(uri), outputCapacity, ffOptions ?? GlobalFFOptions.Current);
var exitCode = await instance.FinishedRunning().ConfigureAwait(false);
if (exitCode != 0)
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
@@ -149,33 +166,32 @@ public static async Task AnalyseAsync(string filePath, int outpu
public static async Task GetFramesAsync(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
- if (!File.Exists(filePath))
- throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
+ return await GetFramesAsync(FileUri(filePath), outputCapacity, ffOptions);
+ }
+ public static async Task GetFramesAsync(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
+ {
+ if (IsLocalFile(uri) && !File.Exists(uri.LocalPath))
+ throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{uri.LocalPath}'");
- using var instance = PrepareFrameAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
+ using var instance = PrepareFrameAnalysisInstance(InputArgument(uri), outputCapacity, ffOptions ?? GlobalFFOptions.Current);
await instance.FinishedRunning().ConfigureAwait(false);
return ParseFramesOutput(instance);
}
public static async Task GetPacketsAsync(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
- if (!File.Exists(filePath))
- throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
+ return await GetPacketsAsync(FileUri(filePath), outputCapacity, ffOptions);
+ }
+ public static async Task GetPacketsAsync(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
+ {
+ if (IsLocalFile(uri) && !File.Exists(uri.LocalPath))
+ throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{uri.LocalPath}'");
- using var instance = PreparePacketAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
+ using var instance = PreparePacketAnalysisInstance(InputArgument(uri), outputCapacity, ffOptions ?? GlobalFFOptions.Current);
await instance.FinishedRunning().ConfigureAwait(false);
return ParsePacketsOutput(instance);
}
- public static async Task AnalyseAsync(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
- {
- using var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
- var exitCode = await instance.FinishedRunning().ConfigureAwait(false);
- if (exitCode != 0)
- throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
-
- return ParseOutput(instance);
- }
public static async Task AnalyseAsync(Stream stream, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
var streamPipeSource = new StreamPipeSource(stream);
@@ -245,13 +261,25 @@ private static FFProbePackets ParsePacketsOutput(Instance instance)
return ffprobeAnalysis;
}
+ private static bool IsLocalFile(Uri uri)
+ {
+ return uri.IsFile || uri.Scheme == "bluray";
+ }
+ private static Uri FileUri(string filePath)
+ {
+ return new Uri(Path.GetFullPath(filePath));
+ }
+ private static string InputArgument(Uri uri)
+ {
+ return uri.IsFile ? uri.LocalPath : uri.GetComponents(UriComponents.AbsoluteUri, UriFormat.Unescaped);
+ }
- private static Instance PrepareStreamAnalysisInstance(string filePath, int outputCapacity, FFOptions ffOptions)
- => PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams {ffOptions.ExtraArguments} \"{filePath}\"", outputCapacity, ffOptions);
- private static Instance PrepareFrameAnalysisInstance(string filePath, int outputCapacity, FFOptions ffOptions)
- => PrepareInstance($"-loglevel error -print_format json -show_frames -v quiet -sexagesimal {ffOptions.ExtraArguments} \"{filePath}\"", outputCapacity, ffOptions);
- private static Instance PreparePacketAnalysisInstance(string filePath, int outputCapacity, FFOptions ffOptions)
- => PrepareInstance($"-loglevel error -print_format json -show_packets -v quiet -sexagesimal \"{filePath}\"", outputCapacity, ffOptions);
+ private static Instance PrepareStreamAnalysisInstance(string input, int outputCapacity, FFOptions ffOptions)
+ => PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams {ffOptions.ExtraArguments} \"{input}\"", outputCapacity, ffOptions);
+ private static Instance PrepareFrameAnalysisInstance(string input, int outputCapacity, FFOptions ffOptions)
+ => PrepareInstance($"-loglevel error -print_format json -show_frames -v quiet -sexagesimal {ffOptions.ExtraArguments} \"{input}\"", outputCapacity, ffOptions);
+ private static Instance PreparePacketAnalysisInstance(string input, int outputCapacity, FFOptions ffOptions)
+ => PrepareInstance($"-loglevel error -print_format json -show_packets -v quiet -sexagesimal \"{input}\"", outputCapacity, ffOptions);
private static Instance PrepareInstance(string arguments, int outputCapacity, FFOptions ffOptions)
{