diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 670acd37f..5166d5413 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -296,8 +296,8 @@ {4f26d5d8-a7b0-42b3-ba42-7cb7d245934e} SocketHttpListener.Portable - - ..\packages\Emby.XmlTv.1.0.7\lib\portable-net45+win8\Emby.XmlTv.dll + + ..\packages\Emby.XmlTv.1.0.8\lib\portable-net45+win8\Emby.XmlTv.dll True diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 21c4006a6..fc0a826b4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -268,12 +268,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings var results = reader.GetChannels(); // Should this method be async? - return results.Select(c => new ChannelInfo() + return results.Select(c => new ChannelInfo { Id = c.Id, Name = c.DisplayName, ImageUrl = c.Icon != null && !String.IsNullOrEmpty(c.Icon.Source) ? c.Icon.Source : null, - Number = c.Id + Number = string.IsNullOrWhiteSpace(c.Number) ? c.Id : c.Number }).ToList(); } diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config index ccabbc27b..ac4e885c7 100644 --- a/Emby.Server.Implementations/packages.config +++ b/Emby.Server.Implementations/packages.config @@ -1,6 +1,6 @@  - + diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 5eea7598b..1b6d55e33 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -912,7 +912,12 @@ namespace MediaBrowser.Api.Playback.Hls 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}\"", + var videoCodec = EncodingHelper.GetVideoEncoder(state, ApiEntryPoint.Instance.GetEncodingOptions()); + var breakOnNonKeyFrames = state.Request.BreakOnNonKeyFrames && string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase); + + var breakOnNonKeyFramesArg = breakOnNonKeyFrames ? " -break_non_keyframes 1" : ""; + + 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{12} -segment_format {11} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"", inputModifier, EncodingHelper.GetInputArgument(state, encodingOptions), threads, @@ -924,7 +929,8 @@ namespace MediaBrowser.Api.Playback.Hls outputPath, outputTsArg, timeDeltaParam, - segmentFormat + segmentFormat, + breakOnNonKeyFramesArg ).Trim(); } diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 4e4e8858e..0ee0dab30 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -127,7 +127,7 @@ namespace MediaBrowser.Api.Playback SetDeviceSpecificData(item, result.MediaSource, profile, authInfo, request.MaxStreamingBitrate, request.StartTimeTicks ?? 0, result.MediaSource.Id, request.AudioStreamIndex, - request.SubtitleStreamIndex, request.MaxAudioChannels, request.PlaySessionId, request.UserId, true, true, true, true); + request.SubtitleStreamIndex, request.MaxAudioChannels, request.PlaySessionId, request.UserId, true, true, true, true, true, true); } else { @@ -169,7 +169,7 @@ namespace MediaBrowser.Api.Playback { var mediaSourceId = request.MediaSourceId; - SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.MaxAudioChannels, request.UserId, request.EnableDirectPlay, request.ForceDirectPlayRemoteMediaSource, request.EnableDirectStream, request.EnableTranscoding); + SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.MaxAudioChannels, request.UserId, request.EnableDirectPlay, request.ForceDirectPlayRemoteMediaSource, request.EnableDirectStream, request.EnableTranscoding, request.AllowVideoStreamCopy, request.AllowAudioStreamCopy); } return info; @@ -255,13 +255,15 @@ namespace MediaBrowser.Api.Playback bool enableDirectPlay, bool forceDirectPlayRemoteMediaSource, bool enableDirectStream, - bool enableTranscoding) + bool enableTranscoding, + bool allowVideoStreamCopy, + bool allowAudioStreamCopy) { var item = _libraryManager.GetItemById(itemId); foreach (var mediaSource in result.MediaSources) { - SetDeviceSpecificData(item, mediaSource, profile, auth, maxBitrate, startTimeTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, maxAudioChannels, result.PlaySessionId, userId, enableDirectPlay, forceDirectPlayRemoteMediaSource, enableDirectStream, enableTranscoding); + SetDeviceSpecificData(item, mediaSource, profile, auth, maxBitrate, startTimeTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, maxAudioChannels, result.PlaySessionId, userId, enableDirectPlay, forceDirectPlayRemoteMediaSource, enableDirectStream, enableTranscoding, allowVideoStreamCopy, allowAudioStreamCopy); } SortMediaSources(result, maxBitrate); @@ -282,7 +284,9 @@ namespace MediaBrowser.Api.Playback bool enableDirectPlay, bool forceDirectPlayRemoteMediaSource, bool enableDirectStream, - bool enableTranscoding) + bool enableTranscoding, + bool allowVideoStreamCopy, + bool allowAudioStreamCopy) { var streamBuilder = new StreamBuilder(_mediaEncoder, Logger); @@ -418,6 +422,15 @@ namespace MediaBrowser.Api.Playback { streamInfo.StartPositionTicks = startTimeTicks; mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).TrimStart('-'); + + if (!allowVideoStreamCopy) + { + mediaSource.TranscodingUrl += "&allowVideoStreamCopy=false"; + } + if (!allowAudioStreamCopy) + { + mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false"; + } mediaSource.TranscodingContainer = streamInfo.Container; mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol; } diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index 551dbf378..ecb6350cd 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -43,6 +43,7 @@ namespace MediaBrowser.Api.Playback public int? SegmentLength { get; set; } public int? MinSegments { get; set; } + public bool BreakOnNonKeyFrames { get; set; } } public class VideoStreamRequest : StreamRequest diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index dd31d39b1..996009524 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -188,6 +188,14 @@ namespace MediaBrowser.Controller.MediaEncoding { return null; } + if (string.Equals(container, "ogm", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + if (string.Equals(container, "divx", StringComparison.OrdinalIgnoreCase)) + { + return null; + } // Seeing reported failures here, not sure yet if this is related to specfying input format if (string.Equals(container, "m4v", StringComparison.OrdinalIgnoreCase)) @@ -750,6 +758,11 @@ namespace MediaBrowser.Controller.MediaEncoding var request = state.BaseRequest; + if (!request.AllowVideoStreamCopy) + { + return false; + } + if (videoStream.IsInterlaced) { if (request.DeInterlace) @@ -895,6 +908,11 @@ namespace MediaBrowser.Controller.MediaEncoding var request = state.BaseRequest; + if (!request.AllowAudioStreamCopy) + { + return false; + } + // Source and target codecs must match if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index 73be78dc9..f044db3d0 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -72,6 +72,9 @@ namespace MediaBrowser.Controller.MediaEncoding [ApiMember(Name = "EnableAutoStreamCopy", Description = "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool EnableAutoStreamCopy { get; set; } + public bool AllowVideoStreamCopy { get; set; } + public bool AllowAudioStreamCopy { get; set; } + /// /// Gets or sets the audio sample rate. /// @@ -218,6 +221,8 @@ namespace MediaBrowser.Controller.MediaEncoding public BaseEncodingJobOptions() { EnableAutoStreamCopy = true; + AllowVideoStreamCopy = true; + AllowAudioStreamCopy = true; Context = EncodingContext.Streaming; } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 36df67b34..120238967 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -484,6 +484,8 @@ namespace MediaBrowser.Model.Dlna playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps; playlistItem.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest; + playlistItem.BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames; + if (transcodingProfile.MinSegments > 0) { playlistItem.MinSegments = transcodingProfile.MinSegments; diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 5705e6477..2c009b37f 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -40,6 +40,7 @@ namespace MediaBrowser.Model.Dlna public int? SegmentLength { get; set; } public int? MinSegments { get; set; } + public bool BreakOnNonKeyFrames { get; set; } public bool RequireAvc { get; set; } public bool DeInterlace { get; set; } @@ -305,6 +306,8 @@ namespace MediaBrowser.Model.Dlna { list.Add(new NameValuePair("MinSegments", item.MinSegments.Value.ToString(CultureInfo.InvariantCulture))); } + + list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString())); } return list; diff --git a/MediaBrowser.Model/Dlna/StreamInfoSorter.cs b/MediaBrowser.Model/Dlna/StreamInfoSorter.cs index 425fb9c93..badd3c5b1 100644 --- a/MediaBrowser.Model/Dlna/StreamInfoSorter.cs +++ b/MediaBrowser.Model/Dlna/StreamInfoSorter.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.MediaInfo; +using System; +using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Session; using System.Collections.Generic; using System.Linq; @@ -47,16 +48,11 @@ namespace MediaBrowser.Model.Dlna { if (i.MediaSource.Bitrate.HasValue) { - if (i.MediaSource.Bitrate.Value <= maxBitrate.Value) - { - return 0; - } - - return 2; + return Math.Abs(i.MediaSource.Bitrate.Value - maxBitrate.Value); } } - return 1; + return 0; }).ToList(); } diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs index 350556e90..9623a68b0 100644 --- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs @@ -48,6 +48,9 @@ namespace MediaBrowser.Model.Dlna [XmlAttribute("segmentLength")] public int SegmentLength { get; set; } + [XmlAttribute("breakOnNonKeyFrames")] + public bool BreakOnNonKeyFrames { get; set; } + public List GetAudioCodecs() { List list = new List(); diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs index 16c9464ac..0518064c9 100644 --- a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs +++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs @@ -28,6 +28,8 @@ namespace MediaBrowser.Model.MediaInfo public bool EnableDirectStream { get; set; } public bool EnableTranscoding { get; set; } public bool ForceDirectPlayRemoteMediaSource { get; set; } + public bool AllowVideoStreamCopy { get; set; } + public bool AllowAudioStreamCopy { get; set; } public PlaybackInfoRequest() { @@ -35,6 +37,8 @@ namespace MediaBrowser.Model.MediaInfo EnableDirectPlay = true; EnableDirectStream = true; EnableTranscoding = true; + AllowVideoStreamCopy = true; + AllowAudioStreamCopy = true; } } } diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs index ab2cd3bed..1c6157c03 100644 --- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs +++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs @@ -160,12 +160,7 @@ namespace MediaBrowser.Providers.Movies var results = searchResults.results ?? new List(); - var index = 0; - var resultTuples = results.Select(result => new Tuple(result, index++)).ToList(); - - return resultTuples.OrderBy(i => GetSearchResultOrder(i.Item1, year)) - .ThenBy(i => i.Item2) - .Select(i => i.Item1) + return results .Select(i => { var remoteResult = new RemoteSearchResult @@ -217,12 +212,7 @@ namespace MediaBrowser.Providers.Movies var results = searchResults.results ?? new List(); - var index = 0; - var resultTuples = results.Select(result => new Tuple(result, index++)).ToList(); - - return resultTuples.OrderBy(i => GetSearchResultOrder(i.Item1, year)) - .ThenBy(i => i.Item2) - .Select(i => i.Item1) + return results .Select(i => { var remoteResult = new RemoteSearchResult @@ -253,40 +243,6 @@ namespace MediaBrowser.Providers.Movies } } - private int GetSearchResultOrder(TmdbMovieSearchResult result, int? year) - { - if (year.HasValue) - { - DateTime r; - - // These dates are always in this exact format - if (DateTime.TryParseExact(result.release_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r)) - { - // Allow one year tolernace, preserve order from Tmdb - return Math.Abs(r.Year - year.Value); - } - } - - return int.MaxValue; - } - - private int GetSearchResultOrder(TvResult result, int? year) - { - if (year.HasValue) - { - DateTime r; - - // These dates are always in this exact format - if (DateTime.TryParseExact(result.first_air_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r)) - { - // Allow one year tolernace, preserve order from Tmdb - return Math.Abs(r.Year - year.Value); - } - } - - return int.MaxValue; - } - /// /// Class TmdbMovieSearchResult /// diff --git a/SharedVersion.cs b/SharedVersion.cs index 0112684be..9de987955 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.10.1")] +[assembly: AssemblyVersion("3.2.10.2")]