diff options
| author | Bond_009 <bond.009@outlook.com> | 2019-12-22 21:39:26 +0100 |
|---|---|---|
| committer | Bond_009 <bond.009@outlook.com> | 2019-12-22 22:09:09 +0100 |
| commit | cf2e2a3f309d59c3c31696fc7f3ef2b6668c89dd (patch) | |
| tree | ecbb2fc0ce4c236c163135d8705a17e6fa2f1022 /MediaBrowser.MediaEncoding | |
| parent | 06dfa2e687304874d4c8de8f7c95354b3d51225c (diff) | |
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
Diffstat (limited to 'MediaBrowser.MediaEncoding')
7 files changed, 518 insertions, 434 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 6bcd6cd46..e0f7b992c 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -397,7 +397,8 @@ namespace MediaBrowser.MediaEncoding.Encoder try { result = await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>( - process.StandardOutput.BaseStream).ConfigureAwait(false); + process.StandardOutput.BaseStream, + cancellationToken: cancellationToken).ConfigureAwait(false); } catch { @@ -406,24 +407,24 @@ namespace MediaBrowser.MediaEncoding.Encoder throw; } - if (result == null || (result.streams == null && result.format == null)) + if (result == null || (result.Streams == null && result.Format == null)) { throw new Exception("ffprobe failed - streams and format are both null."); } - if (result.streams != null) + if (result.Streams != null) { // Normalize aspect ratio if invalid - foreach (var stream in result.streams) + foreach (var stream in result.Streams) { - if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(stream.DisplayAspectRatio, "0:1", StringComparison.OrdinalIgnoreCase)) { - stream.display_aspect_ratio = string.Empty; + stream.DisplayAspectRatio = string.Empty; } - if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(stream.SampleAspectRatio, "0:1", StringComparison.OrdinalIgnoreCase)) { - stream.sample_aspect_ratio = string.Empty; + stream.SampleAspectRatio = string.Empty; } } } @@ -778,6 +779,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _runningProcesses.Add(process); } } + private void StopProcess(ProcessWrapper process, int waitTimeMs) { try @@ -786,18 +788,16 @@ namespace MediaBrowser.MediaEncoding.Encoder { return; } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in WaitForExit"); - } - try - { _logger.LogInformation("Killing ffmpeg process"); process.Process.Kill(); } + catch (InvalidOperationException) + { + // The process has already exited or + // there is no process associated with this Process object. + } catch (Exception ex) { _logger.LogError(ex, "Error killing process"); diff --git a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs index e4eabaf38..cd3d82e86 100644 --- a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs +++ b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs @@ -16,24 +16,19 @@ namespace MediaBrowser.MediaEncoding.Probing throw new ArgumentNullException(nameof(result)); } - if (result.format != null && result.format.tags != null) + if (result.Format != null && result.Format.Tags != null) { - result.format.tags = ConvertDictionaryToCaseInSensitive(result.format.tags); + result.Format.Tags = ConvertDictionaryToCaseInSensitive(result.Format.Tags); } - if (result.streams != null) + if (result.Streams != null) { // Convert all dictionaries to case insensitive - foreach (var stream in result.streams) + foreach (var stream in result.Streams) { - if (stream.tags != null) + if (stream.Tags != null) { - stream.tags = ConvertDictionaryToCaseInSensitive(stream.tags); - } - - if (stream.disposition != null) - { - stream.disposition = ConvertDictionaryToCaseInSensitive(stream.disposition); + stream.Tags = ConvertDictionaryToCaseInSensitive(stream.Tags); } } } @@ -45,7 +40,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// <param name="tags">The tags.</param> /// <param name="key">The key.</param> /// <returns>System.String.</returns> - public static string GetDictionaryValue(Dictionary<string, string> tags, string key) + public static string GetDictionaryValue(IReadOnlyDictionary<string, string> tags, string key) { if (tags == null) { @@ -103,7 +98,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// </summary> /// <param name="dict">The dict.</param> /// <returns>Dictionary{System.StringSystem.String}.</returns> - private static Dictionary<string, string> ConvertDictionaryToCaseInSensitive(Dictionary<string, string> dict) + private static Dictionary<string, string> ConvertDictionaryToCaseInSensitive(IReadOnlyDictionary<string, string> dict) { return new Dictionary<string, string>(dict, StringComparer.OrdinalIgnoreCase); } diff --git a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs index cc9d27608..0e319c1a8 100644 --- a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs +++ b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; +using System.Text.Json.Serialization; namespace MediaBrowser.MediaEncoding.Probing { /// <summary> - /// Class MediaInfoResult + /// Class MediaInfoResult. /// </summary> public class InternalMediaInfoResult { @@ -11,331 +12,21 @@ namespace MediaBrowser.MediaEncoding.Probing /// Gets or sets the streams. /// </summary> /// <value>The streams.</value> - public MediaStreamInfo[] streams { get; set; } + [JsonPropertyName("streams")] + public IReadOnlyList<MediaStreamInfo> Streams { get; set; } /// <summary> /// Gets or sets the format. /// </summary> /// <value>The format.</value> - public MediaFormatInfo format { get; set; } + [JsonPropertyName("format")] + public MediaFormatInfo Format { get; set; } /// <summary> /// Gets or sets the chapters. /// </summary> /// <value>The chapters.</value> - public MediaChapter[] Chapters { get; set; } - } - - public class MediaChapter - { - public int id { get; set; } - public string time_base { get; set; } - public long start { get; set; } - public string start_time { get; set; } - public long end { get; set; } - public string end_time { get; set; } - public Dictionary<string, string> tags { get; set; } - } - - /// <summary> - /// Represents a stream within the output - /// </summary> - public class MediaStreamInfo - { - /// <summary> - /// Gets or sets the index. - /// </summary> - /// <value>The index.</value> - public int index { get; set; } - - /// <summary> - /// Gets or sets the profile. - /// </summary> - /// <value>The profile.</value> - public string profile { get; set; } - - /// <summary> - /// Gets or sets the codec_name. - /// </summary> - /// <value>The codec_name.</value> - public string codec_name { get; set; } - - /// <summary> - /// Gets or sets the codec_long_name. - /// </summary> - /// <value>The codec_long_name.</value> - public string codec_long_name { get; set; } - - /// <summary> - /// Gets or sets the codec_type. - /// </summary> - /// <value>The codec_type.</value> - public string codec_type { get; set; } - - /// <summary> - /// Gets or sets the sample_rate. - /// </summary> - /// <value>The sample_rate.</value> - public string sample_rate { get; set; } - - /// <summary> - /// Gets or sets the channels. - /// </summary> - /// <value>The channels.</value> - public int channels { get; set; } - - /// <summary> - /// Gets or sets the channel_layout. - /// </summary> - /// <value>The channel_layout.</value> - public string channel_layout { get; set; } - - /// <summary> - /// Gets or sets the avg_frame_rate. - /// </summary> - /// <value>The avg_frame_rate.</value> - public string avg_frame_rate { get; set; } - - /// <summary> - /// Gets or sets the duration. - /// </summary> - /// <value>The duration.</value> - public string duration { get; set; } - - /// <summary> - /// Gets or sets the bit_rate. - /// </summary> - /// <value>The bit_rate.</value> - public string bit_rate { get; set; } - - /// <summary> - /// Gets or sets the width. - /// </summary> - /// <value>The width.</value> - public int width { get; set; } - - /// <summary> - /// Gets or sets the refs. - /// </summary> - /// <value>The refs.</value> - public int refs { get; set; } - - /// <summary> - /// Gets or sets the height. - /// </summary> - /// <value>The height.</value> - public int height { get; set; } - - /// <summary> - /// Gets or sets the display_aspect_ratio. - /// </summary> - /// <value>The display_aspect_ratio.</value> - public string display_aspect_ratio { get; set; } - - /// <summary> - /// Gets or sets the tags. - /// </summary> - /// <value>The tags.</value> - public Dictionary<string, string> tags { get; set; } - - /// <summary> - /// Gets or sets the bits_per_sample. - /// </summary> - /// <value>The bits_per_sample.</value> - public int bits_per_sample { get; set; } - - /// <summary> - /// Gets or sets the bits_per_raw_sample. - /// </summary> - /// <value>The bits_per_raw_sample.</value> - public int bits_per_raw_sample { get; set; } - - /// <summary> - /// Gets or sets the r_frame_rate. - /// </summary> - /// <value>The r_frame_rate.</value> - public string r_frame_rate { get; set; } - - /// <summary> - /// Gets or sets the has_b_frames. - /// </summary> - /// <value>The has_b_frames.</value> - public int has_b_frames { get; set; } - - /// <summary> - /// Gets or sets the sample_aspect_ratio. - /// </summary> - /// <value>The sample_aspect_ratio.</value> - public string sample_aspect_ratio { get; set; } - - /// <summary> - /// Gets or sets the pix_fmt. - /// </summary> - /// <value>The pix_fmt.</value> - public string pix_fmt { get; set; } - - /// <summary> - /// Gets or sets the level. - /// </summary> - /// <value>The level.</value> - public int level { get; set; } - - /// <summary> - /// Gets or sets the time_base. - /// </summary> - /// <value>The time_base.</value> - public string time_base { get; set; } - - /// <summary> - /// Gets or sets the start_time. - /// </summary> - /// <value>The start_time.</value> - public string start_time { get; set; } - - /// <summary> - /// Gets or sets the codec_time_base. - /// </summary> - /// <value>The codec_time_base.</value> - public string codec_time_base { get; set; } - - /// <summary> - /// Gets or sets the codec_tag. - /// </summary> - /// <value>The codec_tag.</value> - public string codec_tag { get; set; } - - /// <summary> - /// Gets or sets the codec_tag_string. - /// </summary> - /// <value>The codec_tag_string.</value> - public string codec_tag_string { get; set; } - - /// <summary> - /// Gets or sets the sample_fmt. - /// </summary> - /// <value>The sample_fmt.</value> - public string sample_fmt { get; set; } - - /// <summary> - /// Gets or sets the dmix_mode. - /// </summary> - /// <value>The dmix_mode.</value> - public string dmix_mode { get; set; } - - /// <summary> - /// Gets or sets the start_pts. - /// </summary> - /// <value>The start_pts.</value> - public string start_pts { get; set; } - - /// <summary> - /// Gets or sets the is_avc. - /// </summary> - /// <value>The is_avc.</value> - public string is_avc { get; set; } - - /// <summary> - /// Gets or sets the nal_length_size. - /// </summary> - /// <value>The nal_length_size.</value> - public string nal_length_size { get; set; } - - /// <summary> - /// Gets or sets the ltrt_cmixlev. - /// </summary> - /// <value>The ltrt_cmixlev.</value> - public string ltrt_cmixlev { get; set; } - - /// <summary> - /// Gets or sets the ltrt_surmixlev. - /// </summary> - /// <value>The ltrt_surmixlev.</value> - public string ltrt_surmixlev { get; set; } - - /// <summary> - /// Gets or sets the loro_cmixlev. - /// </summary> - /// <value>The loro_cmixlev.</value> - public string loro_cmixlev { get; set; } - - /// <summary> - /// Gets or sets the loro_surmixlev. - /// </summary> - /// <value>The loro_surmixlev.</value> - public string loro_surmixlev { get; set; } - - public string field_order { get; set; } - - /// <summary> - /// Gets or sets the disposition. - /// </summary> - /// <value>The disposition.</value> - public Dictionary<string, string> disposition { get; set; } - } - - /// <summary> - /// Class MediaFormat - /// </summary> - public class MediaFormatInfo - { - /// <summary> - /// Gets or sets the filename. - /// </summary> - /// <value>The filename.</value> - public string filename { get; set; } - - /// <summary> - /// Gets or sets the nb_streams. - /// </summary> - /// <value>The nb_streams.</value> - public int nb_streams { get; set; } - - /// <summary> - /// Gets or sets the format_name. - /// </summary> - /// <value>The format_name.</value> - public string format_name { get; set; } - - /// <summary> - /// Gets or sets the format_long_name. - /// </summary> - /// <value>The format_long_name.</value> - public string format_long_name { get; set; } - - /// <summary> - /// Gets or sets the start_time. - /// </summary> - /// <value>The start_time.</value> - public string start_time { get; set; } - - /// <summary> - /// Gets or sets the duration. - /// </summary> - /// <value>The duration.</value> - public string duration { get; set; } - - /// <summary> - /// Gets or sets the size. - /// </summary> - /// <value>The size.</value> - public string size { get; set; } - - /// <summary> - /// Gets or sets the bit_rate. - /// </summary> - /// <value>The bit_rate.</value> - public string bit_rate { get; set; } - - /// <summary> - /// Gets or sets the probe_score. - /// </summary> - /// <value>The probe_score.</value> - public int probe_score { get; set; } - - /// <summary> - /// Gets or sets the tags. - /// </summary> - /// <value>The tags.</value> - public Dictionary<string, string> tags { get; set; } + [JsonPropertyName("chapters")] + public IReadOnlyList<MediaChapter> Chapters { get; set; } } } diff --git a/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs b/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs new file mode 100644 index 000000000..a3607a760 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.MediaEncoding.Probing +{ + /// <summary> + /// Class MediaChapter. + /// </summary> + public class MediaChapter + { + [JsonPropertyName("id")] + public int id { get; set; } + + [JsonPropertyName("time_base")] + public string TimeBase { get; set; } + + [JsonPropertyName("start")] + public long Start { get; set; } + + [JsonPropertyName("start_time")] + public string StartTime { get; set; } + + [JsonPropertyName("end")] + public long End { get; set; } + + [JsonPropertyName("end_time")] + public string EndTime { get; set; } + + [JsonPropertyName("tags")] + public IReadOnlyDictionary<string, string> Tags { get; set; } + } +} diff --git a/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs new file mode 100644 index 000000000..d5529e56c --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.MediaEncoding.Probing +{ + /// <summary> + /// Class MediaFormat. + /// </summary> + public class MediaFormatInfo + { + /// <summary> + /// Gets or sets the filename. + /// </summary> + /// <value>The filename.</value> + [JsonPropertyName("filename")] + public string Fileame { get; set; } + + /// <summary> + /// Gets or sets the nb_streams. + /// </summary> + /// <value>The nb_streams.</value> + [JsonPropertyName("nb_streams")] + public int NbStreams { get; set; } + + /// <summary> + /// Gets or sets the format_name. + /// </summary> + /// <value>The format_name.</value> + [JsonPropertyName("format_name")] + public string FormatName { get; set; } + + /// <summary> + /// Gets or sets the format_long_name. + /// </summary> + /// <value>The format_long_name.</value> + [JsonPropertyName("format_long_name")] + public string FormatLongName { get; set; } + + /// <summary> + /// Gets or sets the start_time. + /// </summary> + /// <value>The start_time.</value> + [JsonPropertyName("start_time")] + public string StartTime { get; set; } + + /// <summary> + /// Gets or sets the duration. + /// </summary> + /// <value>The duration.</value> + [JsonPropertyName("duration")] + public string Duration { get; set; } + + /// <summary> + /// Gets or sets the size. + /// </summary> + /// <value>The size.</value> + [JsonPropertyName("size")] + public string Size { get; set; } + + /// <summary> + /// Gets or sets the bit_rate. + /// </summary> + /// <value>The bit_rate.</value> + [JsonPropertyName("bit_rate")] + public string BitRate { get; set; } + + /// <summary> + /// Gets or sets the probe_score. + /// </summary> + /// <value>The probe_score.</value> + [JsonPropertyName("probe_score")] + public int ProbeScore { get; set; } + + /// <summary> + /// Gets or sets the tags. + /// </summary> + /// <value>The tags.</value> + [JsonPropertyName("tags")] + public IReadOnlyDictionary<string, string> Tags { get; set; } + } +} diff --git a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs new file mode 100644 index 000000000..7fa7afa5b --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs @@ -0,0 +1,282 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using MediaBrowser.Common.Json.Converters; + +namespace MediaBrowser.MediaEncoding.Probing +{ + /// <summary> + /// Represents a stream within the output. + /// </summary> + public class MediaStreamInfo + { + /// <summary> + /// Gets or sets the index. + /// </summary> + /// <value>The index.</value> + [JsonPropertyName("index")] + public int Index { get; set; } + + /// <summary> + /// Gets or sets the profile. + /// </summary> + /// <value>The profile.</value> + [JsonPropertyName("profile")] + public string Profile { get; set; } + + /// <summary> + /// Gets or sets the codec_name. + /// </summary> + /// <value>The codec_name.</value> + [JsonPropertyName("codec_name")] + public string CodecName { get; set; } + + /// <summary> + /// Gets or sets the codec_long_name. + /// </summary> + /// <value>The codec_long_name.</value> + [JsonPropertyName("codec_long_name")] + public string CodecLongName { get; set; } + + /// <summary> + /// Gets or sets the codec_type. + /// </summary> + /// <value>The codec_type.</value> + [JsonPropertyName("codec_type")] + public string CodecType { get; set; } + + /// <summary> + /// Gets or sets the sample_rate. + /// </summary> + /// <value>The sample_rate.</value> + [JsonPropertyName("sample_rate")] + public string SampleRate { get; set; } + + /// <summary> + /// Gets or sets the channels. + /// </summary> + /// <value>The channels.</value> + [JsonPropertyName("channels")] + public int Channels { get; set; } + + /// <summary> + /// Gets or sets the channel_layout. + /// </summary> + /// <value>The channel_layout.</value> + [JsonPropertyName("channel_layout")] + public string ChannelLayout { get; set; } + + /// <summary> + /// Gets or sets the avg_frame_rate. + /// </summary> + /// <value>The avg_frame_rate.</value> + [JsonPropertyName("avg_frame_rate")] + public string AverageFrameRate { get; set; } + + /// <summary> + /// Gets or sets the duration. + /// </summary> + /// <value>The duration.</value> + [JsonPropertyName("duration")] + public string Duration { get; set; } + + /// <summary> + /// Gets or sets the bit_rate. + /// </summary> + /// <value>The bit_rate.</value> + [JsonPropertyName("bit_rate")] + public string BitRate { get; set; } + + /// <summary> + /// Gets or sets the width. + /// </summary> + /// <value>The width.</value> + [JsonPropertyName("width")] + public int Width { get; set; } + + /// <summary> + /// Gets or sets the refs. + /// </summary> + /// <value>The refs.</value> + [JsonPropertyName("refs")] + public int Refs { get; set; } + + /// <summary> + /// Gets or sets the height. + /// </summary> + /// <value>The height.</value> + [JsonPropertyName("height")] + public int Height { get; set; } + + /// <summary> + /// Gets or sets the display_aspect_ratio. + /// </summary> + /// <value>The display_aspect_ratio.</value> + [JsonPropertyName("display_aspect_ratio")] + public string DisplayAspectRatio { get; set; } + + /// <summary> + /// Gets or sets the tags. + /// </summary> + /// <value>The tags.</value> + [JsonPropertyName("tags")] + public IReadOnlyDictionary<string, string> Tags { get; set; } + + /// <summary> + /// Gets or sets the bits_per_sample. + /// </summary> + /// <value>The bits_per_sample.</value> + [JsonPropertyName("bits_per_sample")] + public int BitsPerSample { get; set; } + + /// <summary> + /// Gets or sets the bits_per_raw_sample. + /// </summary> + /// <value>The bits_per_raw_sample.</value> + [JsonPropertyName("bits_per_raw_sample")] + [JsonConverter(typeof(JsonInt32Converter))] + public int BitsPerRawSample { get; set; } + + /// <summary> + /// Gets or sets the r_frame_rate. + /// </summary> + /// <value>The r_frame_rate.</value> + [JsonPropertyName("r_frame_rate")] + public string RFrameRate { get; set; } + + /// <summary> + /// Gets or sets the has_b_frames. + /// </summary> + /// <value>The has_b_frames.</value> + [JsonPropertyName("has_b_frames")] + public int HasBFrames { get; set; } + + /// <summary> + /// Gets or sets the sample_aspect_ratio. + /// </summary> + /// <value>The sample_aspect_ratio.</value> + [JsonPropertyName("sample_aspect_ratio")] + public string SampleAspectRatio { get; set; } + + /// <summary> + /// Gets or sets the pix_fmt. + /// </summary> + /// <value>The pix_fmt.</value> + [JsonPropertyName("pix_fmt")] + public string PixelFormat { get; set; } + + /// <summary> + /// Gets or sets the level. + /// </summary> + /// <value>The level.</value> + [JsonPropertyName("level")] + public int Level { get; set; } + + /// <summary> + /// Gets or sets the time_base. + /// </summary> + /// <value>The time_base.</value> + [JsonPropertyName("time_base")] + public string TimeBase { get; set; } + + /// <summary> + /// Gets or sets the start_time. + /// </summary> + /// <value>The start_time.</value> + [JsonPropertyName("start_time")] + public string StartTime { get; set; } + + /// <summary> + /// Gets or sets the codec_time_base. + /// </summary> + /// <value>The codec_time_base.</value> + [JsonPropertyName("codec_time_base")] + public string CodecTimeBase { get; set; } + + /// <summary> + /// Gets or sets the codec_tag. + /// </summary> + /// <value>The codec_tag.</value> + [JsonPropertyName("codec_tag")] + public string CodecTag { get; set; } + + /// <summary> + /// Gets or sets the codec_tag_string. + /// </summary> + /// <value>The codec_tag_string.</value> + [JsonPropertyName("codec_tag_string")] + public string CodecTagString { get; set; } + + /// <summary> + /// Gets or sets the sample_fmt. + /// </summary> + /// <value>The sample_fmt.</value> + [JsonPropertyName("sample_fmt")] + public string SampleFmt { get; set; } + + /// <summary> + /// Gets or sets the dmix_mode. + /// </summary> + /// <value>The dmix_mode.</value> + [JsonPropertyName("dmix_mode")] + public string DmixMode { get; set; } + + /// <summary> + /// Gets or sets the start_pts. + /// </summary> + /// <value>The start_pts.</value> + [JsonPropertyName("start_pts")] + public int StartPts { get; set; } + + /// <summary> + /// Gets or sets the is_avc. + /// </summary> + /// <value>The is_avc.</value> + [JsonPropertyName("is_avc")] + public string IsAvc { get; set; } + + /// <summary> + /// Gets or sets the nal_length_size. + /// </summary> + /// <value>The nal_length_size.</value> + [JsonPropertyName("nal_length_size")] + public string NalLengthSize { get; set; } + + /// <summary> + /// Gets or sets the ltrt_cmixlev. + /// </summary> + /// <value>The ltrt_cmixlev.</value> + [JsonPropertyName("ltrt_cmixlev")] + public string LtrtCmixlev { get; set; } + + /// <summary> + /// Gets or sets the ltrt_surmixlev. + /// </summary> + /// <value>The ltrt_surmixlev.</value> + [JsonPropertyName("ltrt_surmixlev")] + public string LtrtSurmixlev { get; set; } + + /// <summary> + /// Gets or sets the loro_cmixlev. + /// </summary> + /// <value>The loro_cmixlev.</value> + [JsonPropertyName("loro_cmixlev")] + public string LoroCmixlev { get; set; } + + /// <summary> + /// Gets or sets the loro_surmixlev. + /// </summary> + /// <value>The loro_surmixlev.</value> + [JsonPropertyName("loro_surmixlev")] + public string LoroSurmixlev { get; set; } + + [JsonPropertyName("field_order")] + public string FieldOrder { get; set; } + + /// <summary> + /// Gets or sets the disposition. + /// </summary> + /// <value>The disposition.</value> + [JsonPropertyName("disposition")] + public IReadOnlyDictionary<string, int> Disposition { get; set; } + } +} diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 54d02fc9f..99f0df60f 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -8,7 +8,6 @@ using System.Xml; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; @@ -41,21 +40,21 @@ namespace MediaBrowser.MediaEncoding.Probing FFProbeHelpers.NormalizeFFProbeResult(data); SetSize(data, info); - var internalStreams = data.streams ?? new MediaStreamInfo[] { }; + var internalStreams = data.Streams ?? new MediaStreamInfo[] { }; - info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.format)) + info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.Format)) .Where(i => i != null) // Drop subtitle streams if we don't know the codec because it will just cause failures if we don't know how to handle them .Where(i => i.Type != MediaStreamType.Subtitle || !string.IsNullOrWhiteSpace(i.Codec)) .ToList(); - if (data.format != null) + if (data.Format != null) { - info.Container = NormalizeFormat(data.format.format_name); + info.Container = NormalizeFormat(data.Format.FormatName); - if (!string.IsNullOrEmpty(data.format.bit_rate)) + if (!string.IsNullOrEmpty(data.Format.BitRate)) { - if (int.TryParse(data.format.bit_rate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(data.Format.BitRate, NumberStyles.Any, _usCulture, out var value)) { info.Bitrate = value; } @@ -65,22 +64,22 @@ namespace MediaBrowser.MediaEncoding.Probing var tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); var tagStreamType = isAudio ? "audio" : "video"; - if (data.streams != null) + if (data.Streams != null) { - var tagStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, tagStreamType, StringComparison.OrdinalIgnoreCase)); + var tagStream = data.Streams.FirstOrDefault(i => string.Equals(i.CodecType, tagStreamType, StringComparison.OrdinalIgnoreCase)); - if (tagStream != null && tagStream.tags != null) + if (tagStream != null && tagStream.Tags != null) { - foreach (var pair in tagStream.tags) + foreach (var pair in tagStream.Tags) { tags[pair.Key] = pair.Value; } } } - if (data.format != null && data.format.tags != null) + if (data.Format != null && data.Format.Tags != null) { - foreach (var pair in data.format.tags) + foreach (var pair in data.Format.Tags) { tags[pair.Key] = pair.Value; } @@ -153,9 +152,9 @@ namespace MediaBrowser.MediaEncoding.Probing FetchFromItunesInfo(itunesXml, info); } - if (data.format != null && !string.IsNullOrEmpty(data.format.duration)) + if (data.Format != null && !string.IsNullOrEmpty(data.Format.Duration)) { - info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks; + info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.Format.Duration, _usCulture)).Ticks; } FetchWtvInfo(info, data); @@ -523,7 +522,7 @@ namespace MediaBrowser.MediaEncoding.Probing private MediaStream GetMediaStream(bool isAudio, MediaStreamInfo streamInfo, MediaFormatInfo formatInfo) { // These are mp4 chapters - if (string.Equals(streamInfo.codec_name, "mov_text", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(streamInfo.CodecName, "mov_text", StringComparison.OrdinalIgnoreCase)) { // Edit: but these are also sometimes subtitles? //return null; @@ -531,71 +530,71 @@ namespace MediaBrowser.MediaEncoding.Probing var stream = new MediaStream { - Codec = streamInfo.codec_name, - Profile = streamInfo.profile, - Level = streamInfo.level, - Index = streamInfo.index, - PixelFormat = streamInfo.pix_fmt, - NalLengthSize = streamInfo.nal_length_size, - TimeBase = streamInfo.time_base, - CodecTimeBase = streamInfo.codec_time_base + Codec = streamInfo.CodecName, + Profile = streamInfo.Profile, + Level = streamInfo.Level, + Index = streamInfo.Index, + PixelFormat = streamInfo.PixelFormat, + NalLengthSize = streamInfo.NalLengthSize, + TimeBase = streamInfo.TimeBase, + CodecTimeBase = streamInfo.CodecTimeBase }; - if (string.Equals(streamInfo.is_avc, "true", StringComparison.OrdinalIgnoreCase) || - string.Equals(streamInfo.is_avc, "1", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(streamInfo.IsAvc, "true", StringComparison.OrdinalIgnoreCase) || + string.Equals(streamInfo.IsAvc, "1", StringComparison.OrdinalIgnoreCase)) { stream.IsAVC = true; } - else if (string.Equals(streamInfo.is_avc, "false", StringComparison.OrdinalIgnoreCase) || - string.Equals(streamInfo.is_avc, "0", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(streamInfo.IsAvc, "false", StringComparison.OrdinalIgnoreCase) || + string.Equals(streamInfo.IsAvc, "0", StringComparison.OrdinalIgnoreCase)) { stream.IsAVC = false; } - if (!string.IsNullOrWhiteSpace(streamInfo.field_order) && !string.Equals(streamInfo.field_order, "progressive", StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrWhiteSpace(streamInfo.FieldOrder) && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase)) { stream.IsInterlaced = true; } // Filter out junk - if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1) + if (!string.IsNullOrWhiteSpace(streamInfo.CodecTagString) && streamInfo.CodecTagString.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1) { - stream.CodecTag = streamInfo.codec_tag_string; + stream.CodecTag = streamInfo.CodecTagString; } - if (streamInfo.tags != null) + if (streamInfo.Tags != null) { - stream.Language = GetDictionaryValue(streamInfo.tags, "language"); - stream.Comment = GetDictionaryValue(streamInfo.tags, "comment"); - stream.Title = GetDictionaryValue(streamInfo.tags, "title"); + stream.Language = GetDictionaryValue(streamInfo.Tags, "language"); + stream.Comment = GetDictionaryValue(streamInfo.Tags, "comment"); + stream.Title = GetDictionaryValue(streamInfo.Tags, "title"); } - if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(streamInfo.CodecType, "audio", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Audio; - stream.Channels = streamInfo.channels; + stream.Channels = streamInfo.Channels; - if (!string.IsNullOrEmpty(streamInfo.sample_rate)) + if (!string.IsNullOrEmpty(streamInfo.SampleRate)) { - if (int.TryParse(streamInfo.sample_rate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(streamInfo.SampleRate, NumberStyles.Any, _usCulture, out var value)) { stream.SampleRate = value; } } - stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout); + stream.ChannelLayout = ParseChannelLayout(streamInfo.ChannelLayout); - if (streamInfo.bits_per_sample > 0) + if (streamInfo.BitsPerSample > 0) { - stream.BitDepth = streamInfo.bits_per_sample; + stream.BitDepth = streamInfo.BitsPerSample; } - else if (streamInfo.bits_per_raw_sample > 0) + else if (streamInfo.BitsPerRawSample > 0) { - stream.BitDepth = streamInfo.bits_per_raw_sample; + stream.BitDepth = streamInfo.BitsPerRawSample; } } - else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(streamInfo.CodecType, "subtitle", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Subtitle; stream.Codec = NormalizeSubtitleCodec(stream.Codec); @@ -603,14 +602,14 @@ namespace MediaBrowser.MediaEncoding.Probing stream.localizedDefault = _localization.GetLocalizedString("Default"); stream.localizedForced = _localization.GetLocalizedString("Forced"); } - else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(streamInfo.CodecType, "video", StringComparison.OrdinalIgnoreCase)) { stream.Type = isAudio || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase) ? MediaStreamType.EmbeddedImage : MediaStreamType.Video; - stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate); - stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate); + stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate); + stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate); if (isAudio || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase)) @@ -635,17 +634,17 @@ namespace MediaBrowser.MediaEncoding.Probing stream.Type = MediaStreamType.Video; } - stream.Width = streamInfo.width; - stream.Height = streamInfo.height; + stream.Width = streamInfo.Width; + stream.Height = streamInfo.Height; stream.AspectRatio = GetAspectRatio(streamInfo); - if (streamInfo.bits_per_sample > 0) + if (streamInfo.BitsPerSample > 0) { - stream.BitDepth = streamInfo.bits_per_sample; + stream.BitDepth = streamInfo.BitsPerSample; } - else if (streamInfo.bits_per_raw_sample > 0) + else if (streamInfo.BitsPerRawSample > 0) { - stream.BitDepth = streamInfo.bits_per_raw_sample; + stream.BitDepth = streamInfo.BitsPerRawSample; } //stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase) || @@ -653,11 +652,11 @@ namespace MediaBrowser.MediaEncoding.Probing // string.Equals(stream.AspectRatio, "2.40:1", StringComparison.OrdinalIgnoreCase); // http://stackoverflow.com/questions/17353387/how-to-detect-anamorphic-video-with-ffprobe - stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase); + stream.IsAnamorphic = string.Equals(streamInfo.SampleAspectRatio, "0:1", StringComparison.OrdinalIgnoreCase); - if (streamInfo.refs > 0) + if (streamInfo.Refs > 0) { - stream.RefFrames = streamInfo.refs; + stream.RefFrames = streamInfo.Refs; } } else @@ -668,18 +667,18 @@ namespace MediaBrowser.MediaEncoding.Probing // Get stream bitrate var bitrate = 0; - if (!string.IsNullOrEmpty(streamInfo.bit_rate)) + if (!string.IsNullOrEmpty(streamInfo.BitRate)) { - if (int.TryParse(streamInfo.bit_rate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(streamInfo.BitRate, NumberStyles.Any, _usCulture, out var value)) { bitrate = value; } } - if (bitrate == 0 && formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video) + if (bitrate == 0 && formatInfo != null && !string.IsNullOrEmpty(formatInfo.BitRate) && stream.Type == MediaStreamType.Video) { // If the stream info doesn't have a bitrate get the value from the media format info - if (int.TryParse(formatInfo.bit_rate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(formatInfo.BitRate, NumberStyles.Any, _usCulture, out var value)) { bitrate = value; } @@ -690,14 +689,18 @@ namespace MediaBrowser.MediaEncoding.Probing stream.BitRate = bitrate; } - if (streamInfo.disposition != null) + var disposition = streamInfo.Disposition; + if (disposition != null) { - var isDefault = GetDictionaryValue(streamInfo.disposition, "default"); - var isForced = GetDictionaryValue(streamInfo.disposition, "forced"); - - stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase); + if (disposition.GetValueOrDefault("default") == 1) + { + stream.IsDefault = true; + } - stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase); + if (disposition.GetValueOrDefault("forced") == 1) + { + stream.IsForced = true; + } } NormalizeStreamTitle(stream); @@ -724,7 +727,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// <param name="tags">The tags.</param> /// <param name="key">The key.</param> /// <returns>System.String.</returns> - private string GetDictionaryValue(Dictionary<string, string> tags, string key) + private string GetDictionaryValue(IReadOnlyDictionary<string, string> tags, string key) { if (tags == null) { @@ -747,7 +750,7 @@ namespace MediaBrowser.MediaEncoding.Probing private string GetAspectRatio(MediaStreamInfo info) { - var original = info.display_aspect_ratio; + var original = info.DisplayAspectRatio; var parts = (original ?? string.Empty).Split(':'); if (!(parts.Length == 2 && @@ -756,8 +759,8 @@ namespace MediaBrowser.MediaEncoding.Probing width > 0 && height > 0)) { - width = info.width; - height = info.height; + width = info.Width; + height = info.Height; } if (width > 0 && height > 0) @@ -850,20 +853,20 @@ namespace MediaBrowser.MediaEncoding.Probing private void SetAudioRuntimeTicks(InternalMediaInfoResult result, MediaInfo data) { - if (result.streams != null) + if (result.Streams != null) { // Get the first info stream - var stream = result.streams.FirstOrDefault(s => string.Equals(s.codec_type, "audio", StringComparison.OrdinalIgnoreCase)); + var stream = result.Streams.FirstOrDefault(s => string.Equals(s.CodecType, "audio", StringComparison.OrdinalIgnoreCase)); if (stream != null) { // Get duration from stream properties - var duration = stream.duration; + var duration = stream.Duration; // If it's not there go into format properties if (string.IsNullOrEmpty(duration)) { - duration = result.format.duration; + duration = result.Format.Duration; } // If we got something, parse it @@ -877,11 +880,11 @@ namespace MediaBrowser.MediaEncoding.Probing private void SetSize(InternalMediaInfoResult data, MediaInfo info) { - if (data.format != null) + if (data.Format != null) { - if (!string.IsNullOrEmpty(data.format.size)) + if (!string.IsNullOrEmpty(data.Format.Size)) { - info.Size = long.Parse(data.format.size, _usCulture); + info.Size = long.Parse(data.Format.Size, _usCulture); } else { @@ -1194,16 +1197,16 @@ namespace MediaBrowser.MediaEncoding.Probing { var info = new ChapterInfo(); - if (chapter.tags != null) + if (chapter.Tags != null) { - if (chapter.tags.TryGetValue("title", out string name)) + if (chapter.Tags.TryGetValue("title", out string name)) { info.Name = name; } } // Limit accuracy to milliseconds to match xml saving - var secondsString = chapter.start_time; + var secondsString = chapter.StartTime; if (double.TryParse(secondsString, NumberStyles.Any, CultureInfo.InvariantCulture, out var seconds)) { @@ -1218,12 +1221,12 @@ namespace MediaBrowser.MediaEncoding.Probing private void FetchWtvInfo(MediaInfo video, InternalMediaInfoResult data) { - if (data.format == null || data.format.tags == null) + if (data.Format == null || data.Format.Tags == null) { return; } - var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre"); + var genres = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/Genre"); if (!string.IsNullOrWhiteSpace(genres)) { @@ -1239,14 +1242,14 @@ namespace MediaBrowser.MediaEncoding.Probing } } - var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating"); + var officialRating = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/ParentalRating"); if (!string.IsNullOrWhiteSpace(officialRating)) { video.OfficialRating = officialRating; } - var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits"); + var people = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/MediaCredits"); if (!string.IsNullOrEmpty(people)) { @@ -1256,7 +1259,7 @@ namespace MediaBrowser.MediaEncoding.Probing .ToArray(); } - var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime"); + var year = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/OriginalReleaseTime"); if (!string.IsNullOrWhiteSpace(year)) { if (int.TryParse(year, NumberStyles.Integer, _usCulture, out var val)) @@ -1265,7 +1268,7 @@ namespace MediaBrowser.MediaEncoding.Probing } } - var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime"); + var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/MediaOriginalBroadcastDateTime"); if (!string.IsNullOrWhiteSpace(premiereDateString)) { // Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/ @@ -1276,9 +1279,9 @@ namespace MediaBrowser.MediaEncoding.Probing } } - var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription"); + var description = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/SubTitleDescription"); - var subTitle = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitle"); + var subTitle = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/SubTitle"); // For below code, credit to MCEBuddy: https://mcebuddy2x.codeplex.com/ |
