aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs4
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs12
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs4
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs4
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs14
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs28
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs41
-rw-r--r--MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs12
-rw-r--r--MediaBrowser.Api/Playback/StreamRequest.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs10
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs4
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs19
-rw-r--r--MediaBrowser.Model/Dlna/ProfileConditionValue.cs3
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs34
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs52
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs120
-rw-r--r--SharedVersion.cs2
20 files changed, 263 insertions, 107 deletions
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index d048dcde1..c7eae91dd 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -208,7 +208,7 @@ namespace Emby.Dlna.Didl
var targetHeight = streamInfo.TargetHeight;
var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader(streamInfo.Container,
- streamInfo.VideoCodec,
+ streamInfo.TargetVideoCodec,
streamInfo.TargetAudioCodec,
targetWidth,
targetHeight,
@@ -352,7 +352,7 @@ namespace Emby.Dlna.Didl
var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
streamInfo.TargetAudioCodec,
- streamInfo.VideoCodec,
+ streamInfo.TargetVideoCodec,
streamInfo.TargetAudioBitrate,
targetWidth,
targetHeight,
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index 3c07e95db..b73332c4b 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -542,7 +542,7 @@ namespace Emby.Dlna.PlayTo
{
var list = new ContentFeatureBuilder(profile)
.BuildVideoHeader(streamInfo.Container,
- streamInfo.VideoCodec,
+ streamInfo.TargetVideoCodec,
streamInfo.TargetAudioCodec,
streamInfo.TargetWidth,
streamInfo.TargetHeight,
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index d18004f96..eea562524 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -2545,14 +2545,24 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
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 configuredDeviceIds = GetConfiguration().TunerHosts
+ .Where(i => !string.IsNullOrWhiteSpace(i.DeviceId))
+ .Select(i => i.DeviceId)
+ .ToList();
+
foreach (var host in _liveTvManager.TunerHosts)
{
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);
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 92ef24dea..8406d44a7 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -160,9 +160,9 @@ namespace Emby.Server.Implementations.LiveTv
}).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)
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 2f7d04936..2d8744f70 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -684,7 +684,7 @@ namespace MediaBrowser.Api.LiveTv
[Authenticated]
public class DiscoverTuners : IReturn<List<TunerHostInfo>>
{
-
+ public bool NewDevicesOnly { get; set; }
}
public class LiveTvService : BaseApiService
@@ -739,7 +739,7 @@ namespace MediaBrowser.Api.LiveTv
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);
}
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index e1559cabf..b3a00cc92 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -697,6 +697,20 @@ namespace MediaBrowser.Api.Playback
{
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);
+ }
+ }
}
}
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index aaca1793c..98115b840 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -41,9 +41,16 @@ namespace MediaBrowser.Api.Playback.Hls
/// <summary>
/// Gets the segment file extension.
/// </summary>
- /// <param name="state">The state.</param>
- /// <returns>System.String.</returns>
- protected abstract string GetSegmentFileExtension(StreamState state);
+ protected string GetSegmentFileExtension(StreamRequest request)
+ {
+ var segmentContainer = request.SegmentContainer;
+ if (!string.IsNullOrWhiteSpace(segmentContainer))
+ {
+ return "." + segmentContainer;
+ }
+
+ return ".ts";
+ }
/// <summary>
/// Gets the type of the transcoding job.
@@ -261,11 +268,17 @@ namespace MediaBrowser.Api.Playback.Hls
var useGenericSegmenter = false;
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;
- 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,
EncodingHelper.GetInputArgument(state, encodingOptions),
threads,
@@ -276,7 +289,8 @@ namespace MediaBrowser.Api.Playback.Hls
startNumberParam,
outputPath,
outputTsArg,
- timeDeltaParam
+ timeDeltaParam,
+ segmentFormat
).Trim();
}
@@ -286,7 +300,7 @@ namespace MediaBrowser.Api.Playback.Hls
var args = string.Format("{0} {1} {2} -map_metadata -1 -map_chapters -1 -threads {3} {4} {5} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero {6} -hls_time {7} -individual_header_trailer 0 -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
itsOffset,
inputModifier,
- EncodingHelper.GetInputArgument(state, encodingOptions),
+ EncodingHelper.GetInputArgument(state, encodingOptions),
threads,
EncodingHelper.GetMapArgs(state),
GetVideoArguments(state),
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 1074a8bc1..f77a66f8e 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -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 string PlaylistId { get; set; }
@@ -77,8 +77,7 @@ namespace MediaBrowser.Api.Playback.Hls
public string SegmentId { get; set; }
}
- [Route("/Audio/{Id}/hls1/{PlaylistId}/{SegmentId}.aac", "GET")]
- [Route("/Audio/{Id}/hls1/{PlaylistId}/{SegmentId}.ts", "GET")]
+ [Route("/Audio/{Id}/hls1/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
public class GetHlsAudioSegment : StreamRequest
{
public string PlaylistId { get; set; }
@@ -158,7 +157,7 @@ namespace MediaBrowser.Api.Playback.Hls
var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex);
- var segmentExtension = GetSegmentFileExtension(state);
+ var segmentExtension = GetSegmentFileExtension(state.Request);
TranscodingJob job = null;
@@ -420,7 +419,7 @@ namespace MediaBrowser.Api.Playback.Hls
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,
@@ -740,7 +739,7 @@ namespace MediaBrowser.Api.Playback.Hls
name,
index.ToString(UsCulture),
- GetSegmentFileExtension(isOutputVideo),
+ GetSegmentFileExtension(request),
queryString));
index++;
@@ -848,7 +847,7 @@ namespace MediaBrowser.Api.Playback.Hls
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";
@@ -897,7 +896,7 @@ namespace MediaBrowser.Api.Playback.Hls
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;
@@ -907,7 +906,13 @@ namespace MediaBrowser.Api.Playback.Hls
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,
EncodingHelper.GetInputArgument(state, encodingOptions),
threads,
@@ -918,7 +923,8 @@ namespace MediaBrowser.Api.Playback.Hls
startNumberParam,
outputPath,
outputTsArg,
- timeDeltaParam
+ timeDeltaParam,
+ segmentFormat
).Trim();
}
@@ -935,20 +941,5 @@ namespace MediaBrowser.Api.Playback.Hls
outputPath
).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";
- }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
index f3683c6cb..bf78e16b3 100644
--- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
+++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
@@ -63,7 +63,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// <summary>
/// Class GetHlsVideoSegment
/// </summary>
- [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.ts", "GET")]
+ [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
public class GetHlsVideoSegmentLegacy : VideoStreamRequest
{
public string PlaylistId { get; set; }
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index c9c6acc1b..f9164c36f 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -99,7 +99,7 @@ namespace MediaBrowser.Api.Playback.Hls
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
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
if (!hasGraphicalSubs)
@@ -118,16 +118,6 @@ namespace MediaBrowser.Api.Playback.Hls
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)
{
}
diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs
index f223c99ef..d1bf9c120 100644
--- a/MediaBrowser.Api/Playback/StreamRequest.cs
+++ b/MediaBrowser.Api/Playback/StreamRequest.cs
@@ -41,6 +41,7 @@ namespace MediaBrowser.Api.Playback
public string PlaySessionId { get; set; }
public string LiveStreamId { get; set; }
public string Tag { get; set; }
+ public string SegmentContainer { get; set; }
}
public class VideoStreamRequest : StreamRequest
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 0dda303a3..5242c5b1f 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -382,7 +382,7 @@ namespace MediaBrowser.Controller.LiveTv
List<IListingsProvider> ListingProviders { get; }
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>> TimerCancelled;
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 6482b6829..db23712ba 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -733,12 +733,18 @@ namespace MediaBrowser.Controller.MediaEncoding
if (videoStream.IsInterlaced)
{
- return false;
+ if (request.DeInterlace)
+ {
+ return false;
+ }
}
if (videoStream.IsAnamorphic ?? false)
{
- return false;
+ if (request.RequireNonAnamorphic)
+ {
+ return false;
+ }
}
// Can't stream copy if we're burning in subtitles
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index 4bb180d4b..6baf87a04 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -46,7 +46,7 @@ namespace MediaBrowser.Controller.MediaEncoding
AudioBitRate = info.AudioBitrate;
AudioSampleRate = info.TargetAudioSampleRate;
DeviceProfile = deviceProfile;
- VideoCodec = info.VideoCodec;
+ VideoCodec = info.TargetVideoCodec;
VideoBitRate = info.VideoBitrate;
AudioStreamIndex = info.AudioStreamIndex;
MaxRefFrames = info.MaxRefFrames;
@@ -185,6 +185,8 @@ namespace MediaBrowser.Controller.MediaEncoding
[ApiMember(Name = "MaxVideoBitDepth", Description = "Optional.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxVideoBitDepth { get; set; }
public bool RequireAvc { get; set; }
+ public bool DeInterlace { get; set; }
+ public bool RequireNonAnamorphic { get; set; }
public int? TranscodingMaxAudioChannels { get; set; }
public int? CpuCoreLimit { get; set; }
public string OutputContainer { get; set; }
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 4a1bf5305..77b976206 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -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);
if (!string.IsNullOrWhiteSpace(charset))
@@ -756,7 +746,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
return charset;
}
- return charsetFromLanguage;
+ if (!string.IsNullOrWhiteSpace(language))
+ {
+ return GetSubtitleFileCharacterSetFromLanguage(language);
+ }
+
+ return null;
}
public string GetSubtitleFileCharacterSetFromLanguage(string language)
@@ -854,4 +849,4 @@ namespace MediaBrowser.MediaEncoding.Subtitles
throw new ArgumentOutOfRangeException("protocol");
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
index 7e2002f17..dbd574f86 100644
--- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
+++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
@@ -21,6 +21,7 @@
NumVideoStreams = 17,
IsSecondaryAudio = 18,
VideoCodecTag = 19,
- IsAvc = 20
+ IsAvc = 20,
+ IsInterlaced = 21
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 480eb23a5..80d3ea3fb 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -231,6 +231,7 @@ namespace MediaBrowser.Model.Dlna
{
playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(',');
}
+
playlistItem.SubProtocol = transcodingProfile.Protocol;
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
@@ -479,7 +480,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(',');
- playlistItem.VideoCodec = transcodingProfile.VideoCodec;
+ playlistItem.VideoCodecs = transcodingProfile.VideoCodec.Split(',');
playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps;
playlistItem.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
@@ -1137,6 +1138,37 @@ namespace MediaBrowser.Model.Dlna
break;
}
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.Has64BitOffsets:
case ProfileConditionValue.PacketLength:
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index a85e6085b..7e42e7fae 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -18,6 +18,7 @@ namespace MediaBrowser.Model.Dlna
public StreamInfo()
{
AudioCodecs = new string[] { };
+ VideoCodecs = new string[] { };
SubtitleCodecs = new string[] { };
}
@@ -34,13 +35,15 @@ namespace MediaBrowser.Model.Dlna
public long StartPositionTicks { get; set; }
- public string VideoCodec { get; set; }
public string VideoProfile { get; set; }
public bool RequireAvc { get; set; }
+ public bool DeInterlace { get; set; }
+ public bool RequireNonAnamorphic { get; set; }
public bool CopyTimestamps { get; set; }
public bool EnableSubtitlesInManifest { get; set; }
public string[] AudioCodecs { get; set; }
+ public string[] VideoCodecs { get; set; }
public int? AudioStreamIndex { get; set; }
@@ -204,11 +207,15 @@ namespace MediaBrowser.Model.Dlna
string.Empty :
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("DeviceId", item.DeviceId ?? string.Empty));
list.Add(new NameValuePair("MediaSourceId", item.MediaSourceId ?? string.Empty));
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("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));
@@ -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));
}
@@ -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("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;
}
@@ -609,9 +626,34 @@ 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>
- /// Predicts the audio channels that will be in the output stream
- /// </summary>
+ /// Predicts the audio channels that will be in the output stream
+ /// </summary>
public long? TargetSize
{
get
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index e6eb0951d..4aefb62c8 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -45,14 +45,21 @@ namespace MediaBrowser.Providers.Music
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken)
{
var releaseId = searchInfo.GetReleaseId();
+ var releaseGroupId = searchInfo.GetReleaseGroupId();
string url = null;
var isNameSearch = false;
+ bool forceMusicBrainzProper = false;
if (!string.IsNullOrEmpty(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
{
var artistMusicBrainzId = searchInfo.GetMusicBrainzArtistId();
@@ -75,7 +82,7 @@ namespace MediaBrowser.Providers.Music
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);
}
@@ -131,7 +138,14 @@ namespace MediaBrowser.Providers.Music
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();
@@ -139,13 +153,13 @@ namespace MediaBrowser.Providers.Music
if (releaseResult != null)
{
- if (!string.IsNullOrEmpty(releaseResult.ReleaseId))
+ if (!string.IsNullOrWhiteSpace(releaseResult.ReleaseId))
{
releaseId = releaseResult.ReleaseId;
result.HasMetadata = true;
}
- if (!string.IsNullOrEmpty(releaseResult.ReleaseGroupId))
+ if (!string.IsNullOrWhiteSpace(releaseResult.ReleaseGroupId))
{
releaseGroupId = releaseResult.ReleaseGroupId;
result.HasMetadata = true;
@@ -157,13 +171,13 @@ namespace MediaBrowser.Providers.Music
}
// 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;
}
- if (!string.IsNullOrEmpty(releaseId) || !string.IsNullOrEmpty(releaseGroupId))
+ if (!string.IsNullOrWhiteSpace(releaseId) || !string.IsNullOrWhiteSpace(releaseGroupId))
{
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>
/// Gets the release group id internal.
/// </summary>
/// <param name="releaseEntryId">The release entry id.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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);
@@ -514,11 +557,11 @@ namespace MediaBrowser.Providers.Music
private List<MbzUrl> _mbzUrls = null;
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)
{
- var urls = await RefreshMzbUrls().ConfigureAwait(false);
+ var urls = await RefreshMzbUrls(forceMusicBrainzProper).ConfigureAwait(false);
if (urls.Count > 1)
{
@@ -533,31 +576,44 @@ namespace MediaBrowser.Providers.Music
return _chosenUrl;
}
- private async Task<List<MbzUrl>> RefreshMzbUrls()
+ private async Task<List<MbzUrl>> RefreshMzbUrls(bool forceMusicBrainzProper = false)
{
List<MbzUrl> list;
- try
+ if (forceMusicBrainzProper)
{
- var options = new HttpRequestOptions
+ list = new List<MbzUrl>
{
- Url = "https://mb3admin.com/admin/service/standards/musicBrainzUrls",
- UserAgent = _appHost.Name + "/" + _appHost.ApplicationVersion
+ new MbzUrl
+ {
+ url = MusicBrainzBaseUrl,
+ throttleMs = 1000
+ }
};
-
- using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
+ }
+ else
+ {
+ try
{
- var results = _json.DeserializeFromStream<List<MbzUrl>>(stream);
+ var options = new HttpRequestOptions
+ {
+ Url = "https://mb3admin.com/admin/service/standards/musicBrainzUrls",
+ UserAgent = _appHost.Name + "/" + _appHost.ApplicationVersion
+ };
+
+ using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
+ {
+ var results = _json.DeserializeFromStream<List<MbzUrl>>(stream);
- list = results;
+ list = results;
+ }
+ _lastMbzUrlQueryTicks = DateTime.UtcNow.Ticks;
}
- _lastMbzUrlQueryTicks = DateTime.UtcNow.Ticks;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting music brainz info", ex);
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting music brainz info", ex);
- list = new List<MbzUrl>
+ list = new List<MbzUrl>
{
new MbzUrl
{
@@ -565,6 +621,7 @@ namespace MediaBrowser.Providers.Music
throttleMs = 1000
}
};
+ }
}
_mbzUrls = list.ToList();
@@ -572,16 +629,17 @@ namespace MediaBrowser.Providers.Music
return list;
}
+ internal Task<Stream> GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken)
+ {
+ return GetMusicBrainzResponse(url, isSearch, false, cancellationToken);
+ }
+
/// <summary>
/// Gets the music brainz response.
/// </summary>
- /// <param name="url">The URL.</param>
- /// <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)
+ internal async Task<Stream> GetMusicBrainzResponse(string url, bool isSearch, bool forceMusicBrainzProper, CancellationToken cancellationToken)
{
- var urlInfo = await GetMbzUrl().ConfigureAwait(false);
+ var urlInfo = await GetMbzUrl(forceMusicBrainzProper).ConfigureAwait(false);
var throttleMs = urlInfo.throttleMs;
if (throttleMs > 0)
diff --git a/SharedVersion.cs b/SharedVersion.cs
index b001cfb52..1c2997eed 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,3 +1,3 @@
using System.Reflection;
-[assembly: AssemblyVersion("3.2.7.5")]
+[assembly: AssemblyVersion("3.2.8.1")]