update hls to support mpeg2video

pull/1154/head
Luke Pulverenti 8 years ago
parent aaa244be4c
commit ce1ed2bea7

@ -208,7 +208,7 @@ 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.VideoCodec, streamInfo.TargetVideoCodec,
streamInfo.TargetAudioCodec, streamInfo.TargetAudioCodec,
targetWidth, targetWidth,
targetHeight, targetHeight,
@ -352,7 +352,7 @@ namespace Emby.Dlna.Didl
var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container, var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
streamInfo.TargetAudioCodec, streamInfo.TargetAudioCodec,
streamInfo.VideoCodec, streamInfo.TargetVideoCodec,
streamInfo.TargetAudioBitrate, streamInfo.TargetAudioBitrate,
targetWidth, targetWidth,
targetHeight, targetHeight,

@ -542,7 +542,7 @@ namespace Emby.Dlna.PlayTo
{ {
var list = new ContentFeatureBuilder(profile) var list = new ContentFeatureBuilder(profile)
.BuildVideoHeader(streamInfo.Container, .BuildVideoHeader(streamInfo.Container,
streamInfo.VideoCodec, streamInfo.TargetVideoCodec,
streamInfo.TargetAudioCodec, streamInfo.TargetAudioCodec,
streamInfo.TargetWidth, streamInfo.TargetWidth,
streamInfo.TargetHeight, streamInfo.TargetHeight,

@ -2545,14 +2545,24 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private const int TunerDiscoveryDurationMs = 3000; private const int TunerDiscoveryDurationMs = 3000;
public async Task<List<TunerHostInfo>> DiscoverTuners(CancellationToken cancellationToken) public async Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken)
{ {
var list = new List<TunerHostInfo>(); var list = new List<TunerHostInfo>();
var configuredDeviceIds = GetConfiguration().TunerHosts
.Where(i => !string.IsNullOrWhiteSpace(i.DeviceId))
.Select(i => i.DeviceId)
.ToList();
foreach (var host in _liveTvManager.TunerHosts) foreach (var host in _liveTvManager.TunerHosts)
{ {
var discoveredDevices = await DiscoverDevices(host, TunerDiscoveryDurationMs, cancellationToken).ConfigureAwait(false); var discoveredDevices = await DiscoverDevices(host, TunerDiscoveryDurationMs, cancellationToken).ConfigureAwait(false);
if (newDevicesOnly)
{
discoveredDevices = discoveredDevices.Where(d => !configuredDeviceIds.Contains(d.DeviceId, StringComparer.OrdinalIgnoreCase))
.ToList();
}
list.AddRange(discoveredDevices); list.AddRange(discoveredDevices);
} }

@ -160,9 +160,9 @@ namespace Emby.Server.Implementations.LiveTv
}).ToList(); }).ToList();
} }
public Task<List<TunerHostInfo>> DiscoverTuners(CancellationToken cancellationToken) public Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken)
{ {
return EmbyTV.EmbyTV.Current.DiscoverTuners(cancellationToken); return EmbyTV.EmbyTV.Current.DiscoverTuners(newDevicesOnly, cancellationToken);
} }
void service_DataSourceChanged(object sender, EventArgs e) void service_DataSourceChanged(object sender, EventArgs e)

@ -684,7 +684,7 @@ namespace MediaBrowser.Api.LiveTv
[Authenticated] [Authenticated]
public class DiscoverTuners : IReturn<List<TunerHostInfo>> public class DiscoverTuners : IReturn<List<TunerHostInfo>>
{ {
public bool NewDevicesOnly { get; set; }
} }
public class LiveTvService : BaseApiService public class LiveTvService : BaseApiService
@ -739,7 +739,7 @@ namespace MediaBrowser.Api.LiveTv
public async Task<object> Get(DiscoverTuners request) public async Task<object> Get(DiscoverTuners request)
{ {
var result = await _liveTvManager.DiscoverTuners(CancellationToken.None).ConfigureAwait(false); var result = await _liveTvManager.DiscoverTuners(request.NewDevicesOnly, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }

@ -697,6 +697,20 @@ namespace MediaBrowser.Api.Playback
{ {
request.SubtitleCodec = val; request.SubtitleCodec = val;
} }
else if (i == 31)
{
if (videoRequest != null)
{
videoRequest.RequireNonAnamorphic = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
}
}
else if (i == 32)
{
if (videoRequest != null)
{
videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
}
}
} }
} }

@ -41,9 +41,16 @@ namespace MediaBrowser.Api.Playback.Hls
/// <summary> /// <summary>
/// Gets the segment file extension. /// Gets the segment file extension.
/// </summary> /// </summary>
/// <param name="state">The state.</param> protected string GetSegmentFileExtension(StreamRequest request)
/// <returns>System.String.</returns> {
protected abstract string GetSegmentFileExtension(StreamState state); var segmentContainer = request.SegmentContainer;
if (!string.IsNullOrWhiteSpace(segmentContainer))
{
return "." + segmentContainer;
}
return ".ts";
}
/// <summary> /// <summary>
/// Gets the type of the transcoding job. /// Gets the type of the transcoding job.
@ -261,11 +268,17 @@ namespace MediaBrowser.Api.Playback.Hls
var useGenericSegmenter = false; var useGenericSegmenter = false;
if (useGenericSegmenter) if (useGenericSegmenter)
{ {
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state); var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);
var timeDeltaParam = String.Empty; var timeDeltaParam = String.Empty;
return string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"", var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
{
segmentFormat = "mpegts";
}
return string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format {11} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
inputModifier, inputModifier,
EncodingHelper.GetInputArgument(state, encodingOptions), EncodingHelper.GetInputArgument(state, encodingOptions),
threads, threads,
@ -276,7 +289,8 @@ namespace MediaBrowser.Api.Playback.Hls
startNumberParam, startNumberParam,
outputPath, outputPath,
outputTsArg, outputTsArg,
timeDeltaParam timeDeltaParam,
segmentFormat
).Trim(); ).Trim();
} }

@ -65,7 +65,7 @@ namespace MediaBrowser.Api.Playback.Hls
{ {
} }
[Route("/Videos/{Id}/hls1/{PlaylistId}/{SegmentId}.ts", "GET")] [Route("/Videos/{Id}/hls1/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
public class GetHlsVideoSegment : VideoStreamRequest public class GetHlsVideoSegment : VideoStreamRequest
{ {
public string PlaylistId { get; set; } public string PlaylistId { get; set; }
@ -77,8 +77,7 @@ namespace MediaBrowser.Api.Playback.Hls
public string SegmentId { get; set; } public string SegmentId { get; set; }
} }
[Route("/Audio/{Id}/hls1/{PlaylistId}/{SegmentId}.aac", "GET")] [Route("/Audio/{Id}/hls1/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
[Route("/Audio/{Id}/hls1/{PlaylistId}/{SegmentId}.ts", "GET")]
public class GetHlsAudioSegment : StreamRequest public class GetHlsAudioSegment : StreamRequest
{ {
public string PlaylistId { get; set; } public string PlaylistId { get; set; }
@ -158,7 +157,7 @@ namespace MediaBrowser.Api.Playback.Hls
var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex); var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex);
var segmentExtension = GetSegmentFileExtension(state); var segmentExtension = GetSegmentFileExtension(state.Request);
TranscodingJob job = null; TranscodingJob job = null;
@ -420,7 +419,7 @@ namespace MediaBrowser.Api.Playback.Hls
var filename = Path.GetFileNameWithoutExtension(playlist); var filename = Path.GetFileNameWithoutExtension(playlist);
return Path.Combine(folder, filename + index.ToString(UsCulture) + GetSegmentFileExtension(state)); return Path.Combine(folder, filename + index.ToString(UsCulture) + GetSegmentFileExtension(state.Request));
} }
private async Task<object> GetSegmentResult(StreamState state, string playlistPath, private async Task<object> GetSegmentResult(StreamState state, string playlistPath,
@ -740,7 +739,7 @@ namespace MediaBrowser.Api.Playback.Hls
name, name,
index.ToString(UsCulture), index.ToString(UsCulture),
GetSegmentFileExtension(isOutputVideo), GetSegmentFileExtension(request),
queryString)); queryString));
index++; index++;
@ -848,7 +847,7 @@ namespace MediaBrowser.Api.Playback.Hls
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions(); var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
args += " " + EncodingHelper.GetVideoQualityParam(state, EncodingHelper.GetH264Encoder(state, encodingOptions), encodingOptions, GetDefaultH264Preset()) + keyFrameArg; args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultH264Preset()) + keyFrameArg;
//args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0"; //args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
@ -897,7 +896,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (useGenericSegmenter) if (useGenericSegmenter)
{ {
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state); var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);
var timeDeltaParam = String.Empty; var timeDeltaParam = String.Empty;
@ -907,7 +906,13 @@ namespace MediaBrowser.Api.Playback.Hls
timeDeltaParam = string.Format("-segment_time_delta -{0}", startTime); timeDeltaParam = string.Format("-segment_time_delta -{0}", startTime);
} }
return string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"", var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
{
segmentFormat = "mpegts";
}
return string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format {11} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
inputModifier, inputModifier,
EncodingHelper.GetInputArgument(state, encodingOptions), EncodingHelper.GetInputArgument(state, encodingOptions),
threads, threads,
@ -918,7 +923,8 @@ namespace MediaBrowser.Api.Playback.Hls
startNumberParam, startNumberParam,
outputPath, outputPath,
outputTsArg, outputTsArg,
timeDeltaParam timeDeltaParam,
segmentFormat
).Trim(); ).Trim();
} }
@ -935,20 +941,5 @@ namespace MediaBrowser.Api.Playback.Hls
outputPath outputPath
).Trim(); ).Trim();
} }
/// <summary>
/// Gets the segment file extension.
/// </summary>
/// <param name="state">The state.</param>
/// <returns>System.String.</returns>
protected override string GetSegmentFileExtension(StreamState state)
{
return GetSegmentFileExtension(state.IsOutputVideo);
}
protected string GetSegmentFileExtension(bool isOutputVideo)
{
return isOutputVideo ? ".ts" : ".ts";
}
} }
} }

@ -63,7 +63,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// <summary> /// <summary>
/// Class GetHlsVideoSegment /// Class GetHlsVideoSegment
/// </summary> /// </summary>
[Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.ts", "GET")] [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
public class GetHlsVideoSegmentLegacy : VideoStreamRequest public class GetHlsVideoSegmentLegacy : VideoStreamRequest
{ {
public string PlaylistId { get; set; } public string PlaylistId { get; set; }

@ -99,7 +99,7 @@ namespace MediaBrowser.Api.Playback.Hls
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode; var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions(); var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
args += " " + EncodingHelper.GetVideoQualityParam(state, EncodingHelper.GetH264Encoder(state, encodingOptions), encodingOptions, GetDefaultH264Preset()) + keyFrameArg; args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultH264Preset()) + keyFrameArg;
// Add resolution params, if specified // Add resolution params, if specified
if (!hasGraphicalSubs) if (!hasGraphicalSubs)
@ -118,16 +118,6 @@ namespace MediaBrowser.Api.Playback.Hls
return args; return args;
} }
/// <summary>
/// Gets the segment file extension.
/// </summary>
/// <param name="state">The state.</param>
/// <returns>System.String.</returns>
protected override string GetSegmentFileExtension(StreamState state)
{
return ".ts";
}
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext) public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
{ {
} }

@ -41,6 +41,7 @@ namespace MediaBrowser.Api.Playback
public string PlaySessionId { get; set; } public string PlaySessionId { get; set; }
public string LiveStreamId { get; set; } public string LiveStreamId { get; set; }
public string Tag { get; set; } public string Tag { get; set; }
public string SegmentContainer { get; set; }
} }
public class VideoStreamRequest : StreamRequest public class VideoStreamRequest : StreamRequest

@ -382,7 +382,7 @@ namespace MediaBrowser.Controller.LiveTv
List<IListingsProvider> ListingProviders { get; } List<IListingsProvider> ListingProviders { get; }
List<NameIdPair> GetTunerHostTypes(); List<NameIdPair> GetTunerHostTypes();
Task<List<TunerHostInfo>> DiscoverTuners(CancellationToken cancellationToken); Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken);
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled; event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled; event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;

@ -732,14 +732,20 @@ namespace MediaBrowser.Controller.MediaEncoding
var request = state.BaseRequest; var request = state.BaseRequest;
if (videoStream.IsInterlaced) if (videoStream.IsInterlaced)
{
if (request.DeInterlace)
{ {
return false; return false;
} }
}
if (videoStream.IsAnamorphic ?? false) if (videoStream.IsAnamorphic ?? false)
{
if (request.RequireNonAnamorphic)
{ {
return false; return false;
} }
}
// Can't stream copy if we're burning in subtitles // Can't stream copy if we're burning in subtitles
if (request.SubtitleStreamIndex.HasValue) if (request.SubtitleStreamIndex.HasValue)

@ -46,7 +46,7 @@ namespace MediaBrowser.Controller.MediaEncoding
AudioBitRate = info.AudioBitrate; AudioBitRate = info.AudioBitrate;
AudioSampleRate = info.TargetAudioSampleRate; AudioSampleRate = info.TargetAudioSampleRate;
DeviceProfile = deviceProfile; DeviceProfile = deviceProfile;
VideoCodec = info.VideoCodec; VideoCodec = info.TargetVideoCodec;
VideoBitRate = info.VideoBitrate; VideoBitRate = info.VideoBitrate;
AudioStreamIndex = info.AudioStreamIndex; AudioStreamIndex = info.AudioStreamIndex;
MaxRefFrames = info.MaxRefFrames; MaxRefFrames = info.MaxRefFrames;
@ -185,6 +185,8 @@ namespace MediaBrowser.Controller.MediaEncoding
[ApiMember(Name = "MaxVideoBitDepth", Description = "Optional.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "MaxVideoBitDepth", Description = "Optional.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxVideoBitDepth { get; set; } public int? MaxVideoBitDepth { get; set; }
public bool RequireAvc { get; set; } public bool RequireAvc { get; set; }
public bool DeInterlace { get; set; }
public bool RequireNonAnamorphic { get; set; }
public int? TranscodingMaxAudioChannels { get; set; } public int? TranscodingMaxAudioChannels { get; set; }
public int? CpuCoreLimit { get; set; } public int? CpuCoreLimit { get; set; }
public string OutputContainer { get; set; } public string OutputContainer { get; set; }

@ -734,16 +734,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
} }
} }
var charsetFromLanguage = string.IsNullOrWhiteSpace(language)
? null
: GetSubtitleFileCharacterSetFromLanguage(language);
// This assumption should only be made for external subtitles
if (!string.IsNullOrWhiteSpace(charsetFromLanguage) && !string.Equals(charsetFromLanguage, "windows-1252", StringComparison.OrdinalIgnoreCase))
{
return charsetFromLanguage;
}
var charset = await DetectCharset(path, language, protocol, cancellationToken).ConfigureAwait(false); var charset = await DetectCharset(path, language, protocol, cancellationToken).ConfigureAwait(false);
if (!string.IsNullOrWhiteSpace(charset)) if (!string.IsNullOrWhiteSpace(charset))
@ -756,7 +746,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
return charset; return charset;
} }
return charsetFromLanguage; if (!string.IsNullOrWhiteSpace(language))
{
return GetSubtitleFileCharacterSetFromLanguage(language);
}
return null;
} }
public string GetSubtitleFileCharacterSetFromLanguage(string language) public string GetSubtitleFileCharacterSetFromLanguage(string language)

@ -21,6 +21,7 @@
NumVideoStreams = 17, NumVideoStreams = 17,
IsSecondaryAudio = 18, IsSecondaryAudio = 18,
VideoCodecTag = 19, VideoCodecTag = 19,
IsAvc = 20 IsAvc = 20,
IsInterlaced = 21
} }
} }

@ -231,6 +231,7 @@ namespace MediaBrowser.Model.Dlna
{ {
playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(','); playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(',');
} }
playlistItem.SubProtocol = transcodingProfile.Protocol; playlistItem.SubProtocol = transcodingProfile.Protocol;
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>(); List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
@ -479,7 +480,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(','); playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(',');
playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.VideoCodecs = transcodingProfile.VideoCodec.Split(',');
playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps; playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps;
playlistItem.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest; playlistItem.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
@ -1137,6 +1138,37 @@ namespace MediaBrowser.Model.Dlna
break; break;
} }
case ProfileConditionValue.IsAnamorphic: case ProfileConditionValue.IsAnamorphic:
{
bool isAnamorphic;
if (bool.TryParse(value, out isAnamorphic))
{
if (isAnamorphic && condition.Condition == ProfileConditionType.Equals)
{
item.RequireNonAnamorphic = true;
}
else if (!isAnamorphic && condition.Condition == ProfileConditionType.NotEquals)
{
item.RequireNonAnamorphic = true;
}
}
break;
}
case ProfileConditionValue.IsInterlaced:
{
bool isInterlaced;
if (bool.TryParse(value, out isInterlaced))
{
if (isInterlaced && condition.Condition == ProfileConditionType.Equals)
{
item.DeInterlace = true;
}
else if (!isInterlaced && condition.Condition == ProfileConditionType.NotEquals)
{
item.DeInterlace = true;
}
}
break;
}
case ProfileConditionValue.AudioProfile: case ProfileConditionValue.AudioProfile:
case ProfileConditionValue.Has64BitOffsets: case ProfileConditionValue.Has64BitOffsets:
case ProfileConditionValue.PacketLength: case ProfileConditionValue.PacketLength:

@ -18,6 +18,7 @@ namespace MediaBrowser.Model.Dlna
public StreamInfo() public StreamInfo()
{ {
AudioCodecs = new string[] { }; AudioCodecs = new string[] { };
VideoCodecs = new string[] { };
SubtitleCodecs = new string[] { }; SubtitleCodecs = new string[] { };
} }
@ -34,13 +35,15 @@ namespace MediaBrowser.Model.Dlna
public long StartPositionTicks { get; set; } public long StartPositionTicks { get; set; }
public string VideoCodec { get; set; }
public string VideoProfile { get; set; } public string VideoProfile { get; set; }
public bool RequireAvc { get; set; } public bool RequireAvc { get; set; }
public bool DeInterlace { get; set; }
public bool RequireNonAnamorphic { get; set; }
public bool CopyTimestamps { get; set; } public bool CopyTimestamps { get; set; }
public bool EnableSubtitlesInManifest { get; set; } public bool EnableSubtitlesInManifest { get; set; }
public string[] AudioCodecs { get; set; } public string[] AudioCodecs { get; set; }
public string[] VideoCodecs { get; set; }
public int? AudioStreamIndex { get; set; } public int? AudioStreamIndex { get; set; }
@ -204,11 +207,15 @@ namespace MediaBrowser.Model.Dlna
string.Empty : string.Empty :
string.Join(",", item.AudioCodecs); string.Join(",", item.AudioCodecs);
string videoCodecs = item.VideoCodecs.Length == 0 ?
string.Empty :
string.Join(",", item.VideoCodecs);
list.Add(new NameValuePair("DeviceProfileId", item.DeviceProfileId ?? string.Empty)); list.Add(new NameValuePair("DeviceProfileId", item.DeviceProfileId ?? string.Empty));
list.Add(new NameValuePair("DeviceId", item.DeviceId ?? string.Empty)); list.Add(new NameValuePair("DeviceId", item.DeviceId ?? string.Empty));
list.Add(new NameValuePair("MediaSourceId", item.MediaSourceId ?? string.Empty)); list.Add(new NameValuePair("MediaSourceId", item.MediaSourceId ?? string.Empty));
list.Add(new NameValuePair("Static", item.IsDirectStream.ToString().ToLower())); list.Add(new NameValuePair("Static", item.IsDirectStream.ToString().ToLower()));
list.Add(new NameValuePair("VideoCodec", item.VideoCodec ?? string.Empty)); list.Add(new NameValuePair("VideoCodec", videoCodecs));
list.Add(new NameValuePair("AudioCodec", audioCodecs)); list.Add(new NameValuePair("AudioCodec", audioCodecs));
list.Add(new NameValuePair("AudioStreamIndex", item.AudioStreamIndex.HasValue ? StringHelper.ToStringCultureInvariant(item.AudioStreamIndex.Value) : string.Empty)); list.Add(new NameValuePair("AudioStreamIndex", item.AudioStreamIndex.HasValue ? StringHelper.ToStringCultureInvariant(item.AudioStreamIndex.Value) : string.Empty));
list.Add(new NameValuePair("SubtitleStreamIndex", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? StringHelper.ToStringCultureInvariant(item.SubtitleStreamIndex.Value) : string.Empty)); list.Add(new NameValuePair("SubtitleStreamIndex", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? StringHelper.ToStringCultureInvariant(item.SubtitleStreamIndex.Value) : string.Empty));
@ -232,7 +239,9 @@ namespace MediaBrowser.Model.Dlna
// } // }
//} //}
if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls") && !forceStartPosition) var isHls = StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls");
if (isHls && !forceStartPosition)
{ {
list.Add(new NameValuePair("StartTimeTicks", string.Empty)); list.Add(new NameValuePair("StartTimeTicks", string.Empty));
} }
@ -276,6 +285,14 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("SubtitleCodec", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Embed ? subtitleCodecs : string.Empty)); list.Add(new NameValuePair("SubtitleCodec", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Embed ? subtitleCodecs : string.Empty));
list.Add(new NameValuePair("RequireNonAnamorphic", item.RequireNonAnamorphic.ToString().ToLower()));
list.Add(new NameValuePair("DeInterlace", item.DeInterlace.ToString().ToLower()));
if (!isDlna && isHls)
{
list.Add(new NameValuePair("SegmentContainer", item.Container ?? string.Empty));
}
return list; return list;
} }
@ -609,6 +626,31 @@ namespace MediaBrowser.Model.Dlna
} }
} }
public string TargetVideoCodec
{
get
{
MediaStream stream = TargetVideoStream;
string inputCodec = stream == null ? null : stream.Codec;
if (IsDirectStream)
{
return inputCodec;
}
foreach (string codec in VideoCodecs)
{
if (StringHelper.EqualsIgnoreCase(codec, inputCodec))
{
return codec;
}
}
return VideoCodecs.Length == 0 ? null : VideoCodecs[0];
}
}
/// <summary> /// <summary>
/// Predicts the audio channels that will be in the output stream /// Predicts the audio channels that will be in the output stream
/// </summary> /// </summary>

@ -45,14 +45,21 @@ namespace MediaBrowser.Providers.Music
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken) public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken)
{ {
var releaseId = searchInfo.GetReleaseId(); var releaseId = searchInfo.GetReleaseId();
var releaseGroupId = searchInfo.GetReleaseGroupId();
string url = null; string url = null;
var isNameSearch = false; var isNameSearch = false;
bool forceMusicBrainzProper = false;
if (!string.IsNullOrEmpty(releaseId)) if (!string.IsNullOrEmpty(releaseId))
{ {
url = string.Format("/ws/2/release/?query=reid:{0}", releaseId); url = string.Format("/ws/2/release/?query=reid:{0}", releaseId);
} }
else if (!string.IsNullOrEmpty(releaseGroupId))
{
url = string.Format("/ws/2/release?release-group={0}", releaseGroupId);
forceMusicBrainzProper = true;
}
else else
{ {
var artistMusicBrainzId = searchInfo.GetMusicBrainzArtistId(); var artistMusicBrainzId = searchInfo.GetMusicBrainzArtistId();
@ -75,7 +82,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrWhiteSpace(url)) if (!string.IsNullOrWhiteSpace(url))
{ {
using (var stream = await GetMusicBrainzResponse(url, isNameSearch, cancellationToken).ConfigureAwait(false)) using (var stream = await GetMusicBrainzResponse(url, isNameSearch, forceMusicBrainzProper, cancellationToken).ConfigureAwait(false))
{ {
return GetResultsFromResponse(stream); return GetResultsFromResponse(stream);
} }
@ -131,7 +138,14 @@ namespace MediaBrowser.Providers.Music
Item = new MusicAlbum() Item = new MusicAlbum()
}; };
if (string.IsNullOrEmpty(releaseId)) // If we have a release group Id but not a release Id...
if (string.IsNullOrWhiteSpace(releaseId) && !string.IsNullOrWhiteSpace(releaseGroupId))
{
releaseId = await GetReleaseIdFromReleaseGroupId(releaseGroupId, cancellationToken).ConfigureAwait(false);
result.HasMetadata = true;
}
if (string.IsNullOrWhiteSpace(releaseId))
{ {
var artistMusicBrainzId = id.GetMusicBrainzArtistId(); var artistMusicBrainzId = id.GetMusicBrainzArtistId();
@ -139,13 +153,13 @@ namespace MediaBrowser.Providers.Music
if (releaseResult != null) if (releaseResult != null)
{ {
if (!string.IsNullOrEmpty(releaseResult.ReleaseId)) if (!string.IsNullOrWhiteSpace(releaseResult.ReleaseId))
{ {
releaseId = releaseResult.ReleaseId; releaseId = releaseResult.ReleaseId;
result.HasMetadata = true; result.HasMetadata = true;
} }
if (!string.IsNullOrEmpty(releaseResult.ReleaseGroupId)) if (!string.IsNullOrWhiteSpace(releaseResult.ReleaseGroupId))
{ {
releaseGroupId = releaseResult.ReleaseGroupId; releaseGroupId = releaseResult.ReleaseGroupId;
result.HasMetadata = true; result.HasMetadata = true;
@ -157,13 +171,13 @@ namespace MediaBrowser.Providers.Music
} }
// If we have a release Id but not a release group Id... // If we have a release Id but not a release group Id...
if (!string.IsNullOrEmpty(releaseId) && string.IsNullOrEmpty(releaseGroupId)) if (!string.IsNullOrWhiteSpace(releaseId) && string.IsNullOrWhiteSpace(releaseGroupId))
{ {
releaseGroupId = await GetReleaseGroupId(releaseId, cancellationToken).ConfigureAwait(false); releaseGroupId = await GetReleaseGroupFromReleaseId(releaseId, cancellationToken).ConfigureAwait(false);
result.HasMetadata = true; result.HasMetadata = true;
} }
if (!string.IsNullOrEmpty(releaseId) || !string.IsNullOrEmpty(releaseGroupId)) if (!string.IsNullOrWhiteSpace(releaseId) || !string.IsNullOrWhiteSpace(releaseGroupId))
{ {
result.HasMetadata = true; result.HasMetadata = true;
} }
@ -411,13 +425,42 @@ namespace MediaBrowser.Providers.Music
} }
} }
private async Task<string> GetReleaseIdFromReleaseGroupId(string releaseGroupId, CancellationToken cancellationToken)
{
var url = string.Format("/ws/2/release?release-group={0}", releaseGroupId);
using (var stream = await GetMusicBrainzResponse(url, true, true, cancellationToken).ConfigureAwait(false))
{
using (var oReader = new StreamReader(stream, Encoding.UTF8))
{
var settings = _xmlSettings.Create(false);
settings.CheckCharacters = false;
settings.IgnoreProcessingInstructions = true;
settings.IgnoreComments = true;
using (var reader = XmlReader.Create(oReader, settings))
{
var result = ReleaseResult.Parse(reader).FirstOrDefault();
if (result != null)
{
return result.ReleaseId;
}
}
}
}
return null;
}
/// <summary> /// <summary>
/// Gets the release group id internal. /// Gets the release group id internal.
/// </summary> /// </summary>
/// <param name="releaseEntryId">The release entry id.</param> /// <param name="releaseEntryId">The release entry id.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.String}.</returns> /// <returns>Task{System.String}.</returns>
private async Task<string> GetReleaseGroupId(string releaseEntryId, CancellationToken cancellationToken) private async Task<string> GetReleaseGroupFromReleaseId(string releaseEntryId, CancellationToken cancellationToken)
{ {
var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId); var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId);
@ -514,11 +557,11 @@ namespace MediaBrowser.Providers.Music
private List<MbzUrl> _mbzUrls = null; private List<MbzUrl> _mbzUrls = null;
private MbzUrl _chosenUrl; private MbzUrl _chosenUrl;
private async Task<MbzUrl> GetMbzUrl() private async Task<MbzUrl> GetMbzUrl(bool forceMusicBrainzProper = false)
{ {
if (_chosenUrl == null || _mbzUrls == null || (DateTime.UtcNow.Ticks - _lastMbzUrlQueryTicks) > TimeSpan.FromHours(12).Ticks) if (_chosenUrl == null || _mbzUrls == null || (DateTime.UtcNow.Ticks - _lastMbzUrlQueryTicks) > TimeSpan.FromHours(12).Ticks)
{ {
var urls = await RefreshMzbUrls().ConfigureAwait(false); var urls = await RefreshMzbUrls(forceMusicBrainzProper).ConfigureAwait(false);
if (urls.Count > 1) if (urls.Count > 1)
{ {
@ -533,10 +576,23 @@ namespace MediaBrowser.Providers.Music
return _chosenUrl; return _chosenUrl;
} }
private async Task<List<MbzUrl>> RefreshMzbUrls() private async Task<List<MbzUrl>> RefreshMzbUrls(bool forceMusicBrainzProper = false)
{ {
List<MbzUrl> list; List<MbzUrl> list;
if (forceMusicBrainzProper)
{
list = new List<MbzUrl>
{
new MbzUrl
{
url = MusicBrainzBaseUrl,
throttleMs = 1000
}
};
}
else
{
try try
{ {
var options = new HttpRequestOptions var options = new HttpRequestOptions
@ -566,22 +622,24 @@ namespace MediaBrowser.Providers.Music
} }
}; };
} }
}
_mbzUrls = list.ToList(); _mbzUrls = list.ToList();
return list; return list;
} }
internal Task<Stream> GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken)
{
return GetMusicBrainzResponse(url, isSearch, false, cancellationToken);
}
/// <summary> /// <summary>
/// Gets the music brainz response. /// Gets the music brainz response.
/// </summary> /// </summary>
/// <param name="url">The URL.</param> internal async Task<Stream> GetMusicBrainzResponse(string url, bool isSearch, bool forceMusicBrainzProper, CancellationToken cancellationToken)
/// <param name="isSearch">if set to <c>true</c> [is search].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{XmlDocument}.</returns>
internal async Task<Stream> GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken)
{ {
var urlInfo = await GetMbzUrl().ConfigureAwait(false); var urlInfo = await GetMbzUrl(forceMusicBrainzProper).ConfigureAwait(false);
var throttleMs = urlInfo.throttleMs; var throttleMs = urlInfo.throttleMs;
if (throttleMs > 0) if (throttleMs > 0)

@ -1,3 +1,3 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("3.2.7.5")] [assembly: AssemblyVersion("3.2.8.1")]

Loading…
Cancel
Save