|  | @@ -10,19 +10,13 @@ using MediaBrowser.Model.Entities;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.IO;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.MediaInfo;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.Session;
 | 
	
		
			
				|  |  | -using Microsoft.Extensions.Logging;
 | 
	
		
			
				|  |  | -using System.IO;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.Net;
 | 
	
		
			
				|  |  | -using MediaBrowser.Controller.Library;
 | 
	
		
			
				|  |  | -using System.Threading.Tasks;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      // For now, a common base class until the API and MediaEncoding classes are unified
 | 
	
		
			
				|  |  |      public class EncodingJobInfo
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | -        protected readonly IMediaSourceManager MediaSourceManager;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          public MediaStream VideoStream { get; set; }
 | 
	
		
			
				|  |  |          public VideoType VideoType { get; set; }
 | 
	
		
			
				|  |  |          public Dictionary<string, string> RemoteHttpHeaders { get; set; }
 | 
	
	
		
			
				|  | @@ -49,7 +43,6 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |          public string OutputFilePath { get; set; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public string MimeType { get; set; }
 | 
	
		
			
				|  |  | -        public long? EncodingDurationTicks { get; set; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public string GetMimeType(string outputPath, bool enableStreamDefault = true)
 | 
	
		
			
				|  |  |          {
 | 
	
	
		
			
				|  | @@ -68,7 +61,12 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (_transcodeReasons == null)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    _transcodeReasons = (BaseRequest.TranscodeReasons ?? string.Empty)
 | 
	
		
			
				|  |  | +                    if (BaseRequest.TranscodeReasons == null)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        return Array.Empty<TranscodeReason>();
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    _transcodeReasons = BaseRequest.TranscodeReasons
 | 
	
		
			
				|  |  |                          .Split(',')
 | 
	
		
			
				|  |  |                          .Where(i => !string.IsNullOrEmpty(i))
 | 
	
		
			
				|  |  |                          .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
 | 
	
	
		
			
				|  | @@ -98,7 +96,8 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              get
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  // For live tv + in progress recordings
 | 
	
		
			
				|  |  | -                if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase) || string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  | +                if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase)
 | 
	
		
			
				|  |  | +                    || string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      if (!MediaSource.RunTimeTicks.HasValue)
 | 
	
		
			
				|  |  |                      {
 | 
	
	
		
			
				|  | @@ -155,15 +154,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if (forceDeinterlaceIfSourceIsInterlaced)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                if (isInputInterlaced)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    return true;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            return false;
 | 
	
		
			
				|  |  | +            return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public string[] GetRequestedProfiles(string codec)
 | 
	
	
		
			
				|  | @@ -211,7 +202,8 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              if (!string.IsNullOrEmpty(codec))
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  var value = BaseRequest.GetOption(codec, "maxrefframes");
 | 
	
		
			
				|  |  | -                if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  | +                if (!string.IsNullOrEmpty(value)
 | 
	
		
			
				|  |  | +                    && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      return result;
 | 
	
		
			
				|  |  |                  }
 | 
	
	
		
			
				|  | @@ -230,7 +222,8 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              if (!string.IsNullOrEmpty(codec))
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  var value = BaseRequest.GetOption(codec, "videobitdepth");
 | 
	
		
			
				|  |  | -                if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  | +                if (!string.IsNullOrEmpty(value)
 | 
	
		
			
				|  |  | +                    && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      return result;
 | 
	
		
			
				|  |  |                  }
 | 
	
	
		
			
				|  | @@ -249,7 +242,8 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              if (!string.IsNullOrEmpty(codec))
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  var value = BaseRequest.GetOption(codec, "audiobitdepth");
 | 
	
		
			
				|  |  | -                if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  | +                if (!string.IsNullOrEmpty(value)
 | 
	
		
			
				|  |  | +                    && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      return result;
 | 
	
		
			
				|  |  |                  }
 | 
	
	
		
			
				|  | @@ -264,6 +258,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  return BaseRequest.MaxAudioChannels;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |              if (BaseRequest.AudioChannels.HasValue)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  return BaseRequest.AudioChannels;
 | 
	
	
		
			
				|  | @@ -272,7 +267,8 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              if (!string.IsNullOrEmpty(codec))
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  var value = BaseRequest.GetOption(codec, "audiochannels");
 | 
	
		
			
				|  |  | -                if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  | +                if (!string.IsNullOrEmpty(value)
 | 
	
		
			
				|  |  | +                    && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      return result;
 | 
	
		
			
				|  |  |                  }
 | 
	
	
		
			
				|  | @@ -294,7 +290,8 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              SupportedSubtitleCodecs = Array.Empty<string>();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        public bool IsSegmentedLiveStream => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue;
 | 
	
		
			
				|  |  | +        public bool IsSegmentedLiveStream
 | 
	
		
			
				|  |  | +            => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public bool EnableBreakOnNonKeyFrames(string videoCodec)
 | 
	
		
			
				|  |  |          {
 | 
	
	
		
			
				|  | @@ -428,11 +425,12 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.Level;
 | 
	
		
			
				|  |  | +                    return VideoStream?.Level;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  var level = GetRequestedLevel(ActualOutputVideoCodec);
 | 
	
		
			
				|  |  | -                if (!string.IsNullOrEmpty(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  | +                if (!string.IsNullOrEmpty(level)
 | 
	
		
			
				|  |  | +                    && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      return result;
 | 
	
		
			
				|  |  |                  }
 | 
	
	
		
			
				|  | @@ -450,7 +448,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.BitDepth;
 | 
	
		
			
				|  |  | +                    return VideoStream?.BitDepth;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  return null;
 | 
	
	
		
			
				|  | @@ -467,7 +465,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.RefFrames;
 | 
	
		
			
				|  |  | +                    return VideoStream?.RefFrames;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  return null;
 | 
	
	
		
			
				|  | @@ -494,13 +492,14 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              get
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                var defaultValue = string.Equals(OutputContainer, "m2ts", StringComparison.OrdinalIgnoreCase) ?
 | 
	
		
			
				|  |  | +                if (BaseRequest.Static)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    return InputTimestamp;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                return string.Equals(OutputContainer, "m2ts", StringComparison.OrdinalIgnoreCase) ?
 | 
	
		
			
				|  |  |                      TransportStreamTimestamp.Valid :
 | 
	
		
			
				|  |  |                      TransportStreamTimestamp.None;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                return !BaseRequest.Static
 | 
	
		
			
				|  |  | -                    ? defaultValue
 | 
	
		
			
				|  |  | -                    : InputTimestamp;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -513,7 +512,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.PacketLength;
 | 
	
		
			
				|  |  | +                    return VideoStream?.PacketLength;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  return null;
 | 
	
	
		
			
				|  | @@ -529,7 +528,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.Profile;
 | 
	
		
			
				|  |  | +                    return VideoStream?.Profile;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  var requestedProfile = GetRequestedProfiles(ActualOutputVideoCodec).FirstOrDefault();
 | 
	
	
		
			
				|  | @@ -542,42 +541,13 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// Predicts the audio sample rate that will be in the output stream
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        public string TargetVideoRange
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            get
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.VideoRange;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                return "SDR";
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        public string TargetAudioProfile
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            get
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                if (BaseRequest.Static || string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    return AudioStream == null ? null : AudioStream.Profile;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                return null;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          public string TargetVideoCodecTag
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              get
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.CodecTag;
 | 
	
		
			
				|  |  | +                    return VideoStream?.CodecTag;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  return null;
 | 
	
	
		
			
				|  | @@ -590,7 +560,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.IsAnamorphic;
 | 
	
		
			
				|  |  | +                    return VideoStream?.IsAnamorphic;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  return false;
 | 
	
	
		
			
				|  | @@ -605,14 +575,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    var stream = VideoStream;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (stream != null)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        return stream.Codec;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    return null;
 | 
	
		
			
				|  |  | +                    return VideoStream?.Codec;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  return codec;
 | 
	
	
		
			
				|  | @@ -627,14 +590,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    var stream = AudioStream;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (stream != null)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        return stream.Codec;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    return null;
 | 
	
		
			
				|  |  | +                    return AudioStream?.Codec;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  return codec;
 | 
	
	
		
			
				|  | @@ -647,7 +603,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced;
 | 
	
		
			
				|  |  | +                    return VideoStream?.IsInterlaced;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  if (DeInterlace(ActualOutputVideoCodec, true))
 | 
	
	
		
			
				|  | @@ -655,7 +611,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |                      return false;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced;
 | 
	
		
			
				|  |  | +                return VideoStream?.IsInterlaced;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -665,7 +621,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return VideoStream == null ? null : VideoStream.IsAVC;
 | 
	
		
			
				|  |  | +                    return VideoStream?.IsAVC;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  return false;
 |