瀏覽代碼

Merge pull request #2185 from Bond-009/scanerrors

Fix exceptions while scanning
dkanada 5 年之前
父節點
當前提交
162c1ac7b7

+ 1 - 1
MediaBrowser.Common/Json/Converters/GuidConverter.cs → MediaBrowser.Common/Json/Converters/JsonGuidConverter.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Common.Json.Converters
     /// <summary>
     /// Converts a GUID object or value to/from JSON.
     /// </summary>
-    public class GuidConverter : JsonConverter<Guid>
+    public class JsonGuidConverter : JsonConverter<Guid>
     {
         /// <inheritdoc />
         public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

+ 53 - 0
MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Buffers;
+using System.Buffers.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace MediaBrowser.Common.Json.Converters
+{
+    /// <summary>
+    /// Converts a GUID object or value to/from JSON.
+    /// </summary>
+    public class JsonInt32Converter : JsonConverter<int>
+    {
+        /// <inheritdoc />
+        public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        {
+            static void ThrowFormatException() => throw new FormatException("Invalid format for an integer.");
+            ReadOnlySpan<byte> span = stackalloc byte[0];
+
+            if (reader.HasValueSequence)
+            {
+                long sequenceLength = reader.ValueSequence.Length;
+                Span<byte> stackSpan = stackalloc byte[(int)sequenceLength];
+                reader.ValueSequence.CopyTo(stackSpan);
+                span = stackSpan;
+            }
+            else
+            {
+                span = reader.ValueSpan;
+            }
+
+            if (!Utf8Parser.TryParse(span, out int number, out _))
+            {
+                ThrowFormatException();
+            }
+
+            return number;
+        }
+
+        /// <inheritdoc />
+        public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
+        {
+            static void ThrowInvalidOperationException() => throw new InvalidOperationException();
+            Span<byte> span = stackalloc byte[16];
+            if (Utf8Formatter.TryFormat(value, span, out int bytesWritten))
+            {
+                writer.WriteStringValue(span.Slice(0, bytesWritten));
+            }
+
+            ThrowInvalidOperationException();
+        }
+    }
+}

+ 1 - 1
MediaBrowser.Common/Json/JsonDefaults.cs

@@ -21,7 +21,7 @@ namespace MediaBrowser.Common.Json
                 WriteIndented = false
             };
 
-            options.Converters.Add(new GuidConverter());
+            options.Converters.Add(new JsonGuidConverter());
             options.Converters.Add(new JsonStringEnumConverter());
 
             return options;

+ 15 - 15
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");

+ 8 - 13
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);
         }

+ 8 - 317
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; }
     }
 }

+ 32 - 0
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; }
+    }
+}

+ 81 - 0
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 FileName { 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; }
+    }
+}

+ 282 - 0
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; }
+    }
+}

+ 101 - 98
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,9 +40,9 @@ 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))
@@ -53,13 +52,13 @@ namespace MediaBrowser.MediaEncoding.Probing
                 .Where(i => i != null)
                 .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;
                     }
@@ -69,22 +68,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;
                 }
@@ -157,9 +156,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);
@@ -524,27 +523,27 @@ namespace MediaBrowser.MediaEncoding.Probing
         /// <returns>MediaAttachments.</returns>
         private MediaAttachment GetMediaAttachment(MediaStreamInfo streamInfo)
         {
-            if (!string.Equals(streamInfo.codec_type, "attachment", StringComparison.OrdinalIgnoreCase))
+            if (!string.Equals(streamInfo.CodecType, "attachment", StringComparison.OrdinalIgnoreCase))
             {
                 return null;
             }
 
             var attachment = new MediaAttachment
             {
-                Codec = streamInfo.codec_name,
-                Index = streamInfo.index
+                Codec = streamInfo.CodecName,
+                Index = streamInfo.Index
             };
 
-            if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string))
+            if (!string.IsNullOrWhiteSpace(streamInfo.CodecTagString))
             {
-               attachment.CodecTag = streamInfo.codec_tag_string;
+               attachment.CodecTag = streamInfo.CodecTagString;
             }
 
-            if (streamInfo.tags != null)
+            if (streamInfo.Tags != null)
             {
-                attachment.FileName = GetDictionaryValue(streamInfo.tags, "filename");
-                attachment.MimeType = GetDictionaryValue(streamInfo.tags, "mimetype");
-                attachment.Comment = GetDictionaryValue(streamInfo.tags, "comment");
+                attachment.FileName = GetDictionaryValue(streamInfo.Tags, "filename");
+                attachment.MimeType = GetDictionaryValue(streamInfo.Tags, "mimetype");
+                attachment.Comment = GetDictionaryValue(streamInfo.Tags, "comment");
             }
 
             return attachment;
@@ -560,7 +559,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;
@@ -568,71 +567,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);
@@ -640,14 +639,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))
@@ -672,17 +671,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) ||
@@ -690,11 +689,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
@@ -705,18 +704,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;
                 }
@@ -727,14 +726,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);
@@ -761,7 +764,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)
             {
@@ -784,7 +787,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 &&
@@ -793,8 +796,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)
@@ -887,20 +890,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
@@ -914,11 +917,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
                 {
@@ -1231,16 +1234,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))
             {
@@ -1255,12 +1258,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))
             {
@@ -1276,14 +1279,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))
             {
@@ -1293,7 +1296,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))
@@ -1302,7 +1305,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/
@@ -1313,9 +1316,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/