diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 4d003ca7c..3344bfcfe 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -472,6 +472,7 @@ namespace Emby.Dlna.Didl var targetAudioBitrate = streamInfo.TargetAudioBitrate; var targetSampleRate = streamInfo.TargetAudioSampleRate; var targetChannels = streamInfo.TargetAudioChannels; + var targetAudioBitDepth = streamInfo.TargetAudioBitDepth; if (targetChannels.HasValue) { @@ -492,7 +493,8 @@ namespace Emby.Dlna.Didl streamInfo.TargetAudioCodec, targetChannels, targetAudioBitrate, - targetSampleRate); + targetSampleRate, + targetAudioBitDepth); var filename = url.Substring(0, url.IndexOf('?')); @@ -505,6 +507,7 @@ namespace Emby.Dlna.Didl targetAudioBitrate, targetSampleRate, targetChannels, + targetAudioBitDepth, streamInfo.IsDirectStream, streamInfo.RunTimeTicks, streamInfo.TranscodeSeekInfo); diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 8c168dc23..15d73e824 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -532,6 +532,7 @@ namespace Emby.Dlna.PlayTo streamInfo.TargetAudioBitrate, streamInfo.TargetAudioSampleRate, streamInfo.TargetAudioChannels, + streamInfo.TargetAudioBitDepth, streamInfo.IsDirectStream, streamInfo.RunTimeTicks, streamInfo.TranscodeSeekInfo); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index e4ef294d1..8d01e4021 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -869,7 +869,7 @@ namespace MediaBrowser.Api.Playback var videoCodec = state.ActualOutputVideoCodec; var mediaProfile = state.VideoRequest == null ? - profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate) : + profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) : profile.GetVideoMediaProfile(state.OutputContainer, audioCodec, videoCodec, @@ -966,6 +966,7 @@ namespace MediaBrowser.Api.Playback state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioChannels, + state.OutputAudioBitDepth, isStaticallyStreamed, state.RunTimeTicks, state.TranscodeSeekInfo diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs index b9bcd106e..118bf5246 100644 --- a/MediaBrowser.Api/Playback/UniversalAudioService.cs +++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs @@ -52,6 +52,7 @@ namespace MediaBrowser.Api.Playback public string TranscodingContainer { get; set; } public string TranscodingProtocol { get; set; } public int? MaxAudioSampleRate { get; set; } + public int? MaxAudioBitDepth { get; set; } public bool EnableRedirection { get; set; } public bool EnableRemoteMedia { get; set; } @@ -164,6 +165,18 @@ namespace MediaBrowser.Api.Playback }); } + if (request.MaxAudioBitDepth.HasValue) + { + // codec profile + conditions.Add(new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + IsRequired = false, + Property = ProfileConditionValue.AudioBitDepth, + Value = request.MaxAudioBitDepth.Value.ToString(CultureInfo.InvariantCulture) + }); + } + if (request.MaxAudioChannels.HasValue) { // codec profile @@ -266,6 +279,7 @@ namespace MediaBrowser.Api.Playback Static = isStatic, SegmentContainer = request.TranscodingContainer, AudioSampleRate = request.MaxAudioSampleRate, + MaxAudioBitDepth = request.MaxAudioBitDepth, BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames, TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()) }; @@ -310,6 +324,7 @@ namespace MediaBrowser.Api.Playback StartTimeTicks = request.StartTimeTicks, Static = isStatic, AudioSampleRate = request.MaxAudioSampleRate, + MaxAudioBitDepth = request.MaxAudioBitDepth, TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()) }; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index a83a6a15e..b552579a8 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -284,6 +284,29 @@ namespace MediaBrowser.Controller.MediaEncoding } } + public int? OutputAudioBitDepth + { + get + { + if (BaseRequest.Static || string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) + { + if (AudioStream != null) + { + return AudioStream.BitDepth; + } + } + + //else if (BaseRequest.AudioSampleRate.HasValue) + //{ + // // Don't exceed what the encoder supports + // // Seeing issues of attempting to encode to 88200 + // return Math.Min(44100, BaseRequest.AudioSampleRate.Value); + //} + + return null; + } + } + /// /// Predicts the audio sample rate that will be in the output stream /// diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index 28ef66566..5fc93bf38 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -83,6 +83,8 @@ namespace MediaBrowser.Controller.MediaEncoding [ApiMember(Name = "AudioSampleRate", Description = "Optional. Specify a specific audio sample rate, e.g. 44100", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? AudioSampleRate { get; set; } + public int? MaxAudioBitDepth { get; set; } + /// /// Gets or sets the audio bit rate. /// diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index ba5f625f5..50d3d254a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -262,7 +262,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var outputContainer = state.Options.OutputContainer; var mediaProfile = state.IsVideoRequest ? - profile.GetAudioMediaProfile(outputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate) : + profile.GetAudioMediaProfile(outputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) : profile.GetVideoMediaProfile(outputContainer, audioCodec, videoCodec, diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index a388bf98b..291096f75 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Model.Dlna public bool IsVideoConditionSatisfied(ProfileCondition condition, int? width, int? height, - int? bitDepth, + int? videoBitDepth, int? videoBitrate, string videoProfile, double? videoLevel, @@ -46,7 +46,7 @@ namespace MediaBrowser.Model.Dlna case ProfileConditionValue.PacketLength: return IsConditionSatisfied(condition, packetLength); case ProfileConditionValue.VideoBitDepth: - return IsConditionSatisfied(condition, bitDepth); + return IsConditionSatisfied(condition, videoBitDepth); case ProfileConditionValue.VideoBitrate: return IsConditionSatisfied(condition, videoBitrate); case ProfileConditionValue.Height: @@ -79,7 +79,7 @@ namespace MediaBrowser.Model.Dlna } } - public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate) + public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth) { switch (condition.Property) { @@ -89,6 +89,8 @@ namespace MediaBrowser.Model.Dlna return IsConditionSatisfied(condition, audioChannels); case ProfileConditionValue.AudioSampleRate: return IsConditionSatisfied(condition, audioSampleRate); + case ProfileConditionValue.AudioBitDepth: + return IsConditionSatisfied(condition, audioBitDepth); default: throw new ArgumentException("Unexpected condition on audio file: " + condition.Property); } @@ -97,7 +99,8 @@ namespace MediaBrowser.Model.Dlna public bool IsVideoAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, - int? audioSampleRate, + int? audioSampleRate, + int? audioBitDepth, string audioProfile, bool? isSecondaryTrack) { @@ -113,6 +116,8 @@ namespace MediaBrowser.Model.Dlna return IsConditionSatisfied(condition, isSecondaryTrack); case ProfileConditionValue.AudioSampleRate: return IsConditionSatisfied(condition, audioSampleRate); + case ProfileConditionValue.AudioBitDepth: + return IsConditionSatisfied(condition, audioBitDepth); default: throw new ArgumentException("Unexpected condition on audio file: " + condition.Property); } diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index 6f6994a7e..8a9dc1dd1 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -55,6 +55,7 @@ namespace MediaBrowser.Model.Dlna int? audioBitrate, int? audioSampleRate, int? audioChannels, + int? audioBitDepth, bool isDirectStream, long? runtimeTicks, TranscodeSeekInfo transcodeSeekInfo) @@ -86,7 +87,8 @@ namespace MediaBrowser.Model.Dlna audioCodec, audioChannels, audioBitrate, - audioSampleRate); + audioSampleRate, + audioBitDepth); string orgPn = mediaProfile == null ? null : mediaProfile.OrgPn; diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 33d73e3bb..cd7ff08d6 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -185,7 +185,7 @@ namespace MediaBrowser.Model.Dlna return null; } - public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate) + public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth) { container = StringHelper.TrimStart(container ?? string.Empty, '.'); @@ -213,7 +213,7 @@ namespace MediaBrowser.Model.Dlna var anyOff = false; foreach (ProfileCondition c in i.Conditions) { - if (!conditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate)) + if (!conditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth)) { anyOff = true; break; diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs index 208a7df7e..a96e9ac36 100644 --- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs +++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs @@ -23,6 +23,7 @@ VideoCodecTag = 19, IsAvc = 20, IsInterlaced = 21, - AudioSampleRate = 22 + AudioSampleRate = 22, + AudioBitDepth = 23 } } \ No newline at end of file diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index ebfeb358e..342796a10 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -167,6 +167,9 @@ namespace MediaBrowser.Model.Dlna case ProfileConditionValue.VideoBitDepth: return TranscodeReason.VideoBitDepthNotSupported; + case ProfileConditionValue.AudioBitDepth: + return TranscodeReason.AudioBitDepthNotSupported; + case ProfileConditionValue.VideoBitrate: return TranscodeReason.VideoBitrateNotSupported; @@ -234,6 +237,7 @@ namespace MediaBrowser.Model.Dlna int? inputAudioChannels = audioStream == null ? null : audioStream.Channels; int? inputAudioBitrate = audioStream == null ? null : audioStream.BitDepth; int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate; + int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth; if (directPlayMethods.Count > 0) { @@ -250,7 +254,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate)) + if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth)) { LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item); applyConditions = false; @@ -271,7 +275,7 @@ namespace MediaBrowser.Model.Dlna bool all = true; foreach (ProfileCondition c in conditions) { - if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate)) + if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth)) { LogConditionFailure(options.Profile, "AudioCodecProfile", c, item); var transcodeReason = GetTranscodeReasonForFailedCondition(c); @@ -351,7 +355,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate)) + if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth)) { LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item); applyConditions = false; @@ -734,8 +738,9 @@ namespace MediaBrowser.Model.Dlna int? audioChannels = audioStream == null ? null : audioStream.Channels; string audioProfile = audioStream == null ? null : audioStream.Profile; int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate; + int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth; - if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, audioProfile, isSecondaryAudio)) + if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio)) { LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item); applyConditions = false; @@ -972,6 +977,7 @@ namespace MediaBrowser.Model.Dlna int? audioChannels = audioStream == null ? null : audioStream.Channels; string audioProfile = audioStream == null ? null : audioStream.Profile; int? audioSampleRate = audioStream == null ? null : audioStream.SampleRate; + int? audioBitDepth = audioStream == null ? null : audioStream.BitDepth; TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp; int? packetLength = videoStream == null ? null : videoStream.PacketLength; @@ -1066,7 +1072,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioProfile, isSecondaryAudio)) + if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio)) { LogConditionFailure(profile, "VideoAudioCodecProfile", applyCondition, mediaSource); applyConditions = false; @@ -1086,7 +1092,7 @@ namespace MediaBrowser.Model.Dlna foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioProfile, isSecondaryAudio)) + if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio)) { LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource); diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index d70d89cf7..9c8e8b030 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -477,6 +477,18 @@ namespace MediaBrowser.Model.Dlna } } + /// + /// Predicts the audio sample rate that will be in the output stream + /// + public int? TargetAudioBitDepth + { + get + { + MediaStream stream = TargetAudioStream; + return stream == null ? null : stream.BitDepth; + } + } + /// /// Predicts the audio sample rate that will be in the output stream /// diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs index 67eac6fd5..f1cbacd90 100644 --- a/MediaBrowser.Model/Session/TranscodingInfo.cs +++ b/MediaBrowser.Model/Session/TranscodingInfo.cs @@ -47,6 +47,7 @@ namespace MediaBrowser.Model.Session VideoBitrateNotSupported = 16, VideoFramerateNotSupported = 17, VideoLevelNotSupported = 18, - VideoProfileNotSupported = 19 + VideoProfileNotSupported = 19, + AudioBitDepthNotSupported = 20 } } \ No newline at end of file