mirror of
https://github.com/Sonarr/Sonarr
synced 2026-01-24 08:22:16 +01:00
New: Bump FFMpegCore to 5.4.0 and FFprobe to 8.0.1
This commit is contained in:
parent
5f9f8fddad
commit
227db9ef39
8 changed files with 117 additions and 116 deletions
|
|
@ -4,6 +4,5 @@
|
|||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
<add key="Mono.Posix.NETStandard" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/Mono.Posix.NETStandard/nuget/v3/index.json" />
|
||||
<add key="FFMpegCore" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/FFMpegCore/nuget/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using FluentAssertions;
|
||||
using System;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Test.Common;
|
||||
|
|
@ -8,7 +9,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo.MediaInfoFormatterTests
|
|||
[TestFixture]
|
||||
public class FormatAudioCodecFixture : TestBase
|
||||
{
|
||||
private static string sceneName = "My.Series.S01E01-Sonarr";
|
||||
private const string SceneName = "My.Series.S01E01-Sonarr";
|
||||
|
||||
[TestCase("mp2, , ", "droned.s01e03.swedish.720p.hdtv.x264-prince", "MP2")]
|
||||
[TestCase("vorbis, , ", "DB Super HDTV", "Vorbis")]
|
||||
|
|
@ -18,25 +19,33 @@ public class FormatAudioCodecFixture : TestBase
|
|||
[TestCase("truehd, thd+, ", "Atmos", "TrueHD Atmos")]
|
||||
[TestCase("truehd, thd+, ", "TrueHD.Atmos.7.1", "TrueHD Atmos")]
|
||||
[TestCase("truehd, thd+, ", "", "TrueHD Atmos")]
|
||||
[TestCase("truehd, , Dolby TrueHD + Dolby Atmos", "Atmos", "TrueHD Atmos")]
|
||||
[TestCase("truehd, , Dolby TrueHD + Dolby Atmos", "TrueHD.Atmos.7.1", "TrueHD Atmos")]
|
||||
[TestCase("truehd, , Dolby TrueHD + Dolby Atmos", "", "TrueHD Atmos")]
|
||||
[TestCase("wmav1, , ", "Droned.wmv", "WMA")]
|
||||
[TestCase("wmav2, , ", "B.N.S04E18.720p.WEB-DL", "WMA")]
|
||||
[TestCase("opus, , ", "Roadkill Ep3x11 - YouTube.webm", "Opus")]
|
||||
[TestCase("mp3, , ", "climbing.mp4", "MP3")]
|
||||
[TestCase("dts, , DTS-HD MA", "DTS-HD.MA", "DTS-HD MA")]
|
||||
[TestCase("dts, , DTS:X", "DTS-X", "DTS-X")]
|
||||
[TestCase("dts, , DTS-HD MA + DTS:X IMAX", "DTS-X", "DTS-X")]
|
||||
[TestCase("dts, , DTS-HD MA", "DTS-HD.MA", "DTS-HD MA")]
|
||||
[TestCase("dts, , DTS-ES", "DTS-ES", "DTS-ES")]
|
||||
[TestCase("dts, , DTS-ES", "DTS", "DTS-ES")]
|
||||
[TestCase("dts, , DTS-HD HRA", "DTSHD-HRA", "DTS-HD HRA")]
|
||||
[TestCase("dts, , DTS", "DTS", "DTS")]
|
||||
[TestCase("eac3, ec+3, ", "EAC3.Atmos", "EAC3 Atmos")]
|
||||
[TestCase("eac3, , Dolby Digital Plus + Dolby Atmos", "EAC3.Atmos", "EAC3 Atmos")]
|
||||
[TestCase("eac3, , ", "DDP5.1", "EAC3")]
|
||||
[TestCase("ac3, , ", "DD5.1", "AC3")]
|
||||
[TestCase("aac, , ", "AAC2.0", "AAC")]
|
||||
[TestCase("aac, , HE-AAC", "AAC2.0", "HE-AAC")]
|
||||
[TestCase("aac, , xHE-AAC", "AAC2.0", "xHE-AAC")]
|
||||
[TestCase("adpcm_ima_qt, , ", "Custom?", "PCM")]
|
||||
[TestCase("adpcm_ms, , ", "Custom", "PCM")]
|
||||
public void should_format_audio_format(string audioFormatPack, string sceneName, string expectedFormat)
|
||||
{
|
||||
var split = audioFormatPack.Split(new string[] { ", " }, System.StringSplitOptions.None);
|
||||
var split = audioFormatPack.Split(',', StringSplitOptions.TrimEntries);
|
||||
var mediaInfoModel = new MediaInfoModel
|
||||
{
|
||||
AudioFormat = split[0],
|
||||
|
|
@ -56,7 +65,7 @@ public void should_return_AudioFormat_by_default()
|
|||
AudioCodecID = "Other Audio Codec"
|
||||
};
|
||||
|
||||
MediaInfoFormatter.FormatAudioCodec(mediaInfoModel, sceneName).Should().Be(mediaInfoModel.AudioFormat);
|
||||
MediaInfoFormatter.FormatAudioCodec(mediaInfoModel, SceneName).Should().Be(mediaInfoModel.AudioFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using FFMpegCore;
|
||||
using System.Text.Json.Nodes;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common.Categories;
|
||||
|
|
@ -103,39 +102,39 @@ public void get_info_unicode()
|
|||
info.Title.Should().Be("Sample Title");
|
||||
}
|
||||
|
||||
[TestCase(8, "", "", "", null, HdrFormat.None)]
|
||||
[TestCase(10, "", "", "", null, HdrFormat.None)]
|
||||
[TestCase(10, "bt709", "bt709", "", null, HdrFormat.None)]
|
||||
[TestCase(8, "bt2020", "smpte2084", "", null, HdrFormat.None)]
|
||||
[TestCase(10, "bt2020", "bt2020-10", "", null, HdrFormat.None)]
|
||||
[TestCase(10, "bt2020", "arib-std-b67", "", null, HdrFormat.Hlg10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "", null, HdrFormat.Pq10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.SideData", null, HdrFormat.Pq10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.MasteringDisplayMetadata", null, HdrFormat.Hdr10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.ContentLightLevelMetadata", null, HdrFormat.Hdr10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.HdrDynamicMetadataSpmte2094", null, HdrFormat.Hdr10Plus)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.DoviConfigurationRecordSideData", null, HdrFormat.DolbyVision)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.DoviConfigurationRecordSideData", 1, HdrFormat.DolbyVisionHdr10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.DoviConfigurationRecordSideData,FFMpegCore.HdrDynamicMetadataSpmte2094", 1, HdrFormat.DolbyVisionHdr10Plus)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.DoviConfigurationRecordSideData,FFMpegCore.HdrDynamicMetadataSpmte2094", 6, HdrFormat.DolbyVisionHdr10Plus)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.DoviConfigurationRecordSideData", 2, HdrFormat.DolbyVisionSdr)]
|
||||
[TestCase(10, "bt2020", "smpte2084", "FFMpegCore.DoviConfigurationRecordSideData", 4, HdrFormat.DolbyVisionHlg)]
|
||||
public void should_detect_hdr_correctly(int bitDepth, string colourPrimaries, string transferFunction, string sideDataTypes, int? doviConfigId, HdrFormat expected)
|
||||
[TestCase(8, "", "", null, null, HdrFormat.None)]
|
||||
[TestCase(10, "", "", null, null, HdrFormat.None)]
|
||||
[TestCase(10, "bt709", "bt709", null, null, HdrFormat.None)]
|
||||
[TestCase(8, "bt2020", "smpte2084", null, null, HdrFormat.None)]
|
||||
[TestCase(10, "bt2020", "bt2020-10", null, null, HdrFormat.None)]
|
||||
[TestCase(10, "bt2020", "arib-std-b67", null, null, HdrFormat.Hlg10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", null, null, HdrFormat.Pq10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { "" }, null, HdrFormat.Pq10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.MasteringDisplayMetadata }, null, HdrFormat.Hdr10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.ContentLightLevelMetadata }, null, HdrFormat.Hdr10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.HdrDynamicMetadataSpmte2094 }, null, HdrFormat.Hdr10Plus)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.DoviConfigurationRecordSideData }, null, HdrFormat.DolbyVision)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.DoviConfigurationRecordSideData }, 1, HdrFormat.DolbyVisionHdr10)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.DoviConfigurationRecordSideData, FFMpegCoreSideDataTypes.HdrDynamicMetadataSpmte2094 }, 1, HdrFormat.DolbyVisionHdr10Plus)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.DoviConfigurationRecordSideData, FFMpegCoreSideDataTypes.HdrDynamicMetadataSpmte2094 }, 6, HdrFormat.DolbyVisionHdr10Plus)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.DoviConfigurationRecordSideData }, 2, HdrFormat.DolbyVisionSdr)]
|
||||
[TestCase(10, "bt2020", "smpte2084", new[] { FFMpegCoreSideDataTypes.DoviConfigurationRecordSideData }, 4, HdrFormat.DolbyVisionHlg)]
|
||||
public void should_detect_hdr_correctly(int bitDepth, string colourPrimaries, string transferFunction, string[] sideDataTypes, int? doviConfigId, HdrFormat expected)
|
||||
{
|
||||
var assembly = Assembly.GetAssembly(typeof(FFProbe));
|
||||
var types = sideDataTypes.Split(",").Select(x => x.Trim()).ToList();
|
||||
var sideData = types.Where(x => x.IsNotNullOrWhiteSpace()).Select(x => assembly.CreateInstance(x)).Cast<SideData>().ToList();
|
||||
|
||||
if (doviConfigId.HasValue)
|
||||
var sideData = sideDataTypes?.Select(sideDataType =>
|
||||
{
|
||||
sideData.ForEach(x =>
|
||||
var sideData = new Dictionary<string, JsonNode>
|
||||
{
|
||||
if (x.GetType().Name == "DoviConfigurationRecordSideData")
|
||||
{
|
||||
((DoviConfigurationRecordSideData)x).DvBlSignalCompatibilityId = doviConfigId.Value;
|
||||
}
|
||||
});
|
||||
}
|
||||
{ "side_data_type", JsonValue.Create(sideDataType) }
|
||||
};
|
||||
|
||||
if (doviConfigId.HasValue)
|
||||
{
|
||||
sideData.Add("dv_bl_signal_compatibility_id", JsonValue.Create(doviConfigId.Value));
|
||||
}
|
||||
|
||||
return sideData;
|
||||
}).ToList();
|
||||
|
||||
var result = VideoFileInfoReader.GetHdrFormat(bitDepth, colourPrimaries, transferFunction, sideData);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
namespace NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
|
||||
internal static class FFMpegCoreSideDataTypes
|
||||
{
|
||||
public const string DoviConfigurationRecordSideData = "DOVI configuration record";
|
||||
public const string HdrDynamicMetadataSpmte2094 = "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)";
|
||||
public const string MasteringDisplayMetadata = "Mastering display metadata";
|
||||
public const string ContentLightLevelMetadata = "Content light level metadata";
|
||||
}
|
||||
|
|
@ -52,7 +52,11 @@ public static string FormatAudioCodec(MediaInfoModel mediaInfo, string sceneName
|
|||
|
||||
if (audioFormat == "truehd")
|
||||
{
|
||||
return "TrueHD";
|
||||
return audioProfile switch
|
||||
{
|
||||
"Dolby TrueHD + Dolby Atmos" => "TrueHD Atmos",
|
||||
_ => "TrueHD"
|
||||
};
|
||||
}
|
||||
|
||||
if (audioFormat == "flac")
|
||||
|
|
@ -62,37 +66,16 @@ public static string FormatAudioCodec(MediaInfoModel mediaInfo, string sceneName
|
|||
|
||||
if (audioFormat == "dts")
|
||||
{
|
||||
if (audioProfile == "DTS:X")
|
||||
return audioProfile switch
|
||||
{
|
||||
return "DTS-X";
|
||||
}
|
||||
|
||||
if (audioProfile == "DTS-HD MA")
|
||||
{
|
||||
return "DTS-HD MA";
|
||||
}
|
||||
|
||||
if (audioProfile == "DTS-ES")
|
||||
{
|
||||
return "DTS-ES";
|
||||
}
|
||||
|
||||
if (audioProfile == "DTS-HD HRA")
|
||||
{
|
||||
return "DTS-HD HRA";
|
||||
}
|
||||
|
||||
if (audioProfile == "DTS Express")
|
||||
{
|
||||
return "DTS Express";
|
||||
}
|
||||
|
||||
if (audioProfile == "DTS 96/24")
|
||||
{
|
||||
return "DTS 96/24";
|
||||
}
|
||||
|
||||
return "DTS";
|
||||
"DTS:X" or "DTS-HD MA + DTS:X IMAX" => "DTS-X",
|
||||
"DTS-HD MA" => "DTS-HD MA",
|
||||
"DTS-ES" => "DTS-ES",
|
||||
"DTS-HD HRA" => "DTS-HD HRA",
|
||||
"DTS Express" => "DTS Express",
|
||||
"DTS 96/24" => "DTS 96/24",
|
||||
_ => "DTS"
|
||||
};
|
||||
}
|
||||
|
||||
if (audioCodecID == "ec+3")
|
||||
|
|
@ -102,7 +85,11 @@ public static string FormatAudioCodec(MediaInfoModel mediaInfo, string sceneName
|
|||
|
||||
if (audioFormat == "eac3")
|
||||
{
|
||||
return "EAC3";
|
||||
return audioProfile switch
|
||||
{
|
||||
"Dolby Digital Plus + Dolby Atmos" => "EAC3 Atmos",
|
||||
_ => "EAC3"
|
||||
};
|
||||
}
|
||||
|
||||
if (audioFormat == "ac3")
|
||||
|
|
@ -117,7 +104,12 @@ public static string FormatAudioCodec(MediaInfoModel mediaInfo, string sceneName
|
|||
return "HE-AAC";
|
||||
}
|
||||
|
||||
return "AAC";
|
||||
return audioProfile switch
|
||||
{
|
||||
"HE-AAC" => "HE-AAC",
|
||||
"xHE-AAC" => "xHE-AAC",
|
||||
_ => "AAC"
|
||||
};
|
||||
}
|
||||
|
||||
if (audioFormat == "mp3")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using FFMpegCore;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||
|
|
@ -9,7 +8,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
public class MediaInfoModel : IEmbeddedDocument
|
||||
{
|
||||
public string RawStreamData { get; set; }
|
||||
public string RawFrameData { get; set; }
|
||||
|
||||
public int SchemaRevision { get; set; }
|
||||
|
||||
public string ContainerFormat { get; set; }
|
||||
|
|
@ -27,8 +26,6 @@ public class MediaInfoModel : IEmbeddedDocument
|
|||
|
||||
public string VideoTransferCharacteristics { get; set; }
|
||||
|
||||
public DoviConfigurationRecordSideData DoviConfigurationRecord { get; set; }
|
||||
|
||||
public HdrFormat VideoHdrFormat { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using FFMpegCore;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
|
@ -19,10 +20,9 @@ public class VideoFileInfoReader : IVideoFileInfoReader
|
|||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly Logger _logger;
|
||||
private readonly List<FFProbePixelFormat> _pixelFormats;
|
||||
|
||||
public const int MINIMUM_MEDIA_INFO_SCHEMA_REVISION = 12;
|
||||
public const int CURRENT_MEDIA_INFO_SCHEMA_REVISION = 12;
|
||||
public const int MINIMUM_MEDIA_INFO_SCHEMA_REVISION = 13;
|
||||
public const int CURRENT_MEDIA_INFO_SCHEMA_REVISION = 13;
|
||||
|
||||
private static readonly string[] ValidHdrColourPrimaries = { "bt2020" };
|
||||
private static readonly string[] HlgTransferFunctions = { "arib-std-b67" };
|
||||
|
|
@ -36,16 +36,6 @@ public VideoFileInfoReader(IDiskProvider diskProvider, Logger logger)
|
|||
|
||||
// We bundle ffprobe for all platforms
|
||||
GlobalFFOptions.Configure(options => options.BinaryFolder = AppDomain.CurrentDomain.BaseDirectory);
|
||||
|
||||
try
|
||||
{
|
||||
_pixelFormats = FFProbe.GetPixelFormats();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(e, "Failed to get supported pixel formats from ffprobe");
|
||||
_pixelFormats = new List<FFProbePixelFormat>();
|
||||
}
|
||||
}
|
||||
|
||||
public MediaInfoModel GetMediaInfo(string filename)
|
||||
|
|
@ -65,15 +55,13 @@ public MediaInfoModel GetMediaInfo(string filename)
|
|||
try
|
||||
{
|
||||
_logger.Debug("Getting media info from {0}", filename);
|
||||
var ffprobeOutput = FFProbe.GetStreamJson(filename, ffOptions: new FFOptions { ExtraArguments = "-probesize 50000000" });
|
||||
|
||||
var analysis = FFProbe.AnalyseStreamJson(ffprobeOutput);
|
||||
var analysis = FFProbe.Analyse(filename, customArguments: "-probesize 50000000");
|
||||
var primaryVideoStream = GetPrimaryVideoStream(analysis);
|
||||
|
||||
if (analysis.PrimaryAudioStream?.ChannelLayout.IsNullOrWhiteSpace() ?? true)
|
||||
{
|
||||
ffprobeOutput = FFProbe.GetStreamJson(filename, ffOptions: new FFOptions { ExtraArguments = "-probesize 150000000 -analyzeduration 150000000" });
|
||||
analysis = FFProbe.AnalyseStreamJson(ffprobeOutput);
|
||||
analysis = FFProbe.Analyse(filename, customArguments: "-probesize 150000000 -analyzeduration 150000000");
|
||||
}
|
||||
|
||||
var mediaInfoModel = new MediaInfoModel();
|
||||
|
|
@ -85,7 +73,6 @@ public MediaInfoModel GetMediaInfo(string filename)
|
|||
mediaInfoModel.VideoBitDepth = GetPixelFormat(primaryVideoStream?.PixelFormat)?.Components.Min(x => x.BitDepth) ?? 8;
|
||||
mediaInfoModel.VideoColourPrimaries = primaryVideoStream?.ColorPrimaries;
|
||||
mediaInfoModel.VideoTransferCharacteristics = primaryVideoStream?.ColorTransfer;
|
||||
mediaInfoModel.DoviConfigurationRecord = primaryVideoStream?.SideDataList?.Find(x => x.GetType().Name == nameof(DoviConfigurationRecordSideData)) as DoviConfigurationRecordSideData;
|
||||
mediaInfoModel.Height = primaryVideoStream?.Height ?? 0;
|
||||
mediaInfoModel.Width = primaryVideoStream?.Width ?? 0;
|
||||
mediaInfoModel.AudioFormat = analysis.PrimaryAudioStream?.CodecName;
|
||||
|
|
@ -103,8 +90,12 @@ public MediaInfoModel GetMediaInfo(string filename)
|
|||
mediaInfoModel.Subtitles = analysis.SubtitleStreams?.Select(x => x.Language)
|
||||
.Where(l => l.IsNotNullOrWhiteSpace())
|
||||
.ToList();
|
||||
mediaInfoModel.ScanType = "Progressive";
|
||||
mediaInfoModel.RawStreamData = ffprobeOutput;
|
||||
mediaInfoModel.ScanType = primaryVideoStream?.FieldOrder switch
|
||||
{
|
||||
"tt" or "bb" or "tb" or "bt" => "Interlaced",
|
||||
_ => "Progressive"
|
||||
};
|
||||
mediaInfoModel.RawStreamData = string.Concat(analysis.OutputData);
|
||||
mediaInfoModel.SchemaRevision = CURRENT_MEDIA_INFO_SCHEMA_REVISION;
|
||||
|
||||
if (analysis.Format.Tags?.TryGetValue("title", out var title) ?? false)
|
||||
|
|
@ -117,14 +108,11 @@ public MediaInfoModel GetMediaInfo(string filename)
|
|||
// if it looks like PQ10 or similar HDR, do a frame analysis to figure out which type it is
|
||||
if (PqTransferFunctions.Contains(mediaInfoModel.VideoTransferCharacteristics))
|
||||
{
|
||||
var frameOutput = FFProbe.GetFrameJson(filename, ffOptions: new() { ExtraArguments = $"-read_intervals \"%+#1\" -select_streams v:{primaryVideoStream?.Index ?? 0}" });
|
||||
mediaInfoModel.RawFrameData = frameOutput;
|
||||
|
||||
frames = FFProbe.AnalyseFrameJson(frameOutput);
|
||||
frames = FFProbe.GetFrames(filename, customArguments: $"-read_intervals \"%+#1\" -select_streams v:{primaryVideoStream?.Index ?? 0}");
|
||||
}
|
||||
|
||||
var streamSideData = primaryVideoStream?.SideDataList ?? new();
|
||||
var framesSideData = frames?.Frames?.Count > 0 ? frames?.Frames[0]?.SideDataList ?? new() : new();
|
||||
var streamSideData = primaryVideoStream?.SideData ?? new();
|
||||
var framesSideData = frames?.Frames.FirstOrDefault()?.SideData ?? new();
|
||||
|
||||
var sideData = streamSideData.Concat(framesSideData).ToList();
|
||||
mediaInfoModel.VideoHdrFormat = GetHdrFormat(mediaInfoModel.VideoBitDepth, mediaInfoModel.VideoColourPrimaries, mediaInfoModel.VideoTransferCharacteristics, sideData);
|
||||
|
|
@ -176,7 +164,7 @@ private static long GetBitrate(MediaStream mediaStream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
private VideoStream GetPrimaryVideoStream(IMediaAnalysis mediaAnalysis)
|
||||
private static VideoStream GetPrimaryVideoStream(IMediaAnalysis mediaAnalysis)
|
||||
{
|
||||
if (mediaAnalysis.VideoStreams.Count <= 1)
|
||||
{
|
||||
|
|
@ -189,23 +177,30 @@ private VideoStream GetPrimaryVideoStream(IMediaAnalysis mediaAnalysis)
|
|||
return mediaAnalysis.VideoStreams.FirstOrDefault(s => !codecFilter.Contains(s.CodecName)) ?? mediaAnalysis.PrimaryVideoStream;
|
||||
}
|
||||
|
||||
private FFProbePixelFormat GetPixelFormat(string format)
|
||||
private static FFProbePixelFormat GetPixelFormat(string format)
|
||||
{
|
||||
return _pixelFormats.Find(x => x.Name == format);
|
||||
if (format.IsNullOrWhiteSpace())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return FFProbe.TryGetPixelFormat(format, out var pixelFormat) ? pixelFormat : null;
|
||||
}
|
||||
|
||||
public static HdrFormat GetHdrFormat(int bitDepth, string colorPrimaries, string transferFunction, List<SideData> sideData)
|
||||
public static HdrFormat GetHdrFormat(int bitDepth, string colorPrimaries, string transferFunction, List<Dictionary<string, JsonNode>> sideData)
|
||||
{
|
||||
if (bitDepth < 10)
|
||||
{
|
||||
return HdrFormat.None;
|
||||
}
|
||||
|
||||
if (TryGetSideData<DoviConfigurationRecordSideData>(sideData, out var dovi))
|
||||
if (TryGetSideData(sideData, FFMpegCoreSideDataTypes.DoviConfigurationRecordSideData, out var dovi))
|
||||
{
|
||||
var hasHdr10Plus = TryGetSideData<HdrDynamicMetadataSpmte2094>(sideData, out _);
|
||||
var hasHdr10Plus = TryGetSideData(sideData, FFMpegCoreSideDataTypes.HdrDynamicMetadataSpmte2094, out _);
|
||||
|
||||
return dovi.DvBlSignalCompatibilityId switch
|
||||
dovi.TryGetValue("dv_bl_signal_compatibility_id", out var dvBlSignalCompatibilityId);
|
||||
|
||||
return dvBlSignalCompatibilityId?.GetValue<int>() switch
|
||||
{
|
||||
1 => hasHdr10Plus ? HdrFormat.DolbyVisionHdr10Plus : HdrFormat.DolbyVisionHdr10,
|
||||
2 => HdrFormat.DolbyVisionSdr,
|
||||
|
|
@ -227,13 +222,13 @@ public static HdrFormat GetHdrFormat(int bitDepth, string colorPrimaries, string
|
|||
|
||||
if (PqTransferFunctions.Contains(transferFunction))
|
||||
{
|
||||
if (TryGetSideData<HdrDynamicMetadataSpmte2094>(sideData, out _))
|
||||
if (TryGetSideData(sideData, FFMpegCoreSideDataTypes.HdrDynamicMetadataSpmte2094, out _))
|
||||
{
|
||||
return HdrFormat.Hdr10Plus;
|
||||
}
|
||||
|
||||
if (TryGetSideData<MasteringDisplayMetadata>(sideData, out _) ||
|
||||
TryGetSideData<ContentLightLevelMetadata>(sideData, out _))
|
||||
if (TryGetSideData(sideData, FFMpegCoreSideDataTypes.MasteringDisplayMetadata, out _) ||
|
||||
TryGetSideData(sideData, FFMpegCoreSideDataTypes.ContentLightLevelMetadata, out _))
|
||||
{
|
||||
return HdrFormat.Hdr10;
|
||||
}
|
||||
|
|
@ -244,10 +239,11 @@ public static HdrFormat GetHdrFormat(int bitDepth, string colorPrimaries, string
|
|||
return HdrFormat.None;
|
||||
}
|
||||
|
||||
private static bool TryGetSideData<T>(List<SideData> list, out T result)
|
||||
where T : SideData
|
||||
private static bool TryGetSideData(IReadOnlyList<Dictionary<string, JsonNode>> list, string name, out Dictionary<string, JsonNode> result)
|
||||
{
|
||||
result = (T)list?.FirstOrDefault(x => x.GetType().Name == typeof(T).Name);
|
||||
result = list?.FirstOrDefault(item =>
|
||||
item.TryGetValue("side_data_type", out var rawSideDataType) &&
|
||||
rawSideDataType.GetValue<string>().Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return result != null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
<PackageReference Include="MailKit" Version="4.14.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.3" />
|
||||
<PackageReference Include="Openur.FFMpegCore" Version="5.4.0.31" />
|
||||
<PackageReference Include="Openur.FFprobeStatic" Version="8.0.1.289" />
|
||||
<PackageReference Include="Polly" Version="8.6.5" />
|
||||
<PackageReference Include="Servarr.FFMpegCore" Version="4.7.0-26" />
|
||||
<PackageReference Include="Servarr.FFprobe" Version="5.1.4.112" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.1" />
|
||||
|
|
|
|||
Loading…
Reference in a new issue