mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-05-31 20:24:21 -04:00
capture more transcoding info
This commit is contained in:
parent
8dcfda89d1
commit
a107ff0369
@ -265,7 +265,8 @@ namespace MediaBrowser.Api
|
|||||||
Height = state.OutputHeight,
|
Height = state.OutputHeight,
|
||||||
AudioChannels = state.OutputAudioChannels,
|
AudioChannels = state.OutputAudioChannels,
|
||||||
IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
|
IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
|
||||||
IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
|
IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase),
|
||||||
|
TranscodeReasons = state.TranscodeReasons
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,6 +583,10 @@ namespace MediaBrowser.Api.Playback
|
|||||||
videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
|
videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (i == 33)
|
||||||
|
{
|
||||||
|
request.TranscodeReasons = val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,6 +541,11 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
{
|
{
|
||||||
queryString += "&SegmentContainer=" + state.Request.SegmentContainer;
|
queryString += "&SegmentContainer=" + state.Request.SegmentContainer;
|
||||||
}
|
}
|
||||||
|
// from universal audio service
|
||||||
|
if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons) && queryString.IndexOf("TranscodeReasons=", StringComparison.OrdinalIgnoreCase) == -1)
|
||||||
|
{
|
||||||
|
queryString += "&TranscodeReasons=" + state.Request.TranscodeReasons;
|
||||||
|
}
|
||||||
|
|
||||||
// Main stream
|
// Main stream
|
||||||
var playlistUrl = isLiveStream ? "live.m3u8" : "main.m3u8";
|
var playlistUrl = isLiveStream ? "live.m3u8" : "main.m3u8";
|
||||||
|
@ -513,6 +513,8 @@ namespace MediaBrowser.Api.Playback
|
|||||||
var profiles = info.GetSubtitleProfiles(false, "-", accessToken);
|
var profiles = info.GetSubtitleProfiles(false, "-", accessToken);
|
||||||
mediaSource.DefaultSubtitleStreamIndex = info.SubtitleStreamIndex;
|
mediaSource.DefaultSubtitleStreamIndex = info.SubtitleStreamIndex;
|
||||||
|
|
||||||
|
mediaSource.TranscodeReasons = info.TranscodeReasons;
|
||||||
|
|
||||||
foreach (var profile in profiles)
|
foreach (var profile in profiles)
|
||||||
{
|
{
|
||||||
foreach (var stream in mediaSource.MediaStreams)
|
foreach (var stream in mediaSource.MediaStreams)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Api.Playback.Hls;
|
using MediaBrowser.Api.Playback.Hls;
|
||||||
using MediaBrowser.Api.Playback.Progressive;
|
using MediaBrowser.Api.Playback.Progressive;
|
||||||
@ -265,7 +266,8 @@ namespace MediaBrowser.Api.Playback
|
|||||||
Static = isStatic,
|
Static = isStatic,
|
||||||
SegmentContainer = request.TranscodingContainer,
|
SegmentContainer = request.TranscodingContainer,
|
||||||
AudioSampleRate = request.MaxAudioSampleRate,
|
AudioSampleRate = request.MaxAudioSampleRate,
|
||||||
BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames
|
BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames,
|
||||||
|
TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
@ -307,7 +309,8 @@ namespace MediaBrowser.Api.Playback
|
|||||||
PlaySessionId = playbackInfoResult.PlaySessionId,
|
PlaySessionId = playbackInfoResult.PlaySessionId,
|
||||||
StartTimeTicks = request.StartTimeTicks,
|
StartTimeTicks = request.StartTimeTicks,
|
||||||
Static = isStatic,
|
Static = isStatic,
|
||||||
AudioSampleRate = request.MaxAudioSampleRate
|
AudioSampleRate = request.MaxAudioSampleRate,
|
||||||
|
TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
|
@ -487,7 +487,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
var folder = this;
|
var folder = this;
|
||||||
innerProgress.RegisterAction(p =>
|
innerProgress.RegisterAction(p =>
|
||||||
{
|
{
|
||||||
double newPct = .70 * p + 10;
|
double newPct = .80 * p + 10;
|
||||||
progress.Report(newPct);
|
progress.Report(newPct);
|
||||||
ProviderManager.OnRefreshProgress(folder, newPct);
|
ProviderManager.OnRefreshProgress(folder, newPct);
|
||||||
});
|
});
|
||||||
@ -498,11 +498,11 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
if (refreshChildMetadata)
|
if (refreshChildMetadata)
|
||||||
{
|
{
|
||||||
progress.Report(80);
|
progress.Report(90);
|
||||||
|
|
||||||
if (recursive)
|
if (recursive)
|
||||||
{
|
{
|
||||||
ProviderManager.OnRefreshProgress(this, 80);
|
ProviderManager.OnRefreshProgress(this, 90);
|
||||||
}
|
}
|
||||||
|
|
||||||
var container = this as IMetadataContainer;
|
var container = this as IMetadataContainer;
|
||||||
@ -512,7 +512,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
var folder = this;
|
var folder = this;
|
||||||
innerProgress.RegisterAction(p =>
|
innerProgress.RegisterAction(p =>
|
||||||
{
|
{
|
||||||
double newPct = .20 * p + 80;
|
double newPct = .10 * p + 90;
|
||||||
progress.Report(newPct);
|
progress.Report(newPct);
|
||||||
if (recursive)
|
if (recursive)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
@ -9,6 +10,7 @@ using MediaBrowser.Model.IO;
|
|||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
|
using MediaBrowser.Model.Session;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.MediaEncoding
|
namespace MediaBrowser.Controller.MediaEncoding
|
||||||
{
|
{
|
||||||
@ -40,6 +42,24 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
public bool ReadInputAtNativeFramerate { get; set; }
|
public bool ReadInputAtNativeFramerate { get; set; }
|
||||||
|
|
||||||
|
private List<TranscodeReason> _transcodeReasons = null;
|
||||||
|
public List<TranscodeReason> TranscodeReasons
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_transcodeReasons == null)
|
||||||
|
{
|
||||||
|
_transcodeReasons = (BaseRequest.TranscodeReasons ?? string.Empty)
|
||||||
|
.Split(',')
|
||||||
|
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||||
|
.Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _transcodeReasons;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool IgnoreInputDts
|
public bool IgnoreInputDts
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -251,7 +271,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
{
|
{
|
||||||
return AudioStream.SampleRate;
|
return AudioStream.SampleRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (BaseRequest.AudioSampleRate.HasValue)
|
else if (BaseRequest.AudioSampleRate.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -204,6 +204,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
public string SubtitleCodec { get; set; }
|
public string SubtitleCodec { get; set; }
|
||||||
|
|
||||||
|
public string TranscodeReasons { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the index of the audio stream.
|
/// Gets or sets the index of the audio stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -55,7 +55,6 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
|
|
||||||
HidePlayedInLatest = true;
|
HidePlayedInLatest = true;
|
||||||
PlayDefaultAudioTrack = true;
|
PlayDefaultAudioTrack = true;
|
||||||
DisplayMissingEpisodes = true;
|
|
||||||
|
|
||||||
LatestItemsExcludes = new string[] { };
|
LatestItemsExcludes = new string[] { };
|
||||||
OrderedViews = new string[] { };
|
OrderedViews = new string[] { };
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
|
@ -105,8 +105,99 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
|
||||||
|
{
|
||||||
|
switch (condition.Property)
|
||||||
|
{
|
||||||
|
case ProfileConditionValue.AudioBitrate:
|
||||||
|
if (condition.Condition == ProfileConditionType.LessThanEqual)
|
||||||
|
{
|
||||||
|
return TranscodeReason.AudioBitrateNotSupported;
|
||||||
|
}
|
||||||
|
return TranscodeReason.AudioBitrateNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.AudioChannels:
|
||||||
|
if (condition.Condition == ProfileConditionType.LessThanEqual)
|
||||||
|
{
|
||||||
|
return TranscodeReason.AudioChannelsNotSupported;
|
||||||
|
}
|
||||||
|
return TranscodeReason.AudioChannelsNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.AudioProfile:
|
||||||
|
return TranscodeReason.AudioProfileNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.AudioSampleRate:
|
||||||
|
return TranscodeReason.AudioSampleRateNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.Has64BitOffsets:
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case ProfileConditionValue.Height:
|
||||||
|
return TranscodeReason.VideoResolutionNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.IsAnamorphic:
|
||||||
|
return TranscodeReason.AnamorphicVideoNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.IsAvc:
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case ProfileConditionValue.IsInterlaced:
|
||||||
|
return TranscodeReason.InterlacedVideoNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.IsSecondaryAudio:
|
||||||
|
return TranscodeReason.SecondaryAudioNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.NumAudioStreams:
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case ProfileConditionValue.NumVideoStreams:
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case ProfileConditionValue.PacketLength:
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case ProfileConditionValue.RefFrames:
|
||||||
|
return TranscodeReason.RefFramesNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.VideoBitDepth:
|
||||||
|
return TranscodeReason.VideoBitDepthNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.VideoBitrate:
|
||||||
|
return TranscodeReason.VideoBitrateNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.VideoCodecTag:
|
||||||
|
return TranscodeReason.VideoCodecNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.VideoFramerate:
|
||||||
|
return TranscodeReason.VideoFramerateNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.VideoLevel:
|
||||||
|
return TranscodeReason.VideoLevelNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.VideoProfile:
|
||||||
|
return TranscodeReason.VideoProfileNotSupported;
|
||||||
|
|
||||||
|
case ProfileConditionValue.VideoTimestamp:
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case ProfileConditionValue.Width:
|
||||||
|
return TranscodeReason.VideoResolutionNotSupported;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
|
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
|
||||||
{
|
{
|
||||||
|
List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
|
||||||
|
|
||||||
StreamInfo playlistItem = new StreamInfo
|
StreamInfo playlistItem = new StreamInfo
|
||||||
{
|
{
|
||||||
ItemId = options.ItemId,
|
ItemId = options.ItemId,
|
||||||
@ -133,7 +224,10 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
MediaStream audioStream = item.GetDefaultAudioStream(null);
|
MediaStream audioStream = item.GetDefaultAudioStream(null);
|
||||||
|
|
||||||
List<PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options);
|
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
|
||||||
|
|
||||||
|
List<PlayMethod> directPlayMethods = directPlayInfo.Item1;
|
||||||
|
transcodeReasons.AddRange(directPlayInfo.Item2);
|
||||||
|
|
||||||
ConditionProcessor conditionProcessor = new ConditionProcessor();
|
ConditionProcessor conditionProcessor = new ConditionProcessor();
|
||||||
|
|
||||||
@ -180,6 +274,11 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate))
|
if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate))
|
||||||
{
|
{
|
||||||
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
|
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
|
||||||
|
var transcodeReason = GetTranscodeReasonForFailedCondition(c);
|
||||||
|
if (transcodeReason.HasValue)
|
||||||
|
{
|
||||||
|
transcodeReasons.Add(transcodeReason.Value);
|
||||||
|
}
|
||||||
all = false;
|
all = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -292,9 +391,9 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
var longBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate);
|
var longBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate);
|
||||||
playlistItem.AudioBitrate = longBitrate > int.MaxValue ? int.MaxValue : Convert.ToInt32(longBitrate);
|
playlistItem.AudioBitrate = longBitrate > int.MaxValue ? int.MaxValue : Convert.ToInt32(longBitrate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playlistItem.TranscodeReasons = transcodeReasons;
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,8 +407,10 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return options.GetMaxBitrate(isAudio);
|
return options.GetMaxBitrate(isAudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
|
private Tuple<List<PlayMethod>, List<TranscodeReason>> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
|
||||||
{
|
{
|
||||||
|
List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
|
||||||
|
|
||||||
DirectPlayProfile directPlayProfile = null;
|
DirectPlayProfile directPlayProfile = null;
|
||||||
foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
|
foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
|
||||||
{
|
{
|
||||||
@ -325,27 +426,134 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
if (directPlayProfile != null)
|
if (directPlayProfile != null)
|
||||||
{
|
{
|
||||||
// While options takes the network and other factors into account. Only applies to direct stream
|
// While options takes the network and other factors into account. Only applies to direct stream
|
||||||
if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream) && options.EnableDirectStream)
|
if (item.SupportsDirectStream)
|
||||||
{
|
{
|
||||||
playMethods.Add(PlayMethod.DirectStream);
|
if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream))
|
||||||
|
{
|
||||||
|
if (options.EnableDirectStream)
|
||||||
|
{
|
||||||
|
playMethods.Add(PlayMethod.DirectStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The profile describes what the device supports
|
// The profile describes what the device supports
|
||||||
// If device requirements are satisfied then allow both direct stream and direct play
|
// If device requirements are satisfied then allow both direct stream and direct play
|
||||||
if (item.SupportsDirectPlay &&
|
if (item.SupportsDirectPlay)
|
||||||
IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay) && options.EnableDirectPlay)
|
|
||||||
{
|
{
|
||||||
playMethods.Add(PlayMethod.DirectPlay);
|
if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay))
|
||||||
|
{
|
||||||
|
if (options.EnableDirectPlay)
|
||||||
|
{
|
||||||
|
playMethods.Add(PlayMethod.DirectPlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
transcodeReasons.InsertRange(0, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
|
||||||
|
|
||||||
_logger.Info("Profile: {0}, No direct play profiles found for Path: {1}",
|
_logger.Info("Profile: {0}, No direct play profiles found for Path: {1}",
|
||||||
options.Profile.Name ?? "Unknown Profile",
|
options.Profile.Name ?? "Unknown Profile",
|
||||||
item.Path ?? "Unknown path");
|
item.Path ?? "Unknown path");
|
||||||
}
|
}
|
||||||
|
|
||||||
return playMethods;
|
if (playMethods.Count > 0)
|
||||||
|
{
|
||||||
|
transcodeReasons.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transcodeReasons = transcodeReasons.Distinct().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<List<PlayMethod>, List<TranscodeReason>>(playMethods, transcodeReasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
|
||||||
|
{
|
||||||
|
var list = new List<TranscodeReason>();
|
||||||
|
var containerSupported = false;
|
||||||
|
var audioSupported = false;
|
||||||
|
var videoSupported = false;
|
||||||
|
|
||||||
|
foreach (var profile in directPlayProfiles)
|
||||||
|
{
|
||||||
|
if (profile.Container.Length > 0)
|
||||||
|
{
|
||||||
|
// Check container type
|
||||||
|
string mediaContainer = item.Container ?? string.Empty;
|
||||||
|
foreach (string i in profile.GetContainers())
|
||||||
|
{
|
||||||
|
if (StringHelper.EqualsIgnoreCase(i, mediaContainer))
|
||||||
|
{
|
||||||
|
containerSupported = true;
|
||||||
|
|
||||||
|
if (videoStream != null)
|
||||||
|
{
|
||||||
|
// Check video codec
|
||||||
|
List<string> videoCodecs = profile.GetVideoCodecs();
|
||||||
|
if (videoCodecs.Count > 0)
|
||||||
|
{
|
||||||
|
string videoCodec = videoStream.Codec;
|
||||||
|
if (!string.IsNullOrEmpty(videoCodec) && ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec))
|
||||||
|
{
|
||||||
|
videoSupported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
videoSupported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioStream != null)
|
||||||
|
{
|
||||||
|
// Check audio codec
|
||||||
|
List<string> audioCodecs = profile.GetAudioCodecs();
|
||||||
|
if (audioCodecs.Count > 0)
|
||||||
|
{
|
||||||
|
string audioCodec = audioStream.Codec;
|
||||||
|
if (!string.IsNullOrEmpty(audioCodec) && ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec))
|
||||||
|
{
|
||||||
|
audioSupported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioSupported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!containerSupported)
|
||||||
|
{
|
||||||
|
list.Add(TranscodeReason.ContainerNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoStream != null && !videoSupported)
|
||||||
|
{
|
||||||
|
list.Add(TranscodeReason.VideoCodecNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioStream != null && !audioSupported)
|
||||||
|
{
|
||||||
|
list.Add(TranscodeReason.VideoCodecNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
|
private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
|
||||||
@ -393,6 +601,8 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options)
|
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options)
|
||||||
{
|
{
|
||||||
|
List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
|
||||||
|
|
||||||
StreamInfo playlistItem = new StreamInfo
|
StreamInfo playlistItem = new StreamInfo
|
||||||
{
|
{
|
||||||
ItemId = options.ItemId,
|
ItemId = options.ItemId,
|
||||||
@ -428,7 +638,8 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
if (isEligibleForDirectPlay || isEligibleForDirectStream)
|
if (isEligibleForDirectPlay || isEligibleForDirectStream)
|
||||||
{
|
{
|
||||||
// See if it can be direct played
|
// See if it can be direct played
|
||||||
PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream);
|
var directPlayInfo = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream);
|
||||||
|
var directPlay = directPlayInfo.Item1;
|
||||||
|
|
||||||
if (directPlay != null)
|
if (directPlay != null)
|
||||||
{
|
{
|
||||||
@ -445,6 +656,8 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transcodeReasons.AddRange(directPlayInfo.Item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can't direct play, find the transcoding profile
|
// Can't direct play, find the transcoding profile
|
||||||
@ -618,6 +831,8 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playlistItem.TranscodeReasons = transcodeReasons;
|
||||||
|
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,7 +892,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
|
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayMethod? GetVideoDirectPlayProfile(VideoOptions options,
|
private Tuple<PlayMethod?, List<TranscodeReason>> GetVideoDirectPlayProfile(VideoOptions options,
|
||||||
MediaSourceInfo mediaSource,
|
MediaSourceInfo mediaSource,
|
||||||
MediaStream videoStream,
|
MediaStream videoStream,
|
||||||
MediaStream audioStream,
|
MediaStream audioStream,
|
||||||
@ -688,11 +903,11 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
if (options.ForceDirectPlay)
|
if (options.ForceDirectPlay)
|
||||||
{
|
{
|
||||||
return PlayMethod.DirectPlay;
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectPlay, new List<TranscodeReason>());
|
||||||
}
|
}
|
||||||
if (options.ForceDirectStream)
|
if (options.ForceDirectStream)
|
||||||
{
|
{
|
||||||
return PlayMethod.DirectStream;
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoStream == null)
|
if (videoStream == null)
|
||||||
@ -701,7 +916,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
profile.Name ?? "Unknown Profile",
|
profile.Name ?? "Unknown Profile",
|
||||||
mediaSource.Path ?? "Unknown path");
|
mediaSource.Path ?? "Unknown path");
|
||||||
|
|
||||||
return null;
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownVideoStreamInfo });
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if it can be direct played
|
// See if it can be direct played
|
||||||
@ -721,7 +936,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
profile.Name ?? "Unknown Profile",
|
profile.Name ?? "Unknown Profile",
|
||||||
mediaSource.Path ?? "Unknown path");
|
mediaSource.Path ?? "Unknown path");
|
||||||
|
|
||||||
return null;
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
|
||||||
}
|
}
|
||||||
|
|
||||||
string container = mediaSource.Container;
|
string container = mediaSource.Container;
|
||||||
@ -784,7 +999,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
profile.Name ?? "Unknown Profile",
|
profile.Name ?? "Unknown Profile",
|
||||||
mediaSource.Path ?? "Unknown path");
|
mediaSource.Path ?? "Unknown path");
|
||||||
|
|
||||||
return null;
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownVideoStreamInfo });
|
||||||
}
|
}
|
||||||
|
|
||||||
conditions = new List<ProfileCondition>();
|
conditions = new List<ProfileCondition>();
|
||||||
@ -819,7 +1034,12 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
{
|
{
|
||||||
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
||||||
|
|
||||||
return null;
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
||||||
|
var transcodeReasons = transcodeReason.HasValue
|
||||||
|
? new List<TranscodeReason> { transcodeReason.Value }
|
||||||
|
: new List<TranscodeReason> { };
|
||||||
|
|
||||||
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -833,7 +1053,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
profile.Name ?? "Unknown Profile",
|
profile.Name ?? "Unknown Profile",
|
||||||
mediaSource.Path ?? "Unknown path");
|
mediaSource.Path ?? "Unknown path");
|
||||||
|
|
||||||
return null;
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownAudioStreamInfo });
|
||||||
}
|
}
|
||||||
|
|
||||||
conditions = new List<ProfileCondition>();
|
conditions = new List<ProfileCondition>();
|
||||||
@ -870,17 +1090,22 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
{
|
{
|
||||||
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
|
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
|
||||||
|
|
||||||
return null;
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
||||||
|
var transcodeReasons = transcodeReason.HasValue
|
||||||
|
? new List<TranscodeReason> { transcodeReason.Value }
|
||||||
|
: new List<TranscodeReason> { };
|
||||||
|
|
||||||
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
|
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
|
||||||
{
|
{
|
||||||
return PlayMethod.DirectStream;
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
|
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
|
||||||
@ -1047,12 +1272,12 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
// Don't restrict by bitrate if coming from an external domain
|
// Don't restrict by bitrate if coming from an external domain
|
||||||
if (item.IsRemote)
|
if (item.IsRemote)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!maxBitrate.HasValue)
|
if (!maxBitrate.HasValue)
|
||||||
{
|
{
|
||||||
_logger.Info("Cannot "+ playMethod + " due to unknown supported bitrate");
|
_logger.Info("Cannot " + playMethod + " due to unknown supported bitrate");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
AudioCodecs = new string[] { };
|
AudioCodecs = new string[] { };
|
||||||
VideoCodecs = new string[] { };
|
VideoCodecs = new string[] { };
|
||||||
SubtitleCodecs = new string[] { };
|
SubtitleCodecs = new string[] { };
|
||||||
|
TranscodeReasons = new List<TranscodeReason>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ItemId { get; set; }
|
public string ItemId { get; set; }
|
||||||
@ -89,6 +90,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
public string PlaySessionId { get; set; }
|
public string PlaySessionId { get; set; }
|
||||||
public List<MediaSourceInfo> AllMediaSources { get; set; }
|
public List<MediaSourceInfo> AllMediaSources { get; set; }
|
||||||
|
public List<TranscodeReason> TranscodeReasons { get; set; }
|
||||||
|
|
||||||
public string MediaSourceId
|
public string MediaSourceId
|
||||||
{
|
{
|
||||||
@ -231,22 +233,11 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty));
|
list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty));
|
||||||
list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty));
|
list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty));
|
||||||
|
|
||||||
var forceStartPosition = false;
|
|
||||||
long startPositionTicks = item.StartPositionTicks;
|
long startPositionTicks = item.StartPositionTicks;
|
||||||
//if (item.MediaSource.DateLiveStreamOpened.HasValue && startPositionTicks == 0)
|
|
||||||
//{
|
|
||||||
// var elapsed = DateTime.UtcNow - item.MediaSource.DateLiveStreamOpened.Value;
|
|
||||||
// elapsed -= TimeSpan.FromSeconds(20);
|
|
||||||
// if (elapsed.TotalSeconds >= 0)
|
|
||||||
// {
|
|
||||||
// startPositionTicks = elapsed.Ticks + startPositionTicks;
|
|
||||||
// forceStartPosition = true;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
var isHls = StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls");
|
var isHls = StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls");
|
||||||
|
|
||||||
if (isHls && !forceStartPosition)
|
if (isHls)
|
||||||
{
|
{
|
||||||
list.Add(new NameValuePair("StartTimeTicks", string.Empty));
|
list.Add(new NameValuePair("StartTimeTicks", string.Empty));
|
||||||
}
|
}
|
||||||
@ -310,6 +301,11 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString()));
|
list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDlna || !item.IsDirectStream)
|
||||||
|
{
|
||||||
|
list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()).ToArray())));
|
||||||
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ using MediaBrowser.Model.MediaInfo;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Model.Session;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
namespace MediaBrowser.Model.Dto
|
||||||
{
|
{
|
||||||
@ -110,6 +111,9 @@ namespace MediaBrowser.Model.Dto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public List<TranscodeReason> TranscodeReasons { get; set; }
|
||||||
|
|
||||||
public int? DefaultAudioStreamIndex { get; set; }
|
public int? DefaultAudioStreamIndex { get; set; }
|
||||||
public int? DefaultSubtitleStreamIndex { get; set; }
|
public int? DefaultSubtitleStreamIndex { get; set; }
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Session
|
namespace MediaBrowser.Model.Session
|
||||||
{
|
{
|
||||||
public class TranscodingInfo
|
public class TranscodingInfo
|
||||||
@ -15,5 +17,36 @@ namespace MediaBrowser.Model.Session
|
|||||||
public int? Width { get; set; }
|
public int? Width { get; set; }
|
||||||
public int? Height { get; set; }
|
public int? Height { get; set; }
|
||||||
public int? AudioChannels { get; set; }
|
public int? AudioChannels { get; set; }
|
||||||
|
|
||||||
|
public List<TranscodeReason> TranscodeReasons { get; set; }
|
||||||
|
|
||||||
|
public TranscodingInfo()
|
||||||
|
{
|
||||||
|
TranscodeReasons = new List<TranscodeReason>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TranscodeReason
|
||||||
|
{
|
||||||
|
ContainerNotSupported = 0,
|
||||||
|
VideoCodecNotSupported = 1,
|
||||||
|
AudioCodecNotSupported = 2,
|
||||||
|
ContainerBitrateExceedsLimit = 3,
|
||||||
|
AudioBitrateNotSupported = 4,
|
||||||
|
AudioChannelsNotSupported = 5,
|
||||||
|
VideoResolutionNotSupported = 6,
|
||||||
|
UnknownVideoStreamInfo = 7,
|
||||||
|
UnknownAudioStreamInfo = 8,
|
||||||
|
AudioProfileNotSupported = 9,
|
||||||
|
AudioSampleRateNotSupported = 10,
|
||||||
|
AnamorphicVideoNotSupported = 11,
|
||||||
|
InterlacedVideoNotSupported = 12,
|
||||||
|
SecondaryAudioNotSupported = 13,
|
||||||
|
RefFramesNotSupported = 14,
|
||||||
|
VideoBitDepthNotSupported = 15,
|
||||||
|
VideoBitrateNotSupported = 16,
|
||||||
|
VideoFramerateNotSupported = 17,
|
||||||
|
VideoLevelNotSupported = 18,
|
||||||
|
VideoProfileNotSupported = 19
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user