diff options
Diffstat (limited to 'MediaBrowser.Api/Playback')
10 files changed, 183 insertions, 126 deletions
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 5881e22a7..5029ce0bb 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -250,18 +250,18 @@ namespace MediaBrowser.Api.Playback { if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - logFilePrefix = "ffmpeg-directstream"; + logFilePrefix = "ffmpeg-remux"; } else { - logFilePrefix = "ffmpeg-remux"; + logFilePrefix = "ffmpeg-directstream"; } } var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt"); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - Stream logStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); + Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); @@ -327,15 +327,19 @@ namespace MediaBrowser.Api.Playback private bool EnableThrottling(StreamState state) { + var encodingOptions = ServerConfigurationManager.GetEncodingOptions(); + + // enable throttling when NOT using hardware acceleration + if (encodingOptions.HardwareAccelerationType == string.Empty) + { + return state.InputProtocol == MediaProtocol.File && + state.RunTimeTicks.HasValue && + state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && + state.IsInputVideo && + state.VideoType == VideoType.VideoFile && + !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase); + } return false; - //// do not use throttling with hardware encoders - //return state.InputProtocol == MediaProtocol.File && - // state.RunTimeTicks.HasValue && - // state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && - // state.IsInputVideo && - // state.VideoType == VideoType.VideoFile && - // !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && - // string.Equals(GetVideoEncoder(state), "libx264", StringComparison.OrdinalIgnoreCase); } /// <summary> @@ -759,7 +763,7 @@ namespace MediaBrowser.Api.Playback if (mediaSource == null) { - var mediaSources = await MediaSourceManager.GetPlayackMediaSources(LibraryManager.GetItemById(request.Id), null, false, false, cancellationToken).ConfigureAwait(false); + var mediaSources = await MediaSourceManager.GetPlaybackMediaSources(LibraryManager.GetItemById(request.Id), null, false, false, cancellationToken).ConfigureAwait(false); mediaSource = string.IsNullOrEmpty(request.MediaSourceId) ? mediaSources[0] diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 5d0dc98dd..0cbfe4bdf 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -168,7 +168,7 @@ namespace MediaBrowser.Api.Playback.Hls private string GetLivePlaylistText(string path, int segmentLength) { - using (var stream = FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite)) + using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (var reader = new StreamReader(stream)) { @@ -211,7 +211,7 @@ namespace MediaBrowser.Api.Playback.Hls { try { - // Need to use FileShareMode.ReadWrite because we're reading the file at the same time it's being written + // Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written using (var fileStream = GetPlaylistFileStream(playlist)) { using (var reader = new StreamReader(fileStream)) @@ -252,11 +252,11 @@ namespace MediaBrowser.Api.Playback.Hls try { - return FileSystem.GetFileStream(tmpPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, FileOpenOptions.SequentialScan); + return new FileStream(tmpPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, FileOptions.SequentialScan); } catch (IOException) { - return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, FileOpenOptions.SequentialScan); + return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, FileOptions.SequentialScan); } } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 0178f53af..f03e481df 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -16,7 +16,6 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; @@ -537,7 +536,7 @@ namespace MediaBrowser.Api.Playback.Hls return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions { Path = segmentPath, - FileShare = FileShareMode.ReadWrite, + FileShare = FileShare.ReadWrite, OnComplete = () => { Logger.LogDebug("finished serving {0}", segmentPath); @@ -954,12 +953,12 @@ namespace MediaBrowser.Api.Playback.Hls // Unable to force key frames to h264_qsv transcode if (string.Equals(codec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { - Logger.LogInformation("Bug Workaround: Disabling force_key_frames for h264_qsv"); - } + Logger.LogInformation("Bug Workaround: Disabling force_key_frames for h264_qsv"); + } else { args += " " + keyFrameArg; - } + } //args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0"; @@ -1008,6 +1007,7 @@ namespace MediaBrowser.Api.Playback.Hls Logger.LogInformation("Current HLS implementation doesn't support non-keyframe breaks but one is requested, ignoring that request"); state.BaseRequest.BreakOnNonKeyFrames = false; } + var inputModifier = EncodingHelper.GetInputModifier(state, encodingOptions); // If isEncoding is true we're actually starting ffmpeg diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs index bb12ab1f0..87ccde2e0 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -140,7 +140,7 @@ namespace MediaBrowser.Api.Playback.Hls var file = request.SegmentId + Path.GetExtension(Request.PathInfo); file = Path.Combine(ServerConfigurationManager.GetTranscodePath(), file); - return ResultFactory.GetStaticFileResult(Request, file, FileShareMode.ReadWrite); + return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite); } private Task<object> GetFileResult(string path, string playlistPath) @@ -150,7 +150,7 @@ namespace MediaBrowser.Api.Playback.Hls return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions { Path = path, - FileShare = FileShareMode.ReadWrite, + FileShare = FileShare.ReadWrite, OnComplete = () => { if (transcodingJob != null) diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index c3032416b..2aa5e2df1 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -1,6 +1,11 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1402 +#pragma warning disable SA1649 + using System; -using System.Collections.Generic; +using System.Buffers; using System.Globalization; +using System.Text.Json; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -16,7 +21,6 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; @@ -54,7 +58,7 @@ namespace MediaBrowser.Api.Playback public class GetBitrateTestBytes { [ApiMember(Name = "Size", Description = "Size", IsRequired = true, DataType = "int", ParameterType = "query", Verb = "GET")] - public long Size { get; set; } + public int Size { get; set; } public GetBitrateTestBytes() { @@ -72,7 +76,6 @@ namespace MediaBrowser.Api.Playback private readonly INetworkManager _networkManager; private readonly IMediaEncoder _mediaEncoder; private readonly IUserManager _userManager; - private readonly IJsonSerializer _json; private readonly IAuthorizationContext _authContext; public MediaInfoService( @@ -85,7 +88,6 @@ namespace MediaBrowser.Api.Playback INetworkManager networkManager, IMediaEncoder mediaEncoder, IUserManager userManager, - IJsonSerializer json, IAuthorizationContext authContext) : base(logger, serverConfigurationManager, httpResultFactory) { @@ -95,20 +97,35 @@ namespace MediaBrowser.Api.Playback _networkManager = networkManager; _mediaEncoder = mediaEncoder; _userManager = userManager; - _json = json; _authContext = authContext; } public object Get(GetBitrateTestBytes request) { - var bytes = new byte[request.Size]; + const int MaxSize = 10_000_000; + + var size = request.Size; + + if (size <= 0) + { + throw new ArgumentException($"The requested size ({size}) is equal to or smaller than 0.", nameof(request)); + } - for (var i = 0; i < bytes.Length; i++) + if (size > MaxSize) { - bytes[i] = 0; + throw new ArgumentException($"The requested size ({size}) is larger than the max allowed value ({MaxSize}).", nameof(request)); } - return ResultFactory.GetResult(null, bytes, "application/octet-stream"); + byte[] buffer = ArrayPool<byte>.Shared.Rent(size); + try + { + new Random().NextBytes(buffer); + return ResultFactory.GetResult(null, buffer, "application/octet-stream"); + } + finally + { + ArrayPool<byte>.Shared.Return(buffer); + } } public async Task<object> Get(GetPlaybackInfo request) @@ -166,8 +183,7 @@ namespace MediaBrowser.Api.Playback public void Post(CloseMediaSource request) { - var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId); - Task.WaitAll(task); + _mediaSourceManager.CloseLiveStream(request.LiveStreamId).GetAwaiter().GetResult(); } public async Task<PlaybackInfoResponse> GetPlaybackInfo(GetPostedPlaybackInfo request) @@ -176,7 +192,7 @@ namespace MediaBrowser.Api.Playback var profile = request.DeviceProfile; - //Logger.LogInformation("GetPostedPlaybackInfo profile: {profile}", _json.SerializeToString(profile)); + Logger.LogInformation("GetPostedPlaybackInfo profile: {@Profile}", profile); if (profile == null) { @@ -215,9 +231,7 @@ namespace MediaBrowser.Api.Playback StartTimeTicks = request.StartTimeTicks, SubtitleStreamIndex = request.SubtitleStreamIndex, UserId = request.UserId, - OpenToken = mediaSource.OpenToken, - //EnableMediaProbe = request.EnableMediaProbe - + OpenToken = mediaSource.OpenToken }).ConfigureAwait(false); info.MediaSources = new MediaSourceInfo[] { openStreamResult.MediaSource }; @@ -247,42 +261,26 @@ namespace MediaBrowser.Api.Playback return ToOptimizedResult(result); } - private T Clone<T>(T obj) - { - // Since we're going to be setting properties on MediaSourceInfos that come out of _mediaSourceManager, we should clone it - // Should we move this directly into MediaSourceManager? - - var json = _json.SerializeToString(obj); - return _json.DeserializeFromString<T>(json); - } - private async Task<PlaybackInfoResponse> GetPlaybackInfo(Guid id, Guid userId, string[] supportedLiveMediaTypes, string mediaSourceId = null, string liveStreamId = null) { var user = _userManager.GetUserById(userId); var item = _libraryManager.GetItemById(id); var result = new PlaybackInfoResponse(); + MediaSourceInfo[] mediaSources; if (string.IsNullOrWhiteSpace(liveStreamId)) { - IEnumerable<MediaSourceInfo> mediaSources; - try - { - // TODO handle supportedLiveMediaTypes ? - mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, user, true, false, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - mediaSources = new List<MediaSourceInfo>(); - Logger.LogError(ex, "Could not find media sources for item id {id}", id); - // TODO PlaybackException ?? - //result.ErrorCode = ex.ErrorCode; - } - result.MediaSources = mediaSources.ToArray(); + // TODO handle supportedLiveMediaTypes? + var mediaSourcesList = await _mediaSourceManager.GetPlaybackMediaSources(item, user, true, true, CancellationToken.None).ConfigureAwait(false); - if (!string.IsNullOrWhiteSpace(mediaSourceId)) + if (string.IsNullOrWhiteSpace(mediaSourceId)) + { + mediaSources = mediaSourcesList.ToArray(); + } + else { - result.MediaSources = result.MediaSources + mediaSources = mediaSourcesList .Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)) .ToArray(); } @@ -291,11 +289,13 @@ namespace MediaBrowser.Api.Playback { var mediaSource = await _mediaSourceManager.GetLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false); - result.MediaSources = new MediaSourceInfo[] { mediaSource }; + mediaSources = new MediaSourceInfo[] { mediaSource }; } - if (result.MediaSources.Length == 0) + if (mediaSources.Length == 0) { + result.MediaSources = Array.Empty<MediaSourceInfo>(); + if (!result.ErrorCode.HasValue) { result.ErrorCode = PlaybackErrorCode.NoCompatibleStream; @@ -303,7 +303,9 @@ namespace MediaBrowser.Api.Playback } else { - result.MediaSources = Clone(result.MediaSources); + // Since we're going to be setting properties on MediaSourceInfos that come out of _mediaSourceManager, we should clone it + // Should we move this directly into MediaSourceManager? + result.MediaSources = JsonSerializer.Deserialize<MediaSourceInfo[]>(JsonSerializer.SerializeToUtf8Bytes(mediaSources)); result.PlaySessionId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); } @@ -311,7 +313,8 @@ namespace MediaBrowser.Api.Playback return result; } - private void SetDeviceSpecificData(Guid itemId, + private void SetDeviceSpecificData( + Guid itemId, PlaybackInfoResponse result, DeviceProfile profile, AuthorizationInfo auth, @@ -339,7 +342,8 @@ namespace MediaBrowser.Api.Playback SortMediaSources(result, maxBitrate); } - private void SetDeviceSpecificData(BaseItem item, + private void SetDeviceSpecificData( + BaseItem item, MediaSourceInfo mediaSource, DeviceProfile profile, AuthorizationInfo auth, @@ -383,10 +387,12 @@ namespace MediaBrowser.Api.Playback { mediaSource.SupportsDirectPlay = false; } + if (!enableDirectStream) { mediaSource.SupportsDirectStream = false; } + if (!enableTranscoding) { mediaSource.SupportsTranscoding = false; @@ -405,10 +411,12 @@ namespace MediaBrowser.Api.Playback user.Policy.EnableAudioPlaybackTranscoding); } + // Beginning of Playback Determination: Attempt DirectPlay first if (mediaSource.SupportsDirectPlay) { - if (mediaSource.IsRemote && forceDirectPlayRemoteMediaSource) + if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding) { + mediaSource.SupportsDirectPlay = false; } else { @@ -434,9 +442,9 @@ namespace MediaBrowser.Api.Playback } // The MediaSource supports direct stream, now test to see if the client supports it - var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ? - streamBuilder.BuildAudioItem(options) : - streamBuilder.BuildVideoItem(options); + var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) + ? streamBuilder.BuildAudioItem(options) + : streamBuilder.BuildVideoItem(options); if (streamInfo == null || !streamInfo.IsDirectStream) { @@ -455,36 +463,43 @@ namespace MediaBrowser.Api.Playback if (mediaSource.SupportsDirectStream) { - options.MaxBitrate = GetMaxBitrate(maxBitrate, user); - - if (item is Audio) + if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding) { - if (!user.Policy.EnableAudioPlaybackTranscoding) - { - options.ForceDirectStream = true; - } + mediaSource.SupportsDirectStream = false; } - else if (item is Video) + else { - if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing) + options.MaxBitrate = GetMaxBitrate(maxBitrate, user); + + if (item is Audio) { - options.ForceDirectStream = true; + if (!user.Policy.EnableAudioPlaybackTranscoding) + { + options.ForceDirectStream = true; + } + } + else if (item is Video) + { + if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing) + { + options.ForceDirectStream = true; + } } - } // The MediaSource supports direct stream, now test to see if the client supports it - var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ? - streamBuilder.BuildAudioItem(options) : - streamBuilder.BuildVideoItem(options); + var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) + ? streamBuilder.BuildAudioItem(options) + : streamBuilder.BuildVideoItem(options); - if (streamInfo == null || !streamInfo.IsDirectStream) - { - mediaSource.SupportsDirectStream = false; - } + if (streamInfo == null || !streamInfo.IsDirectStream) + { + mediaSource.SupportsDirectStream = false; + } - if (streamInfo != null) - { - SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); + if (streamInfo != null) + { + SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); + } } } @@ -493,35 +508,76 @@ namespace MediaBrowser.Api.Playback options.MaxBitrate = GetMaxBitrate(maxBitrate, user); // The MediaSource supports direct stream, now test to see if the client supports it - var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ? - streamBuilder.BuildAudioItem(options) : - streamBuilder.BuildVideoItem(options); + var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) + ? streamBuilder.BuildAudioItem(options) + : streamBuilder.BuildVideoItem(options); - if (streamInfo != null) + if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding) { - streamInfo.PlaySessionId = playSessionId; - - if (streamInfo.PlayMethod == PlayMethod.Transcode) + if (streamInfo != null) { + streamInfo.PlaySessionId = playSessionId; streamInfo.StartPositionTicks = startTimeTicks; mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).TrimStart('-'); + mediaSource.TranscodingUrl += "&allowVideoStreamCopy=false"; + if (!allowAudioStreamCopy) + { + mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false"; + } + mediaSource.TranscodingContainer = streamInfo.Container; + mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol; + + // Do this after the above so that StartPositionTicks is set + SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); + } + } + else + { + if (streamInfo != null) + { + streamInfo.PlaySessionId = playSessionId; - if (!allowVideoStreamCopy) + if (streamInfo.PlayMethod == PlayMethod.Transcode) { - mediaSource.TranscodingUrl += "&allowVideoStreamCopy=false"; + streamInfo.StartPositionTicks = startTimeTicks; + mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).TrimStart('-'); + + if (!allowVideoStreamCopy) + { + mediaSource.TranscodingUrl += "&allowVideoStreamCopy=false"; + } + if (!allowAudioStreamCopy) + { + mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false"; + } + mediaSource.TranscodingContainer = streamInfo.Container; + mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol; } + if (!allowAudioStreamCopy) { mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false"; } + mediaSource.TranscodingContainer = streamInfo.Container; mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol; - } - // Do this after the above so that StartPositionTicks is set - SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); + // Do this after the above so that StartPositionTicks is set + SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); + } } } + + foreach (var attachment in mediaSource.MediaAttachments) + { + attachment.DeliveryUrl = string.Format( + CultureInfo.InvariantCulture, + "{0}/Videos/{1}/{2}/Attachments/{3}", + ServerConfigurationManager.Configuration.BaseUrl, + item.Id, + mediaSource.Id, + attachment.Index); + } } private long? GetMaxBitrate(long? clientMaxBitrate, User user) @@ -599,14 +655,11 @@ namespace MediaBrowser.Api.Playback }).ThenBy(i => { - switch (i.Protocol) + return i.Protocol switch { - case MediaProtocol.File: - return 0; - default: - return 1; - } - + MediaProtocol.File => 0, + _ => 1, + }; }).ThenBy(i => { if (maxBitrate.HasValue) diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index ed30dbba6..ed68219c9 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -248,7 +248,7 @@ namespace MediaBrowser.Api.Playback.Progressive // ContentType = contentType, // IsHeadRequest = isHeadRequest, // Path = outputPath, - // FileShare = FileShareMode.ReadWrite, + // FileShare = FileShare.ReadWrite, // OnComplete = () => // { // if (transcodingJob != null) diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index 660912065..a53b848f9 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -21,8 +21,6 @@ namespace MediaBrowser.Api.Playback.Progressive private readonly CancellationToken _cancellationToken; private readonly Dictionary<string, string> _outputHeaders; - const int StreamCopyToBufferSize = 81920; - private long _bytesWritten = 0; public long StartPosition { get; set; } public bool AllowEndOfFile = true; @@ -52,14 +50,14 @@ namespace MediaBrowser.Api.Playback.Progressive private Stream GetInputStream(bool allowAsyncFileRead) { - var fileOpenOptions = FileOpenOptions.SequentialScan; + var fileOptions = FileOptions.SequentialScan; if (allowAsyncFileRead) { - fileOpenOptions |= FileOpenOptions.Asynchronous; + fileOptions |= FileOptions.Asynchronous; } - return _fileSystem.GetFileStream(_path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions); + return new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); } public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken) @@ -127,7 +125,7 @@ namespace MediaBrowser.Api.Playback.Progressive private async Task<int> CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, CancellationToken cancellationToken) { - var array = new byte[StreamCopyToBufferSize]; + var array = new byte[IODefaults.CopyToBufferSize]; int bytesRead; int totalBytesRead = 0; @@ -154,7 +152,7 @@ namespace MediaBrowser.Api.Playback.Progressive private async Task<int> CopyToInternalAsync(Stream source, Stream destination, CancellationToken cancellationToken) { - var array = new byte[StreamCopyToBufferSize]; + var array = new byte[IODefaults.CopyToBufferSize]; int bytesRead; int totalBytesRead = 0; diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index 7626cc378..9ba8eda91 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -1,4 +1,3 @@ -using System; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 7396b5c99..d5d2f58c0 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Api.Playback _mediaSourceManager = mediaSourceManager; } - public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float framerate, double? percentComplete, long bytesTranscoded, int? bitRate) + public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) { ApiEntryPoint.Instance.ReportTranscodingProgress(TranscodingJob, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate); } diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs index 9cba9df13..cbf981dfe 100644 --- a/MediaBrowser.Api/Playback/UniversalAudioService.cs +++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs @@ -74,7 +74,6 @@ namespace MediaBrowser.Api.Playback [Authenticated] public class UniversalAudioService : BaseApiService { - private readonly ILoggerFactory _loggerFactory; private readonly EncodingHelper _encodingHelper; public UniversalAudioService( @@ -243,7 +242,6 @@ namespace MediaBrowser.Api.Playback NetworkManager, MediaEncoder, UserManager, - JsonSerializer, AuthorizationContext) { Request = Request @@ -300,6 +298,10 @@ namespace MediaBrowser.Api.Playback var transcodingProfile = deviceProfile.TranscodingProfiles[0]; + // hls segment container can only be mpegts or fmp4 per ffmpeg documentation + // TODO: remove this when we switch back to the segment muxer + var supportedHLSContainers = new string[] { "mpegts", "fmp4" }; + var newRequest = new GetMasterHlsAudioPlaylist { AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(request.MaxStreamingBitrate ?? 192000, int.MaxValue)), @@ -312,7 +314,8 @@ namespace MediaBrowser.Api.Playback PlaySessionId = playbackInfoResult.PlaySessionId, StartTimeTicks = request.StartTimeTicks, Static = isStatic, - SegmentContainer = request.TranscodingContainer, + // fallback to mpegts if device reports some weird value unsupported by hls + SegmentContainer = Array.Exists(supportedHLSContainers, element => element == request.TranscodingContainer) ? request.TranscodingContainer : "mpegts", AudioSampleRate = request.MaxAudioSampleRate, MaxAudioBitDepth = request.MaxAudioBitDepth, BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames, |
