improve support for compressed xmltv

This commit is contained in:
Luke Pulverenti 2017-09-25 01:06:15 -04:00
parent 768f20b1bb
commit 978eedbcb7
17 changed files with 324 additions and 123 deletions

View File

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

View File

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

View File

@ -4,6 +4,7 @@ using SharpCompress.Archives.Rar;
using SharpCompress.Archives.SevenZip; using SharpCompress.Archives.SevenZip;
using SharpCompress.Archives.Tar; using SharpCompress.Archives.Tar;
using SharpCompress.Readers; using SharpCompress.Readers;
using SharpCompress.Readers.GZip;
using SharpCompress.Readers.Zip; using SharpCompress.Readers.Zip;
namespace Emby.Server.Implementations.Archiving 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> /// <summary>
/// Extracts all from7z. /// Extracts all from7z.
/// </summary> /// </summary>

View File

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

View File

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

View File

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

View File

@ -691,22 +691,26 @@ namespace MediaBrowser.Controller.MediaEncoding
param += string.Format(" -r {0}", framerate.Value.ToString(_usCulture)); 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) && if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
{ {
// not supported by h264_omx // 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 // 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 // also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307
@ -756,7 +760,6 @@ namespace MediaBrowser.Controller.MediaEncoding
{ {
param += " -level " + level; param += " -level " + level;
} }
} }
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)) if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
@ -834,18 +837,21 @@ namespace MediaBrowser.Controller.MediaEncoding
return false; return false;
} }
var requestedProfiles = state.GetRequestedProfiles(videoStream.Codec);
// If client is requesting a specific video profile, it must match the source // 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)) if (string.IsNullOrEmpty(videoStream.Profile))
{ {
//return false; //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 currentScore = GetVideoProfileScore(videoStream.Profile);
var requestedScore = GetVideoProfileScore(request.Profile); var requestedScore = GetVideoProfileScore(requestedProfile);
if (currentScore == -1 || currentScore > requestedScore) 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 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; 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) if (!videoStream.Level.HasValue)
{ {

View File

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

View File

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

View File

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

View File

@ -283,7 +283,7 @@ namespace MediaBrowser.Model.Dlna
var conditions = new List<ProfileCondition>(); var conditions = new List<ProfileCondition>();
foreach (CodecProfile i in options.Profile.CodecProfiles) 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; bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions) foreach (ProfileCondition applyCondition in i.ApplyConditions)
@ -375,7 +375,7 @@ namespace MediaBrowser.Model.Dlna
var audioCodecProfiles = new List<CodecProfile>(); var audioCodecProfiles = new List<CodecProfile>();
foreach (CodecProfile i in options.Profile.CodecProfiles) 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); audioCodecProfiles.Add(i);
} }
@ -772,7 +772,7 @@ namespace MediaBrowser.Model.Dlna
var isFirstAppliedCodecProfile = true; var isFirstAppliedCodecProfile = true;
foreach (CodecProfile i in options.Profile.CodecProfiles) 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; bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions) foreach (ProfileCondition applyCondition in i.ApplyConditions)
@ -797,7 +797,7 @@ namespace MediaBrowser.Model.Dlna
var transcodingVideoCodecs = ContainerProfile.SplitValue(transcodingProfile.VideoCodec); var transcodingVideoCodecs = ContainerProfile.SplitValue(transcodingProfile.VideoCodec);
foreach (var transcodingVideoCodec in transcodingVideoCodecs) foreach (var transcodingVideoCodec in transcodingVideoCodecs)
{ {
if (i.ContainsCodec(transcodingVideoCodec, transcodingProfile.Container)) if (i.ContainsAnyCodec(transcodingVideoCodec, transcodingProfile.Container))
{ {
ApplyTranscodingConditions(playlistItem, i.Conditions, transcodingVideoCodec, !isFirstAppliedCodecProfile); ApplyTranscodingConditions(playlistItem, i.Conditions, transcodingVideoCodec, !isFirstAppliedCodecProfile);
isFirstAppliedCodecProfile = false; isFirstAppliedCodecProfile = false;
@ -810,7 +810,7 @@ namespace MediaBrowser.Model.Dlna
var audioTranscodingConditions = new List<ProfileCondition>(); var audioTranscodingConditions = new List<ProfileCondition>();
foreach (CodecProfile i in options.Profile.CodecProfiles) 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; bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions) foreach (ProfileCondition applyCondition in i.ApplyConditions)
@ -899,8 +899,10 @@ namespace MediaBrowser.Model.Dlna
return 192000; 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); int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
// Reduce the bitrate if we're downmixing // Reduce the bitrate if we're downmixing
@ -1064,7 +1066,7 @@ namespace MediaBrowser.Model.Dlna
conditions = new List<ProfileCondition>(); conditions = new List<ProfileCondition>();
foreach (CodecProfile i in profile.CodecProfiles) 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; bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions) foreach (ProfileCondition applyCondition in i.ApplyConditions)
@ -1120,7 +1122,7 @@ namespace MediaBrowser.Model.Dlna
foreach (CodecProfile i in profile.CodecProfiles) 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; bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions) 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 // 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) ?? return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, false) ??
GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, true) ?? GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, true) ??
new SubtitleProfile new SubtitleProfile
{ {
Method = SubtitleDeliveryMethod.Encode, Method = SubtitleDeliveryMethod.Encode,
Format = subtitleStream.Codec Format = subtitleStream.Codec
}; };
} }
private static bool IsSubtitleEmbedSupported(MediaStream subtitleStream, SubtitleProfile subtitleProfile, string transcodingSubProtocol, string transcodingContainer) private static bool IsSubtitleEmbedSupported(MediaStream subtitleStream, SubtitleProfile subtitleProfile, string transcodingSubProtocol, string transcodingContainer)
@ -1555,7 +1557,7 @@ namespace MediaBrowser.Model.Dlna
} }
case ProfileConditionValue.RefFrames: case ProfileConditionValue.RefFrames:
{ {
if (qualifiedOnly) if (string.IsNullOrWhiteSpace(qualifier))
{ {
continue; continue;
} }
@ -1565,15 +1567,15 @@ namespace MediaBrowser.Model.Dlna
{ {
if (condition.Condition == ProfileConditionType.Equals) if (condition.Condition == ProfileConditionType.Equals)
{ {
item.MaxRefFrames = num; item.SetOption(qualifier, "maxrefframes", StringHelper.ToStringCultureInvariant(num));
} }
else if (condition.Condition == ProfileConditionType.LessThanEqual) 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) 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; break;
@ -1605,12 +1607,16 @@ namespace MediaBrowser.Model.Dlna
} }
case ProfileConditionValue.VideoProfile: case ProfileConditionValue.VideoProfile:
{ {
if (qualifiedOnly) if (string.IsNullOrWhiteSpace(qualifier))
{ {
continue; 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; break;
} }
case ProfileConditionValue.Height: case ProfileConditionValue.Height:
@ -1690,7 +1696,7 @@ namespace MediaBrowser.Model.Dlna
} }
case ProfileConditionValue.VideoLevel: case ProfileConditionValue.VideoLevel:
{ {
if (qualifiedOnly) if (string.IsNullOrWhiteSpace(qualifier))
{ {
continue; continue;
} }
@ -1700,15 +1706,15 @@ namespace MediaBrowser.Model.Dlna
{ {
if (condition.Condition == ProfileConditionType.Equals) if (condition.Condition == ProfileConditionType.Equals)
{ {
item.VideoLevel = num; item.SetOption(qualifier, "level", StringHelper.ToStringCultureInvariant(num));
} }
else if (condition.Condition == ProfileConditionType.LessThanEqual) 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) 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; break;

View File

@ -64,8 +64,6 @@ namespace MediaBrowser.Model.Dlna
public long StartPositionTicks { get; set; } public long StartPositionTicks { get; set; }
public string VideoProfile { get; set; }
public int? SegmentLength { get; set; } public int? SegmentLength { get; set; }
public int? MinSegments { get; set; } public int? MinSegments { get; set; }
public bool BreakOnNonKeyFrames { get; set; } public bool BreakOnNonKeyFrames { get; set; }
@ -88,13 +86,10 @@ namespace MediaBrowser.Model.Dlna
public int? VideoBitrate { get; set; } public int? VideoBitrate { get; set; }
public int? VideoLevel { get; set; }
public int? MaxWidth { get; set; } public int? MaxWidth { get; set; }
public int? MaxHeight { get; set; } public int? MaxHeight { get; set; }
public int? MaxVideoBitDepth { get; set; } public int? MaxVideoBitDepth { get; set; }
public int? MaxRefFrames { get; set; }
public float? MaxFramerate { 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("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("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 // no longer used
list.Add(new NameValuePair("Cabac", string.Empty)); list.Add(new NameValuePair("Cabac", string.Empty));
@ -559,8 +577,19 @@ namespace MediaBrowser.Model.Dlna
{ {
get get
{ {
MediaStream stream = TargetVideoStream; if (IsDirectStream)
return stream == null || !IsDirectStream ? null : stream.RefFrames; {
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,13 +614,56 @@ namespace MediaBrowser.Model.Dlna
{ {
get get
{ {
MediaStream stream = TargetVideoStream; if (IsDirectStream)
return VideoLevel.HasValue && !IsDirectStream {
? VideoLevel return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
: stream == null ? null : stream.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> /// <summary>
/// Predicts the audio sample rate that will be in the output stream /// Predicts the audio sample rate that will be in the output stream
/// </summary> /// </summary>
@ -613,10 +685,19 @@ namespace MediaBrowser.Model.Dlna
{ {
get get
{ {
MediaStream stream = TargetVideoStream; if (IsDirectStream)
return !string.IsNullOrEmpty(VideoProfile) && !IsDirectStream {
? VideoProfile return TargetVideoStream == null ? null : TargetVideoStream.Profile;
: stream == null ? null : stream.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> /// <summary>
/// Predicts the audio codec that will be in the output stream /// Predicts the audio codec that will be in the output stream
/// </summary> /// </summary>
public string TargetAudioCodec public string[] TargetAudioCodec
{ {
get get
{ {
@ -686,22 +767,22 @@ namespace MediaBrowser.Model.Dlna
if (IsDirectStream) if (IsDirectStream)
{ {
return inputCodec; return string.IsNullOrWhiteSpace(inputCodec) ? new string[] { } : new[] { inputCodec };
} }
foreach (string codec in AudioCodecs) foreach (string codec in AudioCodecs)
{ {
if (StringHelper.EqualsIgnoreCase(codec, inputCodec)) 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 get
{ {
@ -711,18 +792,18 @@ namespace MediaBrowser.Model.Dlna
if (IsDirectStream) if (IsDirectStream)
{ {
return inputCodec; return string.IsNullOrWhiteSpace(inputCodec) ? new string[] { } : new[] { inputCodec };
} }
foreach (string codec in VideoCodecs) foreach (string codec in VideoCodecs)
{ {
if (StringHelper.EqualsIgnoreCase(codec, inputCodec)) 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; 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.IsNullOrWhiteSpace(videoCodec))
{ {
if (string.Equals(GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase)) if (string.Equals(GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))

View File

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

View File

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

View File

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

View File

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

View File

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