aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Model
diff options
context:
space:
mode:
authorDmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com>2024-09-09 22:16:58 +0300
committerGitHub <noreply@github.com>2024-09-09 13:16:58 -0600
commit3da081ba86940f3fcedb188b2243445d1f95c883 (patch)
treef43bf969d9c36cc42de54ad9f85c86d46b59a8c5 /MediaBrowser.Model
parent43861f0ce112873514d3f97f3c4320525d642b39 (diff)
Add audio ranking for transcoding profiles (#12546)
Diffstat (limited to 'MediaBrowser.Model')
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs100
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(