Răsfoiți Sursa

improve support for compressed xmltv

Luke Pulverenti 7 ani în urmă
părinte
comite
978eedbcb7

+ 6 - 6
Emby.Dlna/Didl/DidlBuilder.cs

@@ -209,8 +209,8 @@ namespace Emby.Dlna.Didl
             var targetHeight = streamInfo.TargetHeight;
 
             var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader(streamInfo.Container,
-                streamInfo.TargetVideoCodec,
-                streamInfo.TargetAudioCodec,
+                streamInfo.TargetVideoCodec.FirstOrDefault(),
+                streamInfo.TargetAudioCodec.FirstOrDefault(),
                 targetWidth,
                 targetHeight,
                 streamInfo.TargetVideoBitDepth,
@@ -353,8 +353,8 @@ namespace Emby.Dlna.Didl
             }
 
             var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
-                streamInfo.TargetAudioCodec,
-                streamInfo.TargetVideoCodec,
+                streamInfo.TargetAudioCodec.FirstOrDefault(),
+                streamInfo.TargetVideoCodec.FirstOrDefault(),
                 streamInfo.TargetAudioBitrate,
                 targetWidth,
                 targetHeight,
@@ -554,7 +554,7 @@ namespace Emby.Dlna.Didl
             }
 
             var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
-                streamInfo.TargetAudioCodec,
+                streamInfo.TargetAudioCodec.FirstOrDefault(),
                 targetChannels,
                 targetAudioBitrate,
                 targetSampleRate,
@@ -567,7 +567,7 @@ namespace Emby.Dlna.Didl
                 : mediaProfile.MimeType;
 
             var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(streamInfo.Container,
-                streamInfo.TargetAudioCodec,
+                streamInfo.TargetAudioCodec.FirstOrDefault(),
                 targetAudioBitrate,
                 targetSampleRate,
                 targetChannels,

+ 4 - 3
Emby.Dlna/PlayTo/PlayToController.cs

@@ -13,6 +13,7 @@ using MediaBrowser.Model.System;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Configuration;
@@ -515,7 +516,7 @@ namespace Emby.Dlna.PlayTo
             {
                 return new ContentFeatureBuilder(profile)
                     .BuildAudioHeader(streamInfo.Container,
-                    streamInfo.TargetAudioCodec,
+                    streamInfo.TargetAudioCodec.FirstOrDefault(),
                     streamInfo.TargetAudioBitrate,
                     streamInfo.TargetAudioSampleRate,
                     streamInfo.TargetAudioChannels,
@@ -529,8 +530,8 @@ namespace Emby.Dlna.PlayTo
             {
                 var list = new ContentFeatureBuilder(profile)
                     .BuildVideoHeader(streamInfo.Container,
-                    streamInfo.TargetVideoCodec,
-                    streamInfo.TargetAudioCodec,
+                    streamInfo.TargetVideoCodec.FirstOrDefault(),
+                    streamInfo.TargetAudioCodec.FirstOrDefault(),
                     streamInfo.TargetWidth,
                     streamInfo.TargetHeight,
                     streamInfo.TargetVideoBitDepth,

+ 17 - 0
Emby.Server.Implementations/Archiving/ZipClient.cs

@@ -4,6 +4,7 @@ using SharpCompress.Archives.Rar;
 using SharpCompress.Archives.SevenZip;
 using SharpCompress.Archives.Tar;
 using SharpCompress.Readers;
+using SharpCompress.Readers.GZip;
 using SharpCompress.Readers.Zip;
 
 namespace Emby.Server.Implementations.Archiving
@@ -72,6 +73,22 @@ namespace Emby.Server.Implementations.Archiving
             }
         }
 
+        public void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles)
+        {
+            using (var reader = GZipReader.Open(source))
+            {
+                var options = new ExtractionOptions();
+                options.ExtractFullPath = true;
+
+                if (overwriteExistingFiles)
+                {
+                    options.Overwrite = true;
+                }
+
+                reader.WriteAllToDirectory(targetPath, options);
+            }
+        }
+
         /// <summary>
         /// Extracts all from7z.
         /// </summary>

+ 2 - 2
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -667,8 +667,8 @@
       <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
       <Private>True</Private>
     </Reference>
-    <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
+    <Reference Include="SharpCompress, Version=0.18.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
+      <HintPath>..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll</HintPath>
     </Reference>
     <Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>

+ 22 - 20
Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs

@@ -65,14 +65,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 
             if (!path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
             {
-                return path;
+                return UnzipIfNeeded(path, path);
             }
 
             var cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + ".xml";
             var cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename);
             if (_fileSystem.FileExists(cacheFile))
             {
-                return UnzipIfNeeded(path, cacheFile);
+                //return UnzipIfNeeded(path, cacheFile);
+                return cacheFile;
             }
 
             _logger.Info("Downloading xmltv listings from {0}", path);
@@ -112,28 +113,29 @@ namespace Emby.Server.Implementations.LiveTv.Listings
             }
 
             _logger.Debug("Returning xmltv path {0}", cacheFile);
-            return UnzipIfNeeded(path, cacheFile);
+            return cacheFile;
+            //return UnzipIfNeeded(path, cacheFile);
         }
 
         private string UnzipIfNeeded(string originalUrl, string file)
         {
-            //var ext = Path.GetExtension(originalUrl);
-
-            //if (string.Equals(ext, ".gz", StringComparison.OrdinalIgnoreCase))
-            //{
-            //    using (var stream = _fileSystem.OpenRead(file))
-            //    {
-            //        var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
-            //        _fileSystem.CreateDirectory(tempFolder);
-
-            //        _zipClient.ExtractAllFromZip(stream, tempFolder, true);
-
-            //        return _fileSystem.GetFiles(tempFolder, true)
-            //            .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
-            //            .Select(i => i.FullName)
-            //            .FirstOrDefault();
-            //    }
-            //}
+            var ext = Path.GetExtension(originalUrl.Split('?')[0]);
+
+            if (string.Equals(ext, ".gz", StringComparison.OrdinalIgnoreCase))
+            {
+                using (var stream = _fileSystem.OpenRead(file))
+                {
+                    var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
+                    _fileSystem.CreateDirectory(tempFolder);
+
+                    _zipClient.ExtractAllFromGz(stream, tempFolder, true);
+
+                    return _fileSystem.GetFiles(tempFolder, true)
+                        .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
+                        .Select(i => i.FullName)
+                        .FirstOrDefault();
+                }
+            }
 
             return file;
         }

+ 1 - 1
Emby.Server.Implementations/packages.config

@@ -2,7 +2,7 @@
 <packages>
   <package id="Emby.XmlTv" version="1.0.10" targetFramework="net46" />
   <package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
-  <package id="SharpCompress" version="0.14.0" targetFramework="net46" />
+  <package id="SharpCompress" version="0.18.2" targetFramework="net46" />
   <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
   <package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
   <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net46" />

+ 18 - 11
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

@@ -691,22 +691,26 @@ namespace MediaBrowser.Controller.MediaEncoding
                 param += string.Format(" -r {0}", framerate.Value.ToString(_usCulture));
             }
 
-            var request = state.BaseRequest;
+            var targetVideoCodec = state.ActualOutputVideoCodec;
 
-            if (!string.IsNullOrEmpty(request.Profile))
+            var request = state.BaseRequest;
+            var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault();
+            if (!string.IsNullOrEmpty(profile))
             {
                 if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
                     !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) &&
                     !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
                 {
                     // not supported by h264_omx
-                    param += " -profile:v " + request.Profile;
+                    param += " -profile:v " + profile;
                 }
             }
 
-            if (!string.IsNullOrEmpty(request.Level))
+            var level = state.GetRequestedLevel(targetVideoCodec);
+
+            if (!string.IsNullOrEmpty(level))
             {
-                var level = NormalizeTranscodingLevel(state.OutputVideoCodec, request.Level);
+                level = NormalizeTranscodingLevel(state.OutputVideoCodec, level);
 
                 // h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
                 // also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307                
@@ -756,7 +760,6 @@ namespace MediaBrowser.Controller.MediaEncoding
                 {
                     param += " -level " + level;
                 }
-
             }
 
             if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
@@ -834,18 +837,21 @@ namespace MediaBrowser.Controller.MediaEncoding
                 return false;
             }
 
+            var requestedProfiles = state.GetRequestedProfiles(videoStream.Codec);
+
             // If client is requesting a specific video profile, it must match the source
-            if (!string.IsNullOrEmpty(request.Profile))
+            if (requestedProfiles.Length > 0)
             {
                 if (string.IsNullOrEmpty(videoStream.Profile))
                 {
                     //return false;
                 }
 
-                if (!string.IsNullOrEmpty(videoStream.Profile) && !string.Equals(request.Profile, videoStream.Profile, StringComparison.OrdinalIgnoreCase))
+                var requestedProfile = requestedProfiles[0];
+                if (!string.IsNullOrEmpty(videoStream.Profile) && !string.Equals(requestedProfile, videoStream.Profile, StringComparison.OrdinalIgnoreCase))
                 {
                     var currentScore = GetVideoProfileScore(videoStream.Profile);
-                    var requestedScore = GetVideoProfileScore(request.Profile);
+                    var requestedScore = GetVideoProfileScore(requestedProfile);
 
                     if (currentScore == -1 || currentScore > requestedScore)
                     {
@@ -910,11 +916,12 @@ namespace MediaBrowser.Controller.MediaEncoding
             }
 
             // If a specific level was requested, the source must match or be less than
-            if (!string.IsNullOrEmpty(request.Level))
+            var level = state.GetRequestedLevel(videoStream.Codec);
+            if (!string.IsNullOrEmpty(level))
             {
                 double requestLevel;
 
-                if (double.TryParse(request.Level, NumberStyles.Any, _usCulture, out requestLevel))
+                if (double.TryParse(level, NumberStyles.Any, _usCulture, out requestLevel))
                 {
                     if (!videoStream.Level.HasValue)
                     {

+ 86 - 12
MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs

@@ -180,6 +180,61 @@ namespace MediaBrowser.Controller.MediaEncoding
             return false;
         }
 
+        public string[] GetRequestedProfiles(string codec)
+        {
+            if (!string.IsNullOrWhiteSpace(BaseRequest.Profile))
+            {
+                return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
+            }
+
+            if (!string.IsNullOrWhiteSpace(codec))
+            {
+                var profile = BaseRequest.GetOption(codec, "profile");
+
+                if (!string.IsNullOrWhiteSpace(profile))
+                {
+                    return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
+                }
+            }
+
+            return new string[] { };
+        }
+
+        public string GetRequestedLevel(string codec)
+        {
+            if (!string.IsNullOrWhiteSpace(BaseRequest.Level))
+            {
+                return BaseRequest.Level;
+            }
+
+            if (!string.IsNullOrWhiteSpace(codec))
+            {
+                return BaseRequest.GetOption(codec, "level");
+            }
+
+            return null;
+        }
+
+        public int? GetRequestedMaxRefFrames(string codec)
+        {
+            if (!string.IsNullOrWhiteSpace(BaseRequest.Level))
+            {
+                return BaseRequest.MaxRefFrames;
+            }
+
+            if (!string.IsNullOrWhiteSpace(codec))
+            {
+                var value = BaseRequest.GetOption(codec, "maxrefframes");
+                int result;
+                if (!string.IsNullOrWhiteSpace(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+                {
+                    return result;
+                }
+            }
+
+            return null;
+        }
+
         public bool IsVideoRequest { get; set; }
         public TranscodingJobType TranscodingType { get; set; }
 
@@ -188,7 +243,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             _logger = logger;
             TranscodingType = jobType;
             RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-            PlayableStreamFileNames = new string[]{};
+            PlayableStreamFileNames = new string[] { };
             SupportedAudioCodecs = new List<string>();
             SupportedVideoCodecs = new List<string>();
             SupportedSubtitleCodecs = new List<string>();
@@ -338,12 +393,19 @@ namespace MediaBrowser.Controller.MediaEncoding
         {
             get
             {
-                var stream = VideoStream;
-                var request = BaseRequest;
+                if (BaseRequest.Static)
+                {
+                    return VideoStream == null ? null : VideoStream.Level;
+                }
+
+                var level = GetRequestedLevel(ActualOutputVideoCodec);
+                double result;
+                if (!string.IsNullOrWhiteSpace(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+                {
+                    return result;
+                }
 
-                return !string.IsNullOrEmpty(request.Level) && !request.Static
-                    ? double.Parse(request.Level, CultureInfo.InvariantCulture)
-                    : stream == null ? null : stream.Level;
+                return null;
             }
         }
 
@@ -367,8 +429,12 @@ namespace MediaBrowser.Controller.MediaEncoding
         {
             get
             {
-                var stream = VideoStream;
-                return stream == null || !BaseRequest.Static ? null : stream.RefFrames;
+                if (BaseRequest.Static)
+                {
+                    return VideoStream == null ? null : VideoStream.RefFrames;
+                }
+
+                return null;
             }
         }
 
@@ -423,10 +489,18 @@ namespace MediaBrowser.Controller.MediaEncoding
         {
             get
             {
-                var stream = VideoStream;
-                return !string.IsNullOrEmpty(BaseRequest.Profile) && !BaseRequest.Static
-                    ? BaseRequest.Profile
-                    : stream == null ? null : stream.Profile;
+                if (BaseRequest.Static)
+                {
+                    return VideoStream == null ? null : VideoStream.Profile;
+                }
+
+                var requestedProfile = GetRequestedProfiles(ActualOutputVideoCodec).FirstOrDefault();
+                if (!string.IsNullOrWhiteSpace(requestedProfile))
+                {
+                    return requestedProfile;
+                }
+
+                return null;
             }
         }
 

+ 5 - 10
MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Services;
 
@@ -39,18 +40,16 @@ namespace MediaBrowser.Controller.MediaEncoding
             MaxWidth = info.MaxWidth;
             MaxHeight = info.MaxHeight;
             MaxFramerate = info.MaxFramerate;
-            Profile = info.VideoProfile;
             ItemId = info.ItemId;
             MediaSourceId = info.MediaSourceId;
-            AudioCodec = info.TargetAudioCodec;
+            AudioCodec = info.TargetAudioCodec.FirstOrDefault();
             MaxAudioChannels = info.MaxAudioChannels;
             AudioBitRate = info.AudioBitrate;
             AudioSampleRate = info.TargetAudioSampleRate;
             DeviceProfile = deviceProfile;
-            VideoCodec = info.TargetVideoCodec;
+            VideoCodec = info.TargetVideoCodec.FirstOrDefault();
             VideoBitRate = info.VideoBitrate;
             AudioStreamIndex = info.AudioStreamIndex;
-            MaxRefFrames = info.MaxRefFrames;
             MaxVideoBitDepth = info.MaxVideoBitDepth;
             SubtitleMethod = info.SubtitleDeliveryMethod;
             Context = info.Context;
@@ -60,11 +59,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
                 SubtitleStreamIndex = info.SubtitleStreamIndex;
             }
-
-            if (info.VideoLevel.HasValue)
-            {
-                Level = info.VideoLevel.Value.ToString(_usCulture);
-            }
+            StreamOptions = info.StreamOptions;
         }
     }
 
@@ -231,7 +226,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             SetOption(qualifier + "-" + name, value);
         }
 
-        public Dictionary<string, string> StreamOptions { get; private set; }
+        public Dictionary<string, string> StreamOptions { get; set; }
 
         public void SetOption(string name, string value)
         {

+ 19 - 2
MediaBrowser.Model/Dlna/CodecProfile.cs

@@ -36,7 +36,12 @@ namespace MediaBrowser.Model.Dlna
             return ContainerProfile.ContainsContainer(Container, container);
         }
 
-        public bool ContainsCodec(string codec, string container)
+        public bool ContainsAnyCodec(string codec, string container)
+        {
+            return ContainsAnyCodec(ContainerProfile.SplitValue(codec), container);
+        }
+
+        public bool ContainsAnyCodec(string[] codec, string container)
         {
             if (!ContainsContainer(container))
             {
@@ -44,8 +49,20 @@ namespace MediaBrowser.Model.Dlna
             }
 
             var codecs = GetCodecs();
+            if (codecs.Length == 0)
+            {
+                return true;
+            }
+
+            foreach (var val in codec)
+            {
+                if (ListHelper.ContainsIgnoreCase(codecs, val))
+                {
+                    return true;
+                }
+            }
 
-            return codecs.Length == 0 || ListHelper.ContainsIgnoreCase(codecs, ContainerProfile.SplitValue(codec)[0]);
+            return false;
         }
     }
 }

+ 30 - 24
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -283,7 +283,7 @@ namespace MediaBrowser.Model.Dlna
                     var conditions = new List<ProfileCondition>();
                     foreach (CodecProfile i in options.Profile.CodecProfiles)
                     {
-                        if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container))
+                        if (i.Type == CodecType.Audio && i.ContainsAnyCodec(audioCodec, item.Container))
                         {
                             bool applyConditions = true;
                             foreach (ProfileCondition applyCondition in i.ApplyConditions)
@@ -375,7 +375,7 @@ namespace MediaBrowser.Model.Dlna
                 var audioCodecProfiles = new List<CodecProfile>();
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
-                    if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
+                    if (i.Type == CodecType.Audio && i.ContainsAnyCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
                     {
                         audioCodecProfiles.Add(i);
                     }
@@ -772,7 +772,7 @@ namespace MediaBrowser.Model.Dlna
                 var isFirstAppliedCodecProfile = true;
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
-                    if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
+                    if (i.Type == CodecType.Video && i.ContainsAnyCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
                     {
                         bool applyConditions = true;
                         foreach (ProfileCondition applyCondition in i.ApplyConditions)
@@ -797,7 +797,7 @@ namespace MediaBrowser.Model.Dlna
                             var transcodingVideoCodecs = ContainerProfile.SplitValue(transcodingProfile.VideoCodec);
                             foreach (var transcodingVideoCodec in transcodingVideoCodecs)
                             {
-                                if (i.ContainsCodec(transcodingVideoCodec, transcodingProfile.Container))
+                                if (i.ContainsAnyCodec(transcodingVideoCodec, transcodingProfile.Container))
                                 {
                                     ApplyTranscodingConditions(playlistItem, i.Conditions, transcodingVideoCodec, !isFirstAppliedCodecProfile);
                                     isFirstAppliedCodecProfile = false;
@@ -810,7 +810,7 @@ namespace MediaBrowser.Model.Dlna
                 var audioTranscodingConditions = new List<ProfileCondition>();
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
-                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(playlistItem.TargetAudioCodec, transcodingProfile.Container))
+                    if (i.Type == CodecType.VideoAudio && i.ContainsAnyCodec(playlistItem.TargetAudioCodec, transcodingProfile.Container))
                     {
                         bool applyConditions = true;
                         foreach (ProfileCondition applyCondition in i.ApplyConditions)
@@ -899,8 +899,10 @@ namespace MediaBrowser.Model.Dlna
             return 192000;
         }
 
-        private int GetAudioBitrate(string subProtocol, long? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream)
+        private int GetAudioBitrate(string subProtocol, long? maxTotalBitrate, int? targetAudioChannels, string[] targetAudioCodecs, MediaStream audioStream)
         {
+            var targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
+
             int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
 
             // Reduce the bitrate if we're downmixing
@@ -1064,7 +1066,7 @@ namespace MediaBrowser.Model.Dlna
             conditions = new List<ProfileCondition>();
             foreach (CodecProfile i in profile.CodecProfiles)
             {
-                if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec, container))
+                if (i.Type == CodecType.Video && i.ContainsAnyCodec(videoCodec, container))
                 {
                     bool applyConditions = true;
                     foreach (ProfileCondition applyCondition in i.ApplyConditions)
@@ -1120,7 +1122,7 @@ namespace MediaBrowser.Model.Dlna
 
                 foreach (CodecProfile i in profile.CodecProfiles)
                 {
-                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec, container))
+                    if (i.Type == CodecType.VideoAudio && i.ContainsAnyCodec(audioCodec, container))
                     {
                         bool applyConditions = true;
                         foreach (ProfileCondition applyCondition in i.ApplyConditions)
@@ -1260,13 +1262,13 @@ namespace MediaBrowser.Model.Dlna
             }
 
             // Look for an external or hls profile that matches the stream type (text/graphical) and doesn't require conversion
-            return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, false) ?? 
-                GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, true) ?? 
+            return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, false) ??
+                GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, true) ??
                 new SubtitleProfile
-            {
-                Method = SubtitleDeliveryMethod.Encode,
-                Format = subtitleStream.Codec
-            };
+                {
+                    Method = SubtitleDeliveryMethod.Encode,
+                    Format = subtitleStream.Codec
+                };
         }
 
         private static bool IsSubtitleEmbedSupported(MediaStream subtitleStream, SubtitleProfile subtitleProfile, string transcodingSubProtocol, string transcodingContainer)
@@ -1555,7 +1557,7 @@ namespace MediaBrowser.Model.Dlna
                         }
                     case ProfileConditionValue.RefFrames:
                         {
-                            if (qualifiedOnly)
+                            if (string.IsNullOrWhiteSpace(qualifier))
                             {
                                 continue;
                             }
@@ -1565,15 +1567,15 @@ namespace MediaBrowser.Model.Dlna
                             {
                                 if (condition.Condition == ProfileConditionType.Equals)
                                 {
-                                    item.MaxRefFrames = num;
+                                    item.SetOption(qualifier, "maxrefframes", StringHelper.ToStringCultureInvariant(num));
                                 }
                                 else if (condition.Condition == ProfileConditionType.LessThanEqual)
                                 {
-                                    item.MaxRefFrames = Math.Min(num, item.MaxRefFrames ?? num);
+                                    item.SetOption(qualifier, "maxrefframes", StringHelper.ToStringCultureInvariant(Math.Min(num, item.GetTargetRefFrames(qualifier) ?? num)));
                                 }
                                 else if (condition.Condition == ProfileConditionType.GreaterThanEqual)
                                 {
-                                    item.MaxRefFrames = Math.Max(num, item.MaxRefFrames ?? num);
+                                    item.SetOption(qualifier, "maxrefframes", StringHelper.ToStringCultureInvariant(Math.Max(num, item.GetTargetRefFrames(qualifier) ?? num)));
                                 }
                             }
                             break;
@@ -1605,12 +1607,16 @@ namespace MediaBrowser.Model.Dlna
                         }
                     case ProfileConditionValue.VideoProfile:
                         {
-                            if (qualifiedOnly)
+                            if (string.IsNullOrWhiteSpace(qualifier))
                             {
                                 continue;
                             }
 
-                            item.VideoProfile = (value ?? string.Empty).Split('|')[0];
+                            if (!string.IsNullOrWhiteSpace(value))
+                            {
+                                // change from split by | to comma
+                                item.SetOption(qualifier, "profile", string.Join(",", value.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)));
+                            }
                             break;
                         }
                     case ProfileConditionValue.Height:
@@ -1690,7 +1696,7 @@ namespace MediaBrowser.Model.Dlna
                         }
                     case ProfileConditionValue.VideoLevel:
                         {
-                            if (qualifiedOnly)
+                            if (string.IsNullOrWhiteSpace(qualifier))
                             {
                                 continue;
                             }
@@ -1700,15 +1706,15 @@ namespace MediaBrowser.Model.Dlna
                             {
                                 if (condition.Condition == ProfileConditionType.Equals)
                                 {
-                                    item.VideoLevel = num;
+                                    item.SetOption(qualifier, "level", StringHelper.ToStringCultureInvariant(num));
                                 }
                                 else if (condition.Condition == ProfileConditionType.LessThanEqual)
                                 {
-                                    item.VideoLevel = Math.Min(num, item.VideoLevel ?? num);
+                                    item.SetOption(qualifier, "level", StringHelper.ToStringCultureInvariant(Math.Min(num, item.GetTargetVideoLevel(qualifier) ?? num)));
                                 }
                                 else if (condition.Condition == ProfileConditionType.GreaterThanEqual)
                                 {
-                                    item.VideoLevel = Math.Max(num, item.VideoLevel ?? num);
+                                    item.SetOption(qualifier, "level", StringHelper.ToStringCultureInvariant(Math.Max(num, item.GetTargetVideoLevel(qualifier) ?? num)));
                                 }
                             }
                             break;

+ 109 - 27
MediaBrowser.Model/Dlna/StreamInfo.cs

@@ -64,8 +64,6 @@ namespace MediaBrowser.Model.Dlna
 
         public long StartPositionTicks { get; set; }
 
-        public string VideoProfile { get; set; }
-
         public int? SegmentLength { get; set; }
         public int? MinSegments { get; set; }
         public bool BreakOnNonKeyFrames { get; set; }
@@ -88,13 +86,10 @@ namespace MediaBrowser.Model.Dlna
 
         public int? VideoBitrate { get; set; }
 
-        public int? VideoLevel { get; set; }
-
         public int? MaxWidth { get; set; }
         public int? MaxHeight { get; set; }
 
         public int? MaxVideoBitDepth { get; set; }
-        public int? MaxRefFrames { get; set; }
 
         public float? MaxFramerate { get; set; }
 
@@ -274,11 +269,34 @@ namespace MediaBrowser.Model.Dlna
                 list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(startPositionTicks)));
             }
 
-            list.Add(new NameValuePair("Level", item.VideoLevel.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoLevel.Value) : string.Empty));
+            if (isDlna)
+            {
+                // hack alert
+                // dlna needs to be update to support the qualified params
+                var level = item.GetTargetVideoLevel("h264");
+
+                list.Add(new NameValuePair("Level", level.HasValue ? StringHelper.ToStringCultureInvariant(level.Value) : string.Empty));
+            }
+
+            if (isDlna)
+            {
+                // hack alert
+                // dlna needs to be update to support the qualified params
+                var refframes = item.GetTargetRefFrames("h264");
+
+                list.Add(new NameValuePair("MaxRefFrames", refframes.HasValue ? StringHelper.ToStringCultureInvariant(refframes.Value) : string.Empty));
+            }
 
-            list.Add(new NameValuePair("MaxRefFrames", item.MaxRefFrames.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxRefFrames.Value) : string.Empty));
             list.Add(new NameValuePair("MaxVideoBitDepth", item.MaxVideoBitDepth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxVideoBitDepth.Value) : string.Empty));
-            list.Add(new NameValuePair("Profile", item.VideoProfile ?? string.Empty));
+
+            if (isDlna)
+            {
+                // hack alert
+                // dlna needs to be update to support the qualified params
+                var profile = item.GetOption("h264", "profile");
+
+                list.Add(new NameValuePair("Profile", profile ?? string.Empty));
+            }
 
             // no longer used
             list.Add(new NameValuePair("Cabac", string.Empty));
@@ -559,8 +577,19 @@ namespace MediaBrowser.Model.Dlna
         {
             get
             {
-                MediaStream stream = TargetVideoStream;
-                return stream == null || !IsDirectStream ? null : stream.RefFrames;
+                if (IsDirectStream)
+                {
+                    return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
+                }
+
+                var targetVideoCodecs = TargetVideoCodec;
+                var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+                if (!string.IsNullOrWhiteSpace(videoCodec))
+                {
+                    return GetTargetRefFrames(videoCodec);
+                }
+
+                return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
             }
         }
 
@@ -585,11 +614,54 @@ namespace MediaBrowser.Model.Dlna
         {
             get
             {
-                MediaStream stream = TargetVideoStream;
-                return VideoLevel.HasValue && !IsDirectStream
-                    ? VideoLevel
-                    : stream == null ? null : stream.Level;
+                if (IsDirectStream)
+                {
+                    return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
+                }
+
+                var targetVideoCodecs = TargetVideoCodec;
+                var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+                if (!string.IsNullOrWhiteSpace(videoCodec))
+                {
+                    return GetTargetVideoLevel(videoCodec);
+                }
+
+                return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
+            }
+        }
+
+        public double? GetTargetVideoLevel(string codec)
+        {
+            var value = GetOption(codec, "level");
+            if (string.IsNullOrWhiteSpace(value))
+            {
+                return null;
             }
+
+            double result;
+            if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+            {
+                return result;
+            }
+
+            return null;
+        }
+
+        public int? GetTargetRefFrames(string codec)
+        {
+            var value = GetOption(codec, "maxrefframes");
+            if (string.IsNullOrWhiteSpace(value))
+            {
+                return null;
+            }
+
+            int result;
+            if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+            {
+                return result;
+            }
+
+            return null;
         }
 
         /// <summary>
@@ -613,10 +685,19 @@ namespace MediaBrowser.Model.Dlna
         {
             get
             {
-                MediaStream stream = TargetVideoStream;
-                return !string.IsNullOrEmpty(VideoProfile) && !IsDirectStream
-                    ? VideoProfile
-                    : stream == null ? null : stream.Profile;
+                if (IsDirectStream)
+                {
+                    return TargetVideoStream == null ? null : TargetVideoStream.Profile;
+                }
+
+                var targetVideoCodecs = TargetVideoCodec;
+                var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+                if (!string.IsNullOrWhiteSpace(videoCodec))
+                {
+                    return GetOption(videoCodec, "profile");
+                }
+
+                return TargetVideoStream == null ? null : TargetVideoStream.Profile;
             }
         }
 
@@ -676,7 +757,7 @@ namespace MediaBrowser.Model.Dlna
         /// <summary>
         /// Predicts the audio codec that will be in the output stream
         /// </summary>
-        public string TargetAudioCodec
+        public string[] TargetAudioCodec
         {
             get
             {
@@ -686,22 +767,22 @@ namespace MediaBrowser.Model.Dlna
 
                 if (IsDirectStream)
                 {
-                    return inputCodec;
+                    return string.IsNullOrWhiteSpace(inputCodec) ? new string[] { } : new[] { inputCodec };
                 }
 
                 foreach (string codec in AudioCodecs)
                 {
                     if (StringHelper.EqualsIgnoreCase(codec, inputCodec))
                     {
-                        return codec;
+                        return string.IsNullOrWhiteSpace(codec) ? new string[] { } : new[] { codec };
                     }
                 }
 
-                return AudioCodecs.Length == 0 ? null : AudioCodecs[0];
+                return AudioCodecs;
             }
         }
 
-        public string TargetVideoCodec
+        public string[] TargetVideoCodec
         {
             get
             {
@@ -711,18 +792,18 @@ namespace MediaBrowser.Model.Dlna
 
                 if (IsDirectStream)
                 {
-                    return inputCodec;
+                    return string.IsNullOrWhiteSpace(inputCodec) ? new string[] { } : new[] { inputCodec };
                 }
 
                 foreach (string codec in VideoCodecs)
                 {
                     if (StringHelper.EqualsIgnoreCase(codec, inputCodec))
                     {
-                        return codec;
+                        return string.IsNullOrWhiteSpace(codec) ? new string[] { } : new[] { codec };
                     }
                 }
 
-                return VideoCodecs.Length == 0 ? null : VideoCodecs[0];
+                return VideoCodecs;
             }
         }
 
@@ -813,7 +894,8 @@ namespace MediaBrowser.Model.Dlna
                     return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
                 }
 
-                var videoCodec = TargetVideoCodec;
+                var targetVideoCodecs = TargetVideoCodec;
+                var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
                 if (!string.IsNullOrWhiteSpace(videoCodec))
                 {
                     if (string.Equals(GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))

+ 2 - 0
MediaBrowser.Model/IO/IZipClient.cs

@@ -23,6 +23,8 @@ namespace MediaBrowser.Model.IO
         /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
         void ExtractAll(Stream source, string targetPath, bool overwriteExistingFiles);
 
+        void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles);
+
         /// <summary>
         /// Extracts all from zip.
         /// </summary>

+ 2 - 3
MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj

@@ -55,9 +55,8 @@
       <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
       <Private>True</Private>
     </Reference>
-    <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
-      <Private>True</Private>
+    <Reference Include="SharpCompress, Version=0.18.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
+      <HintPath>..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll</HintPath>
     </Reference>
     <Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>

+ 1 - 1
MediaBrowser.Server.Mono/packages.config

@@ -2,7 +2,7 @@
 <packages>
   <package id="Mono.Posix" version="4.0.0.0" targetFramework="net45" />
   <package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
-  <package id="SharpCompress" version="0.14.0" targetFramework="net46" />
+  <package id="SharpCompress" version="0.18.2" targetFramework="net46" />
   <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
   <package id="SkiaSharp" version="1.58.1" targetFramework="net46" />
   <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net46" />

+ 2 - 3
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -77,9 +77,8 @@
       <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
       <Private>True</Private>
     </Reference>
-    <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
-      <Private>True</Private>
+    <Reference Include="SharpCompress, Version=0.18.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
+      <HintPath>..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll</HintPath>
     </Reference>
     <Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>

+ 1 - 1
MediaBrowser.ServerApplication/packages.config

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
-  <package id="SharpCompress" version="0.14.0" targetFramework="net462" />
+  <package id="SharpCompress" version="0.18.2" targetFramework="net462" />
   <package id="SimpleInjector" version="4.0.8" targetFramework="net462" />
   <package id="SkiaSharp" version="1.58.1" targetFramework="net462" />
   <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net462" />