aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
diff options
context:
space:
mode:
authorAndrew Rabert <ar@nullsum.net>2018-12-27 18:27:57 -0500
committerAndrew Rabert <ar@nullsum.net>2018-12-27 18:27:57 -0500
commita86b71899ec52c44ddc6c3018e8cc5e9d7ff4d62 (patch)
treea74f6ea4a8abfa1664a605d31d48bc38245ccf58 /MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
parent9bac3ac616b01f67db98381feb09d34ebe821f9a (diff)
Add GPL modules
Diffstat (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs')
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs775
1 files changed, 775 insertions, 0 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
new file mode 100644
index 000000000..3d2871e65
--- /dev/null
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -0,0 +1,775 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Session;
+
+namespace MediaBrowser.Controller.MediaEncoding
+{
+ // For now, a common base class until the API and MediaEncoding classes are unified
+ public abstract class EncodingJobInfo
+ {
+ private readonly ILogger _logger;
+
+ public MediaStream VideoStream { get; set; }
+ public VideoType VideoType { get; set; }
+ public Dictionary<string, string> RemoteHttpHeaders { get; set; }
+ public string OutputVideoCodec { get; set; }
+ public MediaProtocol InputProtocol { get; set; }
+ public string MediaPath { get; set; }
+ public bool IsInputVideo { get; set; }
+ public IIsoMount IsoMount { get; set; }
+ public string[] PlayableStreamFileNames { get; set; }
+ public string OutputAudioCodec { get; set; }
+ public int? OutputVideoBitrate { get; set; }
+ public MediaStream SubtitleStream { get; set; }
+ public SubtitleDeliveryMethod SubtitleDeliveryMethod { get; set; }
+ public string[] SupportedSubtitleCodecs { get; set; }
+
+ public int InternalSubtitleStreamOffset { get; set; }
+ public MediaSourceInfo MediaSource { get; set; }
+ public User User { get; set; }
+
+ public long? RunTimeTicks { get; set; }
+
+ public bool ReadInputAtNativeFramerate { get; set; }
+
+ private TranscodeReason[] _transcodeReasons = null;
+ public TranscodeReason[] TranscodeReasons
+ {
+ get
+ {
+ if (_transcodeReasons == null)
+ {
+ _transcodeReasons = (BaseRequest.TranscodeReasons ?? string.Empty)
+ .Split(',')
+ .Where(i => !string.IsNullOrEmpty(i))
+ .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
+ .ToArray();
+ }
+
+ return _transcodeReasons;
+ }
+ }
+
+ public bool IgnoreInputDts
+ {
+ get
+ {
+ return MediaSource.IgnoreDts;
+ }
+ }
+
+ public bool IgnoreInputIndex
+ {
+ get
+ {
+ return MediaSource.IgnoreIndex;
+ }
+ }
+
+ public bool GenPtsInput
+ {
+ get
+ {
+ return MediaSource.GenPtsInput;
+ }
+ }
+
+ public bool DiscardCorruptFramesInput
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public bool EnableFastSeekInput
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public bool GenPtsOutput
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public string OutputContainer { get; set; }
+
+ public string OutputVideoSync
+ {
+ get
+ {
+ // For live tv + in progress recordings
+ if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase) || string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase))
+ {
+ if (!MediaSource.RunTimeTicks.HasValue)
+ {
+ return "cfr";
+ }
+ }
+
+ return "-1";
+ }
+ }
+
+ public string AlbumCoverPath { get; set; }
+
+ public string InputAudioSync { get; set; }
+ public string InputVideoSync { get; set; }
+ public TransportStreamTimestamp InputTimestamp { get; set; }
+
+ public MediaStream AudioStream { get; set; }
+ public string[] SupportedAudioCodecs { get; set; }
+ public string[] SupportedVideoCodecs { get; set; }
+ public string InputContainer { get; set; }
+ public IsoType? IsoType { get; set; }
+
+ public BaseEncodingJobOptions BaseRequest { get; set; }
+
+ public long? StartTimeTicks
+ {
+ get { return BaseRequest.StartTimeTicks; }
+ }
+
+ public bool CopyTimestamps
+ {
+ get { return BaseRequest.CopyTimestamps; }
+ }
+
+ public int? OutputAudioBitrate;
+ public int? OutputAudioChannels;
+
+ public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced)
+ {
+ var videoStream = VideoStream;
+ var isInputInterlaced = videoStream != null && videoStream.IsInterlaced;
+
+ if (!isInputInterlaced)
+ {
+ return false;
+ }
+
+ // Support general param
+ if (BaseRequest.DeInterlace)
+ {
+ return true;
+ }
+
+ if (!string.IsNullOrEmpty(videoCodec))
+ {
+ if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ if (forceDeinterlaceIfSourceIsInterlaced)
+ {
+ if (isInputInterlaced)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public string[] GetRequestedProfiles(string codec)
+ {
+ if (!string.IsNullOrEmpty(BaseRequest.Profile))
+ {
+ return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
+ }
+
+ if (!string.IsNullOrEmpty(codec))
+ {
+ var profile = BaseRequest.GetOption(codec, "profile");
+
+ if (!string.IsNullOrEmpty(profile))
+ {
+ return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
+ }
+ }
+
+ return new string[] { };
+ }
+
+ public string GetRequestedLevel(string codec)
+ {
+ if (!string.IsNullOrEmpty(BaseRequest.Level))
+ {
+ return BaseRequest.Level;
+ }
+
+ if (!string.IsNullOrEmpty(codec))
+ {
+ return BaseRequest.GetOption(codec, "level");
+ }
+
+ return null;
+ }
+
+ public int? GetRequestedMaxRefFrames(string codec)
+ {
+ if (BaseRequest.MaxRefFrames.HasValue)
+ {
+ return BaseRequest.MaxRefFrames;
+ }
+
+ if (!string.IsNullOrEmpty(codec))
+ {
+ var value = BaseRequest.GetOption(codec, "maxrefframes");
+ int result;
+ if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ public int? GetRequestedVideoBitDepth(string codec)
+ {
+ if (BaseRequest.MaxVideoBitDepth.HasValue)
+ {
+ return BaseRequest.MaxVideoBitDepth;
+ }
+
+ if (!string.IsNullOrEmpty(codec))
+ {
+ var value = BaseRequest.GetOption(codec, "videobitdepth");
+ int result;
+ if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ public int? GetRequestedAudioBitDepth(string codec)
+ {
+ if (BaseRequest.MaxAudioBitDepth.HasValue)
+ {
+ return BaseRequest.MaxAudioBitDepth;
+ }
+
+ if (!string.IsNullOrEmpty(codec))
+ {
+ var value = BaseRequest.GetOption(codec, "audiobitdepth");
+ int result;
+ if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ public int? GetRequestedAudioChannels(string codec)
+ {
+ if (BaseRequest.MaxAudioChannels.HasValue)
+ {
+ return BaseRequest.MaxAudioChannels;
+ }
+ if (BaseRequest.AudioChannels.HasValue)
+ {
+ return BaseRequest.AudioChannels;
+ }
+
+ if (!string.IsNullOrEmpty(codec))
+ {
+ var value = BaseRequest.GetOption(codec, "audiochannels");
+ int result;
+ if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ public bool IsVideoRequest { get; set; }
+ public TranscodingJobType TranscodingType { get; set; }
+
+ public EncodingJobInfo(ILogger logger, IMediaSourceManager unused, TranscodingJobType jobType)
+ {
+ _logger = logger;
+ TranscodingType = jobType;
+ RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ PlayableStreamFileNames = new string[] { };
+ SupportedAudioCodecs = new string[] { };
+ SupportedVideoCodecs = new string[] { };
+ SupportedSubtitleCodecs = new string[] { };
+ }
+
+ public bool IsSegmentedLiveStream
+ {
+ get
+ {
+ return TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue;
+ }
+ }
+
+ public bool EnableBreakOnNonKeyFrames(string videoCodec)
+ {
+ if (TranscodingType != TranscodingJobType.Progressive)
+ {
+ if (IsSegmentedLiveStream)
+ {
+ return false;
+ }
+
+ return BaseRequest.BreakOnNonKeyFrames && string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase);
+ }
+
+ return false;
+ }
+
+ public int? TotalOutputBitrate
+ {
+ get
+ {
+ return (OutputAudioBitrate ?? 0) + (OutputVideoBitrate ?? 0);
+ }
+ }
+
+ public int? OutputWidth
+ {
+ get
+ {
+ if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue)
+ {
+ var size = new ImageSize
+ {
+ Width = VideoStream.Width.Value,
+ Height = VideoStream.Height.Value
+ };
+
+ var newSize = DrawingUtils.Resize(size,
+ BaseRequest.Width ?? 0,
+ BaseRequest.Height ?? 0,
+ BaseRequest.MaxWidth ?? 0,
+ BaseRequest.MaxHeight ?? 0);
+
+ return Convert.ToInt32(newSize.Width);
+ }
+
+ if (!IsVideoRequest)
+ {
+ return null;
+ }
+
+ return BaseRequest.MaxWidth ?? BaseRequest.Width;
+ }
+ }
+
+ public int? OutputHeight
+ {
+ get
+ {
+ if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue)
+ {
+ var size = new ImageSize
+ {
+ Width = VideoStream.Width.Value,
+ Height = VideoStream.Height.Value
+ };
+
+ var newSize = DrawingUtils.Resize(size,
+ BaseRequest.Width ?? 0,
+ BaseRequest.Height ?? 0,
+ BaseRequest.MaxWidth ?? 0,
+ BaseRequest.MaxHeight ?? 0);
+
+ return Convert.ToInt32(newSize.Height);
+ }
+
+ if (!IsVideoRequest)
+ {
+ return null;
+ }
+
+ return BaseRequest.MaxHeight ?? BaseRequest.Height;
+ }
+ }
+
+ public int? OutputAudioSampleRate
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ if (AudioStream != null)
+ {
+ return AudioStream.SampleRate;
+ }
+ }
+
+ else if (BaseRequest.AudioSampleRate.HasValue)
+ {
+ // Don't exceed what the encoder supports
+ // Seeing issues of attempting to encode to 88200
+ return Math.Min(44100, BaseRequest.AudioSampleRate.Value);
+ }
+
+ return null;
+ }
+ }
+
+ public int? OutputAudioBitDepth
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ if (AudioStream != null)
+ {
+ return AudioStream.BitDepth;
+ }
+ }
+
+ //else if (BaseRequest.AudioSampleRate.HasValue)
+ //{
+ // // Don't exceed what the encoder supports
+ // // Seeing issues of attempting to encode to 88200
+ // return Math.Min(44100, BaseRequest.AudioSampleRate.Value);
+ //}
+
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Predicts the audio sample rate that will be in the output stream
+ /// </summary>
+ public double? TargetVideoLevel
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? null : VideoStream.Level;
+ }
+
+ var level = GetRequestedLevel(ActualOutputVideoCodec);
+ double result;
+ if (!string.IsNullOrEmpty(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
+ }
+
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Predicts the audio sample rate that will be in the output stream
+ /// </summary>
+ public int? TargetVideoBitDepth
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? null : VideoStream.BitDepth;
+ }
+
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Gets the target reference frames.
+ /// </summary>
+ /// <value>The target reference frames.</value>
+ public int? TargetRefFrames
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? null : VideoStream.RefFrames;
+ }
+
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Predicts the audio sample rate that will be in the output stream
+ /// </summary>
+ public float? TargetFramerate
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? null : (VideoStream.AverageFrameRate ?? VideoStream.RealFrameRate);
+ }
+
+ return BaseRequest.MaxFramerate ?? BaseRequest.Framerate;
+ }
+ }
+
+ public TransportStreamTimestamp TargetTimestamp
+ {
+ get
+ {
+ var defaultValue = string.Equals(OutputContainer, "m2ts", StringComparison.OrdinalIgnoreCase) ?
+ TransportStreamTimestamp.Valid :
+ TransportStreamTimestamp.None;
+
+ return !BaseRequest.Static
+ ? defaultValue
+ : InputTimestamp;
+ }
+ }
+
+ /// <summary>
+ /// Predicts the audio sample rate that will be in the output stream
+ /// </summary>
+ public int? TargetPacketLength
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? null : VideoStream.PacketLength;
+ }
+
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Predicts the audio sample rate that will be in the output stream
+ /// </summary>
+ public string TargetVideoProfile
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? null : VideoStream.Profile;
+ }
+
+ var requestedProfile = GetRequestedProfiles(ActualOutputVideoCodec).FirstOrDefault();
+ if (!string.IsNullOrEmpty(requestedProfile))
+ {
+ return requestedProfile;
+ }
+
+ return null;
+ }
+ }
+
+ /// <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 null;
+ }
+ }
+
+ public bool? IsTargetAnamorphic
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? null : VideoStream.IsAnamorphic;
+ }
+
+ return false;
+ }
+ }
+
+ public string ActualOutputVideoCodec
+ {
+ get
+ {
+ var codec = OutputVideoCodec;
+
+ if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ var stream = VideoStream;
+
+ if (stream != null)
+ {
+ return stream.Codec;
+ }
+
+ return null;
+ }
+
+ return codec;
+ }
+ }
+
+ public bool? IsTargetInterlaced
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced;
+ }
+
+ if (DeInterlace(ActualOutputVideoCodec, true))
+ {
+ return false;
+ }
+
+ return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced;
+ }
+ }
+
+ public bool? IsTargetAVC
+ {
+ get
+ {
+ if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return VideoStream == null ? null : VideoStream.IsAVC;
+ }
+
+ return false;
+ }
+ }
+
+ public int? TargetVideoStreamCount
+ {
+ get
+ {
+ if (BaseRequest.Static)
+ {
+ return GetMediaStreamCount(MediaStreamType.Video, int.MaxValue);
+ }
+ return GetMediaStreamCount(MediaStreamType.Video, 1);
+ }
+ }
+
+ public int? TargetAudioStreamCount
+ {
+ get
+ {
+ if (BaseRequest.Static)
+ {
+ return GetMediaStreamCount(MediaStreamType.Audio, int.MaxValue);
+ }
+ return GetMediaStreamCount(MediaStreamType.Audio, 1);
+ }
+ }
+
+ private int? GetMediaStreamCount(MediaStreamType type, int limit)
+ {
+ var count = MediaSource.GetStreamCount(type);
+
+ if (count.HasValue)
+ {
+ count = Math.Min(count.Value, limit);
+ }
+
+ return count;
+ }
+
+ protected void DisposeIsoMount()
+ {
+ if (IsoMount != null)
+ {
+ try
+ {
+ IsoMount.Dispose();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error disposing iso mount", ex);
+ }
+
+ IsoMount = null;
+ }
+ }
+
+ public IProgress<double> Progress { get; set; }
+ public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float framerate, double? percentComplete, long bytesTranscoded, int? bitRate) {
+ Progress.Report(percentComplete.Value);
+ }
+
+ public virtual void Dispose () {
+ }
+ }
+
+ /// <summary>
+ /// Enum TranscodingJobType
+ /// </summary>
+ public enum TranscodingJobType
+ {
+ /// <summary>
+ /// The progressive
+ /// </summary>
+ Progressive,
+ /// <summary>
+ /// The HLS
+ /// </summary>
+ Hls,
+ /// <summary>
+ /// The dash
+ /// </summary>
+ Dash
+ }
+}