diff options
| author | Luke <luke.pulverenti@gmail.com> | 2017-10-01 23:35:45 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-10-01 23:35:45 -0400 |
| commit | a73da532d52ae68ad01965dbf368bacc7d56a218 (patch) | |
| tree | a6f05e95515f822dfc129c36554f74f1da4d4c23 /MediaBrowser.Controller | |
| parent | f651fd6ffba80a6f8e54fca7d014622692cc08f7 (diff) | |
| parent | 796f374359d75e22d2095b3f3a8f9b220cacde27 (diff) | |
Merge pull request #2931 from MediaBrowser/beta
Beta
Diffstat (limited to 'MediaBrowser.Controller')
25 files changed, 350 insertions, 187 deletions
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 54faa1443..f74c01994 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -32,6 +32,14 @@ namespace MediaBrowser.Controller.Channels return base.IsVisible(user); } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 16; + value /= 9; + + return value; + } + [IgnoreDataMember] public override bool SupportsInheritedParentImages { diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index d7b68d1e7..542fa5e08 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -117,8 +117,6 @@ namespace MediaBrowser.Controller.Drawing IImageEncoder ImageEncoder { get; set; } - void SaveImageSize(string path, DateTime imageDateModified, ImageSize size); - bool SupportsTransparency(string path); } } diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index 9452446a1..9936b1036 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -21,11 +21,6 @@ namespace MediaBrowser.Controller.Drawing public static IImageProcessor ImageProcessor { get; set; } - public static void SaveImageSize(string path, DateTime dateModified, ImageSize size) - { - ImageProcessor.SaveImageSize(path, dateModified, size); - } - private static ImageSize GetSizeEstimate(ImageProcessingOptions options) { if (options.Width.HasValue && options.Height.HasValue) diff --git a/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs b/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs index cdb6f3f61..d2b4569ba 100644 --- a/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs +++ b/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities.Audio public override double? GetDefaultPrimaryImageAspectRatio() { - return null; + return 1; } } } diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index a61862f28..c06f1cef4 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -42,5 +42,13 @@ namespace MediaBrowser.Controller.Entities return false; } } + + //public override double? GetDefaultPrimaryImageAspectRatio() + //{ + // double value = 16; + // value /= 9; + + // return value; + //} } } diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index a83e084db..5fb9e517c 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -31,6 +31,14 @@ namespace MediaBrowser.Controller.Entities PhysicalFolderIds = EmptyGuidArray; } + //public override double? GetDefaultPrimaryImageAspectRatio() + //{ + // double value = 16; + // value /= 9; + + // return value; + //} + [IgnoreDataMember] public override bool SupportsPlayedStatus { diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 4e78a7fa5..6dc85f3e5 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/MediaBrowser.Controller/Entities/GameGenre.cs @@ -22,6 +22,11 @@ namespace MediaBrowser.Controller.Entities return GetUserDataKeys()[0]; } + public override double? GetDefaultPrimaryImageAspectRatio() + { + return 1; + } + /// <summary> /// Returns the folder containing the item. /// If the item is a folder, it returns the folder itself diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index bbaec14a1..c940b5953 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -44,6 +44,14 @@ namespace MediaBrowser.Controller.Entities } } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 16; + value /= 9; + + return value; + } + /// <summary> /// Gets or sets the game system. /// </summary> diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 790f8938e..569a0dfb8 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -25,6 +25,11 @@ namespace MediaBrowser.Controller.Entities return GetUserDataKeys()[0]; } + public override double? GetDefaultPrimaryImageAspectRatio() + { + return 1; + } + /// <summary> /// Returns the folder containing the item. /// If the item is a folder, it returns the folder itself diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 8e9eac50c..11db633ba 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -62,6 +62,35 @@ namespace MediaBrowser.Controller.Entities return true; } + public override double? GetDefaultPrimaryImageAspectRatio() + { + if (Width.HasValue && Height.HasValue) + { + double width = Width.Value; + double height = Height.Value; + + if (Orientation.HasValue) + { + switch (Orientation.Value) + { + case ImageOrientation.LeftBottom: + case ImageOrientation.LeftTop: + case ImageOrientation.RightBottom: + case ImageOrientation.RightTop: + var temp = height; + height = width; + width = temp; + break; + } + } + + width /= Height.Value; + return width; + } + + return base.GetDefaultPrimaryImageAspectRatio(); + } + public int? Width { get; set; } public int? Height { get; set; } public string CameraMake { get; set; } diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs index af9d8c801..52d743e36 100644 --- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs +++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs @@ -30,5 +30,10 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public override double? GetDefaultPrimaryImageAspectRatio() + { + return 1; + } } } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index e9a794e79..36bbf6886 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -254,6 +254,11 @@ namespace MediaBrowser.Controller.Entities } } + public override double? GetDefaultPrimaryImageAspectRatio() + { + return 1; + } + /// <summary> /// Gets the configuration directory path. /// </summary> diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 66174034d..2152e65cf 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -58,6 +58,14 @@ namespace MediaBrowser.Controller.Entities } } + //public override double? GetDefaultPrimaryImageAspectRatio() + //{ + // double value = 16; + // value /= 9; + + // return value; + //} + public override int GetChildCount(User user) { return GetChildren(user, true).Count; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 3ab82a103..43adc4af6 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -238,12 +238,9 @@ namespace MediaBrowser.Controller.Entities { if (queryParent is UserView) { - return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query); - } - else - { - return GetResult(queryParent.GetChildren(user, true), queryParent, query); + return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, true)), queryParent, query); } + return GetResult(queryParent.GetChildren(user, true), queryParent, query); } } } @@ -1681,7 +1678,7 @@ namespace MediaBrowser.Controller.Entities return true; } - private IEnumerable<Folder> GetMediaFolders(User user) + private IEnumerable<BaseItem> GetMediaFolders(User user) { if (user == null) { @@ -1696,7 +1693,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i)); } - private List<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes) + private List<BaseItem> GetMediaFolders(User user, IEnumerable<string> viewTypes) { if (user == null) { @@ -1717,14 +1714,14 @@ namespace MediaBrowser.Controller.Entities }).ToList(); } - private List<Folder> GetMediaFolders(Folder parent, User user, IEnumerable<string> viewTypes) + private List<BaseItem> GetMediaFolders(Folder parent, User user, IEnumerable<string> viewTypes) { if (parent == null || parent is UserView) { return GetMediaFolders(user, viewTypes); } - return new List<Folder> { parent }; + return new List<BaseItem> { parent }; } private async Task<QueryResult<BaseItem>> GetLiveTvView(Folder queryParent, User user, InternalItemsQuery query) diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index ffb601dc4..8693d867c 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -78,6 +78,14 @@ namespace MediaBrowser.Controller.Entities } } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 16; + value /= 9; + + return value; + } + public override string CreatePresentationUniqueKey() { if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 7d820b007..49b967104 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -32,6 +32,14 @@ namespace MediaBrowser.Controller.Entities } } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 2; + value /= 3; + + return value; + } + [IgnoreDataMember] public override bool SupportsAncestors { diff --git a/MediaBrowser.Controller/IO/StreamHelper.cs b/MediaBrowser.Controller/IO/StreamHelper.cs index af97a0233..106fec41f 100644 --- a/MediaBrowser.Controller/IO/StreamHelper.cs +++ b/MediaBrowser.Controller/IO/StreamHelper.cs @@ -6,11 +6,6 @@ namespace MediaBrowser.Controller.IO { public static class StreamHelper { - public static void CopyTo(Stream source, Stream destination, int bufferSize, CancellationToken cancellationToken) - { - CopyTo(source, destination, bufferSize, null, cancellationToken); - } - public static void CopyTo(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken) { byte[] buffer = new byte[bufferSize]; diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 42c31c629..be85e115c 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -383,7 +383,7 @@ namespace MediaBrowser.Controller.LiveTv event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated; string GetEmbyTvActiveRecordingPath(string id); - Task<LiveStream> GetEmbyTvLiveStream(string id); + Task<ILiveStream> GetEmbyTvLiveStream(string id); ActiveRecordingInfo GetActiveRecordingInfo(string path); diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index fc344298b..2019259c5 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="streamId">The stream identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<MediaSourceInfo>.</returns> - Task<LiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken); + Task<ILiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken); /// <summary> /// Gets the channel stream media sources. /// </summary> @@ -56,4 +56,17 @@ namespace MediaBrowser.Controller.LiveTv /// <returns>Task.</returns> Task Validate(TunerHostInfo info); } + + public interface ILiveStream + { + Task Open(CancellationToken cancellationToken); + Task Close(); + int ConsumerCount { get; } + string OriginalStreamId { get; set; } + bool EnableStreamSharing { get; set; } + ITunerHost TunerHost { get; set; } + MediaSourceInfo OpenedMediaSource { get; set; } + string UniqueId { get; } + List<string> SharedStreamIds { get; } + } } diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs deleted file mode 100644 index 20947462e..000000000 --- a/MediaBrowser.Controller/LiveTv/LiveStream.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.System; - -namespace MediaBrowser.Controller.LiveTv -{ - public class LiveStream - { - public MediaSourceInfo OriginalMediaSource { get; set; } - public MediaSourceInfo OpenedMediaSource { get; set; } - public int ConsumerCount - { - get { return SharedStreamIds.Count; } - } - public ITunerHost TunerHost { get; set; } - public string OriginalStreamId { get; set; } - public bool EnableStreamSharing { get; set; } - public string UniqueId = Guid.NewGuid().ToString("N"); - - public List<string> SharedStreamIds = new List<string>(); - protected readonly IEnvironmentInfo Environment; - protected readonly IFileSystem FileSystem; - const int StreamCopyToBufferSize = 81920; - - public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem) - { - OriginalMediaSource = mediaSource; - Environment = environment; - FileSystem = fileSystem; - OpenedMediaSource = mediaSource; - EnableStreamSharing = true; - } - - public Task Open(CancellationToken cancellationToken) - { - return OpenInternal(cancellationToken); - } - - protected virtual Task OpenInternal(CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - public virtual Task Close() - { - return Task.FromResult(true); - } - - protected Stream GetInputStream(string path, bool allowAsyncFileRead) - { - var fileOpenOptions = FileOpenOptions.SequentialScan; - - if (allowAsyncFileRead) - { - fileOpenOptions |= FileOpenOptions.Asynchronous; - } - - return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions); - } - - protected async Task DeleteTempFile(string path, int retryCount = 0) - { - try - { - FileSystem.DeleteFile(path); - return; - } - catch - { - - } - - if (retryCount > 20) - { - return; - } - - await Task.Delay(500).ConfigureAwait(false); - await DeleteTempFile(path, retryCount + 1).ConfigureAwait(false); - } - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 5ef763b62..b33993859 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -145,7 +145,6 @@ <Compile Include="Library\UserDataSaveEventArgs.cs" /> <Compile Include="LiveTv\IListingsProvider.cs" /> <Compile Include="LiveTv\ITunerHost.cs" /> - <Compile Include="LiveTv\LiveStream.cs" /> <Compile Include="LiveTv\RecordingGroup.cs" /> <Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" /> <Compile Include="LiveTv\ILiveTvRecording.cs" /> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 657b9c959..8b612f809 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -346,7 +346,8 @@ namespace MediaBrowser.Controller.MediaEncoding "Constrained High" }; - return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase)); + // strip spaces because they may be stripped out on the query string + return Array.FindIndex(list.ToArray(), t => string.Equals(t.Replace(" ", ""), profile.Replace(" ", ""), StringComparison.OrdinalIgnoreCase)); } public string GetInputPathArgument(EncodingJobInfo state) @@ -529,7 +530,8 @@ namespace MediaBrowser.Controller.MediaEncoding { var seconds = Math.Round(TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds); - var setPtsParam = state.CopyTimestamps + // hls always copies timestamps + var setPtsParam = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive ? string.Empty : string.Format(",setpts=PTS -{0}/TB", seconds.ToString(_usCulture)); @@ -691,22 +693,26 @@ namespace MediaBrowser.Controller.MediaEncoding param += string.Format(" -r {0}", framerate.Value.ToString(_usCulture)); } - var request = state.BaseRequest; + var targetVideoCodec = state.ActualOutputVideoCodec; - if (!string.IsNullOrEmpty(request.Profile)) + var request = state.BaseRequest; + var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault(); + if (!string.IsNullOrEmpty(profile)) { if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) { // not supported by h264_omx - param += " -profile:v " + request.Profile; + param += " -profile:v " + profile; } } - if (!string.IsNullOrEmpty(request.Level)) + var level = state.GetRequestedLevel(targetVideoCodec); + + if (!string.IsNullOrEmpty(level)) { - var level = NormalizeTranscodingLevel(state.OutputVideoCodec, request.Level); + level = NormalizeTranscodingLevel(state.OutputVideoCodec, level); // h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format // also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307 @@ -756,7 +762,6 @@ namespace MediaBrowser.Controller.MediaEncoding { param += " -level " + level; } - } if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)) @@ -796,7 +801,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (videoStream.IsInterlaced) { - if (request.DeInterlace) + if (state.DeInterlace(videoStream.Codec, false)) { return false; } @@ -828,23 +833,27 @@ namespace MediaBrowser.Controller.MediaEncoding } // Source and target codecs must match - if (string.IsNullOrEmpty(videoStream.Codec) || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase)) + if (string.IsNullOrWhiteSpace(videoStream.Codec) || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase)) { return false; } + var requestedProfiles = state.GetRequestedProfiles(videoStream.Codec); + // If client is requesting a specific video profile, it must match the source - if (!string.IsNullOrEmpty(request.Profile)) + if (requestedProfiles.Length > 0) { - if (string.IsNullOrEmpty(videoStream.Profile)) + if (string.IsNullOrWhiteSpace(videoStream.Profile)) { //return false; } - if (!string.IsNullOrEmpty(videoStream.Profile) && !string.Equals(request.Profile, videoStream.Profile, StringComparison.OrdinalIgnoreCase)) + var requestedProfile = requestedProfiles[0]; + // strip spaces because they may be stripped out on the query string as well + if (!string.IsNullOrWhiteSpace(videoStream.Profile) && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", ""), StringComparer.OrdinalIgnoreCase)) { var currentScore = GetVideoProfileScore(videoStream.Profile); - var requestedScore = GetVideoProfileScore(request.Profile); + var requestedScore = GetVideoProfileScore(requestedProfile); if (currentScore == -1 || currentScore > requestedScore) { @@ -909,11 +918,12 @@ namespace MediaBrowser.Controller.MediaEncoding } // If a specific level was requested, the source must match or be less than - if (!string.IsNullOrEmpty(request.Level)) + var level = state.GetRequestedLevel(videoStream.Codec); + if (!string.IsNullOrEmpty(level)) { double requestLevel; - if (double.TryParse(request.Level, NumberStyles.Any, _usCulture, out requestLevel)) + if (double.TryParse(level, NumberStyles.Any, _usCulture, out requestLevel)) { if (!videoStream.Level.HasValue) { @@ -1074,7 +1084,8 @@ namespace MediaBrowser.Controller.MediaEncoding } } - if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode && !state.CopyTimestamps) + var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive; + if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode && !isCopyingTimestamps) { var seconds = TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds; @@ -1357,9 +1368,10 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add("hwupload"); } - if (state.DeInterlace && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if (state.DeInterlace("h264", true) && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) { - if (string.Equals(options.DeinterlaceMethod, "bobandweave", StringComparison.OrdinalIgnoreCase)) + // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle + if (string.Equals(options.DeinterlaceMethod, "bobandweave", StringComparison.OrdinalIgnoreCase) && (state.VideoStream.RealFrameRate ?? 60) <= 30) { filters.Add("yadif=1:-1:0"); } @@ -1523,11 +1535,18 @@ namespace MediaBrowser.Controller.MediaEncoding /// <returns>System.Int32.</returns> public int GetNumberOfThreads(EncodingJobInfo state, EncodingOptions encodingOptions, bool isWebm) { - var threads = GetNumberOfThreadsInternal(state, encodingOptions, isWebm); + if (isWebm) + { + // Recommended per docs + return Math.Max(Environment.ProcessorCount - 1, 2); + } + + var threads = state.BaseRequest.CpuCoreLimit ?? encodingOptions.EncodingThreadCount; - if (state.BaseRequest.CpuCoreLimit.HasValue && state.BaseRequest.CpuCoreLimit.Value > 0) + // Automatic + if (threads <= 0 || threads >= Environment.ProcessorCount) { - threads = Math.Min(threads, state.BaseRequest.CpuCoreLimit.Value); + return 0; } return threads; @@ -1799,11 +1818,6 @@ namespace MediaBrowser.Controller.MediaEncoding state.InternalSubtitleStreamOffset = mediaStreams.Where(i => i.Type == MediaStreamType.Subtitle && !i.IsExternal).ToList().IndexOf(state.SubtitleStream); } - if (state.VideoStream != null && state.VideoStream.IsInterlaced) - { - state.DeInterlace = true; - } - EnforceResolutionLimit(state); NormalizeSubtitleEmbed(state); @@ -1954,29 +1968,6 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - /// <summary> - /// Gets the number of threads. - /// </summary> - /// <returns>System.Int32.</returns> - private int GetNumberOfThreadsInternal(EncodingJobInfo state, EncodingOptions encodingOptions, bool isWebm) - { - var threads = encodingOptions.EncodingThreadCount; - - if (isWebm) - { - // Recommended per docs - return Math.Max(Environment.ProcessorCount - 1, 2); - } - - // Automatic - if (threads == -1) - { - return 0; - } - - return threads; - } - public string GetSubtitleEmbedArguments(EncodingJobInfo state) { if (state.SubtitleStream == null || state.SubtitleDeliveryMethod != SubtitleDeliveryMethod.Embed) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index e76217fda..506fce3ca 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -160,7 +160,97 @@ namespace MediaBrowser.Controller.MediaEncoding public int? OutputAudioBitrate; public int? OutputAudioChannels; - public bool DeInterlace { get; set; } + + public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced) + { + var videoStream = VideoStream; + var isInputInterlaced = videoStream != null && videoStream.IsInterlaced; + + if (!isInputInterlaced) + { + return false; + } + + // Support general param + if (BaseRequest.DeInterlace) + { + return true; + } + + if (!string.IsNullOrWhiteSpace(videoCodec)) + { + if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + if (forceDeinterlaceIfSourceIsInterlaced) + { + if (isInputInterlaced) + { + return true; + } + } + + return false; + } + + public string[] GetRequestedProfiles(string codec) + { + if (!string.IsNullOrWhiteSpace(BaseRequest.Profile)) + { + return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); + } + + if (!string.IsNullOrWhiteSpace(codec)) + { + var profile = BaseRequest.GetOption(codec, "profile"); + + if (!string.IsNullOrWhiteSpace(profile)) + { + return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); + } + } + + return new string[] { }; + } + + public string GetRequestedLevel(string codec) + { + if (!string.IsNullOrWhiteSpace(BaseRequest.Level)) + { + return BaseRequest.Level; + } + + if (!string.IsNullOrWhiteSpace(codec)) + { + return BaseRequest.GetOption(codec, "level"); + } + + return null; + } + + public int? GetRequestedMaxRefFrames(string codec) + { + if (!string.IsNullOrWhiteSpace(BaseRequest.Level)) + { + return BaseRequest.MaxRefFrames; + } + + if (!string.IsNullOrWhiteSpace(codec)) + { + var value = BaseRequest.GetOption(codec, "maxrefframes"); + int result; + if (!string.IsNullOrWhiteSpace(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result)) + { + return result; + } + } + + return null; + } + public bool IsVideoRequest { get; set; } public TranscodingJobType TranscodingType { get; set; } @@ -169,7 +259,7 @@ namespace MediaBrowser.Controller.MediaEncoding _logger = logger; TranscodingType = jobType; RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - PlayableStreamFileNames = new string[]{}; + PlayableStreamFileNames = new string[] { }; SupportedAudioCodecs = new List<string>(); SupportedVideoCodecs = new List<string>(); SupportedSubtitleCodecs = new List<string>(); @@ -319,12 +409,19 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - var stream = VideoStream; - var request = BaseRequest; + if (BaseRequest.Static) + { + return VideoStream == null ? null : VideoStream.Level; + } - return !string.IsNullOrEmpty(request.Level) && !request.Static - ? double.Parse(request.Level, CultureInfo.InvariantCulture) - : stream == null ? null : stream.Level; + var level = GetRequestedLevel(ActualOutputVideoCodec); + double result; + if (!string.IsNullOrWhiteSpace(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out result)) + { + return result; + } + + return null; } } @@ -348,8 +445,12 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - var stream = VideoStream; - return stream == null || !BaseRequest.Static ? null : stream.RefFrames; + if (BaseRequest.Static) + { + return VideoStream == null ? null : VideoStream.RefFrames; + } + + return null; } } @@ -404,10 +505,18 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - var stream = VideoStream; - return !string.IsNullOrEmpty(BaseRequest.Profile) && !BaseRequest.Static - ? BaseRequest.Profile - : stream == null ? null : stream.Profile; + if (BaseRequest.Static) + { + return VideoStream == null ? null : VideoStream.Profile; + } + + var requestedProfile = GetRequestedProfiles(ActualOutputVideoCodec).FirstOrDefault(); + if (!string.IsNullOrWhiteSpace(requestedProfile)) + { + return requestedProfile; + } + + return null; } } @@ -435,6 +544,28 @@ namespace MediaBrowser.Controller.MediaEncoding } } + public string ActualOutputVideoCodec + { + get + { + var codec = OutputVideoCodec; + + if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) + { + var stream = VideoStream; + + if (stream != null) + { + return stream.Codec; + } + + return null; + } + + return codec; + } + } + public bool? IsTargetInterlaced { get @@ -444,7 +575,7 @@ namespace MediaBrowser.Controller.MediaEncoding return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced; } - if (DeInterlace) + if (DeInterlace(ActualOutputVideoCodec, true)) { return false; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index 5fc93bf38..bac2a6e65 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -1,4 +1,7 @@ -using System.Globalization; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Services; @@ -37,18 +40,16 @@ namespace MediaBrowser.Controller.MediaEncoding MaxWidth = info.MaxWidth; MaxHeight = info.MaxHeight; MaxFramerate = info.MaxFramerate; - Profile = info.VideoProfile; ItemId = info.ItemId; MediaSourceId = info.MediaSourceId; - AudioCodec = info.TargetAudioCodec; + AudioCodec = info.TargetAudioCodec.FirstOrDefault(); MaxAudioChannels = info.MaxAudioChannels; AudioBitRate = info.AudioBitrate; AudioSampleRate = info.TargetAudioSampleRate; DeviceProfile = deviceProfile; - VideoCodec = info.TargetVideoCodec; + VideoCodec = info.TargetVideoCodec.FirstOrDefault(); VideoBitRate = info.VideoBitrate; AudioStreamIndex = info.AudioStreamIndex; - MaxRefFrames = info.MaxRefFrames; MaxVideoBitDepth = info.MaxVideoBitDepth; SubtitleMethod = info.SubtitleDeliveryMethod; Context = info.Context; @@ -58,11 +59,7 @@ namespace MediaBrowser.Controller.MediaEncoding { SubtitleStreamIndex = info.SubtitleStreamIndex; } - - if (info.VideoLevel.HasValue) - { - Level = info.VideoLevel.Value.ToString(_usCulture); - } + StreamOptions = info.StreamOptions; } } @@ -224,12 +221,41 @@ namespace MediaBrowser.Controller.MediaEncoding public EncodingContext Context { get; set; } + public void SetOption(string qualifier, string name, string value) + { + SetOption(qualifier + "-" + name, value); + } + + public Dictionary<string, string> StreamOptions { get; set; } + + public void SetOption(string name, string value) + { + StreamOptions[name] = value; + } + + public string GetOption(string qualifier, string name) + { + return GetOption(qualifier + "-" + name); + } + + public string GetOption(string name) + { + string value; + if (StreamOptions.TryGetValue(name, out value)) + { + return value; + } + + return null; + } + public BaseEncodingJobOptions() { EnableAutoStreamCopy = true; AllowVideoStreamCopy = true; AllowAudioStreamCopy = true; Context = EncodingContext.Streaming; + StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/TV/ITVSeriesManager.cs b/MediaBrowser.Controller/TV/ITVSeriesManager.cs index 0bcb9ae5b..fd41094ee 100644 --- a/MediaBrowser.Controller/TV/ITVSeriesManager.cs +++ b/MediaBrowser.Controller/TV/ITVSeriesManager.cs @@ -15,6 +15,6 @@ namespace MediaBrowser.Controller.TV /// <summary> /// Gets the next up. /// </summary> - QueryResult<BaseItem> GetNextUp(NextUpQuery request, List<Folder> parentsFolders, DtoOptions options); + QueryResult<BaseItem> GetNextUp(NextUpQuery request, List<BaseItem> parentsFolders, DtoOptions options); } } |
