diff options
| author | Luke <luke.pulverenti@gmail.com> | 2017-04-20 23:49:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-04-20 23:49:50 -0400 |
| commit | f525f5a89e68248a81ab7cfdfa044fbe45e51863 (patch) | |
| tree | f029e380a0867d6e8db7895e63d9a69e0cfd426f /MediaBrowser.Controller | |
| parent | 5dca8cb077fb544628f62939bbda292d8c91b637 (diff) | |
| parent | b9fe720e736abacc57ffb846e4ce6644bc110f61 (diff) | |
Merge pull request #2591 from MediaBrowser/beta
Beta
Diffstat (limited to 'MediaBrowser.Controller')
| -rw-r--r-- | MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs | 33 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 66 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Movies/Movie.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/MusicVideo.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Person.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserView.cs | 11 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Video.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/IMediaSourceManager.cs | 11 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 149 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs | 63 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs | 1 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Session/ISessionManager.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Session/SessionInfo.cs | 105 |
14 files changed, 331 insertions, 131 deletions
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 6ad38033a..f40ab3cde 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -9,6 +9,7 @@ using MediaBrowser.Model.Serialization; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Dto; namespace MediaBrowser.Controller.Entities.Audio { @@ -227,7 +228,39 @@ namespace MediaBrowser.Controller.Entities.Audio // Refresh current item await RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false); + if (!refreshOptions.IsAutomated) + { + await RefreshArtists(refreshOptions, cancellationToken).ConfigureAwait(false); + } + progress.Report(100); } + + private async Task RefreshArtists(MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) + { + var artists = AllArtists.Select(i => + { + // This should not be necessary but we're seeing some cases of it + if (string.IsNullOrWhiteSpace(i)) + { + return null; + } + + var artist = LibraryManager.GetArtist(i); + + if (!artist.IsAccessedByName) + { + return null; + } + + return artist; + + }).Where(i => i != null).ToList(); + + foreach (var artist in artists) + { + await artist.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + } + } } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index be41d896d..268fefbd3 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; using MediaBrowser.Model.Channels; @@ -735,9 +736,72 @@ namespace MediaBrowser.Controller.Entities query.ParentId = query.ParentId ?? Id; } + if (RequiresPostFiltering2(query)) + { + return QueryWithPostFiltering2(query); + } + return LibraryManager.GetItemsResult(query); } + private QueryResult<BaseItem> QueryWithPostFiltering2(InternalItemsQuery query) + { + var startIndex = query.StartIndex; + var limit = query.Limit; + + query.StartIndex = null; + query.Limit = null; + + var itemsList = LibraryManager.GetItemList(query); + var user = query.User; + + if (user != null) + { + // needed for boxsets + itemsList = itemsList.Where(i => i.IsVisibleStandalone(query.User)); + } + + IEnumerable<BaseItem> returnItems; + int totalCount = 0; + + if (query.EnableTotalRecordCount) + { + var itemsArray = itemsList.ToArray(); + totalCount = itemsArray.Length; + returnItems = itemsArray; + } + else + { + returnItems = itemsList; + } + + if (limit.HasValue) + { + returnItems = returnItems.Skip(startIndex ?? 0).Take(limit.Value); + } + else if (startIndex.HasValue) + { + returnItems = returnItems.Skip(startIndex.Value); + } + + return new QueryResult<BaseItem> + { + TotalRecordCount = totalCount, + Items = returnItems.ToArray() + }; + } + + private bool RequiresPostFiltering2(InternalItemsQuery query) + { + if (query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], typeof(BoxSet).Name, StringComparison.OrdinalIgnoreCase)) + { + Logger.Debug("Query requires post-filtering due to BoxSet query"); + return true; + } + + return false; + } + private bool RequiresPostFiltering(InternalItemsQuery query) { if (LinkedChildren.Count > 0) @@ -1440,7 +1504,7 @@ namespace MediaBrowser.Controller.Entities { if (itemDto.RecursiveItemCount.Value > 0) { - var unplayedPercentage = (unplayedCount/itemDto.RecursiveItemCount.Value)*100; + var unplayedPercentage = (unplayedCount / itemDto.RecursiveItemCount.Value) * 100; dto.PlayedPercentage = 100 - unplayedPercentage; dto.Played = dto.PlayedPercentage.Value >= 100; } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index ce671a2dc..371be3dfe 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -27,25 +27,16 @@ namespace MediaBrowser.Controller.Entities.Movies RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); RemoteTrailerIds = new List<Guid>(); - Taglines = new List<string>(); } public string AwardSummary { get; set; } - public float? Metascore { get; set; } - public List<Guid> LocalTrailerIds { get; set; } public List<Guid> RemoteTrailerIds { get; set; } public List<MediaUrl> RemoteTrailers { get; set; } /// <summary> - /// Gets or sets the taglines. - /// </summary> - /// <value>The taglines.</value> - public List<string> Taglines { get; set; } - - /// <summary> /// Gets or sets the name of the TMDB collection. /// </summary> /// <value>The name of the TMDB collection.</value> diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index c781ef85b..7344cb8e4 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Entities { get { - return true; + return false; } } diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index b68681d36..005fb2014 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -15,12 +15,6 @@ namespace MediaBrowser.Controller.Entities /// </summary> public class Person : BaseItem, IItemByName, IHasLookupInfo<PersonLookupInfo> { - /// <summary> - /// Gets or sets the place of birth. - /// </summary> - /// <value>The place of birth.</value> - public string PlaceOfBirth { get; set; } - public override List<string> GetUserDataKeys() { var list = base.GetUserDataKeys(); diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index fb00937fb..99601b290 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -153,17 +153,6 @@ namespace MediaBrowser.Controller.Entities return types.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase); } - public static bool IsEligibleForEnhancedView(string viewType) - { - var types = new[] - { - CollectionType.Movies, - CollectionType.TvShows - }; - - return types.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase); - } - public static bool EnableOriginalFolder(string viewType) { var types = new[] diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 890626419..0618fc489 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -484,7 +484,7 @@ namespace MediaBrowser.Controller.Entities return new[] { new FileSystemMetadata { - FullName = System.IO.Path.GetDirectoryName(Path), + FullName = ContainingFolderPath, IsDirectory = true } }; diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 1ab0e4cb0..2f8f37789 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -68,10 +68,9 @@ namespace MediaBrowser.Controller.Library /// Opens the media source. /// </summary> /// <param name="request">The request.</param> - /// <param name="enableAutoClose">if set to <c>true</c> [enable automatic close].</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<MediaSourceInfo>.</returns> - Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken); + Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken); /// <summary> /// Gets the live stream. @@ -82,14 +81,6 @@ namespace MediaBrowser.Controller.Library Task<MediaSourceInfo> GetLiveStream(string id, CancellationToken cancellationToken); Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken); - - /// <summary> - /// Pings the media source. - /// </summary> - /// <param name="id">The live stream identifier.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task PingLiveStream(string id, CancellationToken cancellationToken); /// <summary> /// Closes the media source. diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index c8fa6be8c..7e1dab462 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -367,7 +367,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="items">The items.</param> /// <param name="options">The options.</param> /// <param name="user">The user.</param> - void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user); + Task AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user); /// <summary> /// Called when [recording file deleted]. diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 90ec5aac7..22d09f34a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -663,11 +663,6 @@ namespace MediaBrowser.Controller.MediaEncoding param += string.Format(" -r {0}", framerate.Value.ToString(_usCulture)); } - if (!string.IsNullOrEmpty(state.OutputVideoSync)) - { - param += " -vsync " + state.OutputVideoSync; - } - var request = state.BaseRequest; if (!string.IsNullOrEmpty(request.Profile)) @@ -724,14 +719,15 @@ namespace MediaBrowser.Controller.MediaEncoding } } // nvenc doesn't decode with param -level set ?! - if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)){ - param += ""; + else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) + { + //param += ""; } else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase)) { param += " -level " + level; } - + } if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)) @@ -751,11 +747,6 @@ namespace MediaBrowser.Controller.MediaEncoding public bool CanStreamCopyVideo(EncodingJobInfo state, MediaStream videoStream) { - if (!videoStream.AllowStreamCopy) - { - return false; - } - var request = state.BaseRequest; if (!request.AllowVideoStreamCopy) @@ -901,11 +892,6 @@ namespace MediaBrowser.Controller.MediaEncoding public bool CanStreamCopyAudio(EncodingJobInfo state, MediaStream audioStream, List<string> supportedAudioCodecs) { - if (!audioStream.AllowStreamCopy) - { - return false; - } - var request = state.BaseRequest; if (!request.AllowAudioStreamCopy) @@ -1019,43 +1005,32 @@ namespace MediaBrowser.Controller.MediaEncoding public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions, bool isHls) { - var volParam = string.Empty; - var audioSampleRate = string.Empty; - var channels = state.OutputAudioChannels; + var filters = new List<string>(); + // Boost volume to 200% when downsampling from 6ch to 2ch if (channels.HasValue && channels.Value <= 2) { if (state.AudioStream != null && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5 && !encodingOptions.DownMixAudioBoost.Equals(1)) { - volParam = ",volume=" + encodingOptions.DownMixAudioBoost.ToString(_usCulture); + filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(_usCulture)); } } - if (state.OutputAudioSampleRate.HasValue) - { - audioSampleRate = state.OutputAudioSampleRate.Value + ":"; - } - - var adelay = isHls ? "adelay=1," : string.Empty; - - var pts = string.Empty; - if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode && !state.CopyTimestamps) { var seconds = TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds; - pts = string.Format(",asetpts=PTS-{0}/TB", Math.Round(seconds).ToString(_usCulture)); + filters.Add(string.Format("asetpts=PTS-{0}/TB", Math.Round(seconds).ToString(_usCulture))); } - return string.Format("-af \"{0}aresample={1}async={4}{2}{3}\"", + if (filters.Count > 0) + { + return "-af \"" + string.Join(",", filters.ToArray()) + "\""; + } - adelay, - audioSampleRate, - volParam, - pts, - state.OutputAudioSync); + return string.Empty; } /// <summary> @@ -1287,7 +1262,7 @@ namespace MediaBrowser.Controller.MediaEncoding } var videoSizeParam = string.Empty; - + if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) { videoSizeParam = string.Format("scale={0}:{1}", state.VideoStream.Width.Value.ToString(_usCulture), state.VideoStream.Height.Value.ToString(_usCulture)); @@ -1571,10 +1546,14 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.IsVideoRequest) { + var outputVideoCodec = GetVideoEncoder(state, encodingOptions); + // Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking - if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase) && state.CopyTimestamps) + if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase) && + state.TranscodingType != TranscodingJobType.Progressive && + state.EnableBreakOnNonKeyFrames(outputVideoCodec)) { - //inputModifier += " -noaccurate_seek"; + inputModifier += " -noaccurate_seek"; } if (!string.IsNullOrWhiteSpace(state.InputContainer) && state.VideoType == VideoType.VideoFile && string.IsNullOrWhiteSpace(encodingOptions.HardwareAccelerationType)) @@ -1607,6 +1586,11 @@ namespace MediaBrowser.Controller.MediaEncoding } } + if (state.MediaSource.RequiresLooping) + { + inputModifier += " -stream_loop -1"; + } + return inputModifier; } @@ -1653,7 +1637,6 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.ReadInputAtNativeFramerate || mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase)) { - state.OutputAudioSync = "1000"; state.InputVideoSync = "-1"; state.InputAudioSync = "1"; } @@ -1711,7 +1694,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (state.SubtitleStream == null || state.SubtitleDeliveryMethod != SubtitleDeliveryMethod.Embed) { - return ; + return; } // This is tricky to remux in, after converting to dvdsub it's not positioned correctly @@ -1878,7 +1861,9 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - if (state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase)) + if (state.VideoStream != null && IsH264(state.VideoStream) && + string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && + !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase)) { args += " -bsf:v h264_mp4toannexb"; } @@ -1892,51 +1877,56 @@ namespace MediaBrowser.Controller.MediaEncoding { args += " -flags -global_header -fflags +genpts"; } - - return args; } + else + { + var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"", + 5.ToString(_usCulture)); - var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"", - 5.ToString(_usCulture)); - - args += keyFrameArg; + args += keyFrameArg; - var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - var hasCopyTs = false; - // Add resolution params, if specified - if (!hasGraphicalSubs) - { - var outputSizeParam = GetOutputSizeParam(state, videoCodec); - args += outputSizeParam; - hasCopyTs = outputSizeParam.IndexOf("copyts", StringComparison.OrdinalIgnoreCase) != -1; - } + var hasCopyTs = false; + // Add resolution params, if specified + if (!hasGraphicalSubs) + { + var outputSizeParam = GetOutputSizeParam(state, videoCodec); + args += outputSizeParam; + hasCopyTs = outputSizeParam.IndexOf("copyts", StringComparison.OrdinalIgnoreCase) != -1; + } - if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps) - { - if (!hasCopyTs) + if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps) { - args += " -copyts"; + if (!hasCopyTs) + { + args += " -copyts"; + } + args += " -avoid_negative_ts disabled -start_at_zero"; } - args += " -avoid_negative_ts disabled -start_at_zero"; - } - var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultH264Preset); + var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultH264Preset); - if (!string.IsNullOrEmpty(qualityParam)) - { - args += " " + qualityParam.Trim(); - } + if (!string.IsNullOrEmpty(qualityParam)) + { + args += " " + qualityParam.Trim(); + } - // This is for internal graphical subs - if (hasGraphicalSubs) - { - args += GetGraphicalSubtitleParam(state, videoCodec); + // This is for internal graphical subs + if (hasGraphicalSubs) + { + args += GetGraphicalSubtitleParam(state, videoCodec); + } + + if (!state.RunTimeTicks.HasValue) + { + args += " -flags -global_header"; + } } - if (!state.RunTimeTicks.HasValue) + if (!string.IsNullOrEmpty(state.OutputVideoSync)) { - args += " -flags -global_header"; + args += " -vsync " + state.OutputVideoSync; } return args; @@ -1974,7 +1964,12 @@ namespace MediaBrowser.Controller.MediaEncoding { args += " -ab " + bitrate.Value.ToString(_usCulture); } - + + if (state.OutputAudioSampleRate.HasValue) + { + args += " -ar " + state.OutputAudioSampleRate.Value.ToString(_usCulture); + } + args += " " + GetAudioFilterParam(state, encodingOptions, false); return args; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index f5878864b..f3e6280aa 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -41,8 +41,21 @@ namespace MediaBrowser.Controller.MediaEncoding public string OutputContainer { get; set; } - public string OutputVideoSync = "-1"; - public string OutputAudioSync = "1"; + public string OutputVideoSync + { + get + { + // For live tv + recordings + if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase) || + string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase)) + { + return "cfr"; + } + + return "-1"; + } + } + public string InputAudioSync { get; set; } public string InputVideoSync { get; set; } public TransportStreamTimestamp InputTimestamp { get; set; } @@ -72,10 +85,12 @@ namespace MediaBrowser.Controller.MediaEncoding public int? OutputAudioSampleRate; public bool DeInterlace { get; set; } public bool IsVideoRequest { get; set; } + public TranscodingJobType TranscodingType { get; set; } - public EncodingJobInfo(ILogger logger) + public EncodingJobInfo(ILogger logger, TranscodingJobType jobType) { _logger = logger; + TranscodingType = jobType; RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); PlayableStreamFileNames = new List<string>(); SupportedAudioCodecs = new List<string>(); @@ -83,6 +98,29 @@ namespace MediaBrowser.Controller.MediaEncoding SupportedSubtitleCodecs = new List<string>(); } + public bool IsSegmentedLiveStream + { + get + { + return TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue; + } + } + + public bool EnableBreakOnNonKeyFrames(string videoCodec) + { + if (TranscodingType != TranscodingJobType.Progressive) + { + if (IsSegmentedLiveStream) + { + return false; + } + + return BaseRequest.BreakOnNonKeyFrames && string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase); + } + + return false; + } + /// <summary> /// Predicts the audio sample rate that will be in the output stream /// </summary> @@ -118,4 +156,23 @@ namespace MediaBrowser.Controller.MediaEncoding public abstract void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate); } + + /// <summary> + /// Enum TranscodingJobType + /// </summary> + public enum TranscodingJobType + { + /// <summary> + /// The progressive + /// </summary> + Progressive, + /// <summary> + /// The HLS + /// </summary> + Hls, + /// <summary> + /// The dash + /// </summary> + Dash + } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index 30deae842..632c350ad 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -74,6 +74,7 @@ namespace MediaBrowser.Controller.MediaEncoding public bool AllowVideoStreamCopy { get; set; } public bool AllowAudioStreamCopy { get; set; } + public bool BreakOnNonKeyFrames { get; set; } /// <summary> /// Gets or sets the audio sample rate. diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 387195245..956d4cc95 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -99,6 +99,8 @@ namespace MediaBrowser.Controller.Session /// <exception cref="System.ArgumentNullException"></exception> Task OnPlaybackProgress(PlaybackProgressInfo info); + Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated); + /// <summary> /// Used to report that playback has ended for an item /// </summary> diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 343b15a04..5cef56d1c 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -4,24 +4,30 @@ using System; using System.Collections.Generic; using System.Linq; using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Controller.Session { /// <summary> /// Class SessionInfo /// </summary> - public class SessionInfo + public class SessionInfo : IDisposable { - public SessionInfo() + private ISessionManager _sessionManager; + private readonly ILogger _logger; + + public SessionInfo(ISessionManager sessionManager, ILogger logger) { - QueueableMediaTypes = new List<string>(); + _sessionManager = sessionManager; + _logger = logger; AdditionalUsers = new List<SessionUserInfo>(); PlayState = new PlayerStateInfo(); } public PlayerStateInfo PlayState { get; set; } - + public List<SessionUserInfo> AdditionalUsers { get; set; } public ClientCapabilities Capabilities { get; set; } @@ -33,12 +39,6 @@ namespace MediaBrowser.Controller.Session public string RemoteEndPoint { get; set; } /// <summary> - /// Gets or sets the queueable media types. - /// </summary> - /// <value>The queueable media types.</value> - public List<string> QueueableMediaTypes { get; set; } - - /// <summary> /// Gets or sets the playable media types. /// </summary> /// <value>The playable media types.</value> @@ -133,7 +133,7 @@ namespace MediaBrowser.Controller.Session /// </summary> /// <value>The application icon URL.</value> public string AppIconUrl { get; set; } - + /// <summary> /// Gets or sets the supported commands. /// </summary> @@ -196,5 +196,88 @@ namespace MediaBrowser.Controller.Session { return (UserId ?? Guid.Empty) == userId || AdditionalUsers.Any(i => userId == new Guid(i.UserId)); } + + private readonly object _progressLock = new object(); + private ITimer _progressTimer; + private PlaybackProgressInfo _lastProgressInfo; + + public void StartAutomaticProgress(ITimerFactory timerFactory, PlaybackProgressInfo progressInfo) + { + lock (_progressLock) + { + _lastProgressInfo = progressInfo; + + if (_progressTimer == null) + { + _progressTimer = timerFactory.Create(OnProgressTimerCallback, null, 1000, 1000); + } + else + { + _progressTimer.Change(1000, 1000); + } + } + } + + // 1 second + private const long ProgressIncrement = 10000000; + + private async void OnProgressTimerCallback(object state) + { + var progressInfo = _lastProgressInfo; + if (progressInfo == null) + { + return; + } + if (progressInfo.IsPaused) + { + return; + } + + var positionTicks = progressInfo.PositionTicks ?? 0; + if (positionTicks < 0) + { + positionTicks = 0; + } + + var newPositionTicks = positionTicks + ProgressIncrement; + var item = progressInfo.Item; + long? runtimeTicks = item == null ? null : item.RunTimeTicks; + + // Don't report beyond the runtime + if (runtimeTicks.HasValue && newPositionTicks >= runtimeTicks.Value) + { + return; + } + + progressInfo.PositionTicks = newPositionTicks; + + try + { + await _sessionManager.OnPlaybackProgress(progressInfo, true).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error reporting playback progress", ex); + } + } + + public void StopAutomaticProgress() + { + lock (_progressLock) + { + if (_progressTimer != null) + { + _progressTimer.Dispose(); + _progressTimer = null; + } + _lastProgressInfo = null; + } + } + + public void Dispose() + { + StopAutomaticProgress(); + _sessionManager = null; + } } } |
