From 1cf6cfb11c6cc80ede364267e4b7cd49ad8bb688 Mon Sep 17 00:00:00 2001 From: Jan Friedrich Date: Tue, 13 Sep 2016 18:29:53 +0200 Subject: fix graphical subtitle transcoding with vaapi --- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs') diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 2ded8a66f..9d8b7fd63 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -487,7 +487,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var videoEncoder = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, encodingOptions); if (videoEncoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) { - arg = "-hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; + arg = "-hwaccel vaapi -hwaccel_output_format yuv420p -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; } } @@ -565,7 +565,20 @@ namespace MediaBrowser.MediaEncoding.Encoder { outputSizeParam = await GetOutputSizeParam(state, outputVideoCodec).ConfigureAwait(false); outputSizeParam = outputSizeParam.TrimEnd('"'); - outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase)); + + if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + { + outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase)); + } + else + { + outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase)); + } + } + + if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && outputSizeParam.Length == 0) + { + outputSizeParam = ",format=nv12|vaapi,hwupload"; } var videoSizeParam = string.Empty; -- cgit v1.2.3 From 3d260bd13c3e2ea21dd6ca0209e1c7b0f7cf1ae9 Mon Sep 17 00:00:00 2001 From: Jan Friedrich Date: Sat, 24 Sep 2016 17:34:54 +0200 Subject: vaapi: copy decoded frames to main memory only when necessary --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 10 +++++++++- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 371247ecd..fe9869664 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1037,7 +1037,15 @@ namespace MediaBrowser.Api.Playback var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions(); if (GetVideoEncoder(state).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) { - arg = "-hwaccel vaapi -hwaccel_output_format yuv420p -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode; + var hwOutputFormat = "vaapi"; + + if (hasGraphicalSubs) + { + hwOutputFormat = "yuv420p"; + } + + arg = "-hwaccel vaapi -hwaccel_output_format " + hwOutputFormat + " -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; } } diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 9d8b7fd63..e8121d178 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -487,7 +487,15 @@ namespace MediaBrowser.MediaEncoding.Encoder var videoEncoder = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, encodingOptions); if (videoEncoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) { - arg = "-hwaccel vaapi -hwaccel_output_format yuv420p -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.Options.SubtitleMethod == SubtitleDeliveryMethod.Encode; + var hwOutputFormat = "vaapi"; + + if (hasGraphicalSubs) + { + hwOutputFormat = "yuv420p"; + } + + arg = "-hwaccel vaapi -hwaccel_output_format " + hwOutputFormat + " -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; } } -- cgit v1.2.3 From c4e137e6cf7a52937e1169d1f170da4b8e72ba6a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 4 Oct 2016 01:15:39 -0400 Subject: update timer listings --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 5 ++- MediaBrowser.Api/Playback/BaseStreamingService.cs | 10 +++-- MediaBrowser.Controller/LiveTv/TimerInfo.cs | 1 + MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 10 +++-- MediaBrowser.Model/Dto/BaseItemDto.cs | 1 + MediaBrowser.Model/LiveTv/TimerQuery.cs | 2 + .../LiveTv/EmbyTV/EmbyTV.cs | 44 ++++++++++++---------- .../LiveTv/EmbyTV/RecordingHelper.cs | 20 +++++----- .../LiveTv/LiveTvDtoService.cs | 1 + .../LiveTv/LiveTvManager.cs | 14 +++++++ 10 files changed, 71 insertions(+), 37 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index ecc17374f..4baae031f 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -315,6 +315,8 @@ namespace MediaBrowser.Api.LiveTv public string SeriesTimerId { get; set; } public bool? IsActive { get; set; } + + public bool? IsScheduled { get; set; } } [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")] @@ -1095,7 +1097,8 @@ namespace MediaBrowser.Api.LiveTv { ChannelId = request.ChannelId, SeriesTimerId = request.SeriesTimerId, - IsActive = request.IsActive + IsActive = request.IsActive, + IsScheduled = request.IsScheduled }, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 7f41cb059..bcf3bd28e 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -463,13 +463,15 @@ namespace MediaBrowser.Api.Playback var level = NormalizeTranscodingLevel(state.OutputVideoCodec, state.VideoRequest.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 if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) + string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) || + string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)) { switch (level) { case "30": - param += " -level 3"; + param += " -level 3.0"; break; case "31": param += " -level 3.1"; @@ -478,7 +480,7 @@ namespace MediaBrowser.Api.Playback param += " -level 3.2"; break; case "40": - param += " -level 4"; + param += " -level 4.0"; break; case "41": param += " -level 4.1"; @@ -487,7 +489,7 @@ namespace MediaBrowser.Api.Playback param += " -level 4.2"; break; case "50": - param += " -level 5"; + param += " -level 5.0"; break; case "51": param += " -level 5.1"; diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs index 978e9e1a8..fd614253a 100644 --- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -106,6 +106,7 @@ namespace MediaBrowser.Controller.LiveTv public string EpisodeTitle { get; set; } public DateTime? OriginalAirDate { get; set; } public bool IsProgramSeries { get; set; } + public bool IsRepeat { get; set; } public string HomePageUrl { get; set; } public float? CommunityRating { get; set; } public string ShortOverview { get; set; } diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index e8121d178..f1e2f7241 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -726,13 +726,15 @@ namespace MediaBrowser.MediaEncoding.Encoder levelString = NormalizeTranscodingLevel(state.OutputVideoCodec, levelString); // 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 if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) + string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) || + string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)) { switch (levelString) { case "30": - param += " -level 3"; + param += " -level 3.0"; break; case "31": param += " -level 3.1"; @@ -741,7 +743,7 @@ namespace MediaBrowser.MediaEncoding.Encoder param += " -level 3.2"; break; case "40": - param += " -level 4"; + param += " -level 4.0"; break; case "41": param += " -level 4.1"; @@ -750,7 +752,7 @@ namespace MediaBrowser.MediaEncoding.Encoder param += " -level 4.2"; break; case "50": - param += " -level 5"; + param += " -level 5.0"; break; case "51": param += " -level 5.1"; diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 9434ab03a..19853fd2b 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -1215,6 +1215,7 @@ namespace MediaBrowser.Model.Dto /// /// The timer identifier. public string TimerId { get; set; } + public RecordingStatus TimerStatus { get; set; } /// /// Gets or sets the current program. /// diff --git a/MediaBrowser.Model/LiveTv/TimerQuery.cs b/MediaBrowser.Model/LiveTv/TimerQuery.cs index 87b6b89ac..310dc486f 100644 --- a/MediaBrowser.Model/LiveTv/TimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/TimerQuery.cs @@ -15,5 +15,7 @@ public string SeriesTimerId { get; set; } public bool? IsActive { get; set; } + + public bool? IsScheduled { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 4530bfcb6..a3ba2c6f8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -629,6 +629,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV existingTimer.IsNews = updatedTimer.IsNews; existingTimer.IsMovie = updatedTimer.IsMovie; existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries; + existingTimer.IsRepeat = updatedTimer.IsRepeat; existingTimer.IsSports = updatedTimer.IsSports; existingTimer.Name = updatedTimer.Name; existingTimer.OfficialRating = updatedTimer.OfficialRating; @@ -665,8 +666,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var excludeStatues = new List { - RecordingStatus.Completed, - RecordingStatus.Cancelled + RecordingStatus.Completed }; var timers = _timerProvider.GetAll() @@ -1591,6 +1591,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private bool ShouldCancelTimerForSeriesTimer(SeriesTimerInfo seriesTimer, TimerInfo timer) { + if (!seriesTimer.RecordAnyTime) + { + if (Math.Abs(seriesTimer.StartDate.TimeOfDay.Ticks - timer.StartDate.TimeOfDay.Ticks) >= TimeSpan.FromMinutes(5).Ticks) + { + return true; + } + + if (!seriesTimer.Days.Contains(timer.StartDate.ToLocalTime().DayOfWeek)) + { + return true; + } + } + + if (seriesTimer.RecordNewOnly && timer.IsRepeat) + { + return true; + } + + if (!seriesTimer.RecordAnyChannel && !string.Equals(timer.ChannelId, seriesTimer.ChannelId, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + return seriesTimer.SkipEpisodesInLibrary && IsProgramAlreadyInLibrary(timer); } @@ -1734,23 +1757,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private IEnumerable GetProgramsForSeries(SeriesTimerInfo seriesTimer, IEnumerable allPrograms) { - if (!seriesTimer.RecordAnyTime) - { - allPrograms = allPrograms.Where(epg => Math.Abs(seriesTimer.StartDate.TimeOfDay.Ticks - epg.StartDate.TimeOfDay.Ticks) < TimeSpan.FromMinutes(5).Ticks); - - allPrograms = allPrograms.Where(i => seriesTimer.Days.Contains(i.StartDate.ToLocalTime().DayOfWeek)); - } - - if (seriesTimer.RecordNewOnly) - { - allPrograms = allPrograms.Where(epg => !epg.IsRepeat); - } - - if (!seriesTimer.RecordAnyChannel) - { - allPrograms = allPrograms.Where(epg => string.Equals(epg.ChannelId, seriesTimer.ChannelId, StringComparison.OrdinalIgnoreCase)); - } - if (string.IsNullOrWhiteSpace(seriesTimer.SeriesId)) { _logger.Error("seriesTimer.SeriesId is null. Cannot find programs for series"); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index bb6935e8e..f7b4b3fde 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.LiveTv; using System; using System.Globalization; +using MediaBrowser.Model.LiveTv; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { @@ -12,24 +13,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return timer.StartDate.AddSeconds(-timer.PrePaddingSeconds); } - public static TimerInfo CreateTimer(ProgramInfo parent, SeriesTimerInfo series) + public static TimerInfo CreateTimer(ProgramInfo parent, SeriesTimerInfo seriesTimer) { var timer = new TimerInfo(); timer.ChannelId = parent.ChannelId; - timer.Id = (series.Id + parent.Id).GetMD5().ToString("N"); + timer.Id = (seriesTimer.Id + parent.Id).GetMD5().ToString("N"); timer.StartDate = parent.StartDate; timer.EndDate = parent.EndDate; timer.ProgramId = parent.Id; - timer.PrePaddingSeconds = series.PrePaddingSeconds; - timer.PostPaddingSeconds = series.PostPaddingSeconds; - timer.IsPostPaddingRequired = series.IsPostPaddingRequired; - timer.IsPrePaddingRequired = series.IsPrePaddingRequired; - timer.KeepUntil = series.KeepUntil; - timer.Priority = series.Priority; + timer.PrePaddingSeconds = seriesTimer.PrePaddingSeconds; + timer.PostPaddingSeconds = seriesTimer.PostPaddingSeconds; + timer.IsPostPaddingRequired = seriesTimer.IsPostPaddingRequired; + timer.IsPrePaddingRequired = seriesTimer.IsPrePaddingRequired; + timer.KeepUntil = seriesTimer.KeepUntil; + timer.Priority = seriesTimer.Priority; timer.Name = parent.Name; timer.Overview = parent.Overview; - timer.SeriesTimerId = series.Id; + timer.SeriesTimerId = seriesTimer.Id; CopyProgramInfoToTimerInfo(parent, timer); @@ -53,6 +54,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV timerInfo.CommunityRating = programInfo.CommunityRating; timerInfo.ShortOverview = programInfo.ShortOverview; timerInfo.OfficialRating = programInfo.OfficialRating; + timerInfo.IsRepeat = programInfo.IsRepeat; } public static string GetRecordingName(TimerInfo info) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 348bcd97b..2189cf627 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -72,6 +72,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv dto.ProgramInfo = _dtoService.GetBaseItemDto(program, new DtoOptions()); dto.ProgramInfo.TimerId = dto.Id; + dto.ProgramInfo.SeriesTimerId = dto.SeriesTimerId; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index e34868428..84b162286 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1087,6 +1087,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv program.TimerId = _tvDtoService.GetInternalTimerId(serviceName, timer.Id) .ToString("N"); + program.TimerStatus = timer.Status; + if (!string.IsNullOrEmpty(timer.SeriesTimerId)) { program.SeriesTimerId = _tvDtoService.GetInternalSeriesTimerId(serviceName, timer.SeriesTimerId) @@ -1875,6 +1877,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } + if (query.IsScheduled.HasValue) + { + if (query.IsScheduled.Value) + { + timers = timers.Where(i => i.Item1.Status == RecordingStatus.New || i.Item1.Status == RecordingStatus.Scheduled); + } + else + { + timers = timers.Where(i => !(i.Item1.Status == RecordingStatus.New || i.Item1.Status == RecordingStatus.Scheduled)); + } + } + if (!string.IsNullOrEmpty(query.ChannelId)) { var guid = new Guid(query.ChannelId); -- cgit v1.2.3 From d5b5c8e1a5548f2f1321f0f9a63d86919de0b01e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 11 Oct 2016 02:46:59 -0400 Subject: update display of active recordings --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 4 +- .../Entities/AggregateFolder.cs | 9 ++ .../Entities/Audio/MusicAlbum.cs | 16 ++- .../Entities/Audio/MusicArtist.cs | 9 ++ MediaBrowser.Controller/Entities/BaseItem.cs | 9 ++ .../Entities/CollectionFolder.cs | 9 ++ MediaBrowser.Controller/Entities/Folder.cs | 9 ++ MediaBrowser.Controller/Entities/GameSystem.cs | 9 ++ MediaBrowser.Controller/Entities/IHasUserData.cs | 2 + MediaBrowser.Controller/Entities/Photo.cs | 4 +- MediaBrowser.Controller/Entities/PhotoAlbum.cs | 9 ++ MediaBrowser.Controller/Entities/UserRootFolder.cs | 9 ++ MediaBrowser.Controller/Entities/UserView.cs | 9 ++ MediaBrowser.Controller/Entities/Video.cs | 9 ++ .../LiveTv/LiveTvVideoRecording.cs | 9 ++ .../MediaEncoding/IMediaEncoder.cs | 2 +- .../MediaEncoding/MediaInfoRequest.cs | 1 + MediaBrowser.Controller/Playlists/Playlist.cs | 9 ++ MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 4 +- .../Encoder/EncodingUtils.cs | 15 ++- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 40 ++++++-- MediaBrowser.Model/MediaInfo/MediaProtocol.cs | 3 +- .../Dto/DtoService.cs | 2 +- .../Library/UserDataManager.cs | 3 +- .../LiveTv/EmbyTV/EmbyTV.cs | 54 ++++++---- .../LiveTv/LiveStreamHelper.cs | 110 +++++++++++++++++++++ .../LiveTv/LiveTvManager.cs | 19 ++++ .../LiveTv/LiveTvMediaSourceProvider.cs | 88 +---------------- .../MediaBrowser.Server.Implementations.csproj | 1 + .../Session/SessionManager.cs | 10 +- Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 33 files changed, 361 insertions(+), 135 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs (limited to 'MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index b5bef1ce9..0e91c0b9e 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -819,10 +819,10 @@ namespace MediaBrowser.Api.Playback { if (state.PlayableStreamFileNames.Count > 0) { - return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); + return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); } - return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol); + return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol); } /// diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 9709813dc..7b769deb3 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -45,6 +45,15 @@ namespace MediaBrowser.Controller.Entities return false; } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + /// /// The _virtual children /// diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 1f3b0c92a..3f457d89a 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -17,6 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio /// public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo, IMetadataContainer { + public List AlbumArtists { get; set; } + public List Artists { get; set; } + public MusicAlbum() { Artists = new List(); @@ -48,6 +51,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + [IgnoreDataMember] public override bool SupportsCumulativeRunTimeTicks { @@ -83,8 +95,6 @@ namespace MediaBrowser.Controller.Entities.Audio get { return false; } } - public List AlbumArtists { get; set; } - /// /// Gets the tracks. /// @@ -103,8 +113,6 @@ namespace MediaBrowser.Controller.Entities.Audio return Tracks; } - public List Artists { get; set; } - public override List GetUserDataKeys() { var list = base.GetUserDataKeys(); diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 076a7031a..a31f04fc4 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio get { return true; } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + public override bool CanDelete() { return !IsAccessedByName; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cc4a8fdb9..7eb84fc80 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -129,6 +129,15 @@ namespace MediaBrowser.Controller.Entities get { return false; } } + [IgnoreDataMember] + public virtual bool SupportsPlayedStatus + { + get + { + return false; + } + } + public bool DetectIsInMixedFolder() { if (SupportsIsInMixedFolderDetection) diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 04ba53263..41e277b7c 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -38,6 +38,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + public override bool CanDelete() { return false; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index e5994fde5..993e36fd8 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -61,6 +61,15 @@ namespace MediaBrowser.Controller.Entities get { return false; } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return true; + } + } + /// /// Gets a value indicating whether this instance is folder. /// diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index 1c09ee507..9e00ab260 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -26,6 +26,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + /// /// Gets or sets the game system. /// diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs index 2495b0ccd..c21e170ae 100644 --- a/MediaBrowser.Controller/Entities/IHasUserData.cs +++ b/MediaBrowser.Controller/Entities/IHasUserData.cs @@ -20,5 +20,7 @@ namespace MediaBrowser.Controller.Entities Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user); bool EnableRememberingTrackSelections { get; } + + bool SupportsPlayedStatus { get; } } } diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 41e25e406..a42fce8bb 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -29,13 +29,13 @@ namespace MediaBrowser.Controller.Entities { get { - return Album; + return AlbumEntity; } } [IgnoreDataMember] - public PhotoAlbum Album + public PhotoAlbum AlbumEntity { get { diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs index b0ddcfb8c..cb5c5c453 100644 --- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs +++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs @@ -16,6 +16,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index aff1f5e28..b67817846 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + private void ClearCache() { lock (_childIdsLock) diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 92f8e8a9d..a689e0d09 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities return list; } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + public override int GetChildCount(User user) { return GetChildren(user, true).Count(); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index baf9293bf..e83d1298e 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return true; + } + } + public override string CreatePresentationUniqueKey() { if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index e26dd6a77..635df5dc7 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -54,6 +54,15 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return Status == RecordingStatus.Completed && base.SupportsPlayedStatus; + } + } + [IgnoreDataMember] public override LocationType LocationType { diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index f97fe9560..866a08aa1 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// The input files. /// The protocol. /// System.String. - string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol); + string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol); /// /// Gets the input argument. diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs index ca0c2fdbb..9ff7567d4 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs @@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding public IIsoMount MountedIso { get; set; } public VideoType VideoType { get; set; } public List PlayableStreamFileNames { get; set; } + public int AnalyzeDurationSections { get; set; } public MediaInfoRequest() { diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 654b97d7d..8e0ac7ea8 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -31,6 +31,15 @@ namespace MediaBrowser.Controller.Playlists } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return string.Equals(MediaType, "Video", StringComparison.OrdinalIgnoreCase); + } + } + [IgnoreDataMember] public override bool AlwaysScanInternalMetadataPath { diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index f1e2f7241..c7b78aae3 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -431,10 +431,10 @@ namespace MediaBrowser.MediaEncoding.Encoder { if (state.PlayableStreamFileNames.Count > 0) { - return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); + return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); } - return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol); + return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol); } /// diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index 5d0f1f075..cec272b39 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -26,6 +26,12 @@ namespace MediaBrowser.MediaEncoding.Encoder return string.Format("\"{0}\"", url); } + if (protocol == MediaProtocol.Udp) + { + var url = inputFiles.First(); + + return string.Format("\"{0}\"", url); + } return GetConcatInputArgument(inputFiles); } @@ -74,9 +80,14 @@ namespace MediaBrowser.MediaEncoding.Encoder return path.Replace("\"", "\\\""); } - public static string GetProbeSizeArgument(bool isDvd) + public static string GetProbeSizeArgument(int numInputFiles) + { + return numInputFiles > 1 ? "-probesize 1G" : ""; + } + + public static string GetAnalyzeDurationArgument(int numInputFiles) { - return isDvd ? "-probesize 1G -analyzeduration 200M" : ""; + return numInputFiles > 1 ? "-analyzeduration 200M" : ""; } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 5c3345008..fc1444e1b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -426,10 +426,24 @@ namespace MediaBrowser.MediaEncoding.Encoder var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames); - var probeSizeArgument = GetProbeSizeArgument(inputFiles, request.Protocol); + var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length); + string analyzeDuration; + + if (request.AnalyzeDurationSections > 0) + { + analyzeDuration = "-analyzeduration " + + (request.AnalyzeDurationSections*1000000).ToString(CultureInfo.InvariantCulture); + } + else + { + analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length); + } + + probeSize = probeSize + " " + analyzeDuration; + probeSize = probeSize.Trim(); return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, - probeSizeArgument, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); + probeSize, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); } /// @@ -450,9 +464,23 @@ namespace MediaBrowser.MediaEncoding.Encoder /// The input files. /// The protocol. /// System.String. - public string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol) + public string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol) { - return EncodingUtils.GetProbeSizeArgument(inputFiles.Length > 1); + var results = new List(); + + var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length); + var analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length); + + if (!string.IsNullOrWhiteSpace(probeSize)) + { + results.Add(probeSize); + } + + if (!string.IsNullOrWhiteSpace(analyzeDuration)) + { + results.Add(analyzeDuration); + } + return string.Join(" ", results.ToArray()); } /// @@ -871,7 +899,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) : string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg); - var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol); + var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputPath }, protocol); if (!string.IsNullOrEmpty(probeSize)) { @@ -982,7 +1010,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); - var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol); + var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputArgument }, protocol); if (!string.IsNullOrEmpty(probeSize)) { diff --git a/MediaBrowser.Model/MediaInfo/MediaProtocol.cs b/MediaBrowser.Model/MediaInfo/MediaProtocol.cs index 880310814..1474e6d96 100644 --- a/MediaBrowser.Model/MediaInfo/MediaProtocol.cs +++ b/MediaBrowser.Model/MediaInfo/MediaProtocol.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Model.MediaInfo File = 0, Http = 1, Rtmp = 2, - Rtsp = 3 + Rtsp = 3, + Udp = 4 } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index b878226de..a0f7aa999 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -598,7 +598,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.Altitude = item.Altitude; dto.IsoSpeedRating = item.IsoSpeedRating; - var album = item.Album; + var album = item.AlbumEntity; if (album != null) { diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index ec8ac1a42..139ea0ab6 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -269,9 +269,10 @@ namespace MediaBrowser.Server.Implementations.Library positionTicks = 0; } - if (item is Audio) + if (!item.SupportsPlayedStatus) { positionTicks = 0; + data.Played = false; } data.PlaybackPositionTicks = positionTicks; diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 9781775d5..136a9e195 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -27,6 +27,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml; using CommonIO; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; @@ -59,8 +60,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public static EmbyTV Current; - public event EventHandler DataSourceChanged { add { } remove { } } - public event EventHandler RecordingStatusChanged { add { } remove { } } + public event EventHandler DataSourceChanged; + public event EventHandler RecordingStatusChanged; private readonly ConcurrentDictionary _activeRecordings = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); @@ -1009,7 +1010,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV throw new NotImplementedException(); } - public Task> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken) + public async Task> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken) { ActiveRecordingInfo info; @@ -1017,22 +1018,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (_activeRecordings.TryGetValue(recordingId, out info)) { - return Task.FromResult(new List + var stream = new MediaSourceInfo + { + Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream", + Id = recordingId, + SupportsDirectPlay = false, + SupportsDirectStream = true, + SupportsTranscoding = true, + IsInfiniteStream = true, + RequiresOpening = false, + RequiresClosing = false, + Protocol = Model.MediaInfo.MediaProtocol.Http, + BufferMs = 0 + }; + + var isAudio = false; + await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false); + + return new List { - new MediaSourceInfo - { - Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream", - Id = recordingId, - SupportsDirectPlay = false, - SupportsDirectStream = true, - SupportsTranscoding = true, - IsInfiniteStream = true, - RequiresOpening = false, - RequiresClosing = false, - Protocol = Model.MediaInfo.MediaProtocol.Http, - BufferMs = 0 - } - }); + stream + }; } throw new FileNotFoundException(); @@ -1258,6 +1264,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV string liveStreamId = null; + OnRecordingStatusChanged(); + try { var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); @@ -1353,6 +1361,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { _timerProvider.Delete(timer); } + + OnRecordingStatusChanged(); + } + + private void OnRecordingStatusChanged() + { + EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs + { + + }, _logger); } private async void EnforceKeepUpTo(TimerInfo timer) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs new file mode 100644 index 000000000..336c32bae --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs @@ -0,0 +1,110 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Logging; + +namespace MediaBrowser.Server.Implementations.LiveTv +{ + public class LiveStreamHelper + { + private readonly IMediaEncoder _mediaEncoder; + private readonly ILogger _logger; + + public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger) + { + _mediaEncoder = mediaEncoder; + _logger = logger; + } + + public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) + { + var originalRuntime = mediaSource.RunTimeTicks; + + var now = DateTime.UtcNow; + + var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest + { + InputPath = mediaSource.Path, + Protocol = mediaSource.Protocol, + MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, + ExtractChapters = false, + AnalyzeDurationSections = 2 + + }, cancellationToken).ConfigureAwait(false); + + _logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture)); + + mediaSource.Bitrate = info.Bitrate; + mediaSource.Container = info.Container; + mediaSource.Formats = info.Formats; + mediaSource.MediaStreams = info.MediaStreams; + mediaSource.RunTimeTicks = info.RunTimeTicks; + mediaSource.Size = info.Size; + mediaSource.Timestamp = info.Timestamp; + mediaSource.Video3DFormat = info.Video3DFormat; + mediaSource.VideoType = info.VideoType; + + mediaSource.DefaultSubtitleStreamIndex = null; + + // Null this out so that it will be treated like a live stream + if (!originalRuntime.HasValue) + { + mediaSource.RunTimeTicks = null; + } + + var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio); + + if (audioStream == null || audioStream.Index == -1) + { + mediaSource.DefaultAudioStreamIndex = null; + } + else + { + mediaSource.DefaultAudioStreamIndex = audioStream.Index; + } + + var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video); + if (videoStream != null) + { + if (!videoStream.BitRate.HasValue) + { + var width = videoStream.Width ?? 1920; + + if (width >= 1900) + { + videoStream.BitRate = 8000000; + } + + else if (width >= 1260) + { + videoStream.BitRate = 3000000; + } + + else if (width >= 700) + { + videoStream.BitRate = 1000000; + } + } + + // This is coming up false and preventing stream copy + videoStream.IsAVC = null; + } + + // Try to estimate this + if (!mediaSource.Bitrate.HasValue) + { + var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum(); + + if (total > 0) + { + mediaSource.Bitrate = total; + } + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index a295320ec..bac9789b5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -121,9 +121,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv foreach (var service in _services) { service.DataSourceChanged += service_DataSourceChanged; + service.RecordingStatusChanged += Service_RecordingStatusChanged; } } + private void Service_RecordingStatusChanged(object sender, RecordingStatusChangedEventArgs e) + { + _lastRecordingRefreshTime = DateTime.MinValue; + } + public List TunerHosts { get { return _tunerHosts; } @@ -2299,6 +2305,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false); + info.RecordAnyChannel = true; + info.RecordAnyTime = true; + info.Days = new List + { + DayOfWeek.Sunday, + DayOfWeek.Monday, + DayOfWeek.Tuesday, + DayOfWeek.Wednesday, + DayOfWeek.Thursday, + DayOfWeek.Friday, + DayOfWeek.Saturday + }; + info.Id = null; return new Tuple(info, service); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 521f33e1c..a62796036 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -146,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv } else { - await AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false); + await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false); } } catch (Exception ex) @@ -216,92 +216,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - private async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) - { - var originalRuntime = mediaSource.RunTimeTicks; - - var now = DateTime.UtcNow; - - var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest - { - InputPath = mediaSource.Path, - Protocol = mediaSource.Protocol, - MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, - ExtractChapters = false - - }, cancellationToken).ConfigureAwait(false); - - _logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture)); - - mediaSource.Bitrate = info.Bitrate; - mediaSource.Container = info.Container; - mediaSource.Formats = info.Formats; - mediaSource.MediaStreams = info.MediaStreams; - mediaSource.RunTimeTicks = info.RunTimeTicks; - mediaSource.Size = info.Size; - mediaSource.Timestamp = info.Timestamp; - mediaSource.Video3DFormat = info.Video3DFormat; - mediaSource.VideoType = info.VideoType; - - mediaSource.DefaultSubtitleStreamIndex = null; - - // Null this out so that it will be treated like a live stream - if (!originalRuntime.HasValue) - { - mediaSource.RunTimeTicks = null; - } - - var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio); - - if (audioStream == null || audioStream.Index == -1) - { - mediaSource.DefaultAudioStreamIndex = null; - } - else - { - mediaSource.DefaultAudioStreamIndex = audioStream.Index; - } - - var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video); - if (videoStream != null) - { - if (!videoStream.BitRate.HasValue) - { - var width = videoStream.Width ?? 1920; - - if (width >= 1900) - { - videoStream.BitRate = 8000000; - } - - else if (width >= 1260) - { - videoStream.BitRate = 3000000; - } - - else if (width >= 700) - { - videoStream.BitRate = 1000000; - } - } - - // This is coming up false and preventing stream copy - videoStream.IsAVC = null; - } - - // Try to estimate this - if (!mediaSource.Bitrate.HasValue) - { - var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum(); - - if (total > 0) - { - mediaSource.Bitrate = total; - } - } - } - - public Task CloseMediaSource(string liveStreamId) { return _liveTvManager.CloseLiveStream(liveStreamId); diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 73e6ce1a5..f01a107df 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -234,6 +234,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 2fcc76588..e898a6abd 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -633,10 +633,14 @@ namespace MediaBrowser.Server.Implementations.Session data.PlayCount++; data.LastPlayedDate = DateTime.UtcNow; - if (!(item is Video)) + if (!(item is Video) && item.SupportsPlayedStatus) { data.Played = true; } + else + { + data.Played = false; + } await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false); } @@ -847,11 +851,11 @@ namespace MediaBrowser.Server.Implementations.Session { playedToCompletion = _userDataManager.UpdatePlayState(item, data, positionTicks.Value); } - else + else { // If the client isn't able to report this, then we'll just have to make an assumption data.PlayCount++; - data.Played = true; + data.Played = item.SupportsPlayedStatus; data.PlaybackPositionTicks = 0; playedToCompletion = true; } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 2e4584fd4..1259a759b 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.661 + 3.0.662 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption. Copyright © Emby 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 56c616bd1..931db69fa 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.661 + 3.0.662 MediaBrowser.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 98a070c78..b3d929f59 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.661 + 3.0.662 Media Browser.Server.Core Emby Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Emby Server. Copyright © Emby 2013 - + -- cgit v1.2.3