FFProbe: improve metadata extraction

#3

Former-commit-id: 3e856845ae
This commit is contained in:
Vlad Jerca 2019-04-01 12:38:58 +03:00
parent a5cadc3569
commit 567c9e7390
2 changed files with 78 additions and 51 deletions

View file

@ -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<Stream> Streams { get; set; }
}
}

View file

@ -1,14 +1,15 @@
using FFMpegCore.Helpers; using FFMpegCore.FFMPEG.Exceptions;
using FFMpegCore.Helpers;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO;
namespace FFMpegCore.FFMPEG namespace FFMpegCore.FFMPEG
{ {
public sealed class FFProbe : FFBase public sealed class FFProbe : FFBase
{ {
static readonly double BITS_TO_MB = 1024 * 1024 * 8;
public FFProbe(): base() public FFProbe(): base()
{ {
FFProbeHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); FFProbeHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory);
@ -38,71 +39,56 @@ public VideoInfo ParseVideoInfo(VideoInfo info)
var jsonOutput = var jsonOutput =
RunProcess($"-v quiet -print_format json -show_streams \"{info.FullName}\""); RunProcess($"-v quiet -print_format json -show_streams \"{info.FullName}\"");
var metadata = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(jsonOutput); var metadata = JsonConvert.DeserializeObject<FFMpegStreamMetadata>(jsonOutput);
int videoIndex = metadata["streams"][0]["codec_type"] == "video" ? 0 : 1,
audioIndex = 1 - videoIndex;
var bitRate = Convert.ToDouble(metadata["streams"][videoIndex]["bit_rate"], CultureInfo.InvariantCulture); if (metadata.Streams == null || metadata.Streams.Count == 0)
try
{ {
var duration = Convert.ToDouble(metadata["streams"][videoIndex]["duration"], CultureInfo.InvariantCulture); throw new FFMpegException(FFMpegExceptionType.File, $"No video or audio streams could be detected. Source: ${info.FullName}");
info.Duration = TimeSpan.FromSeconds(duration);
info.Duration = info.Duration.Subtract(TimeSpan.FromMilliseconds(info.Duration.Milliseconds));
} }
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 info.VideoFormat = video.CodecName;
double videoSize = 0, info.Width = video.Width;
audioSize = 0; info.Height = video.Height;
info.FrameRate = Math.Round(
try Convert.ToDouble(fr[0], CultureInfo.InvariantCulture) /
{ Convert.ToDouble(fr[1], CultureInfo.InvariantCulture),
info.VideoFormat = metadata["streams"][videoIndex]["codec_name"]; 3);
videoSize = bitRate * info.Duration / 8388608; info.Ratio = video.Width / commonDenominator + ":" + video.Height / commonDenominator;
} } else
catch (Exception)
{ {
info.VideoFormat = "none"; info.VideoFormat = "none";
} }
// Get audio format - wrap for exceptions if the video has no audio if (audio != null)
try
{ {
info.AudioFormat = metadata["streams"][audioIndex]["codec_name"]; var bitRate = Convert.ToDouble(audio.BitRate, CultureInfo.InvariantCulture);
audioSize = bitRate * info.Duration / 8388608; info.AudioFormat = audio.CodecName;
} audioSize = bitRate * duration.TotalSeconds / BITS_TO_MB;
catch (Exception) } else
{ {
info.AudioFormat = "none"; 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); 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; return info;
} }