|
|
|
@ -101,21 +101,16 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
|
|
|
|
MediaStream audioStream = item.GetDefaultAudioStream(null);
|
|
|
|
|
|
|
|
|
|
ArgumentNullException.ThrowIfNull(audioStream);
|
|
|
|
|
|
|
|
|
|
var directPlayInfo = GetAudioDirectPlayProfile(item, audioStream, options);
|
|
|
|
|
|
|
|
|
|
var directPlayMethod = directPlayInfo.PlayMethod;
|
|
|
|
|
var transcodeReasons = directPlayInfo.TranscodeReasons;
|
|
|
|
|
|
|
|
|
|
var inputAudioChannels = audioStream?.Channels;
|
|
|
|
|
var inputAudioBitrate = audioStream?.BitRate;
|
|
|
|
|
var inputAudioSampleRate = audioStream?.SampleRate;
|
|
|
|
|
var inputAudioBitDepth = audioStream?.BitDepth;
|
|
|
|
|
|
|
|
|
|
if (directPlayMethod is PlayMethod.DirectPlay)
|
|
|
|
|
{
|
|
|
|
|
var profile = options.Profile;
|
|
|
|
|
var audioFailureConditions = GetProfileConditionsForAudio(profile.CodecProfiles, item.Container, audioStream?.Codec, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, true);
|
|
|
|
|
var audioFailureReasons = AggregateFailureConditions(item, profile, "AudioCodecProfile", audioFailureConditions);
|
|
|
|
|
var audioFailureReasons = GetCompatibilityAudioCodec(options, item, item.Container, audioStream, null, false, false);
|
|
|
|
|
transcodeReasons |= audioFailureReasons;
|
|
|
|
|
|
|
|
|
|
if (audioFailureReasons == 0)
|
|
|
|
@ -188,6 +183,11 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
|
|
|
|
SetStreamInfoOptionsFromTranscodingProfile(item, playlistItem, transcodingProfile);
|
|
|
|
|
|
|
|
|
|
var inputAudioChannels = audioStream.Channels;
|
|
|
|
|
var inputAudioBitrate = audioStream.BitRate;
|
|
|
|
|
var inputAudioSampleRate = audioStream.SampleRate;
|
|
|
|
|
var inputAudioBitDepth = audioStream.BitDepth;
|
|
|
|
|
|
|
|
|
|
var audioTranscodingConditions = GetProfileConditionsForAudio(options.Profile.CodecProfiles, transcodingProfile.Container, transcodingProfile.AudioCodec, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, false).ToArray();
|
|
|
|
|
ApplyTranscodingConditions(playlistItem, audioTranscodingConditions, null, true, true);
|
|
|
|
|
|
|
|
|
@ -810,6 +810,10 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
MediaStream? audioStream,
|
|
|
|
|
StreamInfo playlistItem)
|
|
|
|
|
{
|
|
|
|
|
var mediaSource = playlistItem.MediaSource;
|
|
|
|
|
|
|
|
|
|
ArgumentNullException.ThrowIfNull(mediaSource);
|
|
|
|
|
|
|
|
|
|
if (!(item.SupportsTranscoding || item.SupportsDirectStream))
|
|
|
|
|
{
|
|
|
|
|
return (null, null);
|
|
|
|
@ -824,17 +828,7 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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 =>
|
|
|
|
@ -843,24 +837,16 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
|
|
|
|
var container = transcodingProfile.Container;
|
|
|
|
|
|
|
|
|
|
if (options.AllowVideoStreamCopy)
|
|
|
|
|
if (videoStream is not null
|
|
|
|
|
&& options.AllowVideoStreamCopy
|
|
|
|
|
&& ContainerHelper.ContainsContainer(transcodingProfile.VideoCodec, videoCodec))
|
|
|
|
|
{
|
|
|
|
|
if (ContainerHelper.ContainsContainer(transcodingProfile.VideoCodec, 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;
|
|
|
|
|
}
|
|
|
|
|
var failures = GetCompatibilityVideoCodec(options, mediaSource, container, videoStream);
|
|
|
|
|
rank.Video = failures == 0 ? 1 : 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options.AllowAudioStreamCopy)
|
|
|
|
|
if (audioStream is not null
|
|
|
|
|
&& options.AllowAudioStreamCopy)
|
|
|
|
|
{
|
|
|
|
|
// For Audio stream, we prefer the audio codec that can be directly copied, then the codec that can otherwise satisfies
|
|
|
|
|
// the transcoding conditions, then the one does not satisfy the transcoding conditions.
|
|
|
|
@ -870,19 +856,11 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
|
|
|
|
foreach (var transcodingAudioCodec in transcodingAudioCodecs)
|
|
|
|
|
{
|
|
|
|
|
var appliedVideoConditions = options.Profile.CodecProfiles
|
|
|
|
|
.Where(i => i.Type == CodecType.VideoAudio &&
|
|
|
|
|
i.ContainsAnyCodec(transcodingAudioCodec, 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);
|
|
|
|
|
var failures = GetCompatibilityAudioCodec(options, mediaSource, container, audioStream, transcodingAudioCodec, true, false);
|
|
|
|
|
|
|
|
|
|
var rankAudio = 3;
|
|
|
|
|
|
|
|
|
|
if (conditionsSatisfied)
|
|
|
|
|
if (failures == 0)
|
|
|
|
|
{
|
|
|
|
|
rankAudio = string.Equals(transcodingAudioCodec, audioCodec, StringComparison.OrdinalIgnoreCase) ? 1 : 2;
|
|
|
|
|
}
|
|
|
|
@ -984,22 +962,12 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
|
|
|
|
var channelsExceedsLimit = audioStreamWithSupportedCodec is not null && audioStreamWithSupportedCodec.Channels > (playlistItem.TranscodingMaxAudioChannels ?? int.MaxValue);
|
|
|
|
|
|
|
|
|
|
var directAudioStreamSatisfied = audioStreamWithSupportedCodec is not null && !channelsExceedsLimit
|
|
|
|
|
&& options.Profile.CodecProfiles
|
|
|
|
|
.Where(i => i.Type == CodecType.VideoAudio
|
|
|
|
|
&& i.ContainsAnyCodec(audioStreamWithSupportedCodec.Codec, container)
|
|
|
|
|
&& i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioStreamWithSupportedCodec.Channels, audioStreamWithSupportedCodec.BitRate, audioStreamWithSupportedCodec.SampleRate, audioStreamWithSupportedCodec.BitDepth, audioStreamWithSupportedCodec.Profile, false)))
|
|
|
|
|
.Select(i => i.Conditions.All(condition =>
|
|
|
|
|
{
|
|
|
|
|
var satisfied = ConditionProcessor.IsVideoAudioConditionSatisfied(condition, audioStreamWithSupportedCodec.Channels, audioStreamWithSupportedCodec.BitRate, audioStreamWithSupportedCodec.SampleRate, audioStreamWithSupportedCodec.BitDepth, audioStreamWithSupportedCodec.Profile, false);
|
|
|
|
|
if (!satisfied)
|
|
|
|
|
{
|
|
|
|
|
playlistItem.TranscodeReasons |= GetTranscodeReasonForFailedCondition(condition);
|
|
|
|
|
}
|
|
|
|
|
var directAudioFailures = audioStreamWithSupportedCodec is null ? default : GetCompatibilityAudioCodec(options, item, container ?? string.Empty, audioStreamWithSupportedCodec, null, true, false);
|
|
|
|
|
|
|
|
|
|
return satisfied;
|
|
|
|
|
}))
|
|
|
|
|
.All(satisfied => satisfied);
|
|
|
|
|
playlistItem.TranscodeReasons |= directAudioFailures;
|
|
|
|
|
|
|
|
|
|
var directAudioStreamSatisfied = audioStreamWithSupportedCodec is not null && !channelsExceedsLimit
|
|
|
|
|
&& directAudioFailures == 0;
|
|
|
|
|
|
|
|
|
|
directAudioStreamSatisfied = directAudioStreamSatisfied && !playlistItem.TranscodeReasons.HasFlag(TranscodeReason.ContainerBitrateExceedsLimit);
|
|
|
|
|
|
|
|
|
@ -1289,52 +1257,14 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
DeviceProfile profile = options.Profile;
|
|
|
|
|
string container = mediaSource.Container;
|
|
|
|
|
|
|
|
|
|
// Video
|
|
|
|
|
int? width = videoStream?.Width;
|
|
|
|
|
int? height = videoStream?.Height;
|
|
|
|
|
int? bitDepth = videoStream?.BitDepth;
|
|
|
|
|
int? videoBitrate = videoStream?.BitRate;
|
|
|
|
|
double? videoLevel = videoStream?.Level;
|
|
|
|
|
string? videoProfile = videoStream?.Profile;
|
|
|
|
|
VideoRangeType? videoRangeType = videoStream?.VideoRangeType;
|
|
|
|
|
float videoFramerate = videoStream is null ? 0 : videoStream.ReferenceFrameRate ?? 0;
|
|
|
|
|
bool? isAnamorphic = videoStream?.IsAnamorphic;
|
|
|
|
|
bool? isInterlaced = videoStream?.IsInterlaced;
|
|
|
|
|
string? videoCodecTag = videoStream?.CodecTag;
|
|
|
|
|
bool? isAvc = videoStream?.IsAVC;
|
|
|
|
|
|
|
|
|
|
TransportStreamTimestamp? timestamp = videoStream is null ? TransportStreamTimestamp.None : mediaSource.Timestamp;
|
|
|
|
|
int? packetLength = videoStream?.PacketLength;
|
|
|
|
|
int? refFrames = videoStream?.RefFrames;
|
|
|
|
|
|
|
|
|
|
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
|
|
|
|
|
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
|
|
|
|
|
|
|
|
|
|
var checkVideoConditions = (ProfileCondition[] conditions) =>
|
|
|
|
|
conditions.Where(applyCondition => !ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc));
|
|
|
|
|
|
|
|
|
|
// Check container conditions
|
|
|
|
|
var containerProfileReasons = AggregateFailureConditions(
|
|
|
|
|
mediaSource,
|
|
|
|
|
profile,
|
|
|
|
|
"VideoCodecProfile",
|
|
|
|
|
profile.ContainerProfiles
|
|
|
|
|
.Where(containerProfile => containerProfile.Type == DlnaProfileType.Video && containerProfile.ContainsContainer(container))
|
|
|
|
|
.SelectMany(containerProfile => checkVideoConditions(containerProfile.Conditions)));
|
|
|
|
|
var containerProfileReasons = GetCompatibilityContainer(options, mediaSource, container, videoStream);
|
|
|
|
|
|
|
|
|
|
// Check video conditions
|
|
|
|
|
var videoCodecProfileReasons = AggregateFailureConditions(
|
|
|
|
|
mediaSource,
|
|
|
|
|
profile,
|
|
|
|
|
"VideoCodecProfile",
|
|
|
|
|
profile.CodecProfiles
|
|
|
|
|
.Where(codecProfile => codecProfile.Type == CodecType.Video &&
|
|
|
|
|
codecProfile.ContainsAnyCodec(videoStream?.Codec, container) &&
|
|
|
|
|
!checkVideoConditions(codecProfile.ApplyConditions).Any())
|
|
|
|
|
.SelectMany(codecProfile => checkVideoConditions(codecProfile.Conditions)));
|
|
|
|
|
var videoCodecProfileReasons = videoStream is null ? default : GetCompatibilityVideoCodec(options, mediaSource, container, videoStream);
|
|
|
|
|
|
|
|
|
|
// Check audio candidates profile conditions
|
|
|
|
|
var audioStreamMatches = candidateAudioStreams.ToDictionary(s => s, audioStream => CheckVideoAudioStreamDirectPlay(options, mediaSource, container, audioStream));
|
|
|
|
|
var audioStreamMatches = candidateAudioStreams.ToDictionary(s => s, audioStream => GetCompatibilityAudioCodecDirect(options, mediaSource, container, audioStream, true, mediaSource.IsSecondaryAudio(audioStream) ?? false));
|
|
|
|
|
|
|
|
|
|
TranscodeReason subtitleProfileReasons = 0;
|
|
|
|
|
if (subtitleStream is not null)
|
|
|
|
@ -1447,20 +1377,6 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
return (Profile: null, PlayMethod: null, AudioStreamIndex: null, TranscodeReasons: failureReasons);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private TranscodeReason CheckVideoAudioStreamDirectPlay(MediaOptions options, MediaSourceInfo mediaSource, string container, MediaStream audioStream)
|
|
|
|
|
{
|
|
|
|
|
var profile = options.Profile;
|
|
|
|
|
var audioFailureConditions = GetProfileConditionsForVideoAudio(profile.CodecProfiles, container, audioStream.Codec, audioStream.Channels, audioStream.BitRate, audioStream.SampleRate, audioStream.BitDepth, audioStream.Profile, mediaSource.IsSecondaryAudio(audioStream));
|
|
|
|
|
|
|
|
|
|
var audioStreamFailureReasons = AggregateFailureConditions(mediaSource, profile, "VideoAudioCodecProfile", audioFailureConditions);
|
|
|
|
|
if (audioStream.IsExternal == true)
|
|
|
|
|
{
|
|
|
|
|
audioStreamFailureReasons |= TranscodeReason.AudioIsExternal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return audioStreamFailureReasons;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private TranscodeReason AggregateFailureConditions(MediaSourceInfo mediaSource, DeviceProfile profile, string type, IEnumerable<ProfileCondition> conditions)
|
|
|
|
|
{
|
|
|
|
|
return conditions.Aggregate<ProfileCondition, TranscodeReason>(0, (reasons, i) =>
|
|
|
|
@ -2315,5 +2231,140 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check the profile conditions.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="conditions">Profile conditions.</param>
|
|
|
|
|
/// <param name="mediaSource">Media source.</param>
|
|
|
|
|
/// <param name="videoStream">Video stream.</param>
|
|
|
|
|
/// <returns>Failed profile conditions.</returns>
|
|
|
|
|
private IEnumerable<ProfileCondition> CheckVideoConditions(ProfileCondition[] conditions, MediaSourceInfo mediaSource, MediaStream? videoStream)
|
|
|
|
|
{
|
|
|
|
|
int? width = videoStream?.Width;
|
|
|
|
|
int? height = videoStream?.Height;
|
|
|
|
|
int? bitDepth = videoStream?.BitDepth;
|
|
|
|
|
int? videoBitrate = videoStream?.BitRate;
|
|
|
|
|
double? videoLevel = videoStream?.Level;
|
|
|
|
|
string? videoProfile = videoStream?.Profile;
|
|
|
|
|
VideoRangeType? videoRangeType = videoStream?.VideoRangeType;
|
|
|
|
|
float videoFramerate = videoStream is null ? 0 : videoStream.ReferenceFrameRate ?? 0;
|
|
|
|
|
bool? isAnamorphic = videoStream?.IsAnamorphic;
|
|
|
|
|
bool? isInterlaced = videoStream?.IsInterlaced;
|
|
|
|
|
string? videoCodecTag = videoStream?.CodecTag;
|
|
|
|
|
bool? isAvc = videoStream?.IsAVC;
|
|
|
|
|
|
|
|
|
|
TransportStreamTimestamp? timestamp = videoStream is null ? TransportStreamTimestamp.None : mediaSource.Timestamp;
|
|
|
|
|
int? packetLength = videoStream?.PacketLength;
|
|
|
|
|
int? refFrames = videoStream?.RefFrames;
|
|
|
|
|
|
|
|
|
|
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
|
|
|
|
|
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
|
|
|
|
|
|
|
|
|
|
return conditions.Where(applyCondition => !ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check the compatibility of the container.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="options">Media options.</param>
|
|
|
|
|
/// <param name="mediaSource">Media source.</param>
|
|
|
|
|
/// <param name="container">Container.</param>
|
|
|
|
|
/// <param name="videoStream">Video stream.</param>
|
|
|
|
|
/// <returns>Transcode reasons if the container is not fully compatible.</returns>
|
|
|
|
|
private TranscodeReason GetCompatibilityContainer(MediaOptions options, MediaSourceInfo mediaSource, string container, MediaStream? videoStream)
|
|
|
|
|
{
|
|
|
|
|
var profile = options.Profile;
|
|
|
|
|
|
|
|
|
|
var failures = AggregateFailureConditions(
|
|
|
|
|
mediaSource,
|
|
|
|
|
profile,
|
|
|
|
|
"VideoCodecProfile",
|
|
|
|
|
profile.ContainerProfiles
|
|
|
|
|
.Where(containerProfile => containerProfile.Type == DlnaProfileType.Video && containerProfile.ContainsContainer(container))
|
|
|
|
|
.SelectMany(containerProfile => CheckVideoConditions(containerProfile.Conditions, mediaSource, videoStream)));
|
|
|
|
|
|
|
|
|
|
return failures;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check the compatibility of the video codec.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="options">Media options.</param>
|
|
|
|
|
/// <param name="mediaSource">Media source.</param>
|
|
|
|
|
/// <param name="container">Container.</param>
|
|
|
|
|
/// <param name="videoStream">Video stream.</param>
|
|
|
|
|
/// <returns>Transcode reasons if the video stream is not fully compatible.</returns>
|
|
|
|
|
private TranscodeReason GetCompatibilityVideoCodec(MediaOptions options, MediaSourceInfo mediaSource, string container, MediaStream videoStream)
|
|
|
|
|
{
|
|
|
|
|
var profile = options.Profile;
|
|
|
|
|
|
|
|
|
|
string videoCodec = videoStream.Codec;
|
|
|
|
|
|
|
|
|
|
var failures = AggregateFailureConditions(
|
|
|
|
|
mediaSource,
|
|
|
|
|
profile,
|
|
|
|
|
"VideoCodecProfile",
|
|
|
|
|
profile.CodecProfiles
|
|
|
|
|
.Where(codecProfile => codecProfile.Type == CodecType.Video &&
|
|
|
|
|
codecProfile.ContainsAnyCodec(videoCodec, container) &&
|
|
|
|
|
!CheckVideoConditions(codecProfile.ApplyConditions, mediaSource, videoStream).Any())
|
|
|
|
|
.SelectMany(codecProfile => CheckVideoConditions(codecProfile.Conditions, mediaSource, videoStream)));
|
|
|
|
|
|
|
|
|
|
return failures;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check the compatibility of the audio codec.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="options">Media options.</param>
|
|
|
|
|
/// <param name="mediaSource">Media source.</param>
|
|
|
|
|
/// <param name="container">Container.</param>
|
|
|
|
|
/// <param name="audioStream">Audio stream.</param>
|
|
|
|
|
/// <param name="transcodingAudioCodec">Override audio codec.</param>
|
|
|
|
|
/// <param name="isVideo">The media source is video.</param>
|
|
|
|
|
/// <param name="isSecondaryAudio">The audio stream is secondary.</param>
|
|
|
|
|
/// <returns>Transcode reasons if the audio stream is not fully compatible.</returns>
|
|
|
|
|
private TranscodeReason GetCompatibilityAudioCodec(MediaOptions options, MediaSourceInfo mediaSource, string container, MediaStream audioStream, string? transcodingAudioCodec, bool isVideo, bool isSecondaryAudio)
|
|
|
|
|
{
|
|
|
|
|
var profile = options.Profile;
|
|
|
|
|
|
|
|
|
|
var audioCodec = transcodingAudioCodec ?? audioStream.Codec;
|
|
|
|
|
var audioProfile = audioStream.Profile;
|
|
|
|
|
var audioChannels = audioStream.Channels;
|
|
|
|
|
var audioBitrate = audioStream.BitRate;
|
|
|
|
|
var audioSampleRate = audioStream.SampleRate;
|
|
|
|
|
var audioBitDepth = audioStream.BitDepth;
|
|
|
|
|
|
|
|
|
|
var audioFailureConditions = isVideo
|
|
|
|
|
? GetProfileConditionsForVideoAudio(profile.CodecProfiles, container, audioCodec, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio)
|
|
|
|
|
: GetProfileConditionsForAudio(profile.CodecProfiles, container, audioCodec, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, true);
|
|
|
|
|
|
|
|
|
|
var failures = AggregateFailureConditions(mediaSource, profile, "AudioCodecProfile", audioFailureConditions);
|
|
|
|
|
|
|
|
|
|
return failures;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check the compatibility of the audio codec for direct playback.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="options">Media options.</param>
|
|
|
|
|
/// <param name="mediaSource">Media source.</param>
|
|
|
|
|
/// <param name="container">Container.</param>
|
|
|
|
|
/// <param name="audioStream">Audio stream.</param>
|
|
|
|
|
/// <param name="isVideo">The media source is video.</param>
|
|
|
|
|
/// <param name="isSecondaryAudio">The audio stream is secondary.</param>
|
|
|
|
|
/// <returns>Transcode reasons if the audio stream is not fully compatible for direct playback.</returns>
|
|
|
|
|
private TranscodeReason GetCompatibilityAudioCodecDirect(MediaOptions options, MediaSourceInfo mediaSource, string container, MediaStream audioStream, bool isVideo, bool isSecondaryAudio)
|
|
|
|
|
{
|
|
|
|
|
var failures = GetCompatibilityAudioCodec(options, mediaSource, container, audioStream, null, isVideo, isSecondaryAudio);
|
|
|
|
|
|
|
|
|
|
if (audioStream.IsExternal)
|
|
|
|
|
{
|
|
|
|
|
failures |= TranscodeReason.AudioIsExternal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return failures;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|