diff --git a/FFMpegCore.Test/FFMpegCore.Test.csproj b/FFMpegCore.Test/FFMpegCore.Test.csproj
index d7fa1ad..33df305 100644
--- a/FFMpegCore.Test/FFMpegCore.Test.csproj
+++ b/FFMpegCore.Test/FFMpegCore.Test.csproj
@@ -30,6 +30,9 @@
Always
+
+ Always
+
Always
diff --git a/FFMpegCore.Test/Resources/VideoLibrary.cs b/FFMpegCore.Test/Resources/VideoLibrary.cs
index 56ef201..74f5b7f 100644
--- a/FFMpegCore.Test/Resources/VideoLibrary.cs
+++ b/FFMpegCore.Test/Resources/VideoLibrary.cs
@@ -17,6 +17,7 @@ public enum ImageType
public static class VideoLibrary
{
public static readonly FileInfo LocalVideo = new FileInfo(".\\Resources\\input.mp4");
+ public static readonly FileInfo LocalVideoAudioOnly = new FileInfo(".\\Resources\\audio_only.mp4");
public static readonly FileInfo LocalVideoNoAudio = new FileInfo(".\\Resources\\mute.mp4");
public static readonly FileInfo LocalAudio = new FileInfo(".\\Resources\\audio.mp3");
public static readonly FileInfo LocalCover = new FileInfo(".\\Resources\\cover.png");
diff --git a/FFMpegCore.Test/Resources/audio_only.mp4 b/FFMpegCore.Test/Resources/audio_only.mp4
new file mode 100644
index 0000000..55aa483
Binary files /dev/null and b/FFMpegCore.Test/Resources/audio_only.mp4 differ
diff --git a/FFMpegCore.Test/VideoTest.cs b/FFMpegCore.Test/VideoTest.cs
index 242aacf..bb5e109 100644
--- a/FFMpegCore.Test/VideoTest.cs
+++ b/FFMpegCore.Test/VideoTest.cs
@@ -308,5 +308,15 @@ public void Video_Join_Image_Sequence()
}
}
}
+
+ [TestMethod]
+ public void Video_With_Only_Audio_Should_Extract_Metadata()
+ {
+ var video = VideoInfo.FromFileInfo(VideoLibrary.LocalVideoAudioOnly);
+ Assert.AreEqual(video.VideoFormat, "none");
+ Assert.AreEqual(video.AudioFormat, "aac");
+ Assert.AreEqual(video.Duration.TotalSeconds, 79);
+ Assert.AreEqual(video.Size, 1.25);
+ }
}
}
diff --git a/FFMpegCore/FFMPEG/FFMpegStreamMetadata.cs b/FFMpegCore/FFMPEG/FFMpegStreamMetadata.cs
new file mode 100644
index 0000000..68269cf
--- /dev/null
+++ b/FFMpegCore/FFMPEG/FFMpegStreamMetadata.cs
@@ -0,0 +1,41 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace FFMpegCore.FFMPEG
+{
+ internal class Stream
+ {
+ [JsonProperty("index")]
+ internal int Index { get; set; }
+
+ [JsonProperty("codec_name")]
+ internal string CodecName { get; set; }
+
+ [JsonProperty("bit_rate")]
+ internal string BitRate { get; set; }
+
+ [JsonProperty("profile")]
+ internal string Profile { get; set; }
+
+ [JsonProperty("codec_type")]
+ internal string CodecType { get; set; }
+
+ [JsonProperty("width")]
+ internal int Width { get; set; }
+
+ [JsonProperty("height")]
+ internal int Height { get; set; }
+
+ [JsonProperty("duration")]
+ internal string Duration { get; set; }
+
+ [JsonProperty("r_frame_rate")]
+ internal string FrameRate { get; set; }
+ }
+
+ internal class FFMpegStreamMetadata
+ {
+ [JsonProperty("streams")]
+ internal List Streams { get; set; }
+ }
+}
diff --git a/FFMpegCore/FFMPEG/FFProbe.cs b/FFMpegCore/FFMPEG/FFProbe.cs
index d285186..ad7a9bc 100644
--- a/FFMpegCore/FFMPEG/FFProbe.cs
+++ b/FFMpegCore/FFMPEG/FFProbe.cs
@@ -1,14 +1,15 @@
-using FFMpegCore.Helpers;
+using FFMpegCore.FFMPEG.Exceptions;
+using FFMpegCore.Helpers;
using Newtonsoft.Json;
using System;
-using System.Collections.Generic;
using System.Globalization;
-using System.IO;
namespace FFMpegCore.FFMPEG
{
public sealed class FFProbe : FFBase
{
+ static readonly double BITS_TO_MB = 1024 * 1024 * 8;
+
public FFProbe(): base()
{
FFProbeHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory);
@@ -38,71 +39,56 @@ public VideoInfo ParseVideoInfo(VideoInfo info)
var jsonOutput =
RunProcess($"-v quiet -print_format json -show_streams \"{info.FullName}\"");
- var metadata = JsonConvert.DeserializeObject>(jsonOutput);
- int videoIndex = metadata["streams"][0]["codec_type"] == "video" ? 0 : 1,
- audioIndex = 1 - videoIndex;
+ var metadata = JsonConvert.DeserializeObject(jsonOutput);
- var bitRate = Convert.ToDouble(metadata["streams"][videoIndex]["bit_rate"], CultureInfo.InvariantCulture);
-
- try
+ if (metadata.Streams == null || metadata.Streams.Count == 0)
{
- var duration = Convert.ToDouble(metadata["streams"][videoIndex]["duration"], CultureInfo.InvariantCulture);
- info.Duration = TimeSpan.FromSeconds(duration);
- info.Duration = info.Duration.Subtract(TimeSpan.FromMilliseconds(info.Duration.Milliseconds));
+ throw new FFMpegException(FFMpegExceptionType.File, $"No video or audio streams could be detected. Source: ${info.FullName}");
}
- catch (Exception)
+
+ var video = metadata.Streams.Find(s => s.CodecType == "video");
+ var audio = metadata.Streams.Find(s => s.CodecType == "audio");
+
+ double videoSize = 0d;
+ double audioSize = 0d;
+
+ var duration = TimeSpan.FromSeconds(double.TryParse((video ?? audio).Duration, out var output) ? output : 0);
+ info.Duration = duration.Subtract(TimeSpan.FromMilliseconds(duration.Milliseconds));
+
+ if (video != null)
{
- info.Duration = TimeSpan.FromSeconds(0);
- }
+ var bitRate = Convert.ToDouble(video.BitRate, CultureInfo.InvariantCulture);
+ var fr = video.FrameRate.Split('/');
+ var commonDenominator = FFProbeHelper.Gcd(video.Width, video.Height);
+ videoSize = bitRate * duration.TotalSeconds / BITS_TO_MB;
- // Get video size in megabytes
- double videoSize = 0,
- audioSize = 0;
-
- try
- {
- info.VideoFormat = metadata["streams"][videoIndex]["codec_name"];
- videoSize = bitRate * info.Duration / 8388608;
- }
- catch (Exception)
+ info.VideoFormat = video.CodecName;
+ info.Width = video.Width;
+ info.Height = video.Height;
+ info.FrameRate = Math.Round(
+ Convert.ToDouble(fr[0], CultureInfo.InvariantCulture) /
+ Convert.ToDouble(fr[1], CultureInfo.InvariantCulture),
+ 3);
+ info.Ratio = video.Width / commonDenominator + ":" + video.Height / commonDenominator;
+ } else
{
info.VideoFormat = "none";
}
- // Get audio format - wrap for exceptions if the video has no audio
- try
+ if (audio != null)
{
- info.AudioFormat = metadata["streams"][audioIndex]["codec_name"];
- audioSize = bitRate * info.Duration / 8388608;
- }
- catch (Exception)
+ var bitRate = Convert.ToDouble(audio.BitRate, CultureInfo.InvariantCulture);
+ info.AudioFormat = audio.CodecName;
+ audioSize = bitRate * duration.TotalSeconds / BITS_TO_MB;
+ } else
{
info.AudioFormat = "none";
+
}
- // Get video format
-
-
- // Get video width
- info.Width = metadata["streams"][videoIndex]["width"];
-
- // Get video height
- info.Height = metadata["streams"][videoIndex]["height"];
-
info.Size = Math.Round(videoSize + audioSize, 2);
- // Get video aspect ratio
- var cd = FFProbeHelper.Gcd(info.Width, info.Height);
- info.Ratio = info.Width / cd + ":" + info.Height / cd;
-
- // Get video framerate
- var fr = ((string)metadata["streams"][videoIndex]["r_frame_rate"]).Split('/');
- info.FrameRate = Math.Round(
- Convert.ToDouble(fr[0], CultureInfo.InvariantCulture) /
- Convert.ToDouble(fr[1], CultureInfo.InvariantCulture),
- 3);
-
return info;
}