diff options
| author | Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com> | 2024-09-09 22:16:58 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-09 13:16:58 -0600 |
| commit | 3da081ba86940f3fcedb188b2243445d1f95c883 (patch) | |
| tree | f43bf969d9c36cc42de54ad9f85c86d46b59a8c5 /MediaBrowser.Model | |
| parent | 43861f0ce112873514d3f97f3c4320525d642b39 (diff) | |
Add audio ranking for transcoding profiles (#12546)
Diffstat (limited to 'MediaBrowser.Model')
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamBuilder.cs | 100 |
1 files changed, 69 insertions, 31 deletions
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 490ae4e62..f68a8bca3 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -751,8 +751,9 @@ namespace MediaBrowser.Model.Dlna { // Can't direct play, find the transcoding profile // If we do this for direct-stream we will overwrite the info - var transcodingProfile = GetVideoTranscodeProfile(item, options, videoStream, audioStream, candidateAudioStreams, subtitleStream, playlistItem); - if (transcodingProfile is not null) + var (transcodingProfile, playMethod) = GetVideoTranscodeProfile(item, options, videoStream, audioStream, candidateAudioStreams, subtitleStream, playlistItem); + + if (transcodingProfile is not null && playMethod.HasValue) { SetStreamInfoOptionsFromTranscodingProfile(item, playlistItem, transcodingProfile); @@ -790,7 +791,7 @@ namespace MediaBrowser.Model.Dlna return playlistItem; } - private TranscodingProfile? GetVideoTranscodeProfile( + private (TranscodingProfile? Profile, PlayMethod? PlayMethod) GetVideoTranscodeProfile( MediaSourceInfo item, MediaOptions options, MediaStream? videoStream, @@ -801,7 +802,7 @@ namespace MediaBrowser.Model.Dlna { if (!(item.SupportsTranscoding || item.SupportsDirectStream)) { - return null; + return (null, null); } var transcodingProfiles = options.Profile.TranscodingProfiles @@ -812,41 +813,78 @@ namespace MediaBrowser.Model.Dlna transcodingProfiles = transcodingProfiles.Where(i => string.Equals(i.Container, "ts", StringComparison.OrdinalIgnoreCase)); } - if (options.AllowVideoStreamCopy) - { - // prefer direct copy profile - float videoFramerate = videoStream?.ReferenceFrameRate ?? 0; - TransportStreamTimestamp? timestamp = videoStream is null ? TransportStreamTimestamp.None : item.Timestamp; - int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio); - int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video); + var videoCodec = videoStream?.Codec; + float videoFramerate = videoStream?.ReferenceFrameRate ?? 0; + TransportStreamTimestamp? timestamp = videoStream is null ? TransportStreamTimestamp.None : item.Timestamp; + int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio); + int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video); - transcodingProfiles = transcodingProfiles.ToLookup(transcodingProfile => + var audioCodec = audioStream?.Codec; + var audioProfile = audioStream?.Profile; + var audioChannels = audioStream?.Channels; + var audioBitrate = audioStream?.BitRate; + var audioSampleRate = audioStream?.SampleRate; + var audioBitDepth = audioStream?.BitDepth; + + var analyzedProfiles = transcodingProfiles + .Select(transcodingProfile => { - var videoCodecs = ContainerProfile.SplitValue(transcodingProfile.VideoCodec); + var rank = (Video: 3, Audio: 3); + + var container = transcodingProfile.Container; + + if (options.AllowVideoStreamCopy) + { + var videoCodecs = ContainerProfile.SplitValue(transcodingProfile.VideoCodec); + + if (ContainerProfile.ContainsContainer(videoCodecs, videoCodec)) + { + var appliedVideoConditions = options.Profile.CodecProfiles + .Where(i => i.Type == CodecType.Video && + i.ContainsAnyCodec(videoCodec, container) && + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.VideoRangeType, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))) + .Select(i => + i.Conditions.All(condition => ConditionProcessor.IsVideoConditionSatisfied(condition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.VideoRangeType, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))); + + // An empty appliedVideoConditions means that the codec has no conditions for the current video stream + var conditionsSatisfied = appliedVideoConditions.All(satisfied => satisfied); + rank.Video = conditionsSatisfied ? 1 : 2; + } + } + + if (options.AllowAudioStreamCopy) + { + var audioCodecs = ContainerProfile.SplitValue(transcodingProfile.AudioCodec); + + if (ContainerProfile.ContainsContainer(audioCodecs, audioCodec)) + { + var appliedVideoConditions = options.Profile.CodecProfiles + .Where(i => i.Type == CodecType.VideoAudio && + i.ContainsAnyCodec(audioCodec, container) && + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, false))) + .Select(i => + i.Conditions.All(condition => ConditionProcessor.IsVideoAudioConditionSatisfied(condition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, false))); + + // An empty appliedVideoConditions means that the codec has no conditions for the current audio stream + var conditionsSatisfied = appliedVideoConditions.All(satisfied => satisfied); + rank.Audio = conditionsSatisfied ? 1 : 2; + } + } + + PlayMethod playMethod = PlayMethod.Transcode; - if (ContainerProfile.ContainsContainer(videoCodecs, item.VideoStream?.Codec)) + if (rank.Video == 1) { - var videoCodec = videoStream?.Codec; - var container = transcodingProfile.Container; - var appliedVideoConditions = options.Profile.CodecProfiles - .Where(i => i.Type == CodecType.Video && - i.ContainsAnyCodec(videoCodec, container) && - i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.VideoRangeType, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))) - .Select(i => - i.Conditions.All(condition => ConditionProcessor.IsVideoConditionSatisfied(condition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.VideoRangeType, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))); - - // An empty appliedVideoConditions means that the codec has no conditions for the current video stream - var conditionsSatisfied = appliedVideoConditions.All(satisfied => satisfied); - return conditionsSatisfied ? 1 : 2; + playMethod = PlayMethod.DirectStream; } - return 3; + return (Profile: transcodingProfile, PlayMethod: playMethod, Rank: rank); }) - .OrderBy(lookup => lookup.Key) - .SelectMany(lookup => lookup); - } + .OrderBy(analysis => analysis.Rank); + + var profileMatch = analyzedProfiles.FirstOrDefault(); - return transcodingProfiles.FirstOrDefault(); + return (profileMatch.Profile, profileMatch.PlayMethod); } private void BuildStreamVideoItem( |
