diff options
Diffstat (limited to 'MediaBrowser.Controller/MediaEncoding')
11 files changed, 319 insertions, 234 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/DroidSansFallback.ttf.REMOVED.git-id b/MediaBrowser.Controller/MediaEncoding/DroidSansFallback.ttf.REMOVED.git-id deleted file mode 100644 index 3c0ca209e..000000000 --- a/MediaBrowser.Controller/MediaEncoding/DroidSansFallback.ttf.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -4366f8d8bf9886d71e3e9ddae8480d953caf02cf
\ No newline at end of file diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 5dca45c1e..e086f9d33 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -3,14 +3,15 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Threading; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Extensions; namespace MediaBrowser.Controller.MediaEncoding { @@ -21,6 +22,8 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly IMediaEncoder _mediaEncoder; private readonly IFileSystem _fileSystem; private readonly ISubtitleEncoder _subtitleEncoder; + // private readonly IApplicationPaths _appPaths; + // private readonly IAssemblyInfo _assemblyInfo; public EncodingHelper(IMediaEncoder mediaEncoder, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder) { @@ -40,56 +43,55 @@ namespace MediaBrowser.Controller.MediaEncoding { var hwType = encodingOptions.HardwareAccelerationType; - if (!encodingOptions.EnableHardwareEncoding) - { - hwType = null; - } - - if (string.Equals(hwType, "qsv", StringComparison.OrdinalIgnoreCase) || - string.Equals(hwType, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + var codecMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { - return GetAvailableEncoder("h264_qsv", defaultEncoder); - } + {"qsv", "h264_qsv"}, + {"h264_qsv", "h264_qsv"}, + {"nvenc", "h264_nvenc"}, + {"amf", "h264_amf"}, + {"omx", "h264_omx"}, + {"h264_v4l2m2m", "h264_v4l2m2m"}, + {"mediacodec", "h264_mediacodec"}, + {"vaapi", "h264_vaapi"} + }; - if (string.Equals(hwType, "nvenc", StringComparison.OrdinalIgnoreCase)) - { - return GetAvailableEncoder("h264_nvenc", defaultEncoder); - } - if (string.Equals(hwType, "amf", StringComparison.OrdinalIgnoreCase)) - { - return GetAvailableEncoder("h264_amf", defaultEncoder); - } - if (string.Equals(hwType, "omx", StringComparison.OrdinalIgnoreCase)) - { - return GetAvailableEncoder("h264_omx", defaultEncoder); - } - if (string.Equals(hwType, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(hwType) + && encodingOptions.EnableHardwareEncoding && codecMap.ContainsKey(hwType)) { - return GetAvailableEncoder("h264_v4l2m2m", defaultEncoder); - } - if (string.Equals(hwType, "mediacodec", StringComparison.OrdinalIgnoreCase)) - { - return GetAvailableEncoder("h264_mediacodec", defaultEncoder); - } - if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(encodingOptions.VaapiDevice)) - { - if (IsVaapiSupported(state)) + if (CheckVaapi(state, hwType, encodingOptions)) { - return GetAvailableEncoder("h264_vaapi", defaultEncoder); + var preferredEncoder = codecMap[hwType]; + + if (_mediaEncoder.SupportsEncoder(preferredEncoder)) + { + return preferredEncoder; + } } } + } + // Avoid performing a second attempt when the first one + // hasn't tried hardware encoding anyway. + encodingOptions.EnableHardwareEncoding = false; return defaultEncoder; } - private string GetAvailableEncoder(string preferredEncoder, string defaultEncoder) + private bool CheckVaapi(EncodingJobInfo state, string hwType, EncodingOptions encodingOptions) { - if (_mediaEncoder.SupportsEncoder(preferredEncoder)) + if (!string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase)) { - return preferredEncoder; + // No vaapi requested, return OK. + return true; } - return defaultEncoder; + + if (string.IsNullOrEmpty(encodingOptions.VaapiDevice)) + { + // No device specified, return OK. + return true; + } + + return IsVaapiSupported(state); } private bool IsVaapiSupported(EncodingJobInfo state) @@ -340,7 +342,7 @@ namespace MediaBrowser.Controller.MediaEncoding public int GetVideoProfileScore(string profile) { - string[] list = + var list = new[] { "ConstrainedBaseline", "Baseline", @@ -538,14 +540,54 @@ namespace MediaBrowser.Controller.MediaEncoding ? string.Empty : string.Format(",setpts=PTS -{0}/TB", seconds.ToString(_usCulture)); - string fallbackFontParam = string.Empty; + // TODO + // var fallbackFontPath = Path.Combine(_appPaths.ProgramDataPath, "fonts", "DroidSansFallback.ttf"); + // string fallbackFontParam = string.Empty; + + // if (!_fileSystem.FileExists(fallbackFontPath)) + // { + // _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(fallbackFontPath)); + // using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), GetType().Namespace + ".DroidSansFallback.ttf")) + // { + // using (var fileStream = _fileSystem.GetFileStream(fallbackFontPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) + // { + // stream.CopyTo(fileStream); + // } + // } + // } + + // fallbackFontParam = string.Format(":force_style='FontName=Droid Sans Fallback':fontsdir='{0}'", _mediaEncoder.EscapeSubtitleFilterPath(_fileSystem.GetDirectoryName(fallbackFontPath))); + + if (state.SubtitleStream.IsExternal) + { + var subtitlePath = state.SubtitleStream.Path; + + var charsetParam = string.Empty; + + if (!string.IsNullOrEmpty(state.SubtitleStream.Language)) + { + var charenc = _subtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language, state.MediaSource.Protocol, CancellationToken.None).Result; + + if (!string.IsNullOrEmpty(charenc)) + { + charsetParam = ":charenc=" + charenc; + } + } + + // TODO: Perhaps also use original_size=1920x800 ?? + return string.Format("subtitles=filename='{0}'{1}{2}{3}", + _mediaEncoder.EscapeSubtitleFilterPath(subtitlePath), + charsetParam, + // fallbackFontParam, + setPtsParam); + } var mediaPath = state.MediaPath ?? string.Empty; - return string.Format("subtitles='{0}:si={1}'{2}{3}", + return string.Format("subtitles='{0}:si={1}'{2}", _mediaEncoder.EscapeSubtitleFilterPath(mediaPath), state.InternalSubtitleStreamOffset.ToString(_usCulture), - fallbackFontParam, + // fallbackFontParam, setPtsParam); } @@ -718,14 +760,18 @@ namespace MediaBrowser.Controller.MediaEncoding var request = state.BaseRequest; var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault(); - if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + + // vaapi does not support Baseline profile, force Constrained Baseline in this case, + // which is compatible (and ugly) + if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && + profile != null && profile.ToLower().Contains("baseline")) { - param += " -profile:v 578"; + profile = "constrained_baseline"; } - else if (!string.IsNullOrEmpty(profile)) + + if (!string.IsNullOrEmpty(profile)) { if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) && - !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) { // not supported by h264_omx @@ -943,9 +989,7 @@ namespace MediaBrowser.Controller.MediaEncoding var level = state.GetRequestedLevel(videoStream.Codec); if (!string.IsNullOrEmpty(level)) { - double requestLevel; - - if (double.TryParse(level, NumberStyles.Any, _usCulture, out requestLevel)) + if (double.TryParse(level, NumberStyles.Any, _usCulture, out var requestLevel)) { if (!videoStream.Level.HasValue) { @@ -1041,51 +1085,67 @@ namespace MediaBrowser.Controller.MediaEncoding { var bitrate = request.VideoBitRate; - if (videoStream != null) + // If specific values were requested, then force the caller to supply a bitrate as well + if (request.Height.HasValue && request.Width.HasValue) { - var isUpscaling = request.Height.HasValue && videoStream.Height.HasValue && - request.Height.Value > videoStream.Height.Value && request.Width.HasValue && videoStream.Width.HasValue && - request.Width.Value > videoStream.Width.Value; + return bitrate; + } - // Don't allow bitrate increases unless upscaling - if (!isUpscaling) + if (videoStream != null) + { + if (bitrate.HasValue) { - if (bitrate.HasValue && videoStream.BitRate.HasValue) + var inputVideoCodec = videoStream.Codec; + bitrate = ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec); + + // If a max bitrate was requested, don't let the scaled bitrate exceed it + if (request.VideoBitRate.HasValue) { - bitrate = GetMinBitrate(videoStream.BitRate.Value, bitrate.Value); + bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value); } } } - if (bitrate.HasValue) - { - var inputVideoCodec = videoStream == null ? null : videoStream.Codec; - bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec); + return bitrate; + } - // If a max bitrate was requested, don't let the scaled bitrate exceed it - if (request.VideoBitRate.HasValue) - { - bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value); - } + private static double GetVideoBitrateScaleFactor(string codec) + { + if (StringHelper.EqualsIgnoreCase(codec, "h265") || + StringHelper.EqualsIgnoreCase(codec, "hevc") || + StringHelper.EqualsIgnoreCase(codec, "vp9")) + { + return .5; } - - return bitrate; + return 1; } - private int GetMinBitrate(int sourceBitrate, int requestedBitrate) + private static int ScaleBitrate(int bitrate, string inputVideoCodec, string outputVideoCodec) { - if (sourceBitrate <= 2000000) + var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec); + var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec); + var scaleFactor = outputScaleFactor / inputScaleFactor; + + if (bitrate <= 500000) { - sourceBitrate = Convert.ToInt32(sourceBitrate * 2.5); + scaleFactor = Math.Max(scaleFactor, 4); } - else if (sourceBitrate <= 3000000) + else if (bitrate <= 1000000) { - sourceBitrate = Convert.ToInt32(sourceBitrate * 2); + scaleFactor = Math.Max(scaleFactor, 3); + } + else if (bitrate <= 2000000) + { + scaleFactor = Math.Max(scaleFactor, 2.5); + } + else if (bitrate <= 3000000) + { + scaleFactor = Math.Max(scaleFactor, 2); } - var bitrate = Math.Min(sourceBitrate, requestedBitrate); + var newBitrate = scaleFactor * bitrate; - return bitrate; + return Convert.ToInt32(newBitrate); } public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream) @@ -1407,7 +1467,7 @@ namespace MediaBrowser.Controller.MediaEncoding videoSizeParam); } - private Tuple<int?, int?> GetFixedOutputSize(int? videoWidth, + private ValueTuple<int?, int?> GetFixedOutputSize(int? videoWidth, int? videoHeight, int? requestedWidth, int? requestedHeight, @@ -1416,11 +1476,11 @@ namespace MediaBrowser.Controller.MediaEncoding { if (!videoWidth.HasValue && !requestedWidth.HasValue) { - return new Tuple<int?, int?>(null, null); + return new ValueTuple<int?, int?>(null, null); } if (!videoHeight.HasValue && !requestedHeight.HasValue) { - return new Tuple<int?, int?>(null, null); + return new ValueTuple<int?, int?>(null, null); } decimal inputWidth = Convert.ToDecimal(videoWidth ?? requestedWidth); @@ -1440,7 +1500,7 @@ namespace MediaBrowser.Controller.MediaEncoding outputWidth = 2 * Math.Truncate(outputWidth / 2); outputHeight = 2 * Math.Truncate(outputHeight / 2); - return new Tuple<int?, int?>(Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight)); + return new ValueTuple<int?, int?>(Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight)); } public List<string> GetScalingFilters(int? videoWidth, @@ -1671,7 +1731,7 @@ namespace MediaBrowser.Controller.MediaEncoding var inputHeight = videoStream == null ? null : videoStream.Height; var threeDFormat = state.MediaSource.Video3DFormat; - var videoDecoder = GetVideoDecoder(state, options); + var videoDecoder = this.GetHardwareAcceleratedVideoDecoder(state, options); filters.AddRange(GetScalingFilters(inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight)); @@ -1853,7 +1913,7 @@ namespace MediaBrowser.Controller.MediaEncoding inputModifier += " -fflags " + string.Join("", flags.ToArray()); } - var videoDecoder = GetVideoDecoder(state, encodingOptions); + var videoDecoder = this.GetHardwareAcceleratedVideoDecoder(state, encodingOptions); if (!string.IsNullOrEmpty(videoDecoder)) { inputModifier += " " + videoDecoder; @@ -1895,7 +1955,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.MediaSource.RequiresLooping) { - inputModifier += " -stream_loop -1"; + inputModifier += " -stream_loop -1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 2"; } return inputModifier; @@ -1991,7 +2051,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (string.IsNullOrEmpty(requestedUrl)) { - requestedUrl = "test." + videoRequest.OutputContainer; + requestedUrl = "test." + videoRequest.Container; } videoRequest.VideoCodec = InferVideoCodec(requestedUrl); @@ -2017,6 +2077,49 @@ namespace MediaBrowser.Controller.MediaEncoding } state.MediaSource = mediaSource; + + var request = state.BaseRequest; + if (!string.IsNullOrWhiteSpace(request.AudioCodec)) + { + var supportedAudioCodecsList = request.AudioCodec.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); + + ShiftAudioCodecsIfNeeded(supportedAudioCodecsList, state.AudioStream); + + state.SupportedAudioCodecs = supportedAudioCodecsList.ToArray(); + + request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => _mediaEncoder.CanEncodeToAudioCodec(i)) + ?? state.SupportedAudioCodecs.FirstOrDefault(); + } + } + + private void ShiftAudioCodecsIfNeeded(List<string> audioCodecs, MediaStream audioStream) + { + // Nothing to do here + if (audioCodecs.Count < 2) + { + return; + } + + var inputChannels = audioStream == null ? 6 : audioStream.Channels ?? 6; + if (inputChannels >= 6) + { + return; + } + + // Transcoding to 2ch ac3 almost always causes a playback failure + // Keep it in the supported codecs list, but shift it to the end of the list so that if transcoding happens, another codec is used + var shiftAudioCodecs = new[] { "ac3", "eac3" }; + if (audioCodecs.All(i => shiftAudioCodecs.Contains(i, StringComparer.OrdinalIgnoreCase))) + { + return; + } + + while (shiftAudioCodecs.Contains(audioCodecs[0], StringComparer.OrdinalIgnoreCase)) + { + var removed = shiftAudioCodecs[0]; + audioCodecs.RemoveAt(0); + audioCodecs.Add(removed); + } } private void NormalizeSubtitleEmbed(EncodingJobInfo state) @@ -2037,17 +2140,17 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets the name of the output video codec /// </summary> - protected string GetVideoDecoder(EncodingJobInfo state, EncodingOptions encodingOptions) + protected string GetHardwareAcceleratedVideoDecoder(EncodingJobInfo state, EncodingOptions encodingOptions) { if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { return null; } - return GetVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions); + return this.GetHardwareAcceleratedVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions); } - public string GetVideoDecoder(VideoType videoType, MediaStream videoStream, EncodingOptions encodingOptions) + public string GetHardwareAcceleratedVideoDecoder(VideoType videoType, MediaStream videoStream, EncodingOptions encodingOptions) { // Only use alternative encoders for video files. // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully @@ -2072,6 +2175,7 @@ namespace MediaBrowser.Controller.MediaEncoding // qsv decoder does not support 10-bit input if ((videoStream.BitDepth ?? 8) > 8) { + encodingOptions.HardwareDecodingCodecs = Array.Empty<string>(); return null; } return "-c:v h264_qsv "; @@ -2206,6 +2310,11 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)) { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + return "-hwaccel dxva2"; + } + switch (videoStream.Codec.ToLower()) { case "avc": @@ -2225,6 +2334,9 @@ namespace MediaBrowser.Controller.MediaEncoding } } + // Avoid a second attempt if no hardware acceleration is being used + encodingOptions.HardwareDecodingCodecs = Array.Empty<string>(); + // leave blank so ffmpeg will decide return null; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 3f6da59d8..6651a6d70 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -1,24 +1,27 @@ -using System; +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.Drawing; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Drawing; 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 abstract class EncodingJobInfo + public class EncodingJobInfo { - private readonly ILogger _logger; + protected readonly IMediaSourceManager MediaSourceManager; public MediaStream VideoStream { get; set; } public VideoType VideoType { get; set; } @@ -43,6 +46,21 @@ namespace MediaBrowser.Controller.MediaEncoding public bool ReadInputAtNativeFramerate { get; set; } + public string OutputFilePath { get; set; } + + public string MimeType { get; set; } + public long? EncodingDurationTicks { get; set; } + + public string GetMimeType(string outputPath, bool enableStreamDefault = true) + { + if (!string.IsNullOrEmpty(MimeType)) + { + return MimeType; + } + + return MimeTypes.GetMimeType(outputPath, enableStreamDefault); + } + private TranscodeReason[] _transcodeReasons = null; public TranscodeReason[] TranscodeReasons { @@ -61,53 +79,17 @@ namespace MediaBrowser.Controller.MediaEncoding } } - public bool IgnoreInputDts - { - get - { - return MediaSource.IgnoreDts; - } - } + public bool IgnoreInputDts => MediaSource.IgnoreDts; - public bool IgnoreInputIndex - { - get - { - return MediaSource.IgnoreIndex; - } - } + public bool IgnoreInputIndex => MediaSource.IgnoreIndex; - public bool GenPtsInput - { - get - { - return MediaSource.GenPtsInput; - } - } + public bool GenPtsInput => MediaSource.GenPtsInput; - public bool DiscardCorruptFramesInput - { - get - { - return false; - } - } + public bool DiscardCorruptFramesInput => false; - public bool EnableFastSeekInput - { - get - { - return false; - } - } + public bool EnableFastSeekInput => false; - public bool GenPtsOutput - { - get - { - return false; - } - } + public bool GenPtsOutput => false; public string OutputContainer { get; set; } @@ -142,15 +124,9 @@ namespace MediaBrowser.Controller.MediaEncoding public BaseEncodingJobOptions BaseRequest { get; set; } - public long? StartTimeTicks - { - get { return BaseRequest.StartTimeTicks; } - } + public long? StartTimeTicks => BaseRequest.StartTimeTicks; - public bool CopyTimestamps - { - get { return BaseRequest.CopyTimestamps; } - } + public bool CopyTimestamps => BaseRequest.CopyTimestamps; public int? OutputAudioBitrate; public int? OutputAudioChannels; @@ -235,8 +211,7 @@ namespace MediaBrowser.Controller.MediaEncoding 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)) + if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -255,8 +230,7 @@ namespace MediaBrowser.Controller.MediaEncoding 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)) + if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -275,8 +249,7 @@ namespace MediaBrowser.Controller.MediaEncoding 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)) + if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -299,8 +272,7 @@ namespace MediaBrowser.Controller.MediaEncoding 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)) + if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -312,9 +284,8 @@ namespace MediaBrowser.Controller.MediaEncoding public bool IsVideoRequest { get; set; } public TranscodingJobType TranscodingType { get; set; } - public EncodingJobInfo(ILogger logger, IMediaSourceManager unused, TranscodingJobType jobType) + public EncodingJobInfo(TranscodingJobType jobType) { - _logger = logger; TranscodingType = jobType; RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); PlayableStreamFileNames = Array.Empty<string>(); @@ -323,13 +294,7 @@ namespace MediaBrowser.Controller.MediaEncoding SupportedSubtitleCodecs = Array.Empty<string>(); } - public bool IsSegmentedLiveStream - { - get - { - return TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue; - } - } + public bool IsSegmentedLiveStream => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue; public bool EnableBreakOnNonKeyFrames(string videoCodec) { @@ -346,13 +311,7 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - public int? TotalOutputBitrate - { - get - { - return (OutputAudioBitrate ?? 0) + (OutputVideoBitrate ?? 0); - } - } + public int? TotalOutputBitrate => (OutputAudioBitrate ?? 0) + (OutputVideoBitrate ?? 0); public int? OutputWidth { @@ -473,8 +432,7 @@ namespace MediaBrowser.Controller.MediaEncoding } var level = GetRequestedLevel(ActualOutputVideoCodec); - double result; - if (!string.IsNullOrEmpty(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out result)) + if (!string.IsNullOrEmpty(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -661,6 +619,28 @@ namespace MediaBrowser.Controller.MediaEncoding } } + public string ActualOutputAudioCodec + { + get + { + var codec = OutputAudioCodec; + + if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) + { + var stream = AudioStream; + + if (stream != null) + { + return stream.Codec; + } + + return null; + } + + return codec; + } + } + public bool? IsTargetInterlaced { get @@ -716,6 +696,14 @@ namespace MediaBrowser.Controller.MediaEncoding } } + public int HlsListSize + { + get + { + return 0; + } + } + private int? GetMediaStreamCount(MediaStreamType type, int limit) { var count = MediaSource.GetStreamCount(type); @@ -727,29 +715,15 @@ namespace MediaBrowser.Controller.MediaEncoding return count; } - protected void DisposeIsoMount() - { - if (IsoMount != null) - { - try - { - IsoMount.Dispose(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error disposing iso mount"); - } - - IsoMount = null; - } - } public IProgress<double> Progress { get; set; } - public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float framerate, double? percentComplete, long bytesTranscoded, int? bitRate) { + public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float framerate, double? percentComplete, long bytesTranscoded, int? bitRate) + { Progress.Report(percentComplete.Value); } - public virtual void Dispose () { + public virtual void Dispose() + { } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index 101748a5a..be97c75a2 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -11,32 +11,26 @@ namespace MediaBrowser.Controller.MediaEncoding { public string OutputDirectory { get; set; } public string ItemId { get; set; } - public string MediaSourceId { get; set; } - public string AudioCodec { get; set; } + public string TempDirectory { get; set; } public bool ReadInputAtNativeFramerate { get; set; } /// <summary> /// Gets a value indicating whether this instance has fixed resolution. /// </summary> /// <value><c>true</c> if this instance has fixed resolution; otherwise, <c>false</c>.</value> - public bool HasFixedResolution - { - get - { - return Width.HasValue || Height.HasValue; - } - } + public bool HasFixedResolution => Width.HasValue || Height.HasValue; + + public DeviceProfile DeviceProfile { get; set; } - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); public EncodingJobOptions(StreamInfo info, DeviceProfile deviceProfile) { - OutputContainer = info.Container; + Container = info.Container; StartTimeTicks = info.StartPositionTicks; MaxWidth = info.MaxWidth; MaxHeight = info.MaxHeight; MaxFramerate = info.MaxFramerate; - ItemId = info.ItemId.ToString(""); + Id = info.ItemId; MediaSourceId = info.MediaSourceId; AudioCodec = info.TargetAudioCodec.FirstOrDefault(); MaxAudioChannels = info.GlobalMaxAudioChannels; @@ -61,6 +55,29 @@ namespace MediaBrowser.Controller.MediaEncoding // For now until api and media encoding layers are unified public class BaseEncodingJobOptions { + /// <summary> + /// Gets or sets the id. + /// </summary> + /// <value>The id.</value> + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public Guid Id { get; set; } + + [ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string MediaSourceId { get; set; } + + [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string DeviceId { get; set; } + + [ApiMember(Name = "Container", Description = "Container", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Container { get; set; } + + /// <summary> + /// Gets or sets the audio codec. + /// </summary> + /// <value>The audio codec.</value> + [ApiMember(Name = "AudioCodec", Description = "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string AudioCodec { get; set; } + [ApiMember(Name = "EnableAutoStreamCopy", Description = "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool EnableAutoStreamCopy { get; set; } @@ -186,7 +203,7 @@ namespace MediaBrowser.Controller.MediaEncoding public bool RequireNonAnamorphic { get; set; } public int? TranscodingMaxAudioChannels { get; set; } public int? CpuCoreLimit { get; set; } - public string OutputContainer { get; set; } + public string LiveStreamId { get; set; } public bool EnableMpegtsM2TsMode { get; set; } @@ -234,8 +251,7 @@ namespace MediaBrowser.Controller.MediaEncoding public string GetOption(string name) { - string value; - if (StreamOptions.TryGetValue(name, out value)) + if (StreamOptions.TryGetValue(name, out var value)) { return value; } @@ -251,11 +267,5 @@ namespace MediaBrowser.Controller.MediaEncoding Context = EncodingContext.Streaming; StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); } - - public string TempDirectory { get; set; } - public string DeviceId { get; set; } - public Guid Id { get; set; } - public string Container { get; set; } - public DeviceProfile DeviceProfile { get; set; } } } diff --git a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs index 7d50efd5e..e560999e8 100644 --- a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs +++ b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Entities; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.MediaEncoding { diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 2b85b8975..48055a37e 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -1,11 +1,11 @@ -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.MediaInfo; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Controller.MediaEncoding { diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs index de7496d42..174e74f34 100644 --- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs @@ -1,8 +1,8 @@ -using MediaBrowser.Model.MediaInfo; using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Controller.MediaEncoding { diff --git a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs index d69c2e47d..361dd79dc 100644 --- a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs @@ -1,4 +1,3 @@ - namespace MediaBrowser.Controller.MediaEncoding { public class ImageEncodingOptions diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index 0554822a8..b812a8ddc 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -1,9 +1,9 @@ -using MediaBrowser.Model.Extensions; using System; using System.Globalization; using System.IO; using System.Linq; using System.Text; +using MediaBrowser.Model.Extensions; using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.MediaEncoding @@ -74,9 +74,8 @@ namespace MediaBrowser.Controller.MediaEncoding (i + 1 < parts.Length)) { var rate = parts[i + 1]; - float val; - if (float.TryParse(rate, NumberStyles.Any, _usCulture, out val)) + if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) { framerate = val; } @@ -85,9 +84,8 @@ namespace MediaBrowser.Controller.MediaEncoding part.StartsWith("time=", StringComparison.OrdinalIgnoreCase)) { var time = part.Split(new[] { '=' }, 2).Last(); - TimeSpan val; - if (TimeSpan.TryParse(time, _usCulture, out val)) + if (TimeSpan.TryParse(time, _usCulture, out var val)) { var currentMs = startMs + val.TotalMilliseconds; @@ -110,9 +108,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (scale.HasValue) { - long val; - - if (long.TryParse(size, NumberStyles.Any, _usCulture, out val)) + if (long.TryParse(size, NumberStyles.Any, _usCulture, out var val)) { bytesTranscoded = val * scale.Value; } @@ -131,9 +127,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (scale.HasValue) { - float val; - - if (float.TryParse(rate, NumberStyles.Any, _usCulture, out val)) + if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) { bitRate = (int)Math.Ceiling(val * scale.Value); } diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs index 70e4db84f..7f842c1d0 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs @@ -1,8 +1,8 @@ -using MediaBrowser.Model.IO; -using MediaBrowser.Model.MediaInfo; using System; using System.IO; using System.Linq; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Controller.MediaEncoding { @@ -31,14 +31,14 @@ namespace MediaBrowser.Controller.MediaEncoding return GetPlayableStreamFiles(fileSystem, isoMount.MountedPath, playableStreamFileNames); } - return new[] {videoPath}; + return new[] { videoPath }; } private static string[] GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, string[] filenames) { if (filenames.Length == 0) { - return new string[]{}; + return new string[] { }; } var allFiles = fileSystem diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs index b191f9905..b78ef0b80 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs @@ -1,10 +1,7 @@ -using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.MediaInfo; -using System.Collections.Generic; -using MediaBrowser.Model.Dto; using System; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.IO; namespace MediaBrowser.Controller.MediaEncoding { |
