mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-07-09 07:10:34 +02:00
commit
2c9e056d52
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,6 +1,3 @@
|
||||||
[submodule "ThirdParty/taglib-sharp"]
|
|
||||||
path = ThirdParty/taglib-sharp
|
|
||||||
url = https://github.com/mono/taglib-sharp.git
|
|
||||||
[submodule "MediaBrowser.WebDashboard/jellyfin-web"]
|
[submodule "MediaBrowser.WebDashboard/jellyfin-web"]
|
||||||
path = MediaBrowser.WebDashboard/jellyfin-web
|
path = MediaBrowser.WebDashboard/jellyfin-web
|
||||||
url = https://github.com/jellyfin/jellyfin-web.git
|
url = https://github.com/jellyfin/jellyfin-web.git
|
||||||
|
|
|
@ -3,13 +3,16 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||||
<ProjectReference Include="..\ThirdParty\taglib-sharp\src\taglib-sharp.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\SharedVersion.cs" />
|
<Compile Include="..\SharedVersion.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="TagLibSharp" Version="2.2.0-beta" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
|
|
@ -4712,9 +4712,21 @@ namespace Emby.Server.Implementations.Data
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramName = "@HasAnyProviderId" + index;
|
// TODO this seems to be an idea for a better schema where ProviderIds are their own table
|
||||||
|
// buut this is not implemented
|
||||||
//hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
|
//hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
|
||||||
|
|
||||||
|
// TODO this is a really BAD way to do it since the pair:
|
||||||
|
// Tmdb, 1234 matches Tmdb=1234 but also Tmdb=1234567
|
||||||
|
// and maybe even NotTmdb=1234.
|
||||||
|
|
||||||
|
// this is a placeholder for this specific pair to correlate it in the bigger query
|
||||||
|
var paramName = "@HasAnyProviderId" + index;
|
||||||
|
|
||||||
|
// this is a search for the placeholder
|
||||||
hasProviderIds.Add("ProviderIds like " + paramName + "");
|
hasProviderIds.Add("ProviderIds like " + paramName + "");
|
||||||
|
|
||||||
|
// this replaces the placeholder with a value, here: %key=val%
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
|
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
|
||||||
|
|
|
@ -105,26 +105,22 @@ namespace Emby.Server.Implementations.Diagnostics
|
||||||
{
|
{
|
||||||
return _process.WaitForExit(timeMs);
|
return _process.WaitForExit(timeMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<bool> WaitForExitAsync(int timeMs)
|
public Task<bool> WaitForExitAsync(int timeMs)
|
||||||
{
|
{
|
||||||
//if (_process.WaitForExit(100))
|
//Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true.
|
||||||
//{
|
|
||||||
// return Task.FromResult(true);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//timeMs -= 100;
|
|
||||||
timeMs = Math.Max(0, timeMs);
|
|
||||||
|
|
||||||
var tcs = new TaskCompletionSource<bool>();
|
|
||||||
|
|
||||||
var cancellationToken = new CancellationTokenSource(timeMs).Token;
|
|
||||||
|
|
||||||
if (HasExited)
|
if (HasExited)
|
||||||
{
|
{
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timeMs = Math.Max(0, timeMs);
|
||||||
|
|
||||||
|
var tcs = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
|
var cancellationToken = new CancellationTokenSource(timeMs).Token;
|
||||||
|
|
||||||
_process.Exited += (sender, args) => tcs.TrySetResult(true);
|
_process.Exited += (sender, args) => tcs.TrySetResult(true);
|
||||||
|
|
||||||
cancellationToken.Register(() => tcs.TrySetResult(HasExited));
|
cancellationToken.Register(() => tcs.TrySetResult(HasExited));
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||||
|
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||||
|
|
|
@ -74,8 +74,19 @@ namespace MediaBrowser.Api.Playback
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IJsonSerializer _json;
|
private readonly IJsonSerializer _json;
|
||||||
private readonly IAuthorizationContext _authContext;
|
private readonly IAuthorizationContext _authContext;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager, IMediaEncoder mediaEncoder, IUserManager userManager, IJsonSerializer json, IAuthorizationContext authContext)
|
public MediaInfoService(
|
||||||
|
IMediaSourceManager mediaSourceManager,
|
||||||
|
IDeviceManager deviceManager,
|
||||||
|
ILibraryManager libraryManager,
|
||||||
|
IServerConfigurationManager config,
|
||||||
|
INetworkManager networkManager,
|
||||||
|
IMediaEncoder mediaEncoder,
|
||||||
|
IUserManager userManager,
|
||||||
|
IJsonSerializer json,
|
||||||
|
IAuthorizationContext authContext,
|
||||||
|
ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_deviceManager = deviceManager;
|
_deviceManager = deviceManager;
|
||||||
|
@ -86,6 +97,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_json = json;
|
_json = json;
|
||||||
_authContext = authContext;
|
_authContext = authContext;
|
||||||
|
_logger = loggerFactory.CreateLogger(nameof(MediaInfoService));
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetBitrateTestBytes request)
|
public object Get(GetBitrateTestBytes request)
|
||||||
|
@ -165,7 +177,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
var profile = request.DeviceProfile;
|
var profile = request.DeviceProfile;
|
||||||
|
|
||||||
//Logger.Info("GetPostedPlaybackInfo profile: {0}", _json.SerializeToString(profile));
|
//Logger.LogInformation("GetPostedPlaybackInfo profile: {profile}", _json.SerializeToString(profile));
|
||||||
|
|
||||||
if (profile == null)
|
if (profile == null)
|
||||||
{
|
{
|
||||||
|
@ -262,7 +274,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
mediaSources = new List<MediaSourceInfo>();
|
mediaSources = new List<MediaSourceInfo>();
|
||||||
// TODO Log exception
|
_logger.LogError(ex, "Could not find media sources for item id {id}", id);
|
||||||
// TODO PlaybackException ??
|
// TODO PlaybackException ??
|
||||||
//result.ErrorCode = ex.ErrorCode;
|
//result.ErrorCode = ex.ErrorCode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using MediaBrowser.Model.Services;
|
using MediaBrowser.Model.Services;
|
||||||
using MediaBrowser.Model.System;
|
using MediaBrowser.Model.System;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
|
@ -75,7 +76,24 @@ namespace MediaBrowser.Api.Playback
|
||||||
[Authenticated]
|
[Authenticated]
|
||||||
public class UniversalAudioService : BaseApiService
|
public class UniversalAudioService : BaseApiService
|
||||||
{
|
{
|
||||||
public UniversalAudioService(IServerConfigurationManager serverConfigurationManager, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, IDeviceManager deviceManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, INetworkManager networkManager, IEnvironmentInfo environmentInfo)
|
public UniversalAudioService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
IUserManager userManager,
|
||||||
|
ILibraryManager libraryManager,
|
||||||
|
IIsoManager isoManager,
|
||||||
|
IMediaEncoder mediaEncoder,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
IDlnaManager dlnaManager,
|
||||||
|
IDeviceManager deviceManager,
|
||||||
|
ISubtitleEncoder subtitleEncoder,
|
||||||
|
IMediaSourceManager mediaSourceManager,
|
||||||
|
IZipClient zipClient,
|
||||||
|
IJsonSerializer jsonSerializer,
|
||||||
|
IAuthorizationContext authorizationContext,
|
||||||
|
IImageProcessor imageProcessor,
|
||||||
|
INetworkManager networkManager,
|
||||||
|
IEnvironmentInfo environmentInfo,
|
||||||
|
ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
ServerConfigurationManager = serverConfigurationManager;
|
ServerConfigurationManager = serverConfigurationManager;
|
||||||
UserManager = userManager;
|
UserManager = userManager;
|
||||||
|
@ -93,6 +111,8 @@ namespace MediaBrowser.Api.Playback
|
||||||
ImageProcessor = imageProcessor;
|
ImageProcessor = imageProcessor;
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
EnvironmentInfo = environmentInfo;
|
EnvironmentInfo = environmentInfo;
|
||||||
|
_loggerFactory = loggerFactory;
|
||||||
|
_logger = loggerFactory.CreateLogger(nameof(UniversalAudioService));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
|
protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
|
||||||
|
@ -111,6 +131,8 @@ namespace MediaBrowser.Api.Playback
|
||||||
protected IImageProcessor ImageProcessor { get; private set; }
|
protected IImageProcessor ImageProcessor { get; private set; }
|
||||||
protected INetworkManager NetworkManager { get; private set; }
|
protected INetworkManager NetworkManager { get; private set; }
|
||||||
protected IEnvironmentInfo EnvironmentInfo { get; private set; }
|
protected IEnvironmentInfo EnvironmentInfo { get; private set; }
|
||||||
|
private ILoggerFactory _loggerFactory;
|
||||||
|
private ILogger _logger;
|
||||||
|
|
||||||
public Task<object> Get(GetUniversalAudioStream request)
|
public Task<object> Get(GetUniversalAudioStream request)
|
||||||
{
|
{
|
||||||
|
@ -221,7 +243,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
|
AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
|
||||||
|
|
||||||
var mediaInfoService = new MediaInfoService(MediaSourceManager, DeviceManager, LibraryManager, ServerConfigurationManager, NetworkManager, MediaEncoder, UserManager, JsonSerializer, AuthorizationContext)
|
var mediaInfoService = new MediaInfoService(MediaSourceManager, DeviceManager, LibraryManager, ServerConfigurationManager, NetworkManager, MediaEncoder, UserManager, JsonSerializer, AuthorizationContext, _loggerFactory)
|
||||||
{
|
{
|
||||||
Request = Request
|
Request = Request
|
||||||
};
|
};
|
||||||
|
|
|
@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The tracks.</value>
|
/// <value>The tracks.</value>
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public IEnumerable<BaseItem> Tracks => GetRecursiveChildren(i => i is Audio);
|
public IEnumerable<Audio> Tracks => GetRecursiveChildren(i => i is Audio).Cast<Audio>();
|
||||||
|
|
||||||
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||||
{
|
{
|
||||||
|
|
|
@ -357,7 +357,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
var list = new List<Tuple<StringBuilder, bool>>();
|
var list = new List<Tuple<StringBuilder, bool>>();
|
||||||
|
|
||||||
int thisMarker = 0, thisNumericChunk = 0;
|
int thisMarker = 0;
|
||||||
|
|
||||||
while (thisMarker < s1.Length)
|
while (thisMarker < s1.Length)
|
||||||
{
|
{
|
||||||
|
|
|
@ -644,12 +644,9 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return PostFilterAndSort(items, query, true);
|
return PostFilterAndSort(items, query, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(this is UserRootFolder) && !(this is AggregateFolder))
|
if (!(this is UserRootFolder) && !(this is AggregateFolder) && query.ParentId == Guid.Empty)
|
||||||
{
|
{
|
||||||
if (!query.ParentId.Equals(Guid.Empty))
|
query.Parent = this;
|
||||||
{
|
|
||||||
query.Parent = this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RequiresPostFiltering2(query))
|
if (RequiresPostFiltering2(query))
|
||||||
|
|
|
@ -437,7 +437,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
FileName = _mediaEncoder.EncoderPath,
|
FileName = _mediaEncoder.EncoderPath,
|
||||||
Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
|
Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
|
||||||
|
EnableRaisingEvents = true,
|
||||||
IsHidden = true,
|
IsHidden = true,
|
||||||
ErrorDialog = false
|
ErrorDialog = false
|
||||||
});
|
});
|
||||||
|
@ -574,7 +574,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
{
|
{
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
|
EnableRaisingEvents = true,
|
||||||
FileName = _mediaEncoder.EncoderPath,
|
FileName = _mediaEncoder.EncoderPath,
|
||||||
Arguments = processArgs,
|
Arguments = processArgs,
|
||||||
IsHidden = true,
|
IsHidden = true,
|
||||||
|
|
|
@ -66,21 +66,21 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return MaxBitrate;
|
return MaxBitrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Profile != null)
|
if (Profile == null)
|
||||||
{
|
{
|
||||||
if (Context == EncodingContext.Static)
|
return null;
|
||||||
{
|
|
||||||
if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
|
|
||||||
{
|
|
||||||
return Profile.MaxStaticMusicBitrate;
|
|
||||||
}
|
|
||||||
return Profile.MaxStaticBitrate;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Profile.MaxStreamingBitrate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
if (Context == EncodingContext.Static)
|
||||||
|
{
|
||||||
|
if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
|
||||||
|
{
|
||||||
|
return Profile.MaxStaticMusicBitrate;
|
||||||
|
}
|
||||||
|
return Profile.MaxStaticBitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Profile.MaxStreamingBitrate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,10 @@ using MediaBrowser.Model.MediaInfo;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
public class ConditionProcessor
|
public static class ConditionProcessor
|
||||||
{
|
{
|
||||||
public bool IsVideoConditionSatisfied(ProfileCondition condition,
|
public static bool IsVideoConditionSatisfied(
|
||||||
|
ProfileCondition condition,
|
||||||
int? width,
|
int? width,
|
||||||
int? height,
|
int? height,
|
||||||
int? videoBitDepth,
|
int? videoBitDepth,
|
||||||
|
@ -64,7 +65,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
|
public static bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
|
||||||
{
|
{
|
||||||
switch (condition.Property)
|
switch (condition.Property)
|
||||||
{
|
{
|
||||||
|
@ -77,7 +78,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
|
public static bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
|
||||||
{
|
{
|
||||||
switch (condition.Property)
|
switch (condition.Property)
|
||||||
{
|
{
|
||||||
|
@ -94,7 +95,8 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsVideoAudioConditionSatisfied(ProfileCondition condition,
|
public static bool IsVideoAudioConditionSatisfied(
|
||||||
|
ProfileCondition condition,
|
||||||
int? audioChannels,
|
int? audioChannels,
|
||||||
int? audioBitrate,
|
int? audioBitrate,
|
||||||
int? audioSampleRate,
|
int? audioSampleRate,
|
||||||
|
@ -121,7 +123,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsConditionSatisfied(ProfileCondition condition, int? currentValue)
|
private static bool IsConditionSatisfied(ProfileCondition condition, int? currentValue)
|
||||||
{
|
{
|
||||||
if (!currentValue.HasValue)
|
if (!currentValue.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -150,7 +152,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsConditionSatisfied(ProfileCondition condition, string currentValue)
|
private static bool IsConditionSatisfied(ProfileCondition condition, string currentValue)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(currentValue))
|
if (string.IsNullOrEmpty(currentValue))
|
||||||
{
|
{
|
||||||
|
@ -175,7 +177,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
|
private static bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
|
||||||
{
|
{
|
||||||
if (!currentValue.HasValue)
|
if (!currentValue.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -199,7 +201,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsConditionSatisfied(ProfileCondition condition, float currentValue)
|
private static bool IsConditionSatisfied(ProfileCondition condition, float currentValue)
|
||||||
{
|
{
|
||||||
if (currentValue <= 0)
|
if (currentValue <= 0)
|
||||||
{
|
{
|
||||||
|
@ -227,7 +229,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsConditionSatisfied(ProfileCondition condition, double? currentValue)
|
private static bool IsConditionSatisfied(ProfileCondition condition, double? currentValue)
|
||||||
{
|
{
|
||||||
if (!currentValue.HasValue)
|
if (!currentValue.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -255,7 +257,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsConditionSatisfied(ProfileCondition condition, TransportStreamTimestamp? timestamp)
|
private static bool IsConditionSatisfied(ProfileCondition condition, TransportStreamTimestamp? timestamp)
|
||||||
{
|
{
|
||||||
if (!timestamp.HasValue)
|
if (!timestamp.HasValue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -188,12 +188,10 @@ namespace MediaBrowser.Model.Dlna
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var conditionProcessor = new ConditionProcessor();
|
|
||||||
|
|
||||||
var anyOff = false;
|
var anyOff = false;
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth))
|
if (!ConditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth))
|
||||||
{
|
{
|
||||||
anyOff = true;
|
anyOff = true;
|
||||||
break;
|
break;
|
||||||
|
@ -235,12 +233,10 @@ namespace MediaBrowser.Model.Dlna
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var conditionProcessor = new ConditionProcessor();
|
|
||||||
|
|
||||||
var anyOff = false;
|
var anyOff = false;
|
||||||
foreach (var c in i.Conditions)
|
foreach (var c in i.Conditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsImageConditionSatisfied(GetModelProfileCondition(c), width, height))
|
if (!ConditionProcessor.IsImageConditionSatisfied(GetModelProfileCondition(c), width, height))
|
||||||
{
|
{
|
||||||
anyOff = true;
|
anyOff = true;
|
||||||
break;
|
break;
|
||||||
|
@ -301,12 +297,10 @@ namespace MediaBrowser.Model.Dlna
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var conditionProcessor = new ConditionProcessor();
|
|
||||||
|
|
||||||
var anyOff = false;
|
var anyOff = false;
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
if (!ConditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
||||||
{
|
{
|
||||||
anyOff = true;
|
anyOff = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -93,19 +93,10 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return GetOptimalStream(streams, options.GetMaxBitrate(false) ?? 0);
|
return GetOptimalStream(streams, options.GetMaxBitrate(false) ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
|
private static StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
|
||||||
{
|
=> SortMediaSources(streams, maxBitrate).FirstOrDefault();
|
||||||
var sorted = SortMediaSources(streams, maxBitrate);
|
|
||||||
|
|
||||||
foreach (StreamInfo stream in sorted)
|
private static IOrderedEnumerable<StreamInfo> SortMediaSources(List<StreamInfo> streams, long maxBitrate)
|
||||||
{
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private StreamInfo[] SortMediaSources(List<StreamInfo> streams, long maxBitrate)
|
|
||||||
{
|
{
|
||||||
return streams.OrderBy(i =>
|
return streams.OrderBy(i =>
|
||||||
{
|
{
|
||||||
|
@ -151,25 +142,17 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}).ThenBy(streams.IndexOf).ToArray();
|
}).ThenBy(streams.IndexOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
|
private static TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
|
||||||
{
|
{
|
||||||
switch (condition.Property)
|
switch (condition.Property)
|
||||||
{
|
{
|
||||||
case ProfileConditionValue.AudioBitrate:
|
case ProfileConditionValue.AudioBitrate:
|
||||||
if (condition.Condition == ProfileConditionType.LessThanEqual)
|
|
||||||
{
|
|
||||||
return TranscodeReason.AudioBitrateNotSupported;
|
|
||||||
}
|
|
||||||
return TranscodeReason.AudioBitrateNotSupported;
|
return TranscodeReason.AudioBitrateNotSupported;
|
||||||
|
|
||||||
case ProfileConditionValue.AudioChannels:
|
case ProfileConditionValue.AudioChannels:
|
||||||
if (condition.Condition == ProfileConditionType.LessThanEqual)
|
|
||||||
{
|
|
||||||
return TranscodeReason.AudioChannelsNotSupported;
|
|
||||||
}
|
|
||||||
return TranscodeReason.AudioChannelsNotSupported;
|
return TranscodeReason.AudioChannelsNotSupported;
|
||||||
|
|
||||||
case ProfileConditionValue.AudioProfile:
|
case ProfileConditionValue.AudioProfile:
|
||||||
|
@ -246,7 +229,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, string unused1, DeviceProfile profile, DlnaProfileType type)
|
public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, string _, DeviceProfile profile, DlnaProfileType type)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(inputContainer))
|
if (string.IsNullOrEmpty(inputContainer))
|
||||||
{
|
{
|
||||||
|
@ -266,12 +249,10 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
foreach (var directPlayProfile in profile.DirectPlayProfiles)
|
foreach (var directPlayProfile in profile.DirectPlayProfiles)
|
||||||
{
|
{
|
||||||
if (directPlayProfile.Type == type)
|
if (directPlayProfile.Type == type
|
||||||
|
&& directPlayProfile.SupportsContainer(format))
|
||||||
{
|
{
|
||||||
if (directPlayProfile.SupportsContainer(format))
|
return format;
|
||||||
{
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,9 +263,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
|
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
|
||||||
{
|
{
|
||||||
var transcodeReasons = new List<TranscodeReason>();
|
StreamInfo playlistItem = new StreamInfo
|
||||||
|
|
||||||
var playlistItem = new StreamInfo
|
|
||||||
{
|
{
|
||||||
ItemId = options.ItemId,
|
ItemId = options.ItemId,
|
||||||
MediaType = DlnaProfileType.Audio,
|
MediaType = DlnaProfileType.Audio,
|
||||||
|
@ -313,18 +292,16 @@ namespace MediaBrowser.Model.Dlna
|
||||||
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
|
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
|
||||||
|
|
||||||
var directPlayMethods = directPlayInfo.Item1;
|
var directPlayMethods = directPlayInfo.Item1;
|
||||||
transcodeReasons.AddRange(directPlayInfo.Item2);
|
var transcodeReasons = directPlayInfo.Item2.ToList();
|
||||||
|
|
||||||
var conditionProcessor = new ConditionProcessor();
|
int? inputAudioChannels = audioStream?.Channels;
|
||||||
|
int? inputAudioBitrate = audioStream?.BitDepth;
|
||||||
|
int? inputAudioSampleRate = audioStream?.SampleRate;
|
||||||
|
int? inputAudioBitDepth = audioStream.BitDepth;
|
||||||
|
|
||||||
int? inputAudioChannels = audioStream == null ? null : audioStream.Channels;
|
if (directPlayMethods.Count() > 0)
|
||||||
int? inputAudioBitrate = audioStream == null ? null : audioStream.BitDepth;
|
|
||||||
int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
|
|
||||||
int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
|
|
||||||
|
|
||||||
if (directPlayMethods.Count > 0)
|
|
||||||
{
|
{
|
||||||
string audioCodec = audioStream == null ? null : audioStream.Codec;
|
string audioCodec = audioStream?.Codec;
|
||||||
|
|
||||||
// Make sure audio codec profiles are satisfied
|
// Make sure audio codec profiles are satisfied
|
||||||
var conditions = new List<ProfileCondition>();
|
var conditions = new List<ProfileCondition>();
|
||||||
|
@ -335,7 +312,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
bool applyConditions = true;
|
bool applyConditions = true;
|
||||||
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
if (!ConditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
||||||
{
|
{
|
||||||
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
|
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
|
||||||
applyConditions = false;
|
applyConditions = false;
|
||||||
|
@ -345,10 +322,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
if (applyConditions)
|
if (applyConditions)
|
||||||
{
|
{
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
conditions.AddRange(i.Conditions);
|
||||||
{
|
|
||||||
conditions.Add(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,7 +330,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
bool all = true;
|
bool all = true;
|
||||||
foreach (ProfileCondition c in conditions)
|
foreach (ProfileCondition c in conditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
if (!ConditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
||||||
{
|
{
|
||||||
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
|
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
|
||||||
var transcodeReason = GetTranscodeReasonForFailedCondition(c);
|
var transcodeReason = GetTranscodeReasonForFailedCondition(c);
|
||||||
|
@ -385,13 +359,12 @@ namespace MediaBrowser.Model.Dlna
|
||||||
TranscodingProfile transcodingProfile = null;
|
TranscodingProfile transcodingProfile = null;
|
||||||
foreach (var i in options.Profile.TranscodingProfiles)
|
foreach (var i in options.Profile.TranscodingProfiles)
|
||||||
{
|
{
|
||||||
if (i.Type == playlistItem.MediaType && i.Context == options.Context)
|
if (i.Type == playlistItem.MediaType
|
||||||
|
&& i.Context == options.Context
|
||||||
|
&& _transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container))
|
||||||
{
|
{
|
||||||
if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container))
|
transcodingProfile = i;
|
||||||
{
|
break;
|
||||||
transcodingProfile = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +394,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
bool applyConditions = true;
|
bool applyConditions = true;
|
||||||
foreach (var applyCondition in i.ApplyConditions)
|
foreach (var applyCondition in i.ApplyConditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
if (!ConditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
||||||
{
|
{
|
||||||
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
|
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
|
||||||
applyConditions = false;
|
applyConditions = false;
|
||||||
|
@ -463,7 +436,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options, bool isAudio)
|
private static long? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options, bool isAudio)
|
||||||
{
|
{
|
||||||
if (item.Protocol == MediaProtocol.File)
|
if (item.Protocol == MediaProtocol.File)
|
||||||
{
|
{
|
||||||
|
@ -473,66 +446,57 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return options.GetMaxBitrate(isAudio);
|
return options.GetMaxBitrate(isAudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tuple<List<PlayMethod>, List<TranscodeReason>> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
|
private (IEnumerable<PlayMethod>, IEnumerable<TranscodeReason>) GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
|
||||||
{
|
{
|
||||||
var transcodeReasons = new List<TranscodeReason>();
|
DirectPlayProfile directPlayProfile = options.Profile.DirectPlayProfiles
|
||||||
|
.FirstOrDefault(x => x.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(x, item, audioStream));
|
||||||
|
|
||||||
DirectPlayProfile directPlayProfile = null;
|
if (directPlayProfile == null)
|
||||||
foreach (var i in options.Profile.DirectPlayProfiles)
|
|
||||||
{
|
{
|
||||||
if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream))
|
|
||||||
{
|
|
||||||
directPlayProfile = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var playMethods = new List<PlayMethod>();
|
|
||||||
|
|
||||||
if (directPlayProfile != null)
|
|
||||||
{
|
|
||||||
// While options takes the network and other factors into account. Only applies to direct stream
|
|
||||||
if (item.SupportsDirectStream)
|
|
||||||
{
|
|
||||||
if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
|
|
||||||
{
|
|
||||||
if (options.EnableDirectStream)
|
|
||||||
{
|
|
||||||
playMethods.Add(PlayMethod.DirectStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The profile describes what the device supports
|
|
||||||
// If device requirements are satisfied then allow both direct stream and direct play
|
|
||||||
if (item.SupportsDirectPlay)
|
|
||||||
{
|
|
||||||
if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
|
|
||||||
{
|
|
||||||
if (options.EnableDirectPlay)
|
|
||||||
{
|
|
||||||
playMethods.Add(PlayMethod.DirectPlay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
transcodeReasons.InsertRange(0, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
|
|
||||||
|
|
||||||
_logger.LogInformation("Profile: {0}, No direct play profiles found for Path: {1}",
|
_logger.LogInformation("Profile: {0}, No direct play profiles found for Path: {1}",
|
||||||
options.Profile.Name ?? "Unknown Profile",
|
options.Profile.Name ?? "Unknown Profile",
|
||||||
item.Path ?? "Unknown path");
|
item.Path ?? "Unknown path");
|
||||||
|
|
||||||
|
return (Enumerable.Empty<PlayMethod>(), GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var playMethods = new List<PlayMethod>();
|
||||||
|
var transcodeReasons = new List<TranscodeReason>();
|
||||||
|
|
||||||
|
// While options takes the network and other factors into account. Only applies to direct stream
|
||||||
|
if (item.SupportsDirectStream)
|
||||||
|
{
|
||||||
|
if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
|
||||||
|
{
|
||||||
|
if (options.EnableDirectStream)
|
||||||
|
{
|
||||||
|
playMethods.Add(PlayMethod.DirectStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The profile describes what the device supports
|
||||||
|
// If device requirements are satisfied then allow both direct stream and direct play
|
||||||
|
if (item.SupportsDirectPlay)
|
||||||
|
{
|
||||||
|
if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
|
||||||
|
{
|
||||||
|
if (options.EnableDirectPlay)
|
||||||
|
{
|
||||||
|
playMethods.Add(PlayMethod.DirectPlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (playMethods.Count > 0)
|
if (playMethods.Count > 0)
|
||||||
{
|
{
|
||||||
transcodeReasons.Clear();
|
transcodeReasons.Clear();
|
||||||
|
@ -542,41 +506,25 @@ namespace MediaBrowser.Model.Dlna
|
||||||
transcodeReasons = transcodeReasons.Distinct().ToList();
|
transcodeReasons = transcodeReasons.Distinct().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tuple<List<PlayMethod>, List<TranscodeReason>>(playMethods, transcodeReasons);
|
return (playMethods, transcodeReasons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
|
private static List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
|
||||||
{
|
{
|
||||||
var list = new List<TranscodeReason>();
|
|
||||||
var containerSupported = false;
|
var containerSupported = false;
|
||||||
var audioSupported = false;
|
var audioSupported = false;
|
||||||
var videoSupported = false;
|
var videoSupported = false;
|
||||||
|
|
||||||
foreach (var profile in directPlayProfiles)
|
foreach (var profile in directPlayProfiles)
|
||||||
{
|
{
|
||||||
audioSupported = false;
|
|
||||||
videoSupported = false;
|
|
||||||
|
|
||||||
// Check container type
|
// Check container type
|
||||||
if (profile.SupportsContainer(item.Container))
|
if (profile.SupportsContainer(item.Container))
|
||||||
{
|
{
|
||||||
containerSupported = true;
|
containerSupported = true;
|
||||||
|
|
||||||
if (videoStream != null)
|
videoSupported = videoStream != null && profile.SupportsVideoCodec(videoStream.Codec);
|
||||||
{
|
|
||||||
if (profile.SupportsVideoCodec(videoStream.Codec))
|
|
||||||
{
|
|
||||||
videoSupported = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audioStream != null)
|
audioSupported = audioStream != null && profile.SupportsAudioCodec(audioStream.Codec);
|
||||||
{
|
|
||||||
if (profile.SupportsAudioCodec(audioStream.Codec))
|
|
||||||
{
|
|
||||||
audioSupported = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoSupported && audioSupported)
|
if (videoSupported && audioSupported)
|
||||||
{
|
{
|
||||||
|
@ -585,6 +533,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var list = new List<TranscodeReason>();
|
||||||
if (!containerSupported)
|
if (!containerSupported)
|
||||||
{
|
{
|
||||||
list.Add(TranscodeReason.ContainerNotSupported);
|
list.Add(TranscodeReason.ContainerNotSupported);
|
||||||
|
@ -603,18 +552,17 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
|
private static int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
|
||||||
{
|
{
|
||||||
int highestScore = -1;
|
int highestScore = -1;
|
||||||
|
|
||||||
foreach (var stream in item.MediaStreams)
|
foreach (var stream in item.MediaStreams)
|
||||||
{
|
{
|
||||||
if (stream.Type == MediaStreamType.Subtitle && stream.Score.HasValue)
|
if (stream.Type == MediaStreamType.Subtitle
|
||||||
|
&& stream.Score.HasValue
|
||||||
|
&& stream.Score.Value > highestScore)
|
||||||
{
|
{
|
||||||
if (stream.Score.Value > highestScore)
|
highestScore = stream.Score.Value;
|
||||||
{
|
|
||||||
highestScore = stream.Score.Value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,7 +594,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return item.DefaultSubtitleStreamIndex;
|
return item.DefaultSubtitleStreamIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetStreamInfoOptionsFromTranscodingProfile(StreamInfo playlistItem, TranscodingProfile transcodingProfile)
|
private static void SetStreamInfoOptionsFromTranscodingProfile(StreamInfo playlistItem, TranscodingProfile transcodingProfile)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(transcodingProfile.AudioCodec))
|
if (string.IsNullOrEmpty(transcodingProfile.AudioCodec))
|
||||||
{
|
{
|
||||||
|
@ -686,12 +634,10 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
playlistItem.SubProtocol = transcodingProfile.Protocol;
|
playlistItem.SubProtocol = transcodingProfile.Protocol;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels))
|
if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels)
|
||||||
|
&& int.TryParse(transcodingProfile.MaxAudioChannels, NumberStyles.Any, CultureInfo.InvariantCulture, out int transcodingMaxAudioChannels))
|
||||||
{
|
{
|
||||||
if (int.TryParse(transcodingProfile.MaxAudioChannels, NumberStyles.Any, CultureInfo.InvariantCulture, out var transcodingMaxAudioChannels))
|
playlistItem.TranscodingMaxAudioChannels = transcodingMaxAudioChannels;
|
||||||
{
|
|
||||||
playlistItem.TranscodingMaxAudioChannels = transcodingMaxAudioChannels;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,9 +648,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
throw new ArgumentNullException(nameof(item));
|
throw new ArgumentNullException(nameof(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
var transcodeReasons = new List<TranscodeReason>();
|
StreamInfo playlistItem = new StreamInfo
|
||||||
|
|
||||||
var playlistItem = new StreamInfo
|
|
||||||
{
|
{
|
||||||
ItemId = options.ItemId,
|
ItemId = options.ItemId,
|
||||||
MediaType = DlnaProfileType.Video,
|
MediaType = DlnaProfileType.Video,
|
||||||
|
@ -737,6 +681,8 @@ namespace MediaBrowser.Model.Dlna
|
||||||
isEligibleForDirectPlay,
|
isEligibleForDirectPlay,
|
||||||
isEligibleForDirectStream);
|
isEligibleForDirectStream);
|
||||||
|
|
||||||
|
var transcodeReasons = new List<TranscodeReason>();
|
||||||
|
|
||||||
if (isEligibleForDirectPlay || isEligibleForDirectStream)
|
if (isEligibleForDirectPlay || isEligibleForDirectStream)
|
||||||
{
|
{
|
||||||
// See if it can be direct played
|
// See if it can be direct played
|
||||||
|
@ -803,8 +749,6 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
SetStreamInfoOptionsFromTranscodingProfile(playlistItem, transcodingProfile);
|
SetStreamInfoOptionsFromTranscodingProfile(playlistItem, transcodingProfile);
|
||||||
|
|
||||||
var conditionProcessor = new ConditionProcessor();
|
|
||||||
|
|
||||||
var isFirstAppliedCodecProfile = true;
|
var isFirstAppliedCodecProfile = true;
|
||||||
foreach (var i in options.Profile.CodecProfiles)
|
foreach (var i in options.Profile.CodecProfiles)
|
||||||
{
|
{
|
||||||
|
@ -813,26 +757,26 @@ namespace MediaBrowser.Model.Dlna
|
||||||
bool applyConditions = true;
|
bool applyConditions = true;
|
||||||
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
||||||
{
|
{
|
||||||
int? width = videoStream == null ? null : videoStream.Width;
|
int? width = videoStream?.Width;
|
||||||
int? height = videoStream == null ? null : videoStream.Height;
|
int? height = videoStream?.Height;
|
||||||
int? bitDepth = videoStream == null ? null : videoStream.BitDepth;
|
int? bitDepth = videoStream?.BitDepth;
|
||||||
int? videoBitrate = videoStream == null ? null : videoStream.BitRate;
|
int? videoBitrate = videoStream?.BitRate;
|
||||||
double? videoLevel = videoStream == null ? null : videoStream.Level;
|
double? videoLevel = videoStream?.Level;
|
||||||
string videoProfile = videoStream == null ? null : videoStream.Profile;
|
string videoProfile = videoStream?.Profile;
|
||||||
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
|
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
|
||||||
bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
|
bool? isAnamorphic = videoStream?.IsAnamorphic;
|
||||||
bool? isInterlaced = videoStream == null ? (bool?)null : videoStream.IsInterlaced;
|
bool? isInterlaced = videoStream?.IsInterlaced;
|
||||||
string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
|
string videoCodecTag = videoStream?.CodecTag;
|
||||||
bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
|
bool? isAvc = videoStream?.IsAVC;
|
||||||
|
|
||||||
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
|
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
|
||||||
int? packetLength = videoStream == null ? null : videoStream.PacketLength;
|
int? packetLength = videoStream?.PacketLength;
|
||||||
int? refFrames = videoStream == null ? null : videoStream.RefFrames;
|
int? refFrames = videoStream?.RefFrames;
|
||||||
|
|
||||||
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
|
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
|
||||||
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
|
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
|
||||||
|
|
||||||
if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
if (!ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
||||||
{
|
{
|
||||||
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
|
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
|
||||||
applyConditions = false;
|
applyConditions = false;
|
||||||
|
@ -876,7 +820,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
|
int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
|
||||||
int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
|
int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
|
||||||
|
|
||||||
if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))
|
if (!ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))
|
||||||
{
|
{
|
||||||
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
|
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
|
||||||
applyConditions = false;
|
applyConditions = false;
|
||||||
|
@ -922,7 +866,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
|
private static int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
|
||||||
{
|
{
|
||||||
if ((audioStream.Channels ?? 0) >= 6)
|
if ((audioStream.Channels ?? 0) >= 6)
|
||||||
{
|
{
|
||||||
|
@ -932,33 +876,37 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return 192000;
|
return 192000;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetAudioBitrate(string subProtocol, long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item)
|
private static int GetAudioBitrate(string subProtocol, long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item)
|
||||||
{
|
{
|
||||||
var targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
|
string targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
|
||||||
|
|
||||||
var targetAudioChannels = item.GetTargetAudioChannels(targetAudioCodec);
|
int? targetAudioChannels = item.GetTargetAudioChannels(targetAudioCodec);
|
||||||
|
|
||||||
int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
|
|
||||||
|
|
||||||
// Reduce the bitrate if we're downmixing
|
|
||||||
if (targetAudioChannels.HasValue && audioStream != null && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
|
|
||||||
{
|
|
||||||
defaultBitrate = targetAudioChannels.Value <= 2 ? 128000 : 192000;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
int defaultBitrate;
|
||||||
int encoderAudioBitrateLimit = int.MaxValue;
|
int encoderAudioBitrateLimit = int.MaxValue;
|
||||||
|
|
||||||
if (audioStream != null)
|
if (audioStream == null)
|
||||||
{
|
{
|
||||||
|
defaultBitrate = 192000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (targetAudioChannels.HasValue && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
|
||||||
|
{
|
||||||
|
// Reduce the bitrate if we're downmixing
|
||||||
|
defaultBitrate = targetAudioChannels.Value < 2 ? 128000 : 192000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
defaultBitrate = audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
|
||||||
|
}
|
||||||
|
|
||||||
// Seeing webm encoding failures when source has 1 audio channel and 22k bitrate.
|
// Seeing webm encoding failures when source has 1 audio channel and 22k bitrate.
|
||||||
// Any attempts to transcode over 64k will fail
|
// Any attempts to transcode over 64k will fail
|
||||||
if (audioStream.Channels.HasValue &&
|
if (audioStream.Channels == 1
|
||||||
audioStream.Channels.Value == 1)
|
&& (audioStream.BitRate ?? 0) < 64000)
|
||||||
{
|
{
|
||||||
if ((audioStream.BitRate ?? 0) < 64000)
|
encoderAudioBitrateLimit = 64000;
|
||||||
{
|
|
||||||
encoderAudioBitrateLimit = 64000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,19 +918,17 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
|
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetMaxAudioBitrateForTotalBitrate(long totalBitrate)
|
private static int GetMaxAudioBitrateForTotalBitrate(long totalBitrate)
|
||||||
{
|
{
|
||||||
if (totalBitrate <= 640000)
|
if (totalBitrate <= 640000)
|
||||||
{
|
{
|
||||||
return 128000;
|
return 128000;
|
||||||
}
|
}
|
||||||
|
else if (totalBitrate <= 2000000)
|
||||||
if (totalBitrate <= 2000000)
|
|
||||||
{
|
{
|
||||||
return 384000;
|
return 384000;
|
||||||
}
|
}
|
||||||
|
else if (totalBitrate <= 3000000)
|
||||||
if (totalBitrate <= 3000000)
|
|
||||||
{
|
{
|
||||||
return 448000;
|
return 448000;
|
||||||
}
|
}
|
||||||
|
@ -990,24 +936,25 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return 640000;
|
return 640000;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tuple<PlayMethod?, List<TranscodeReason>> GetVideoDirectPlayProfile(VideoOptions options,
|
private (PlayMethod?, List<TranscodeReason>) GetVideoDirectPlayProfile(
|
||||||
|
VideoOptions options,
|
||||||
MediaSourceInfo mediaSource,
|
MediaSourceInfo mediaSource,
|
||||||
MediaStream videoStream,
|
MediaStream videoStream,
|
||||||
MediaStream audioStream,
|
MediaStream audioStream,
|
||||||
bool isEligibleForDirectPlay,
|
bool isEligibleForDirectPlay,
|
||||||
bool isEligibleForDirectStream)
|
bool isEligibleForDirectStream)
|
||||||
{
|
{
|
||||||
DeviceProfile profile = options.Profile;
|
|
||||||
|
|
||||||
if (options.ForceDirectPlay)
|
if (options.ForceDirectPlay)
|
||||||
{
|
{
|
||||||
return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectPlay, new List<TranscodeReason>());
|
return (PlayMethod.DirectPlay, new List<TranscodeReason>());
|
||||||
}
|
}
|
||||||
if (options.ForceDirectStream)
|
if (options.ForceDirectStream)
|
||||||
{
|
{
|
||||||
return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
|
return (PlayMethod.DirectStream, new List<TranscodeReason>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeviceProfile profile = options.Profile;
|
||||||
|
|
||||||
// See if it can be direct played
|
// See if it can be direct played
|
||||||
DirectPlayProfile directPlay = null;
|
DirectPlayProfile directPlay = null;
|
||||||
foreach (var i in profile.DirectPlayProfiles)
|
foreach (var i in profile.DirectPlayProfiles)
|
||||||
|
@ -1025,7 +972,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
profile.Name ?? "Unknown Profile",
|
profile.Name ?? "Unknown Profile",
|
||||||
mediaSource.Path ?? "Unknown path");
|
mediaSource.Path ?? "Unknown path");
|
||||||
|
|
||||||
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
|
return (null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
|
||||||
}
|
}
|
||||||
|
|
||||||
string container = mediaSource.Container;
|
string container = mediaSource.Container;
|
||||||
|
@ -1033,8 +980,8 @@ namespace MediaBrowser.Model.Dlna
|
||||||
var conditions = new List<ProfileCondition>();
|
var conditions = new List<ProfileCondition>();
|
||||||
foreach (var i in profile.ContainerProfiles)
|
foreach (var i in profile.ContainerProfiles)
|
||||||
{
|
{
|
||||||
if (i.Type == DlnaProfileType.Video &&
|
if (i.Type == DlnaProfileType.Video
|
||||||
i.ContainsContainer(container))
|
&& i.ContainsContainer(container))
|
||||||
{
|
{
|
||||||
foreach (var c in i.Conditions)
|
foreach (var c in i.Conditions)
|
||||||
{
|
{
|
||||||
|
@ -1043,29 +990,27 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var conditionProcessor = new ConditionProcessor();
|
int? width = videoStream?.Width;
|
||||||
|
int? height = videoStream?.Height;
|
||||||
int? width = videoStream == null ? null : videoStream.Width;
|
int? bitDepth = videoStream?.BitDepth;
|
||||||
int? height = videoStream == null ? null : videoStream.Height;
|
int? videoBitrate = videoStream?.BitRate;
|
||||||
int? bitDepth = videoStream == null ? null : videoStream.BitDepth;
|
double? videoLevel = videoStream?.Level;
|
||||||
int? videoBitrate = videoStream == null ? null : videoStream.BitRate;
|
string videoProfile = videoStream?.Profile;
|
||||||
double? videoLevel = videoStream == null ? null : videoStream.Level;
|
|
||||||
string videoProfile = videoStream == null ? null : videoStream.Profile;
|
|
||||||
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
|
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
|
||||||
bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
|
bool? isAnamorphic = videoStream?.IsAnamorphic;
|
||||||
bool? isInterlaced = videoStream == null ? (bool?)null : videoStream.IsInterlaced;
|
bool? isInterlaced = videoStream?.IsInterlaced;
|
||||||
string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
|
string videoCodecTag = videoStream?.CodecTag;
|
||||||
bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
|
bool? isAvc = videoStream?.IsAVC;
|
||||||
|
|
||||||
int? audioBitrate = audioStream == null ? null : audioStream.BitRate;
|
int? audioBitrate = audioStream?.BitRate;
|
||||||
int? audioChannels = audioStream == null ? null : audioStream.Channels;
|
int? audioChannels = audioStream?.Channels;
|
||||||
string audioProfile = audioStream == null ? null : audioStream.Profile;
|
string audioProfile = audioStream?.Profile;
|
||||||
int? audioSampleRate = audioStream == null ? null : audioStream.SampleRate;
|
int? audioSampleRate = audioStream?.SampleRate;
|
||||||
int? audioBitDepth = audioStream == null ? null : audioStream.BitDepth;
|
int? audioBitDepth = audioStream?.BitDepth;
|
||||||
|
|
||||||
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp;
|
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp;
|
||||||
int? packetLength = videoStream == null ? null : videoStream.PacketLength;
|
int? packetLength = videoStream?.PacketLength;
|
||||||
int? refFrames = videoStream == null ? null : videoStream.RefFrames;
|
int? refFrames = videoStream?.RefFrames;
|
||||||
|
|
||||||
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
|
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
|
||||||
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
|
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
|
||||||
|
@ -1073,20 +1018,20 @@ namespace MediaBrowser.Model.Dlna
|
||||||
// Check container conditions
|
// Check container conditions
|
||||||
foreach (ProfileCondition i in conditions)
|
foreach (ProfileCondition i in conditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
if (!ConditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
||||||
{
|
{
|
||||||
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
|
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
|
||||||
|
|
||||||
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
||||||
var transcodeReasons = transcodeReason.HasValue
|
var transcodeReasons = transcodeReason.HasValue
|
||||||
? new List<TranscodeReason> { transcodeReason.Value }
|
? new List<TranscodeReason> { transcodeReason.Value }
|
||||||
: new List<TranscodeReason> { };
|
: new List<TranscodeReason>();
|
||||||
|
|
||||||
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
|
return (null, transcodeReasons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string videoCodec = videoStream == null ? null : videoStream.Codec;
|
string videoCodec = videoStream?.Codec;
|
||||||
|
|
||||||
conditions = new List<ProfileCondition>();
|
conditions = new List<ProfileCondition>();
|
||||||
foreach (var i in profile.CodecProfiles)
|
foreach (var i in profile.CodecProfiles)
|
||||||
|
@ -1096,7 +1041,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
bool applyConditions = true;
|
bool applyConditions = true;
|
||||||
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
if (!ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
||||||
{
|
{
|
||||||
//LogConditionFailure(profile, "VideoCodecProfile.ApplyConditions", applyCondition, mediaSource);
|
//LogConditionFailure(profile, "VideoCodecProfile.ApplyConditions", applyCondition, mediaSource);
|
||||||
applyConditions = false;
|
applyConditions = false;
|
||||||
|
@ -1116,23 +1061,22 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
foreach (ProfileCondition i in conditions)
|
foreach (ProfileCondition i in conditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
if (!ConditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
||||||
{
|
{
|
||||||
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
||||||
|
|
||||||
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
||||||
var transcodeReasons = transcodeReason.HasValue
|
var transcodeReasons = transcodeReason.HasValue
|
||||||
? new List<TranscodeReason> { transcodeReason.Value }
|
? new List<TranscodeReason> { transcodeReason.Value }
|
||||||
: new List<TranscodeReason> { };
|
: new List<TranscodeReason>();
|
||||||
|
|
||||||
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
|
return (null, transcodeReasons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioStream != null)
|
if (audioStream != null)
|
||||||
{
|
{
|
||||||
string audioCodec = audioStream.Codec;
|
string audioCodec = audioStream.Codec;
|
||||||
|
|
||||||
conditions = new List<ProfileCondition>();
|
conditions = new List<ProfileCondition>();
|
||||||
bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream);
|
bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream);
|
||||||
|
|
||||||
|
@ -1143,7 +1087,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
bool applyConditions = true;
|
bool applyConditions = true;
|
||||||
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
|
if (!ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
|
||||||
{
|
{
|
||||||
//LogConditionFailure(profile, "VideoAudioCodecProfile.ApplyConditions", applyCondition, mediaSource);
|
//LogConditionFailure(profile, "VideoAudioCodecProfile.ApplyConditions", applyCondition, mediaSource);
|
||||||
applyConditions = false;
|
applyConditions = false;
|
||||||
|
@ -1163,26 +1107,26 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
foreach (ProfileCondition i in conditions)
|
foreach (ProfileCondition i in conditions)
|
||||||
{
|
{
|
||||||
if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
|
if (!ConditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
|
||||||
{
|
{
|
||||||
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
|
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
|
||||||
|
|
||||||
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
||||||
var transcodeReasons = transcodeReason.HasValue
|
var transcodeReasons = transcodeReason.HasValue
|
||||||
? new List<TranscodeReason> { transcodeReason.Value }
|
? new List<TranscodeReason> { transcodeReason.Value }
|
||||||
: new List<TranscodeReason> { };
|
: new List<TranscodeReason>();
|
||||||
|
|
||||||
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
|
return (null, transcodeReasons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
|
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
|
||||||
{
|
{
|
||||||
return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
|
return (PlayMethod.DirectStream, new List<TranscodeReason>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
|
return (null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
|
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
|
||||||
|
@ -1197,7 +1141,8 @@ namespace MediaBrowser.Model.Dlna
|
||||||
mediaSource.Path ?? "Unknown path");
|
mediaSource.Path ?? "Unknown path");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTuple<bool, TranscodeReason?> IsEligibleForDirectPlay(MediaSourceInfo item,
|
private (bool directPlay, TranscodeReason? reason) IsEligibleForDirectPlay(
|
||||||
|
MediaSourceInfo item,
|
||||||
long maxBitrate,
|
long maxBitrate,
|
||||||
MediaStream subtitleStream,
|
MediaStream subtitleStream,
|
||||||
VideoOptions options,
|
VideoOptions options,
|
||||||
|
@ -1210,21 +1155,23 @@ namespace MediaBrowser.Model.Dlna
|
||||||
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
|
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Not eligible for {0} due to unsupported subtitles", playMethod);
|
_logger.LogInformation("Not eligible for {0} due to unsupported subtitles", playMethod);
|
||||||
return new ValueTuple<bool, TranscodeReason?>(false, TranscodeReason.SubtitleCodecNotSupported);
|
return (false, TranscodeReason.SubtitleCodecNotSupported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
|
bool result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
|
||||||
|
|
||||||
if (result)
|
return (result, result ? (TranscodeReason?)null : TranscodeReason.ContainerBitrateExceedsLimit);
|
||||||
{
|
|
||||||
return new ValueTuple<bool, TranscodeReason?>(result, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ValueTuple<bool, TranscodeReason?>(result, TranscodeReason.ContainerBitrateExceedsLimit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SubtitleProfile GetSubtitleProfile(MediaSourceInfo mediaSource, MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, ITranscoderSupport transcoderSupport, string outputContainer, string transcodingSubProtocol)
|
public static SubtitleProfile GetSubtitleProfile(
|
||||||
|
MediaSourceInfo mediaSource,
|
||||||
|
MediaStream subtitleStream,
|
||||||
|
SubtitleProfile[] subtitleProfiles,
|
||||||
|
PlayMethod playMethod,
|
||||||
|
ITranscoderSupport transcoderSupport,
|
||||||
|
string outputContainer,
|
||||||
|
string transcodingSubProtocol)
|
||||||
{
|
{
|
||||||
if (!subtitleStream.IsExternal && (playMethod != PlayMethod.Transcode || !string.Equals(transcodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)))
|
if (!subtitleStream.IsExternal && (playMethod != PlayMethod.Transcode || !string.Equals(transcodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
|
@ -1301,27 +1248,20 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(transcodingContainer))
|
if (!string.IsNullOrEmpty(transcodingContainer))
|
||||||
{
|
{
|
||||||
var normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
|
string[] normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
|
||||||
|
|
||||||
if (ContainerProfile.ContainsContainer(normalizedContainers, "ts"))
|
if (ContainerProfile.ContainsContainer(normalizedContainers, "ts")
|
||||||
|
|| ContainerProfile.ContainsContainer(normalizedContainers, "mpegts")
|
||||||
|
|| ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ContainerProfile.ContainsContainer(normalizedContainers, "mpegts"))
|
else if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv")
|
||||||
{
|
|| ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv") ||
|
|
||||||
ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1388,22 +1328,22 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var requestedMaxBitrate = maxBitrate > 0 ? maxBitrate : 1000000;
|
long requestedMaxBitrate = maxBitrate > 0 ? maxBitrate : 1000000;
|
||||||
|
|
||||||
// If we don't know the bitrate, then force a transcode if requested max bitrate is under 40 mbps
|
// If we don't know the bitrate, then force a transcode if requested max bitrate is under 40 mbps
|
||||||
var itemBitrate = item.Bitrate ??
|
int itemBitrate = item.Bitrate ?? 40000000;
|
||||||
40000000;
|
|
||||||
|
|
||||||
if (itemBitrate > requestedMaxBitrate)
|
if (itemBitrate > requestedMaxBitrate)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Bitrate exceeds " + playMethod + " limit: media bitrate: {0}, max bitrate: {1}", itemBitrate.ToString(CultureInfo.InvariantCulture), requestedMaxBitrate.ToString(CultureInfo.InvariantCulture));
|
_logger.LogInformation("Bitrate exceeds {PlayBackMethod} limit: media bitrate: {MediaBitrate}, max bitrate: {MaxBitrate}",
|
||||||
|
playMethod, itemBitrate, requestedMaxBitrate);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateInput(VideoOptions options)
|
private static void ValidateInput(VideoOptions options)
|
||||||
{
|
{
|
||||||
ValidateAudioInput(options);
|
ValidateAudioInput(options);
|
||||||
|
|
||||||
|
@ -1418,7 +1358,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateAudioInput(AudioOptions options)
|
private static void ValidateAudioInput(AudioOptions options)
|
||||||
{
|
{
|
||||||
if (options.ItemId.Equals(Guid.Empty))
|
if (options.ItemId.Equals(Guid.Empty))
|
||||||
{
|
{
|
||||||
|
@ -1438,32 +1378,6 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyTranscodingConditions(StreamInfo item, List<CodecProfile> codecProfiles)
|
|
||||||
{
|
|
||||||
foreach (var profile in codecProfiles)
|
|
||||||
{
|
|
||||||
ApplyTranscodingConditions(item, profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyTranscodingConditions(StreamInfo item, CodecProfile codecProfile)
|
|
||||||
{
|
|
||||||
var codecs = ContainerProfile.SplitValue(codecProfile.Codec);
|
|
||||||
if (codecs.Length == 0)
|
|
||||||
{
|
|
||||||
ApplyTranscodingConditions(item, codecProfile.Conditions, null, true, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var enableNonQualified = true;
|
|
||||||
|
|
||||||
foreach (var codec in codecs)
|
|
||||||
{
|
|
||||||
ApplyTranscodingConditions(item, codecProfile.Conditions, codec, true, enableNonQualified);
|
|
||||||
enableNonQualified = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyTranscodingConditions(StreamInfo item, IEnumerable<ProfileCondition> conditions, string qualifier, bool enableQualifiedConditions, bool enableNonQualifiedConditions)
|
private void ApplyTranscodingConditions(StreamInfo item, IEnumerable<ProfileCondition> conditions, string qualifier, bool enableQualifiedConditions, bool enableNonQualifiedConditions)
|
||||||
{
|
{
|
||||||
foreach (ProfileCondition condition in conditions)
|
foreach (ProfileCondition condition in conditions)
|
||||||
|
@ -1838,7 +1752,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsAudioDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream)
|
private static bool IsAudioDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream)
|
||||||
{
|
{
|
||||||
// Check container type
|
// Check container type
|
||||||
if (!profile.SupportsContainer(item.Container))
|
if (!profile.SupportsContainer(item.Container))
|
||||||
|
@ -1847,7 +1761,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check audio codec
|
// Check audio codec
|
||||||
string audioCodec = audioStream == null ? null : audioStream.Codec;
|
string audioCodec = audioStream?.Codec;
|
||||||
if (!profile.SupportsAudioCodec(audioCodec))
|
if (!profile.SupportsAudioCodec(audioCodec))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -1865,20 +1779,16 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check video codec
|
// Check video codec
|
||||||
string videoCodec = videoStream == null ? null : videoStream.Codec;
|
string videoCodec = videoStream?.Codec;
|
||||||
if (!profile.SupportsVideoCodec(videoCodec))
|
if (!profile.SupportsVideoCodec(videoCodec))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check audio codec
|
// Check audio codec
|
||||||
if (audioStream != null)
|
if (audioStream != null && !profile.SupportsAudioCodec(audioStream.Codec))
|
||||||
{
|
{
|
||||||
string audioCodec = audioStream == null ? null : audioStream.Codec;
|
return false;
|
||||||
if (!profile.SupportsAudioCodec(audioCodec))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -42,8 +42,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Notifications", "Emby.
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Naming", "Emby.Naming\Emby.Naming.csproj", "{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Naming", "Emby.Naming\Emby.Naming.csproj", "{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "taglib-sharp", "ThirdParty\taglib-sharp\src\taglib-sharp.csproj", "{D45FC504-D06B-41A0-A220-C20B7E8F1304}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.XmlTv", "Emby.XmlTv\Emby.XmlTv\Emby.XmlTv.csproj", "{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.XmlTv", "Emby.XmlTv\Emby.XmlTv\Emby.XmlTv.csproj", "{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IsoMounter", "Emby.IsoMounting\IsoMounter\IsoMounter.csproj", "{9BA471D2-6DB9-4DBF-B3A0-9FB3171F94A6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IsoMounter", "Emby.IsoMounting\IsoMounter\IsoMounter.csproj", "{9BA471D2-6DB9-4DBF-B3A0-9FB3171F94A6}"
|
||||||
|
@ -144,10 +142,6 @@ Global
|
||||||
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{D45FC504-D06B-41A0-A220-C20B7E8F1304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D45FC504-D06B-41A0-A220-C20B7E8F1304}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D45FC504-D06B-41A0-A220-C20B7E8F1304}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D45FC504-D06B-41A0-A220-C20B7E8F1304}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
|
|
@ -47,7 +47,6 @@ namespace Mono.Nat
|
||||||
{
|
{
|
||||||
public event EventHandler<DeviceEventArgs> DeviceFound;
|
public event EventHandler<DeviceEventArgs> DeviceFound;
|
||||||
|
|
||||||
private DateTime nextSearch;
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
|
|
||||||
|
@ -98,11 +97,6 @@ namespace Mono.Nat
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime NextSearch
|
|
||||||
{
|
|
||||||
get { return nextSearch; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDeviceFound(DeviceEventArgs args)
|
private void OnDeviceFound(DeviceEventArgs args)
|
||||||
{
|
{
|
||||||
if (DeviceFound != null)
|
if (DeviceFound != null)
|
||||||
|
|
|
@ -13,12 +13,6 @@ namespace SocketHttpListener
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Internal Fields
|
|
||||||
|
|
||||||
internal byte[] EntityBodyData;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Protected Fields
|
#region Protected Fields
|
||||||
|
|
||||||
protected const string CrLf = "\r\n";
|
protected const string CrLf = "\r\n";
|
||||||
|
@ -37,18 +31,6 @@ namespace SocketHttpListener
|
||||||
|
|
||||||
#region Public Properties
|
#region Public Properties
|
||||||
|
|
||||||
public string EntityBody
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var data = EntityBodyData;
|
|
||||||
|
|
||||||
return data != null && data.Length > 0
|
|
||||||
? getEncoding(_headers["Content-Type"]).GetString(data, 0, data.Length)
|
|
||||||
: string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueryParamCollection Headers => _headers;
|
public QueryParamCollection Headers => _headers;
|
||||||
|
|
||||||
public Version ProtocolVersion => _version;
|
public Version ProtocolVersion => _version;
|
||||||
|
|
|
@ -115,10 +115,6 @@ namespace SocketHttpListener
|
||||||
|
|
||||||
output.Append(CrLf);
|
output.Append(CrLf);
|
||||||
|
|
||||||
var entity = EntityBody;
|
|
||||||
if (entity.Length > 0)
|
|
||||||
output.Append(entity);
|
|
||||||
|
|
||||||
return output.ToString();
|
return output.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,6 @@ namespace SocketHttpListener.Net
|
||||||
int _reuses;
|
int _reuses;
|
||||||
bool _contextBound;
|
bool _contextBound;
|
||||||
bool secure;
|
bool secure;
|
||||||
int _timeout = 90000; // 90k ms for first request, 15k ms from then on
|
|
||||||
private Timer _timer;
|
|
||||||
IPEndPoint local_ep;
|
IPEndPoint local_ep;
|
||||||
HttpListener _lastListener;
|
HttpListener _lastListener;
|
||||||
X509Certificate cert;
|
X509Certificate cert;
|
||||||
|
@ -91,8 +89,6 @@ namespace SocketHttpListener.Net
|
||||||
|
|
||||||
public async Task Init()
|
public async Task Init()
|
||||||
{
|
{
|
||||||
_timer = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
|
|
||||||
|
|
||||||
if (ssl_stream != null)
|
if (ssl_stream != null)
|
||||||
{
|
{
|
||||||
var enableAsync = true;
|
var enableAsync = true;
|
||||||
|
@ -162,14 +158,10 @@ namespace SocketHttpListener.Net
|
||||||
_buffer = new byte[BufferSize];
|
_buffer = new byte[BufferSize];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_reuses == 1)
|
|
||||||
_timeout = 15000;
|
|
||||||
//_timer.Change(_timeout, Timeout.Infinite);
|
|
||||||
_stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this);
|
_stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
//_timer.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
@ -216,7 +208,6 @@ namespace SocketHttpListener.Net
|
||||||
|
|
||||||
private void OnReadInternal(IAsyncResult ares)
|
private void OnReadInternal(IAsyncResult ares)
|
||||||
{
|
{
|
||||||
//_timer.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
int nread = -1;
|
int nread = -1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,6 @@ namespace SocketHttpListener
|
||||||
{
|
{
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private string _base64Key;
|
|
||||||
private Action _closeContext;
|
private Action _closeContext;
|
||||||
private CompressionMethod _compression;
|
private CompressionMethod _compression;
|
||||||
private WebSocketContext _context;
|
private WebSocketContext _context;
|
||||||
|
@ -35,20 +34,12 @@ namespace SocketHttpListener
|
||||||
private object _forMessageEventQueue;
|
private object _forMessageEventQueue;
|
||||||
private object _forSend;
|
private object _forSend;
|
||||||
private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
private Func<WebSocketContext, string>
|
|
||||||
_handshakeRequestChecker;
|
|
||||||
private Queue<MessageEventArgs> _messageEventQueue;
|
private Queue<MessageEventArgs> _messageEventQueue;
|
||||||
private uint _nonceCount;
|
|
||||||
private string _origin;
|
|
||||||
private bool _preAuth;
|
|
||||||
private string _protocol;
|
private string _protocol;
|
||||||
private string[] _protocols;
|
|
||||||
private Uri _proxyUri;
|
|
||||||
private volatile WebSocketState _readyState;
|
private volatile WebSocketState _readyState;
|
||||||
private AutoResetEvent _receivePong;
|
private AutoResetEvent _receivePong;
|
||||||
private bool _secure;
|
private bool _secure;
|
||||||
private Stream _stream;
|
private Stream _stream;
|
||||||
private Uri _uri;
|
|
||||||
private const string _version = "13";
|
private const string _version = "13";
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
13
jellyfin.ruleset
Normal file
13
jellyfin.ruleset
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RuleSet Name="Rules for Jellyfin.Server" Description="Code analysis rules for Jellyfin.Server.csproj" ToolsVersion="14.0">
|
||||||
|
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
|
||||||
|
<!-- disable warning SA1101: Prefix local calls with 'this.' -->
|
||||||
|
<Rule Id="SA1101" Action="None" />
|
||||||
|
<!-- disable warning SA1200: 'using' directive must appear within a namespace declaration -->
|
||||||
|
<Rule Id="SA1200" Action="None" />
|
||||||
|
<!-- disable warning SA1309: Fields must not begin with an underscore -->
|
||||||
|
<Rule Id="SA1309" Action="None" />
|
||||||
|
<!-- disable warning SA1633: The file header is missing or not located at the top of the file -->
|
||||||
|
<Rule Id="SA1633" Action="None" />
|
||||||
|
</Rules>
|
||||||
|
</RuleSet>
|
Loading…
Reference in a new issue