From fdd8c67162233659656d3c719a6734cbe5f87d9f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 22 Apr 2014 20:50:47 -0400 Subject: [PATCH] add correct media format profiles to res elements --- .../Playback/BaseStreamingService.cs | 174 +++++++++--------- .../Playback/Hls/BaseHlsService.cs | 27 +-- .../Playback/Hls/DynamicHlsService.cs | 27 +-- .../Playback/Hls/VideoHlsService.cs | 4 +- .../Playback/Progressive/AudioService.cs | 15 +- .../BaseProgressiveStreamingService.cs | 11 +- .../Playback/Progressive/VideoService.cs | 7 +- MediaBrowser.Api/Playback/StreamState.cs | 78 +++++++- MediaBrowser.Dlna/Server/ControlHandler.cs | 74 ++++++-- .../Encoder/InternalEncodingTaskFactory.cs | 50 ++--- .../Dlna/MediaFormatProfileResolver.cs | 166 +++++++++++------ 11 files changed, 364 insertions(+), 269 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index ff9596757d..a470bc2fae 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -126,7 +126,7 @@ namespace MediaBrowser.Api.Playback /// /// The state. /// System.String. - protected virtual string GetOutputFilePath(StreamState state) + protected string GetOutputFilePath(StreamState state) { var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath; @@ -137,11 +137,6 @@ namespace MediaBrowser.Api.Playback protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// - /// The fast seek offset seconds - /// - private const int FastSeekOffsetSeconds = 1; - /// /// Gets the fast seek command line parameter. /// @@ -165,17 +160,6 @@ namespace MediaBrowser.Api.Playback return string.Empty; } - /// - /// Gets the slow seek command line parameter. - /// - /// The request. - /// System.String. - /// The slow seek command line parameter. - protected string GetSlowSeekCommandLineParameter(StreamRequest request) - { - return string.Empty; - } - /// /// Gets the map args. /// @@ -415,9 +399,9 @@ namespace MediaBrowser.Api.Playback param += string.Format(" -r {0}", framerate.Value.ToString(UsCulture)); } - if (!string.IsNullOrEmpty(state.VideoSync)) + if (!string.IsNullOrEmpty(state.OutputVideoSync)) { - param += " -vsync " + state.VideoSync; + param += " -vsync " + state.OutputVideoSync; } if (!string.IsNullOrEmpty(state.VideoRequest.Profile)) @@ -438,7 +422,7 @@ namespace MediaBrowser.Api.Playback var volParam = string.Empty; var audioSampleRate = string.Empty; - var channels = GetNumAudioChannelsParam(state.Request, state.AudioStream); + var channels = state.OutputAudioChannels; // Boost volume to 200% when downsampling from 6ch to 2ch if (channels.HasValue && channels.Value <= 2) @@ -449,9 +433,9 @@ namespace MediaBrowser.Api.Playback } } - if (state.Request.AudioSampleRate.HasValue) + if (state.OutputAudioSampleRate.HasValue) { - audioSampleRate = state.Request.AudioSampleRate.Value + ":"; + audioSampleRate = state.OutputAudioSampleRate.Value + ":"; } var adelay = isHls ? "adelay=1," : string.Empty; @@ -478,7 +462,7 @@ namespace MediaBrowser.Api.Playback audioSampleRate, volParam, pts, - state.AudioSync); + state.OutputAudioSync); } /// @@ -746,7 +730,7 @@ namespace MediaBrowser.Api.Playback /// The request. /// The audio stream. /// System.Nullable{System.Int32}. - protected int? GetNumAudioChannelsParam(StreamRequest request, MediaStream audioStream) + private int? GetNumAudioChannelsParam(StreamRequest request, MediaStream audioStream) { if (audioStream != null) { @@ -973,17 +957,17 @@ namespace MediaBrowser.Api.Playback } } - protected int? GetVideoBitrateParamValue(StreamState state) + private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream) { - var bitrate = state.VideoRequest.VideoBitRate; + var bitrate = request.VideoBitRate; - if (state.VideoStream != null) + if (videoStream != null) { - var isUpscaling = state.VideoRequest.Height.HasValue && state.VideoStream.Height.HasValue && - state.VideoRequest.Height.Value > state.VideoStream.Height.Value; + var isUpscaling = request.Height.HasValue && videoStream.Height.HasValue && + request.Height.Value > videoStream.Height.Value; - if (state.VideoRequest.Width.HasValue && state.VideoStream.Width.HasValue && - state.VideoRequest.Width.Value > state.VideoStream.Width.Value) + if (request.Width.HasValue && videoStream.Width.HasValue && + request.Width.Value > videoStream.Width.Value) { isUpscaling = true; } @@ -991,9 +975,9 @@ namespace MediaBrowser.Api.Playback // Don't allow bitrate increases unless upscaling if (!isUpscaling) { - if (bitrate.HasValue && state.VideoStream.BitRate.HasValue) + if (bitrate.HasValue && videoStream.BitRate.HasValue) { - bitrate = Math.Min(bitrate.Value, state.VideoStream.BitRate.Value); + bitrate = Math.Min(bitrate.Value, videoStream.BitRate.Value); } } } @@ -1003,7 +987,7 @@ namespace MediaBrowser.Api.Playback protected string GetVideoBitrateParam(StreamState state, string videoCodec, bool isHls) { - var bitrate = GetVideoBitrateParamValue(state); + var bitrate = state.OutputVideoBitrate; if (bitrate.HasValue) { @@ -1045,14 +1029,14 @@ namespace MediaBrowser.Api.Playback return string.Empty; } - protected int? GetAudioBitrateParam(StreamState state) + private int? GetAudioBitrateParam(StreamRequest request, MediaStream audioStream) { - if (state.Request.AudioBitRate.HasValue) + if (request.AudioBitRate.HasValue) { // Make sure we don't request a bitrate higher than the source - var currentBitrate = state.AudioStream == null ? state.Request.AudioBitRate.Value : state.AudioStream.BitRate ?? state.Request.AudioBitRate.Value; + var currentBitrate = audioStream == null ? request.AudioBitRate.Value : audioStream.BitRate ?? request.AudioBitRate.Value; - return Math.Min(currentBitrate, state.Request.AudioBitRate.Value); + return Math.Min(currentBitrate, request.AudioBitRate.Value); } return null; @@ -1399,7 +1383,7 @@ namespace MediaBrowser.Api.Playback } state.ReadInputAtNativeFramerate = recording.RecordingInfo.Status == RecordingStatus.InProgress; - state.AudioSync = "1000"; + state.OutputAudioSync = "1000"; state.DeInterlace = true; state.InputVideoSync = "-1"; state.InputAudioSync = "1"; @@ -1430,7 +1414,7 @@ namespace MediaBrowser.Api.Playback } state.ReadInputAtNativeFramerate = true; - state.AudioSync = "1000"; + state.OutputAudioSync = "1000"; state.DeInterlace = true; state.InputVideoSync = "-1"; state.InputAudioSync = "1"; @@ -1492,10 +1476,26 @@ namespace MediaBrowser.Api.Playback state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10; state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440; + var container = Path.GetExtension(state.RequestedUrl); + + if (string.IsNullOrEmpty(container)) + { + container = Path.GetExtension(GetOutputFilePath(state)); + } + + state.OutputContainer = (container ?? string.Empty).TrimStart('.'); + ApplyDeviceProfileSettings(state); + state.OutputContainer = GetOutputFileExtension(state).TrimStart('.'); + state.OutputAudioBitrate = GetAudioBitrateParam(state.Request, state.AudioStream); + state.OutputAudioSampleRate = request.AudioSampleRate; + state.OutputAudioChannels = GetNumAudioChannelsParam(state.Request, state.AudioStream); + if (videoRequest != null) { + state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream); + if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream)) { videoRequest.VideoCodec = "copy"; @@ -1649,13 +1649,6 @@ namespace MediaBrowser.Api.Playback return; } - var container = Path.GetExtension(state.RequestedUrl); - - if (string.IsNullOrEmpty(container)) - { - container = Path.GetExtension(GetOutputFilePath(state)); - } - var audioCodec = state.Request.AudioCodec; if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null) @@ -1671,8 +1664,8 @@ namespace MediaBrowser.Api.Playback } var mediaProfile = state.VideoRequest == null ? - profile.GetAudioMediaProfile(container, audioCodec, state.AudioStream) : - profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream); + profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.AudioStream) : + profile.GetVideoMediaProfile(state.OutputContainer, audioCodec, videoCodec, state.AudioStream, state.VideoStream); if (mediaProfile != null) { @@ -1681,8 +1674,8 @@ namespace MediaBrowser.Api.Playback } var transcodingProfile = state.VideoRequest == null ? - profile.GetAudioTranscodingProfile(container, audioCodec) : - profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec); + profile.GetAudioTranscodingProfile(state.OutputContainer, audioCodec) : + profile.GetVideoTranscodingProfile(state.OutputContainer, audioCodec, videoCodec); if (transcodingProfile != null) { @@ -1710,9 +1703,6 @@ namespace MediaBrowser.Api.Playback responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode; responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*"; - var contentFeatures = string.Empty; - var extension = GetOutputFileExtension(state); - // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none var orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(state.RunTimeTicks.HasValue, isStaticallyStreamed, state.TranscodeSeekInfo); @@ -1740,52 +1730,64 @@ namespace MediaBrowser.Api.Playback var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000", Enum.Format(typeof(DlnaFlags), flagValue, "x")); - if (!string.IsNullOrWhiteSpace(state.OrgPn)) - { - contentFeatures = "DLNA.ORG_PN=" + state.OrgPn; - } - else if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MP3"; - } - else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AAC_ISO"; - } - else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=WMABASE"; - } - else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AVI"; - } - else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase)) + var orgPn = GetOrgPnValue(state); + + var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : + "DLNA.ORG_PN=" + orgPn; + + if (!string.IsNullOrEmpty(contentFeatures)) { - contentFeatures = "DLNA.ORG_PN=MATROSKA"; + responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); } - else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase)) + + foreach (var item in responseHeaders) { - contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC"; + Request.Response.AddHeader(item.Key, item.Value); } - else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase)) + } + + private string GetOrgPnValue(StreamState state) + { + if (!string.IsNullOrWhiteSpace(state.OrgPn)) { - contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; + return state.OrgPn; } - else if (string.Equals(extension, ".ts", StringComparison.OrdinalIgnoreCase)) + + if (state.VideoRequest == null) { - contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; + var format = new MediaFormatProfileResolver() + .ResolveAudioFormat(state.OutputContainer, + state.OutputAudioBitrate, + state.OutputAudioSampleRate, + state.OutputAudioChannels); + + return format.HasValue ? format.Value.ToString() : null; } - if (!string.IsNullOrEmpty(contentFeatures)) + var audioCodec = state.Request.AudioCodec; + + if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null) { - responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + audioCodec = state.AudioStream.Codec; } - foreach (var item in responseHeaders) + var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec; + + if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null) { - Request.Response.AddHeader(item.Key, item.Value); + videoCodec = state.VideoStream.Codec; } + + var videoFormat = new MediaFormatProfileResolver() + .ResolveVideoFormat(state.OutputContainer, + videoCodec, + audioCodec, + state.OutputWidth, + state.OutputHeight, + state.TotalOutputBitrate, + TransportStreamTimestamp.VALID); + + return videoFormat.HasValue ? videoFormat.Value.ToString() : null; } private void AddTimeSeekResponseHeaders(StreamState state, IDictionary responseHeaders) diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index b5cd1bd409..2852d2489f 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -29,15 +29,6 @@ namespace MediaBrowser.Api.Playback.Hls { } - protected override string GetOutputFilePath(StreamState state) - { - var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath; - - var outputFileExtension = GetOutputFileExtension(state); - - return Path.Combine(folder, GetCommandLineArguments("dummy\\dummy", state, false).GetMD5() + (outputFileExtension ?? string.Empty).ToLower()); - } - /// /// Gets the audio arguments. /// @@ -93,17 +84,6 @@ namespace MediaBrowser.Api.Playback.Hls { var state = GetState(request, CancellationToken.None).Result; - if (!state.VideoRequest.VideoBitRate.HasValue && (string.IsNullOrEmpty(state.VideoRequest.VideoCodec) || !string.Equals(state.VideoRequest.VideoCodec, "copy", StringComparison.OrdinalIgnoreCase))) - { - state.Dispose(); - throw new ArgumentException("A video bitrate is required"); - } - if (!state.Request.AudioBitRate.HasValue && (string.IsNullOrEmpty(state.Request.AudioCodec) || !string.Equals(state.Request.AudioCodec, "copy", StringComparison.OrdinalIgnoreCase))) - { - state.Dispose(); - throw new ArgumentException("An audio bitrate is required"); - } - var playlist = GetOutputFilePath(state); if (File.Exists(playlist)) @@ -192,8 +172,8 @@ namespace MediaBrowser.Api.Playback.Hls /// The video bitrate. protected void GetPlaylistBitrates(StreamState state, out int audioBitrate, out int videoBitrate) { - var audioBitrateParam = GetAudioBitrateParam(state); - var videoBitrateParam = GetVideoBitrateParamValue(state); + var audioBitrateParam = state.OutputAudioBitrate; + var videoBitrateParam = state.OutputVideoBitrate; if (!audioBitrateParam.HasValue) { @@ -307,11 +287,10 @@ namespace MediaBrowser.Api.Playback.Hls // If performSubtitleConversions is true we're actually starting ffmpeg var startNumberParam = performSubtitleConversions ? GetStartNumber(state).ToString(UsCulture) : "0"; - var args = string.Format("{0} {1} -i {2}{3} -map_metadata -1 -threads {4} {5} {6} -sc_threshold 0 {7} -hls_time {8} -start_number {9} -hls_list_size {10} \"{11}\"", + var args = string.Format("{0} {1} -i {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9} \"{10}\"", itsOffset, inputModifier, GetInputArgument(state), - GetSlowSeekCommandLineParameter(state.Request), threads, GetMapArgs(state), GetVideoArguments(state, performSubtitleConversions), diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index ab0cd8871f..c865504045 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Dto; @@ -64,17 +63,6 @@ namespace MediaBrowser.Api.Playback.Hls { } - protected override string GetOutputFilePath(StreamState state) - { - var folder = (state.MediaPath + state.Request.DeviceId).GetMD5().ToString("N"); - - folder = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, folder); - - var outputFileExtension = GetOutputFileExtension(state); - - return Path.Combine(folder, GetCommandLineArguments("dummy\\dummy", state, false).GetMD5() + (outputFileExtension ?? string.Empty).ToLower()); - } - public object Get(GetMasterHlsVideoStream request) { var result = GetAsync(request).Result; @@ -136,15 +124,6 @@ namespace MediaBrowser.Api.Playback.Hls { var state = await GetState(request, CancellationToken.None).ConfigureAwait(false); - if (!state.VideoRequest.VideoBitRate.HasValue && (string.IsNullOrEmpty(state.VideoRequest.VideoCodec) || !string.Equals(state.VideoRequest.VideoCodec, "copy", StringComparison.OrdinalIgnoreCase))) - { - throw new ArgumentException("A video bitrate is required"); - } - if (!state.Request.AudioBitRate.HasValue && (string.IsNullOrEmpty(state.Request.AudioCodec) || !string.Equals(state.Request.AudioCodec, "copy", StringComparison.OrdinalIgnoreCase))) - { - throw new ArgumentException("An audio bitrate is required"); - } - int audioBitrate; int videoBitrate; GetPlaylistBitrates(state, out audioBitrate, out videoBitrate); @@ -260,14 +239,14 @@ namespace MediaBrowser.Api.Playback.Hls if (state.AudioStream != null) { - var channels = GetNumAudioChannelsParam(state.Request, state.AudioStream); + var channels = state.OutputAudioChannels; if (channels.HasValue) { args += " -ac " + channels.Value; } - var bitrate = GetAudioBitrateParam(state); + var bitrate = state.OutputAudioBitrate; if (bitrate.HasValue) { diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index 1bca4cae9a..efd98616f9 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -126,14 +126,14 @@ namespace MediaBrowser.Api.Playback.Hls if (state.AudioStream != null) { - var channels = GetNumAudioChannelsParam(state.Request, state.AudioStream); + var channels = state.OutputAudioChannels; if (channels.HasValue) { args += " -ac " + channels.Value; } - var bitrate = GetAudioBitrateParam(state); + var bitrate = state.OutputAudioBitrate; if (bitrate.HasValue) { diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index 55b311f867..d746b265df 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -82,23 +82,21 @@ namespace MediaBrowser.Api.Playback.Progressive var audioTranscodeParams = new List(); - var bitrate = GetAudioBitrateParam(state); + var bitrate = state.OutputAudioBitrate; if (bitrate.HasValue) { audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(UsCulture)); } - var channels = GetNumAudioChannelsParam(request, state.AudioStream); - - if (channels.HasValue) + if (state.OutputAudioChannels.HasValue) { - audioTranscodeParams.Add("-ac " + channels.Value); + audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture)); } - if (request.AudioSampleRate.HasValue) + if (state.OutputAudioSampleRate.HasValue) { - audioTranscodeParams.Add("-ar " + request.AudioSampleRate.Value); + audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture)); } const string vn = " -vn"; @@ -107,10 +105,9 @@ namespace MediaBrowser.Api.Playback.Progressive var inputModifier = GetInputModifier(state); - return string.Format("{0} -i {1}{2} -threads {3}{4} {5} -id3v2_version 3 -write_id3v1 1 \"{6}\"", + return string.Format("{0} -i {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 \"{5}\"", inputModifier, GetInputArgument(state), - GetSlowSeekCommandLineParameter(request), threads, vn, string.Join(" ", audioTranscodeParams.ToArray()), diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 29ad3e500b..f39169dbd8 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -308,16 +308,7 @@ namespace MediaBrowser.Api.Playback.Progressive /// System.Nullable{System.Int64}. private long? GetEstimatedContentLength(StreamState state) { - var totalBitrate = 0; - - if (state.Request.AudioBitRate.HasValue) - { - totalBitrate += state.Request.AudioBitRate.Value; - } - if (state.VideoRequest != null && state.VideoRequest.VideoBitRate.HasValue) - { - totalBitrate += state.VideoRequest.VideoBitRate.Value; - } + var totalBitrate = state.TotalOutputBitrate ?? 0; if (totalBitrate > 0 && state.RunTimeTicks.HasValue) { diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index 0d09854670..d61e8d73ad 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -107,10 +107,9 @@ namespace MediaBrowser.Api.Playback.Progressive var inputModifier = GetInputModifier(state); - return string.Format("{0} -i {1}{2}{3} {4} {5} -map_metadata -1 -threads {6} {7}{8} \"{9}\"", + return string.Format("{0} -i {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} \"{8}\"", inputModifier, GetInputArgument(state), - GetSlowSeekCommandLineParameter(state.Request), keyFrame, GetMapArgs(state), GetVideoArguments(state, videoCodec, performSubtitleConversions), @@ -204,14 +203,14 @@ namespace MediaBrowser.Api.Playback.Progressive var args = "-acodec " + codec; // Add the number of audio channels - var channels = GetNumAudioChannelsParam(request, state.AudioStream); + var channels = state.OutputAudioChannels; if (channels.HasValue) { args += " -ac " + channels.Value; } - var bitrate = GetAudioBitrateParam(state); + var bitrate = state.OutputAudioBitrate; if (bitrate.HasValue) { diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index e41f296638..067a3f978a 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -32,9 +33,7 @@ namespace MediaBrowser.Api.Playback public Stream LogFileStream { get; set; } public MediaStream AudioStream { get; set; } - public MediaStream VideoStream { get; set; } - public MediaStream SubtitleStream { get; set; } /// @@ -50,7 +49,6 @@ namespace MediaBrowser.Api.Playback public bool IsInputVideo { get; set; } public VideoType VideoType { get; set; } - public IsoType? IsoType { get; set; } public List PlayableStreamFileNames { get; set; } @@ -64,8 +62,8 @@ namespace MediaBrowser.Api.Playback public long? RunTimeTicks; - public string AudioSync = "1"; - public string VideoSync = "vfr"; + public string OutputAudioSync = "1"; + public string OutputVideoSync = "vfr"; public List SupportedAudioCodecs { get; set; } @@ -80,19 +78,14 @@ namespace MediaBrowser.Api.Playback public string InputVideoSync { get; set; } public bool DeInterlace { get; set; } - public bool ReadInputAtNativeFramerate { get; set; } - public string InputFormat { get; set; } - public string InputVideoCodec { get; set; } - public string InputAudioCodec { get; set; } public string MimeType { get; set; } public string OrgPn { get; set; } - // DLNA Settings public bool EstimateContentLength { get; set; } public bool EnableMpegtsM2TsMode { get; set; } public TranscodeSeekInfo TranscodeSeekInfo { get; set; } @@ -162,5 +155,70 @@ namespace MediaBrowser.Api.Playback } } } + + public int? OutputAudioChannels; + public int? OutputAudioSampleRate; + public int? OutputAudioBitrate; + public int? OutputVideoBitrate; + + public string OutputContainer { get; set; } + + public int? TotalOutputBitrate + { + get + { + return (OutputAudioBitrate ?? 0) + (OutputVideoBitrate ?? 0); + } + } + + public int? OutputWidth + { + get + { + if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue) + { + var size = new ImageSize + { + Width = VideoStream.Width.Value, + Height = VideoStream.Height.Value + }; + + var newSize = DrawingUtils.Resize(size, + VideoRequest.Width, + VideoRequest.Height, + VideoRequest.MaxWidth, + VideoRequest.MaxHeight); + + return Convert.ToInt32(newSize.Width); + } + + return VideoRequest.MaxWidth ?? VideoRequest.Width; + } + } + + public int? OutputHeight + { + get + { + if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue) + { + var size = new ImageSize + { + Width = VideoStream.Width.Value, + Height = VideoStream.Height.Value + }; + + var newSize = DrawingUtils.Resize(size, + VideoRequest.Width, + VideoRequest.Height, + VideoRequest.MaxWidth, + VideoRequest.MaxHeight); + + return Convert.ToInt32(newSize.Height); + } + + return VideoRequest.MaxHeight ?? VideoRequest.Height; + } + } } } diff --git a/MediaBrowser.Dlna/Server/ControlHandler.cs b/MediaBrowser.Dlna/Server/ControlHandler.cs index a7c25cd382..368f06df47 100644 --- a/MediaBrowser.Dlna/Server/ControlHandler.cs +++ b/MediaBrowser.Dlna/Server/ControlHandler.cs @@ -630,24 +630,42 @@ namespace MediaBrowser.Dlna.Server res.SetAttribute("bitrate", targetAudioBitrate.Value.ToString(_usCulture)); } - var formatProfile = new MediaFormatProfileResolver().ResolveVideoFormat(streamInfo.Container, - targetVideoCodec, - targetAudioCodec, - targetWidth, - targetHeight, - targetBitrate, - TransportStreamTimestamp.NONE); + var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container, + streamInfo.AudioCodec, + streamInfo.VideoCodec, + streamInfo.TargetAudioStream, + streamInfo.TargetVideoStream); + + var formatProfile = mediaProfile == null ? null : mediaProfile.OrgPn; + + if (string.IsNullOrEmpty(formatProfile)) + { + var format = new MediaFormatProfileResolver().ResolveVideoFormat(streamInfo.Container, + targetVideoCodec, + targetAudioCodec, + targetWidth, + targetHeight, + targetBitrate, + TransportStreamTimestamp.VALID); + + formatProfile = format.HasValue ? format.Value.ToString() : null; + } var filename = url.Substring(0, url.IndexOf('?')); + var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType) + ? MimeTypes.GetMimeType(filename) + : mediaProfile.MimeType; + var orgOpValue = DlnaMaps.GetOrgOpValue(mediaSource.RunTimeTicks.HasValue, streamInfo.IsDirectStream, streamInfo.TranscodeSeekInfo); var orgCi = streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; + var orgPn = !string.IsNullOrEmpty(formatProfile) ? "DLNA.ORG_PN=:" + formatProfile + ";" : string.Empty; res.SetAttribute("protocolInfo", String.Format( - "http-get:*:{0}:DLNA.ORG_PN={1};DLNA.ORG_OP={2};DLNA.ORG_CI={3};DLNA.ORG_FLAGS={4}", - MimeTypes.GetMimeType(filename), - formatProfile, + "http-get:*:{0}:{1}DLNA.ORG_OP={2};DLNA.ORG_CI={3};DLNA.ORG_FLAGS={4}", + mimeType, + orgPn, orgOpValue, orgCi, DlnaMaps.DefaultStreaming @@ -712,18 +730,36 @@ namespace MediaBrowser.Dlna.Server res.SetAttribute("bitrate", targetAudioBitrate.Value.ToString(_usCulture)); } - var formatProfile = new MediaFormatProfileResolver().ResolveAudioFormat(streamInfo.Container, targetAudioBitrate, targetSampleRate, targetChannels); + var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container, + streamInfo.AudioCodec, + streamInfo.TargetAudioStream); + + var formatProfile = mediaProfile == null ? null : mediaProfile.OrgPn; + + if (string.IsNullOrEmpty(formatProfile)) + { + var format = new MediaFormatProfileResolver().ResolveAudioFormat(streamInfo.Container, + targetAudioBitrate, targetSampleRate, targetChannels); + + formatProfile = format.HasValue ? format.Value.ToString() : null; + } var filename = url.Substring(0, url.IndexOf('?')); + var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType) + ? MimeTypes.GetMimeType(filename) + : mediaProfile.MimeType; + var orgOpValue = DlnaMaps.GetOrgOpValue(mediaSource.RunTimeTicks.HasValue, streamInfo.IsDirectStream, streamInfo.TranscodeSeekInfo); var orgCi = streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; + var orgPn = !string.IsNullOrEmpty(formatProfile) ? "DLNA.ORG_PN=:" + formatProfile + ";" : string.Empty; + res.SetAttribute("protocolInfo", String.Format( - "http-get:*:{0}:DLNA.ORG_PN={1};DLNA.ORG_OP={2};DLNA.ORG_CI={3};DLNA.ORG_FLAGS={4}", - MimeTypes.GetMimeType(filename), - formatProfile, + "http-get:*:{0}:{1}DLNA.ORG_OP={2};DLNA.ORG_CI={3};DLNA.ORG_FLAGS={4}", + mimeType, + orgPn, orgOpValue, orgCi, DlnaMaps.DefaultStreaming @@ -815,7 +851,7 @@ namespace MediaBrowser.Dlna.Server } element.AppendChild(CreateObjectClass(element.OwnerDocument, item)); - + if (filter.Contains("dc:date")) { if (item.PremiereDate.HasValue) @@ -962,9 +998,13 @@ namespace MediaBrowser.Dlna.Server var mediaProfile = new MediaFormatProfileResolver().ResolveImageFormat("jpg", width, height); + var orgPn = mediaProfile.HasValue ? "DLNA.ORG_PN=:" + mediaProfile.Value + ";" : string.Empty; + res.SetAttribute("protocolInfo", string.Format( - "http-get:*:{1}DLNA.ORG_PN=:{0};DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS={2}", - mediaProfile, "image/jpeg", DlnaMaps.DefaultStreaming + "http-get:*:{1}:{0}DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS={2}", + orgPn, + "image/jpeg", + DlnaMaps.DefaultStreaming )); if (width.HasValue && height.HasValue) diff --git a/MediaBrowser.MediaEncoding/Encoder/InternalEncodingTaskFactory.cs b/MediaBrowser.MediaEncoding/Encoder/InternalEncodingTaskFactory.cs index e6b67b0df6..f52f072dff 100644 --- a/MediaBrowser.MediaEncoding/Encoder/InternalEncodingTaskFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/InternalEncodingTaskFactory.cs @@ -262,31 +262,31 @@ namespace MediaBrowser.MediaEncoding.Encoder videoCodec = state.VideoStream.Codec; } - var mediaProfile = state.VideoRequest == null ? - profile.GetAudioMediaProfile(container, audioCodec, state.AudioStream) : - profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream); - - if (mediaProfile != null) - { - state.MimeType = mediaProfile.MimeType; - state.OrgPn = mediaProfile.OrgPn; - } - - var transcodingProfile = state.VideoRequest == null ? - profile.GetAudioTranscodingProfile(container, audioCodec) : - profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec); - - if (transcodingProfile != null) - { - //state.EstimateContentLength = transcodingProfile.EstimateContentLength; - state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; - //state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; - - if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.VideoProfile)) - { - state.VideoRequest.VideoProfile = transcodingProfile.VideoProfile; - } - } + //var mediaProfile = state.VideoRequest == null ? + // profile.GetAudioMediaProfile(container, audioCodec) : + // profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream); + + //if (mediaProfile != null) + //{ + // state.MimeType = mediaProfile.MimeType; + // state.OrgPn = mediaProfile.OrgPn; + //} + + //var transcodingProfile = state.VideoRequest == null ? + // profile.GetAudioTranscodingProfile(container, audioCodec) : + // profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec); + + //if (transcodingProfile != null) + //{ + // //state.EstimateContentLength = transcodingProfile.EstimateContentLength; + // state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; + // //state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; + + // if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.VideoProfile)) + // { + // state.VideoRequest.VideoProfile = transcodingProfile.VideoProfile; + // } + //} } private EncodingQuality GetQualitySetting() diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index 8b5966c9a1..7034aee724 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -1,39 +1,60 @@ using System; +using System.Collections.Generic; +using System.Linq; namespace MediaBrowser.Model.Dlna { public class MediaFormatProfileResolver { - public MediaFormatProfile ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType) + public MediaFormatProfile? ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType) { if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) - return ResolveVideoASFFormat(videoCodec, audioCodec, width, height, bitrate); + return ResolveVideoASFFormat(videoCodec, audioCodec, width, height); + if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase)) return ResolveVideoMP4Format(videoCodec, audioCodec, width, height, bitrate); + if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.AVI; + if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.MATROSKA; - if (string.Equals(container, "mpeg2ps", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase)) + + if (string.Equals(container, "mpeg2ps", StringComparison.OrdinalIgnoreCase) || + string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase)) // MediaFormatProfile.MPEG_PS_PAL, MediaFormatProfile.MPEG_PS_NTSC return MediaFormatProfile.MPEG_PS_NTSC; + if (string.Equals(container, "mpeg1video", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.MPEG1; - if (string.Equals(container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "mpegts", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase)) - return ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, bitrate, timestampType); + + if (string.Equals(container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) || + string.Equals(container, "mpegts", StringComparison.OrdinalIgnoreCase) || + string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase)) + { + + var list = ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, bitrate, timestampType) + .ToList(); + + return list.Count > 0 ? list[0] : (MediaFormatProfile?)null; + } + if (string.Equals(container, "flv", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.FLV; + if (string.Equals(container, "wtv", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.WTV; + if (string.Equals(container, "3gp", StringComparison.OrdinalIgnoreCase)) - return ResolveVideo3GPFormat(videoCodec, audioCodec, width, height, bitrate); + return ResolveVideo3GPFormat(videoCodec, audioCodec); + if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.OGV; - throw new ArgumentException("Unsupported container: " + container); + return null; } - private MediaFormatProfile ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType) + private IEnumerable ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType) { var suffix = ""; @@ -47,48 +68,59 @@ namespace MediaBrowser.Model.Dlna break; } - String resolution = "S"; + var resolution = "S"; if ((width.HasValue && width.Value > 720) || (height.HasValue && height.Value > 576)) { resolution = "H"; } - // if (videoCodec == VideoCodec.MPEG2) - // { - // List!(MediaFormatProfile) profiles = Arrays.asList(cast(MediaFormatProfile[])[ MediaFormatProfile.valueOf("MPEG_TS_SD_EU" + suffix), MediaFormatProfile.valueOf("MPEG_TS_SD_NA" + suffix), MediaFormatProfile.valueOf("MPEG_TS_SD_KO" + suffix) ]); + if (string.Equals(videoCodec, "mpeg2video", StringComparison.OrdinalIgnoreCase)) + { + var list = new List(); + + list.Add(ValueOf("MPEG_TS_SD_NA" + suffix)); + list.Add(ValueOf("MPEG_TS_SD_EU" + suffix)); + list.Add(ValueOf("MPEG_TS_SD_KO" + suffix)); - // if ((timestampType == TransportStreamTimestamp.VALID) && (audioCodec == AudioCodec.AAC)) { - // profiles.add(MediaFormatProfile.MPEG_TS_JP_T); - // } - // return profiles; - // } + if ((timestampType == TransportStreamTimestamp.VALID) && string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { + list.Add(MediaFormatProfile.MPEG_TS_JP_T); + } + return list; + } if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(audioCodec, "lpcm", StringComparison.OrdinalIgnoreCase)) - return MediaFormatProfile.AVC_TS_HD_50_LPCM_T; + return new[] { MediaFormatProfile.AVC_TS_HD_50_LPCM_T }; if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase)) { if (timestampType == TransportStreamTimestamp.NONE) { - return MediaFormatProfile.AVC_TS_HD_DTS_ISO; + return new[] { MediaFormatProfile.AVC_TS_HD_DTS_ISO }; } - return MediaFormatProfile.AVC_TS_HD_DTS_T; + return new[] { MediaFormatProfile.AVC_TS_HD_DTS_T }; } - //if (audioCodec == AudioCodec.MP2) { - // if (isNoTimestamp(timestampType)) { - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_HP_%sD_MPEG1_L2_ISO", cast(Object[])[ resolution ]))); - // } - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_HP_%sD_MPEG1_L2_T", cast(Object[])[ resolution ]))); - //} - - //if (audioCodec == AudioCodec.AAC) - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_MP_%sD_AAC_MULT5%s", cast(Object[])[ resolution, suffix ]))); - //if (audioCodec == AudioCodec.MP3) - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_MP_%sD_MPEG1_L3%s", cast(Object[])[ resolution, suffix ]))); - //if ((audioCodec is null) || (audioCodec == AudioCodec.AC3)) { - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_MP_%sD_AC3%s", cast(Object[])[ resolution, suffix ]))); - //} + + if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) + { + if (timestampType == TransportStreamTimestamp.NONE) + { + return new[] { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_ISO", resolution)) }; + } + + return new[] { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_T", resolution)) }; + } + + if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + return new[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix)) }; + + if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) + return new[] { ValueOf(string.Format("AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix)) }; + + if (string.IsNullOrEmpty(audioCodec) || + string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) + return new[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AC3{1}", resolution, suffix)) }; } else if (string.Equals(videoCodec, "vc1", StringComparison.OrdinalIgnoreCase)) { @@ -96,9 +128,9 @@ namespace MediaBrowser.Model.Dlna { if ((width.HasValue && width.Value > 720) || (height.HasValue && height.Value > 576)) { - return MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO; + return new[] { MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO }; } - return MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO; + return new[] { MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO }; } // if (audioCodec == AudioCodec.DTS) { // suffix = suffix.equals("_ISO") ? suffix : "_T"; @@ -116,10 +148,15 @@ namespace MediaBrowser.Model.Dlna // } } - throw new ArgumentException("Mpeg video file does not match any supported DLNA profile"); + return new List(); + } + + private MediaFormatProfile ValueOf(string value) + { + return (MediaFormatProfile)Enum.Parse(typeof(MediaFormatProfile), value, true); } - private MediaFormatProfile ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height, int? bitrate) + private MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height, int? bitrate) { if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { @@ -177,10 +214,10 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.MPEG4_H263_MP4_P0_L10_AAC; } - throw new ArgumentException("MP4 video file does not match any supported DLNA profile"); + return null; } - private MediaFormatProfile ResolveVideo3GPFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate) + private MediaFormatProfile? ResolveVideo3GPFormat(string videoCodec, string audioCodec) { if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { @@ -200,9 +237,10 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.MPEG4_H263_3GPP_P0_L10_AMR; } - throw new ArgumentException("3GP video file does not match any supported DLNA profile"); + return null; } - private MediaFormatProfile ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate) + + private MediaFormatProfile? ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height) { if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase) && (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "wmapro", StringComparison.OrdinalIgnoreCase))) @@ -244,29 +282,38 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.DVR_MS; } - throw new ArgumentException("ASF video file does not match any supported DLNA profile"); + return null; } - public MediaFormatProfile ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels) + public MediaFormatProfile? ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels) { if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) - return ResolveAudioASFFormat(bitrate, frequency, channels); + return ResolveAudioASFFormat(bitrate); + if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.MP3; + if (string.Equals(container, "lpcm", StringComparison.OrdinalIgnoreCase)) - return ResolveAudioLPCMFormat(bitrate, frequency, channels); - if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase)) - return ResolveAudioMP4Format(bitrate, frequency, channels); + return ResolveAudioLPCMFormat(frequency, channels); + + if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase) || + string.Equals(container, "aac", StringComparison.OrdinalIgnoreCase)) + return ResolveAudioMP4Format(bitrate); + if (string.Equals(container, "adts", StringComparison.OrdinalIgnoreCase)) - return ResolveAudioADTSFormat(bitrate, frequency, channels); + return ResolveAudioADTSFormat(bitrate); + if (string.Equals(container, "flac", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.FLAC; - if (string.Equals(container, "oga", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) + + if (string.Equals(container, "oga", StringComparison.OrdinalIgnoreCase) || + string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.OGG; - throw new ArgumentException("Unsupported container: " + container); + + return null; } - private MediaFormatProfile ResolveAudioASFFormat(int? bitrate, int? frequency, int? channels) + private MediaFormatProfile ResolveAudioASFFormat(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 193) { @@ -275,7 +322,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.WMA_FULL; } - private MediaFormatProfile ResolveAudioLPCMFormat(int? bitrate, int? frequency, int? channels) + private MediaFormatProfile? ResolveAudioLPCMFormat(int? frequency, int? channels) { if (frequency.HasValue && channels.HasValue) { @@ -296,13 +343,13 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.LPCM16_48_STEREO; } - throw new ArgumentException("Unsupported LPCM format of file %s. Only 44100 / 48000 Hz and Mono / Stereo files are allowed."); + return null; } return MediaFormatProfile.LPCM16_48_STEREO; } - private MediaFormatProfile ResolveAudioMP4Format(int? bitrate, int? frequency, int? channels) + private MediaFormatProfile ResolveAudioMP4Format(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 320) { @@ -311,7 +358,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.AAC_ISO; } - private MediaFormatProfile ResolveAudioADTSFormat(int? bitrate, int? frequency, int? channels) + private MediaFormatProfile ResolveAudioADTSFormat(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 320) { @@ -320,19 +367,22 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.AAC_ADTS; } - public MediaFormatProfile ResolveImageFormat(string container, int? width, int? height) + public MediaFormatProfile? ResolveImageFormat(string container, int? width, int? height) { if (string.Equals(container, "jpeg", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "jpg", StringComparison.OrdinalIgnoreCase)) return ResolveImageJPGFormat(width, height); + if (string.Equals(container, "png", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.PNG_LRG; + if (string.Equals(container, "gif", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.GIF_LRG; + if (string.Equals(container, "raw", StringComparison.OrdinalIgnoreCase)) return MediaFormatProfile.RAW; - throw new ArgumentException("Unsupported container: " + container); + return null; } private MediaFormatProfile ResolveImageJPGFormat(int? width, int? height)