Merge pull request #9227 from Bond-009/ffprobe
Improve ffprobe json parsing and don't log error for Codec Type attachment
This commit is contained in:
commit
9e155eacea
|
@ -14,6 +14,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Extensions;
|
using Jellyfin.Extensions;
|
||||||
using Jellyfin.Extensions.Json;
|
using Jellyfin.Extensions.Json;
|
||||||
|
using Jellyfin.Extensions.Json.Converters;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
|
@ -58,7 +59,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
_socketFactory = socketFactory;
|
_socketFactory = socketFactory;
|
||||||
_streamHelper = streamHelper;
|
_streamHelper = streamHelper;
|
||||||
|
|
||||||
_jsonOptions = JsonDefaults.Options;
|
_jsonOptions = new JsonSerializerOptions(JsonDefaults.Options);
|
||||||
|
_jsonOptions.Converters.Add(new JsonBoolNumberConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => "HD Homerun";
|
public string Name => "HD Homerun";
|
||||||
|
|
|
@ -12,6 +12,7 @@ using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Extensions.Json;
|
using Jellyfin.Extensions.Json;
|
||||||
|
using Jellyfin.Extensions.Json.Converters;
|
||||||
using MediaBrowser.Common;
|
using MediaBrowser.Common;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
|
@ -105,7 +106,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
_config = config;
|
_config = config;
|
||||||
_serverConfig = serverConfig;
|
_serverConfig = serverConfig;
|
||||||
_startupOptionFFmpegPath = config.GetValue<string>(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? string.Empty;
|
_startupOptionFFmpegPath = config.GetValue<string>(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? string.Empty;
|
||||||
_jsonSerializerOptions = JsonDefaults.Options;
|
|
||||||
|
_jsonSerializerOptions = new JsonSerializerOptions(JsonDefaults.Options);
|
||||||
|
_jsonSerializerOptions.Converters.Add(new JsonBoolStringConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
32
MediaBrowser.MediaEncoding/Probing/CodecType.cs
Normal file
32
MediaBrowser.MediaEncoding/Probing/CodecType.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
namespace MediaBrowser.MediaEncoding.Probing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// FFmpeg Codec Type.
|
||||||
|
/// </summary>
|
||||||
|
public enum CodecType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Video.
|
||||||
|
/// </summary>
|
||||||
|
Video,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Audio.
|
||||||
|
/// </summary>
|
||||||
|
Audio,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opaque data information usually continuous.
|
||||||
|
/// </summary>
|
||||||
|
Data,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtitles.
|
||||||
|
/// </summary>
|
||||||
|
Subtitle,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opaque data information usually sparse.
|
||||||
|
/// </summary>
|
||||||
|
Attachment
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The codec_type.</value>
|
/// <value>The codec_type.</value>
|
||||||
[JsonPropertyName("codec_type")]
|
[JsonPropertyName("codec_type")]
|
||||||
public string CodecType { get; set; }
|
public CodecType CodecType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the sample_rate.
|
/// Gets or sets the sample_rate.
|
||||||
|
@ -228,11 +228,11 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
public long StartPts { get; set; }
|
public long StartPts { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the is_avc.
|
/// Gets or sets a value indicating whether the stream is AVC.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The is_avc.</value>
|
/// <value>The is_avc.</value>
|
||||||
[JsonPropertyName("is_avc")]
|
[JsonPropertyName("is_avc")]
|
||||||
public string IsAvc { get; set; }
|
public bool IsAvc { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the nal_length_size.
|
/// Gets or sets the nal_length_size.
|
||||||
|
|
|
@ -107,9 +107,9 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
}
|
}
|
||||||
|
|
||||||
var tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
var tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
var tagStreamType = isAudio ? "audio" : "video";
|
var tagStreamType = isAudio ? CodecType.Audio : CodecType.Video;
|
||||||
|
|
||||||
var tagStream = data.Streams?.FirstOrDefault(i => string.Equals(i.CodecType, tagStreamType, StringComparison.OrdinalIgnoreCase));
|
var tagStream = data.Streams?.FirstOrDefault(i => i.CodecType == tagStreamType);
|
||||||
|
|
||||||
if (tagStream?.Tags is not null)
|
if (tagStream?.Tags is not null)
|
||||||
{
|
{
|
||||||
|
@ -599,7 +599,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
/// <returns>MediaAttachments.</returns>
|
/// <returns>MediaAttachments.</returns>
|
||||||
private MediaAttachment GetMediaAttachment(MediaStreamInfo streamInfo)
|
private MediaAttachment GetMediaAttachment(MediaStreamInfo streamInfo)
|
||||||
{
|
{
|
||||||
if (!string.Equals(streamInfo.CodecType, "attachment", StringComparison.OrdinalIgnoreCase)
|
if (streamInfo.CodecType != CodecType.Attachment
|
||||||
&& streamInfo.Disposition?.GetValueOrDefault("attached_pic") != 1)
|
&& streamInfo.Disposition?.GetValueOrDefault("attached_pic") != 1)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -651,20 +651,10 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
PixelFormat = streamInfo.PixelFormat,
|
PixelFormat = streamInfo.PixelFormat,
|
||||||
NalLengthSize = streamInfo.NalLengthSize,
|
NalLengthSize = streamInfo.NalLengthSize,
|
||||||
TimeBase = streamInfo.TimeBase,
|
TimeBase = streamInfo.TimeBase,
|
||||||
CodecTimeBase = streamInfo.CodecTimeBase
|
CodecTimeBase = streamInfo.CodecTimeBase,
|
||||||
|
IsAVC = streamInfo.IsAvc
|
||||||
};
|
};
|
||||||
|
|
||||||
if (string.Equals(streamInfo.IsAvc, "true", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(streamInfo.IsAvc, "1", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
stream.IsAVC = true;
|
|
||||||
}
|
|
||||||
else if (string.Equals(streamInfo.IsAvc, "false", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(streamInfo.IsAvc, "0", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
stream.IsAVC = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter out junk
|
// Filter out junk
|
||||||
if (!string.IsNullOrWhiteSpace(streamInfo.CodecTagString) && !streamInfo.CodecTagString.Contains("[0]", StringComparison.OrdinalIgnoreCase))
|
if (!string.IsNullOrWhiteSpace(streamInfo.CodecTagString) && !streamInfo.CodecTagString.Contains("[0]", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
@ -678,18 +668,15 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
stream.Title = GetDictionaryValue(streamInfo.Tags, "title");
|
stream.Title = GetDictionaryValue(streamInfo.Tags, "title");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(streamInfo.CodecType, "audio", StringComparison.OrdinalIgnoreCase))
|
if (streamInfo.CodecType == CodecType.Audio)
|
||||||
{
|
{
|
||||||
stream.Type = MediaStreamType.Audio;
|
stream.Type = MediaStreamType.Audio;
|
||||||
|
|
||||||
stream.Channels = streamInfo.Channels;
|
stream.Channels = streamInfo.Channels;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(streamInfo.SampleRate))
|
if (int.TryParse(streamInfo.SampleRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value))
|
||||||
{
|
{
|
||||||
if (int.TryParse(streamInfo.SampleRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value))
|
stream.SampleRate = value;
|
||||||
{
|
|
||||||
stream.SampleRate = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.ChannelLayout = ParseChannelLayout(streamInfo.ChannelLayout);
|
stream.ChannelLayout = ParseChannelLayout(streamInfo.ChannelLayout);
|
||||||
|
@ -713,7 +700,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (string.Equals(streamInfo.CodecType, "subtitle", StringComparison.OrdinalIgnoreCase))
|
else if (streamInfo.CodecType == CodecType.Subtitle)
|
||||||
{
|
{
|
||||||
stream.Type = MediaStreamType.Subtitle;
|
stream.Type = MediaStreamType.Subtitle;
|
||||||
stream.Codec = NormalizeSubtitleCodec(stream.Codec);
|
stream.Codec = NormalizeSubtitleCodec(stream.Codec);
|
||||||
|
@ -733,7 +720,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (string.Equals(streamInfo.CodecType, "video", StringComparison.OrdinalIgnoreCase))
|
else if (streamInfo.CodecType == CodecType.Video)
|
||||||
{
|
{
|
||||||
stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate);
|
stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate);
|
||||||
stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate);
|
stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate);
|
||||||
|
@ -854,13 +841,12 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (string.Equals(streamInfo.CodecType, "data", StringComparison.OrdinalIgnoreCase))
|
else if (streamInfo.CodecType == CodecType.Data)
|
||||||
{
|
{
|
||||||
stream.Type = MediaStreamType.Data;
|
stream.Type = MediaStreamType.Data;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogError("Codec Type {CodecType} unknown. The stream (index: {Index}) will be ignored. Warning: Subsequential streams will have a wrong stream specifier!", streamInfo.CodecType, streamInfo.Index);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -895,29 +881,26 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
|
|
||||||
// Extract bitrate info from tag "BPS" if possible.
|
// Extract bitrate info from tag "BPS" if possible.
|
||||||
if (!stream.BitRate.HasValue
|
if (!stream.BitRate.HasValue
|
||||||
&& (string.Equals(streamInfo.CodecType, "audio", StringComparison.OrdinalIgnoreCase)
|
&& (streamInfo.CodecType == CodecType.Audio
|
||||||
|| string.Equals(streamInfo.CodecType, "video", StringComparison.OrdinalIgnoreCase)))
|
|| streamInfo.CodecType == CodecType.Video))
|
||||||
{
|
{
|
||||||
var bps = GetBPSFromTags(streamInfo);
|
var bps = GetBPSFromTags(streamInfo);
|
||||||
if (bps > 0)
|
if (bps > 0)
|
||||||
{
|
{
|
||||||
stream.BitRate = bps;
|
stream.BitRate = bps;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
// Get average bitrate info from tag "NUMBER_OF_BYTES" and "DURATION" if possible.
|
|
||||||
if (!stream.BitRate.HasValue
|
|
||||||
&& (string.Equals(streamInfo.CodecType, "audio", StringComparison.OrdinalIgnoreCase)
|
|
||||||
|| string.Equals(streamInfo.CodecType, "video", StringComparison.OrdinalIgnoreCase)))
|
|
||||||
{
|
|
||||||
var durationInSeconds = GetRuntimeSecondsFromTags(streamInfo);
|
|
||||||
var bytes = GetNumberOfBytesFromTags(streamInfo);
|
|
||||||
if (durationInSeconds is not null && bytes is not null)
|
|
||||||
{
|
{
|
||||||
var bps = Convert.ToInt32(bytes * 8 / durationInSeconds, CultureInfo.InvariantCulture);
|
// Get average bitrate info from tag "NUMBER_OF_BYTES" and "DURATION" if possible.
|
||||||
if (bps > 0)
|
var durationInSeconds = GetRuntimeSecondsFromTags(streamInfo);
|
||||||
|
var bytes = GetNumberOfBytesFromTags(streamInfo);
|
||||||
|
if (durationInSeconds is not null && bytes is not null)
|
||||||
{
|
{
|
||||||
stream.BitRate = bps;
|
bps = Convert.ToInt32(bytes * 8 / durationInSeconds, CultureInfo.InvariantCulture);
|
||||||
|
if (bps > 0)
|
||||||
|
{
|
||||||
|
stream.BitRate = bps;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -948,12 +931,8 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
|
|
||||||
private void NormalizeStreamTitle(MediaStream stream)
|
private void NormalizeStreamTitle(MediaStream stream)
|
||||||
{
|
{
|
||||||
if (string.Equals(stream.Title, "cc", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(stream.Title, "cc", StringComparison.OrdinalIgnoreCase)
|
||||||
{
|
|| stream.Type == MediaStreamType.EmbeddedImage)
|
||||||
stream.Title = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream.Type == MediaStreamType.EmbeddedImage)
|
|
||||||
{
|
{
|
||||||
stream.Title = null;
|
stream.Title = null;
|
||||||
}
|
}
|
||||||
|
@ -984,7 +963,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return input.Split('(').FirstOrDefault();
|
return input.AsSpan().LeftPart('(').ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetAspectRatio(MediaStreamInfo info)
|
private string GetAspectRatio(MediaStreamInfo info)
|
||||||
|
@ -992,11 +971,11 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
var original = info.DisplayAspectRatio;
|
var original = info.DisplayAspectRatio;
|
||||||
|
|
||||||
var parts = (original ?? string.Empty).Split(':');
|
var parts = (original ?? string.Empty).Split(':');
|
||||||
if (!(parts.Length == 2 &&
|
if (!(parts.Length == 2
|
||||||
int.TryParse(parts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out var width) &&
|
&& int.TryParse(parts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out var width)
|
||||||
int.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var height) &&
|
&& int.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var height)
|
||||||
width > 0 &&
|
&& width > 0
|
||||||
height > 0))
|
&& height > 0))
|
||||||
{
|
{
|
||||||
width = info.Width;
|
width = info.Width;
|
||||||
height = info.Height;
|
height = info.Height;
|
||||||
|
@ -1077,12 +1056,6 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
int index = value.IndexOf('/');
|
int index = value.IndexOf('/');
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
{
|
{
|
||||||
// REVIEW: is this branch actually required? (i.e. does ffprobe ever output something other than a fraction?)
|
|
||||||
if (float.TryParse(value, NumberStyles.AllowThousands | NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1098,7 +1071,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
private void SetAudioRuntimeTicks(InternalMediaInfoResult result, MediaInfo data)
|
private void SetAudioRuntimeTicks(InternalMediaInfoResult result, MediaInfo data)
|
||||||
{
|
{
|
||||||
// Get the first info stream
|
// Get the first info stream
|
||||||
var stream = result.Streams?.FirstOrDefault(s => string.Equals(s.CodecType, "audio", StringComparison.OrdinalIgnoreCase));
|
var stream = result.Streams?.FirstOrDefault(s => s.CodecType == CodecType.Audio);
|
||||||
if (stream is null)
|
if (stream is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -1128,8 +1101,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
}
|
}
|
||||||
|
|
||||||
var bps = GetDictionaryValue(streamInfo.Tags, "BPS-eng") ?? GetDictionaryValue(streamInfo.Tags, "BPS");
|
var bps = GetDictionaryValue(streamInfo.Tags, "BPS-eng") ?? GetDictionaryValue(streamInfo.Tags, "BPS");
|
||||||
if (!string.IsNullOrEmpty(bps)
|
if (int.TryParse(bps, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedBps))
|
||||||
&& int.TryParse(bps, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedBps))
|
|
||||||
{
|
{
|
||||||
return parsedBps;
|
return parsedBps;
|
||||||
}
|
}
|
||||||
|
@ -1162,8 +1134,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
|
|
||||||
var numberOfBytes = GetDictionaryValue(streamInfo.Tags, "NUMBER_OF_BYTES-eng")
|
var numberOfBytes = GetDictionaryValue(streamInfo.Tags, "NUMBER_OF_BYTES-eng")
|
||||||
?? GetDictionaryValue(streamInfo.Tags, "NUMBER_OF_BYTES");
|
?? GetDictionaryValue(streamInfo.Tags, "NUMBER_OF_BYTES");
|
||||||
if (!string.IsNullOrEmpty(numberOfBytes)
|
if (long.TryParse(numberOfBytes, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedBytes))
|
||||||
&& long.TryParse(numberOfBytes, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedBytes))
|
|
||||||
{
|
{
|
||||||
return parsedBytes;
|
return parsedBytes;
|
||||||
}
|
}
|
||||||
|
@ -1455,7 +1426,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
{
|
{
|
||||||
var disc = tags.GetValueOrDefault(tagName);
|
var disc = tags.GetValueOrDefault(tagName);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(disc) && int.TryParse(disc.AsSpan().LeftPart('/'), out var discNum))
|
if (int.TryParse(disc.AsSpan().LeftPart('/'), out var discNum))
|
||||||
{
|
{
|
||||||
return discNum;
|
return discNum;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Buffers.Text;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Jellyfin.Extensions.Json.Converters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a string to a boolean.
|
||||||
|
/// This is needed for FFprobe.
|
||||||
|
/// </summary>
|
||||||
|
public class JsonBoolStringConverter : JsonConverter<bool>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonTokenType.String)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<byte> utf8Span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
|
||||||
|
if (Utf8Parser.TryParse(utf8Span, out bool val, out _, 'l'))
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader.GetBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
|
||||||
|
=> writer.WriteBooleanValue(value);
|
||||||
|
}
|
|
@ -39,7 +39,6 @@ namespace Jellyfin.Extensions.Json
|
||||||
new JsonFlagEnumConverterFactory(),
|
new JsonFlagEnumConverterFactory(),
|
||||||
new JsonStringEnumConverter(),
|
new JsonStringEnumConverter(),
|
||||||
new JsonNullableStructConverterFactory(),
|
new JsonNullableStructConverterFactory(),
|
||||||
new JsonBoolNumberConverter(),
|
|
||||||
new JsonDateTimeConverter(),
|
new JsonDateTimeConverter(),
|
||||||
new JsonStringConverter()
|
new JsonStringConverter()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System.Text.Json;
|
||||||
|
using Jellyfin.Extensions.Json.Converters;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Jellyfin.Extensions.Tests.Json.Converters
|
||||||
|
{
|
||||||
|
public class JsonBoolStringTests
|
||||||
|
{
|
||||||
|
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions()
|
||||||
|
{
|
||||||
|
Converters =
|
||||||
|
{
|
||||||
|
new JsonBoolStringConverter()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(@"{ ""Value"": ""true"" }", true)]
|
||||||
|
[InlineData(@"{ ""Value"": ""false"" }", false)]
|
||||||
|
public void Deserialize_String_Valid_Success(string input, bool output)
|
||||||
|
{
|
||||||
|
var s = JsonSerializer.Deserialize<TestStruct>(input, _jsonOptions);
|
||||||
|
Assert.Equal(s.Value, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(true, "true")]
|
||||||
|
[InlineData(false, "false")]
|
||||||
|
public void Serialize_Bool_Success(bool input, string output)
|
||||||
|
{
|
||||||
|
var value = JsonSerializer.Serialize(input, _jsonOptions);
|
||||||
|
Assert.Equal(value, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly record struct TestStruct(bool Value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Jellyfin.Extensions.Json;
|
|
||||||
using MediaBrowser.MediaEncoding.Probing;
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Jellyfin.MediaEncoding.Tests
|
|
||||||
{
|
|
||||||
public class FFprobeParserTests
|
|
||||||
{
|
|
||||||
[Theory]
|
|
||||||
[InlineData("ffprobe1.json")]
|
|
||||||
public async Task Test(string fileName)
|
|
||||||
{
|
|
||||||
var path = Path.Join("Test Data", fileName);
|
|
||||||
await using (var stream = AsyncFile.OpenRead(path))
|
|
||||||
{
|
|
||||||
var res = await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream, JsonDefaults.Options).ConfigureAwait(false);
|
|
||||||
Assert.NotNull(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Jellyfin.Extensions.Json;
|
using Jellyfin.Extensions.Json;
|
||||||
|
using Jellyfin.Extensions.Json.Converters;
|
||||||
using MediaBrowser.MediaEncoding.Probing;
|
using MediaBrowser.MediaEncoding.Probing;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
|
@ -15,9 +16,15 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
|
||||||
{
|
{
|
||||||
public class ProbeResultNormalizerTests
|
public class ProbeResultNormalizerTests
|
||||||
{
|
{
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
private readonly JsonSerializerOptions _jsonOptions;
|
||||||
private readonly ProbeResultNormalizer _probeResultNormalizer = new ProbeResultNormalizer(new NullLogger<EncoderValidatorTests>(), null);
|
private readonly ProbeResultNormalizer _probeResultNormalizer = new ProbeResultNormalizer(new NullLogger<EncoderValidatorTests>(), null);
|
||||||
|
|
||||||
|
public ProbeResultNormalizerTests()
|
||||||
|
{
|
||||||
|
_jsonOptions = new JsonSerializerOptions(JsonDefaults.Options);
|
||||||
|
_jsonOptions.Converters.Add(new JsonBoolStringConverter());
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("2997/125", 23.976f)]
|
[InlineData("2997/125", 23.976f)]
|
||||||
[InlineData("1/50", 0.02f)]
|
[InlineData("1/50", 0.02f)]
|
||||||
|
@ -148,6 +155,19 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
|
||||||
Assert.False(res.MediaStreams[5].IsHearingImpaired);
|
Assert.False(res.MediaStreams[5].IsHearingImpaired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMediaInfo_TS_Success()
|
||||||
|
{
|
||||||
|
var bytes = File.ReadAllBytes("Test Data/Probing/video_ts.json");
|
||||||
|
var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions);
|
||||||
|
|
||||||
|
MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_metadata.mkv", MediaProtocol.File);
|
||||||
|
|
||||||
|
Assert.Equal(2, res.MediaStreams.Count);
|
||||||
|
|
||||||
|
Assert.False(res.MediaStreams[0].IsAVC);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetMediaInfo_ProgressiveVideoNoFieldOrder_Success()
|
public void GetMediaInfo_ProgressiveVideoNoFieldOrder_Success()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user