mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-04 02:01:28 +01:00 
			
		
		
		
	update sync encoding to match streaming
This commit is contained in:
		
							parent
							
								
									d28ef71d93
								
							
						
					
					
						commit
						d1de9e0179
					
				@ -19,38 +19,40 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override string GetCommandLineArguments(EncodingJob job)
 | 
			
		||||
        protected override string GetCommandLineArguments(EncodingJob state)
 | 
			
		||||
        {
 | 
			
		||||
            var audioTranscodeParams = new List<string>();
 | 
			
		||||
 | 
			
		||||
            var bitrate = job.OutputAudioBitrate;
 | 
			
		||||
            var bitrate = state.OutputAudioBitrate;
 | 
			
		||||
 | 
			
		||||
            if (bitrate.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(UsCulture));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (job.OutputAudioChannels.HasValue)
 | 
			
		||||
            if (state.OutputAudioChannels.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                audioTranscodeParams.Add("-ac " + job.OutputAudioChannels.Value.ToString(UsCulture));
 | 
			
		||||
                audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (job.OutputAudioSampleRate.HasValue)
 | 
			
		||||
            if (state.OutputAudioSampleRate.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                audioTranscodeParams.Add("-ar " + job.OutputAudioSampleRate.Value.ToString(UsCulture));
 | 
			
		||||
                audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var threads = GetNumberOfThreads(job, false);
 | 
			
		||||
            const string vn = " -vn";
 | 
			
		||||
 | 
			
		||||
            var inputModifier = GetInputModifier(job);
 | 
			
		||||
            var threads = GetNumberOfThreads(state, false);
 | 
			
		||||
 | 
			
		||||
            var inputModifier = GetInputModifier(state);
 | 
			
		||||
 | 
			
		||||
            return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
 | 
			
		||||
                inputModifier,
 | 
			
		||||
                GetInputArgument(job),
 | 
			
		||||
                GetInputArgument(state),
 | 
			
		||||
                threads,
 | 
			
		||||
                " -vn",
 | 
			
		||||
                vn,
 | 
			
		||||
                string.Join(" ", audioTranscodeParams.ToArray()),
 | 
			
		||||
                job.OutputFilePath).Trim();
 | 
			
		||||
                state.OutputFilePath).Trim();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override string GetOutputFileExtension(EncodingJob state)
 | 
			
		||||
 | 
			
		||||
@ -303,15 +303,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            return job.Options.CpuCoreLimit ?? 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected string GetInputModifier(EncodingJob job, bool genPts = true)
 | 
			
		||||
        protected string GetInputModifier(EncodingJob state, bool genPts = true)
 | 
			
		||||
        {
 | 
			
		||||
            var inputModifier = string.Empty;
 | 
			
		||||
 | 
			
		||||
            var probeSize = GetProbeSizeArgument(job);
 | 
			
		||||
            var probeSize = GetProbeSizeArgument(state);
 | 
			
		||||
            inputModifier += " " + probeSize;
 | 
			
		||||
            inputModifier = inputModifier.Trim();
 | 
			
		||||
 | 
			
		||||
            var userAgentParam = GetUserAgentParam(job);
 | 
			
		||||
            var userAgentParam = GetUserAgentParam(state);
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(userAgentParam))
 | 
			
		||||
            {
 | 
			
		||||
@ -320,35 +320,43 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
 | 
			
		||||
            inputModifier = inputModifier.Trim();
 | 
			
		||||
 | 
			
		||||
            inputModifier += " " + GetFastSeekCommandLineParameter(job.Options);
 | 
			
		||||
            inputModifier += " " + GetFastSeekCommandLineParameter(state.Options);
 | 
			
		||||
            inputModifier = inputModifier.Trim();
 | 
			
		||||
 | 
			
		||||
            if (job.IsVideoRequest && genPts)
 | 
			
		||||
            if (state.IsVideoRequest && genPts)
 | 
			
		||||
            {
 | 
			
		||||
                inputModifier += " -fflags +genpts";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(job.InputAudioSync))
 | 
			
		||||
            if (!string.IsNullOrEmpty(state.InputAudioSync))
 | 
			
		||||
            {
 | 
			
		||||
                inputModifier += " -async " + job.InputAudioSync;
 | 
			
		||||
                inputModifier += " -async " + state.InputAudioSync;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(job.InputVideoSync))
 | 
			
		||||
            if (!string.IsNullOrEmpty(state.InputVideoSync))
 | 
			
		||||
            {
 | 
			
		||||
                inputModifier += " -vsync " + job.InputVideoSync;
 | 
			
		||||
                inputModifier += " -vsync " + state.InputVideoSync;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (job.ReadInputAtNativeFramerate)
 | 
			
		||||
            if (state.ReadInputAtNativeFramerate)
 | 
			
		||||
            {
 | 
			
		||||
                inputModifier += " -re";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var videoDecoder = GetVideoDecoder(job);
 | 
			
		||||
            var videoDecoder = GetVideoDecoder(state);
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(videoDecoder))
 | 
			
		||||
            {
 | 
			
		||||
                inputModifier += " " + videoDecoder;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //if (state.IsVideoRequest)
 | 
			
		||||
            //{
 | 
			
		||||
            //    if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            //    {
 | 
			
		||||
            //        //inputModifier += " -noaccurate_seek";
 | 
			
		||||
            //    }
 | 
			
		||||
            //}
 | 
			
		||||
 | 
			
		||||
            return inputModifier;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -392,11 +400,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetUserAgentParam(EncodingJob job)
 | 
			
		||||
        private string GetUserAgentParam(EncodingJob state)
 | 
			
		||||
        {
 | 
			
		||||
            string useragent = null;
 | 
			
		||||
 | 
			
		||||
            job.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
 | 
			
		||||
            state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(useragent))
 | 
			
		||||
            {
 | 
			
		||||
@ -409,31 +417,31 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the probe size argument.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="job">The job.</param>
 | 
			
		||||
        /// <param name="state">The state.</param>
 | 
			
		||||
        /// <returns>System.String.</returns>
 | 
			
		||||
        private string GetProbeSizeArgument(EncodingJob job)
 | 
			
		||||
        private string GetProbeSizeArgument(EncodingJob state)
 | 
			
		||||
        {
 | 
			
		||||
            if (job.PlayableStreamFileNames.Count > 0)
 | 
			
		||||
            if (state.PlayableStreamFileNames.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                return MediaEncoder.GetProbeSizeArgument(job.PlayableStreamFileNames.ToArray(), job.InputProtocol);
 | 
			
		||||
                return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return MediaEncoder.GetProbeSizeArgument(new[] { job.MediaPath }, job.InputProtocol);
 | 
			
		||||
            return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the fast seek command line parameter.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="options">The options.</param>
 | 
			
		||||
        /// <param name="request">The request.</param>
 | 
			
		||||
        /// <returns>System.String.</returns>
 | 
			
		||||
        /// <value>The fast seek command line parameter.</value>
 | 
			
		||||
        protected string GetFastSeekCommandLineParameter(EncodingJobOptions options)
 | 
			
		||||
        protected string GetFastSeekCommandLineParameter(EncodingJobOptions request)
 | 
			
		||||
        {
 | 
			
		||||
            var time = options.StartTimeTicks;
 | 
			
		||||
            var time = request.StartTimeTicks ?? 0;
 | 
			
		||||
 | 
			
		||||
            if (time.HasValue && time.Value > 0)
 | 
			
		||||
            if (time > 0)
 | 
			
		||||
            {
 | 
			
		||||
                return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(time.Value));
 | 
			
		||||
                return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(time));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return string.Empty;
 | 
			
		||||
@ -442,34 +450,35 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the input argument.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="job">The job.</param>
 | 
			
		||||
        /// <param name="state">The state.</param>
 | 
			
		||||
        /// <returns>System.String.</returns>
 | 
			
		||||
        protected string GetInputArgument(EncodingJob job)
 | 
			
		||||
        protected string GetInputArgument(EncodingJob state)
 | 
			
		||||
        {
 | 
			
		||||
            var arg = "-i " + GetInputPathArgument(job);
 | 
			
		||||
            var arg = string.Format("-i {0}", GetInputPathArgument(state));
 | 
			
		||||
 | 
			
		||||
            if (job.SubtitleStream != null)
 | 
			
		||||
            if (state.SubtitleStream != null)
 | 
			
		||||
            {
 | 
			
		||||
                if (job.SubtitleStream.IsExternal && !job.SubtitleStream.IsTextSubtitleStream)
 | 
			
		||||
                if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
 | 
			
		||||
                {
 | 
			
		||||
                    arg += " -i \"" + job.SubtitleStream.Path + "\"";
 | 
			
		||||
                    arg += " -i \"" + state.SubtitleStream.Path + "\"";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return arg;
 | 
			
		||||
            return arg.Trim();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetInputPathArgument(EncodingJob job)
 | 
			
		||||
        private string GetInputPathArgument(EncodingJob state)
 | 
			
		||||
        {
 | 
			
		||||
            var protocol = job.InputProtocol;
 | 
			
		||||
            var protocol = state.InputProtocol;
 | 
			
		||||
            var mediaPath = state.MediaPath ?? string.Empty;
 | 
			
		||||
 | 
			
		||||
            var inputPath = new[] { job.MediaPath };
 | 
			
		||||
            var inputPath = new[] { mediaPath };
 | 
			
		||||
 | 
			
		||||
            if (job.IsInputVideo)
 | 
			
		||||
            if (state.IsInputVideo)
 | 
			
		||||
            {
 | 
			
		||||
                if (!(job.VideoType == VideoType.Iso && job.IsoMount == null))
 | 
			
		||||
                if (!(state.VideoType == VideoType.Iso && state.IsoMount == null))
 | 
			
		||||
                {
 | 
			
		||||
                    inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, job.MediaPath, job.InputProtocol, job.IsoMount, job.PlayableStreamFileNames);
 | 
			
		||||
                    inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, mediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -491,7 +500,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
 | 
			
		||||
                }, false, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                AttachMediaStreamInfo(state, liveStreamResponse.MediaSource, state.Options);
 | 
			
		||||
                AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.Options);
 | 
			
		||||
 | 
			
		||||
                if (state.IsVideoRequest)
 | 
			
		||||
                {
 | 
			
		||||
@ -505,11 +514,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AttachMediaStreamInfo(EncodingJob state,
 | 
			
		||||
        private void AttachMediaSourceInfo(EncodingJob state,
 | 
			
		||||
          MediaSourceInfo mediaSource,
 | 
			
		||||
          EncodingJobOptions videoRequest)
 | 
			
		||||
        {
 | 
			
		||||
            EncodingJobFactory.AttachMediaStreamInfo(state, mediaSource, videoRequest);
 | 
			
		||||
            EncodingJobFactory.AttachMediaSourceInfo(state, mediaSource, videoRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -572,7 +581,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            {
 | 
			
		||||
                param = "-preset superfast";
 | 
			
		||||
 | 
			
		||||
                param += " -crf 28";
 | 
			
		||||
                param += " -crf 23";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
@ -582,6 +591,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
                param += " -crf 28";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // h264 (h264_qsv)
 | 
			
		||||
            else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                param = "-preset 7 -look_ahead 0";
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // h264 (libnvenc)
 | 
			
		||||
            else if (string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                param = "-preset high-performance";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // webm
 | 
			
		||||
            else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
@ -644,9 +666,53 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
                param += " -profile:v " + state.Options.Profile;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (state.Options.Level.HasValue)
 | 
			
		||||
            var levelString = state.Options.Level.HasValue ? state.Options.Level.Value.ToString(CultureInfo.InvariantCulture) : null;
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(levelString))
 | 
			
		||||
            {
 | 
			
		||||
                param += " -level " + state.Options.Level.Value.ToString(UsCulture);
 | 
			
		||||
                var h264Encoder = EncodingJobFactory.GetH264Encoder(state, GetEncodingOptions());
 | 
			
		||||
 | 
			
		||||
                // h264_qsv and libnvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
 | 
			
		||||
                if (String.Equals(h264Encoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || String.Equals(h264Encoder, "libnvenc", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    switch (levelString)
 | 
			
		||||
                    {
 | 
			
		||||
                        case "30":
 | 
			
		||||
                            param += " -level 3";
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "31":
 | 
			
		||||
                            param += " -level 3.1";
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "32":
 | 
			
		||||
                            param += " -level 3.2";
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "40":
 | 
			
		||||
                            param += " -level 4";
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "41":
 | 
			
		||||
                            param += " -level 4.1";
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "42":
 | 
			
		||||
                            param += " -level 4.2";
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "50":
 | 
			
		||||
                            param += " -level 5";
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "51":
 | 
			
		||||
                            param += " -level 5.1";
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "52":
 | 
			
		||||
                            param += " -level 5.2";
 | 
			
		||||
                            break;
 | 
			
		||||
                        default:
 | 
			
		||||
                            param += " -level " + levelString;
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    param += " -level " + levelString;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return "-pix_fmt yuv420p " + param;
 | 
			
		||||
@ -658,15 +724,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
 | 
			
		||||
            if (bitrate.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                var hasFixedResolution = state.Options.HasFixedResolution;
 | 
			
		||||
 | 
			
		||||
                if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    if (hasFixedResolution)
 | 
			
		||||
                    {
 | 
			
		||||
                        return string.Format(" -minrate:v ({0}*.90) -maxrate:v ({0}*1.10) -bufsize:v {0} -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // With vpx when crf is used, b:v becomes a max rate
 | 
			
		||||
                    // https://trac.ffmpeg.org/wiki/vpxEncodingGuide. But higher bitrate source files -b:v causes judder so limite the bitrate but dont allow it to "saturate" the bitrate. So dont contrain it down just up.
 | 
			
		||||
                    return string.Format(" -maxrate:v {0} -bufsize:v ({0}*2) -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
@ -677,20 +736,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
                    return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // H264
 | 
			
		||||
                if (hasFixedResolution)
 | 
			
		||||
                // h264
 | 
			
		||||
                if (isHls)
 | 
			
		||||
                {
 | 
			
		||||
                    if (isHls)
 | 
			
		||||
                    {
 | 
			
		||||
                        return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
                    return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
 | 
			
		||||
                        bitrate.Value.ToString(UsCulture),
 | 
			
		||||
                        (bitrate.Value * 2).ToString(UsCulture));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return string.Format(" -maxrate {0} -bufsize {1}",
 | 
			
		||||
                    bitrate.Value.ToString(UsCulture),
 | 
			
		||||
                    (bitrate.Value * 2).ToString(UsCulture));
 | 
			
		||||
                return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return string.Empty;
 | 
			
		||||
@ -698,20 +752,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
 | 
			
		||||
        protected double? GetFramerateParam(EncodingJob state)
 | 
			
		||||
        {
 | 
			
		||||
            if (state.Options.Framerate.HasValue)
 | 
			
		||||
            if (state.Options != null)
 | 
			
		||||
            {
 | 
			
		||||
                return state.Options.Framerate.Value;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var maxrate = state.Options.MaxFramerate;
 | 
			
		||||
 | 
			
		||||
            if (maxrate.HasValue && state.VideoStream != null)
 | 
			
		||||
            {
 | 
			
		||||
                var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate;
 | 
			
		||||
 | 
			
		||||
                if (contentRate.HasValue && contentRate.Value > maxrate.Value)
 | 
			
		||||
                if (state.Options.Framerate.HasValue)
 | 
			
		||||
                {
 | 
			
		||||
                    return maxrate;
 | 
			
		||||
                    return state.Options.Framerate.Value;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var maxrate = state.Options.MaxFramerate;
 | 
			
		||||
 | 
			
		||||
                if (maxrate.HasValue && state.VideoStream != null)
 | 
			
		||||
                {
 | 
			
		||||
                    var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate;
 | 
			
		||||
 | 
			
		||||
                    if (contentRate.HasValue && contentRate.Value > maxrate.Value)
 | 
			
		||||
                    {
 | 
			
		||||
                        return maxrate;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -852,7 +909,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            {
 | 
			
		||||
                var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
 | 
			
		||||
 | 
			
		||||
                filters.Add(string.Format("scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam));
 | 
			
		||||
                filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If a max height was requested
 | 
			
		||||
@ -863,6 +920,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
                filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(ih\\,{0})", maxHeightParam));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                if (filters.Count > 1)
 | 
			
		||||
                {
 | 
			
		||||
                    //filters[filters.Count - 1] += ":flags=fast_bilinear";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var output = string.Empty;
 | 
			
		||||
 | 
			
		||||
            if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
 | 
			
		||||
@ -917,8 +982,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
                    seconds.ToString(UsCulture));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var mediaPath = state.MediaPath ?? string.Empty;
 | 
			
		||||
 | 
			
		||||
            return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB",
 | 
			
		||||
                MediaEncoder.EscapeSubtitleFilterPath(state.MediaPath),
 | 
			
		||||
                MediaEncoder.EscapeSubtitleFilterPath(mediaPath),
 | 
			
		||||
                state.InternalSubtitleStreamOffset.ToString(UsCulture),
 | 
			
		||||
                seconds.ToString(UsCulture));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ using MediaBrowser.Model.MediaInfo;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
@ -66,38 +67,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
               ? mediaSources.First()
 | 
			
		||||
               : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
 | 
			
		||||
 | 
			
		||||
            AttachMediaStreamInfo(state, mediaSource, options);
 | 
			
		||||
            var videoRequest = state.Options;
 | 
			
		||||
 | 
			
		||||
            state.OutputAudioBitrate = GetAudioBitrateParam(request, state.AudioStream);
 | 
			
		||||
            AttachMediaSourceInfo(state, mediaSource, videoRequest);
 | 
			
		||||
 | 
			
		||||
            //var container = Path.GetExtension(state.RequestedUrl);
 | 
			
		||||
 | 
			
		||||
            //if (string.IsNullOrEmpty(container))
 | 
			
		||||
            //{
 | 
			
		||||
            //    container = request.Static ?
 | 
			
		||||
            //        state.InputContainer :
 | 
			
		||||
            //        (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.');
 | 
			
		||||
            //}
 | 
			
		||||
 | 
			
		||||
            //state.OutputContainer = (container ?? string.Empty).TrimStart('.');
 | 
			
		||||
 | 
			
		||||
            state.OutputAudioBitrate = GetAudioBitrateParam(state.Options, state.AudioStream);
 | 
			
		||||
            state.OutputAudioSampleRate = request.AudioSampleRate;
 | 
			
		||||
 | 
			
		||||
            state.OutputAudioCodec = GetAudioCodec(request);
 | 
			
		||||
            state.OutputAudioCodec = state.Options.AudioCodec;
 | 
			
		||||
 | 
			
		||||
            state.OutputAudioChannels = GetNumAudioChannelsParam(request, state.AudioStream, state.OutputAudioCodec);
 | 
			
		||||
            state.OutputAudioChannels = GetNumAudioChannelsParam(state.Options, state.AudioStream, state.OutputAudioCodec);
 | 
			
		||||
 | 
			
		||||
            if (isVideoRequest)
 | 
			
		||||
            if (videoRequest != null)
 | 
			
		||||
            {
 | 
			
		||||
                state.OutputVideoCodec = GetVideoCodec(request);
 | 
			
		||||
                state.OutputVideoBitrate = GetVideoBitrateParamValue(request, state.VideoStream);
 | 
			
		||||
                state.OutputVideoCodec = state.Options.VideoCodec;
 | 
			
		||||
                state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream);
 | 
			
		||||
 | 
			
		||||
                if (state.OutputVideoBitrate.HasValue)
 | 
			
		||||
                {
 | 
			
		||||
                    var resolution = ResolutionNormalizer.Normalize(
 | 
			
		||||
						state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
 | 
			
		||||
						state.OutputVideoBitrate.Value,
 | 
			
		||||
						state.VideoStream == null ? null : state.VideoStream.Codec,
 | 
			
		||||
                        state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
 | 
			
		||||
                        state.OutputVideoBitrate.Value,
 | 
			
		||||
                        state.VideoStream == null ? null : state.VideoStream.Codec,
 | 
			
		||||
                        state.OutputVideoCodec,
 | 
			
		||||
                        request.MaxWidth,
 | 
			
		||||
                        request.MaxHeight);
 | 
			
		||||
                        videoRequest.MaxWidth,
 | 
			
		||||
                        videoRequest.MaxHeight);
 | 
			
		||||
 | 
			
		||||
                    request.MaxWidth = resolution.MaxWidth;
 | 
			
		||||
                    request.MaxHeight = resolution.MaxHeight;
 | 
			
		||||
                    videoRequest.MaxWidth = resolution.MaxWidth;
 | 
			
		||||
                    videoRequest.MaxHeight = resolution.MaxHeight;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ApplyDeviceProfileSettings(state);
 | 
			
		||||
 | 
			
		||||
            TryStreamCopy(state, request);
 | 
			
		||||
            if (videoRequest != null)
 | 
			
		||||
            {
 | 
			
		||||
                TryStreamCopy(state, videoRequest);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //state.OutputFilePath = GetOutputFilePath(state);
 | 
			
		||||
 | 
			
		||||
            return state;
 | 
			
		||||
        }
 | 
			
		||||
@ -119,7 +138,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal static void AttachMediaStreamInfo(EncodingJob state,
 | 
			
		||||
        internal static void AttachMediaSourceInfo(EncodingJob state,
 | 
			
		||||
            MediaSourceInfo mediaSource,
 | 
			
		||||
            EncodingJobOptions videoRequest)
 | 
			
		||||
        {
 | 
			
		||||
@ -131,11 +150,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            state.RunTimeTicks = mediaSource.RunTimeTicks;
 | 
			
		||||
            state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
 | 
			
		||||
 | 
			
		||||
            if (mediaSource.ReadAtNativeFramerate)
 | 
			
		||||
            {
 | 
			
		||||
                state.ReadInputAtNativeFramerate = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (mediaSource.VideoType.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                state.VideoType = mediaSource.VideoType.Value;
 | 
			
		||||
@ -156,6 +170,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
 | 
			
		||||
            state.InputBitrate = mediaSource.Bitrate;
 | 
			
		||||
            state.InputFileSize = mediaSource.Size;
 | 
			
		||||
            state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
 | 
			
		||||
 | 
			
		||||
            if (state.ReadInputAtNativeFramerate ||
 | 
			
		||||
                mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
@ -165,6 +180,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
                state.InputAudioSync = "1";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                // Seeing some stuttering when transcoding wma to audio-only HLS
 | 
			
		||||
                state.InputAudioSync = "1";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var mediaStreams = mediaSource.MediaStreams;
 | 
			
		||||
 | 
			
		||||
            if (videoRequest != null)
 | 
			
		||||
@ -210,19 +231,21 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
        /// <returns>System.Nullable{VideoCodecs}.</returns>
 | 
			
		||||
        private static string InferVideoCodec(string container)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            var ext = "." + (container ?? string.Empty);
 | 
			
		||||
 | 
			
		||||
            if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "wmv";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "webm", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "vpx";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "theora";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "h264";
 | 
			
		||||
            }
 | 
			
		||||
@ -232,35 +255,37 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
 | 
			
		||||
        private string InferAudioCodec(string container)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            var ext = "." + (container ?? string.Empty);
 | 
			
		||||
 | 
			
		||||
            if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "mp3";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "aac", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "aac";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "wma", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "wma";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "vorbis";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "oga", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "vorbis";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "vorbis";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "webm", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "vorbis";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(container, "webma", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "vorbis";
 | 
			
		||||
            }
 | 
			
		||||
@ -398,15 +423,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
 | 
			
		||||
            if (bitrate.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                var hasFixedResolution = state.Options.HasFixedResolution;
 | 
			
		||||
 | 
			
		||||
                if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    if (hasFixedResolution)
 | 
			
		||||
                    {
 | 
			
		||||
                        return string.Format(" -minrate:v ({0}*.90) -maxrate:v ({0}*1.10) -bufsize:v {0} -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // With vpx when crf is used, b:v becomes a max rate
 | 
			
		||||
                    // https://trac.ffmpeg.org/wiki/vpxEncodingGuide. But higher bitrate source files -b:v causes judder so limite the bitrate but dont allow it to "saturate" the bitrate. So dont contrain it down just up.
 | 
			
		||||
                    return string.Format(" -maxrate:v {0} -bufsize:v ({0}*2) -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
@ -417,20 +435,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
                    return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // H264
 | 
			
		||||
                if (hasFixedResolution)
 | 
			
		||||
                // h264
 | 
			
		||||
                if (isHls)
 | 
			
		||||
                {
 | 
			
		||||
                    if (isHls)
 | 
			
		||||
                    {
 | 
			
		||||
                        return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
                    return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
 | 
			
		||||
                        bitrate.Value.ToString(UsCulture),
 | 
			
		||||
                        (bitrate.Value * 2).ToString(UsCulture));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return string.Format(" -maxrate {0} -bufsize {1}",
 | 
			
		||||
                    bitrate.Value.ToString(UsCulture),
 | 
			
		||||
                    (bitrate.Value * 2).ToString(UsCulture));
 | 
			
		||||
                return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return string.Empty;
 | 
			
		||||
@ -466,11 +479,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the name of the output audio codec
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="request">The request.</param>
 | 
			
		||||
        /// <param name="state">The state.</param>
 | 
			
		||||
        /// <returns>System.String.</returns>
 | 
			
		||||
        private string GetAudioCodec(EncodingJobOptions request)
 | 
			
		||||
        internal static string GetAudioEncoder(EncodingJob state)
 | 
			
		||||
        {
 | 
			
		||||
            var codec = request.AudioCodec;
 | 
			
		||||
            var codec = state.OutputAudioCodec;
 | 
			
		||||
 | 
			
		||||
            if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
@ -489,40 +502,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
                return "wmav2";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (codec ?? string.Empty).ToLower();
 | 
			
		||||
            return codec.ToLower();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the name of the output video codec
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="request">The request.</param>
 | 
			
		||||
        /// <param name="state">The state.</param>
 | 
			
		||||
        /// <param name="options">The options.</param>
 | 
			
		||||
        /// <returns>System.String.</returns>
 | 
			
		||||
        private string GetVideoCodec(EncodingJobOptions request)
 | 
			
		||||
        internal static string GetVideoEncoder(EncodingJob state, EncodingOptions options)
 | 
			
		||||
        {
 | 
			
		||||
            var codec = request.VideoCodec;
 | 
			
		||||
            var codec = state.OutputVideoCodec;
 | 
			
		||||
 | 
			
		||||
            if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (!string.IsNullOrEmpty(codec))
 | 
			
		||||
            {
 | 
			
		||||
                return "libx264";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "libx265";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "libvpx";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "wmv2";
 | 
			
		||||
            }
 | 
			
		||||
            if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return "libtheora";
 | 
			
		||||
                if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    return GetH264Encoder(state, options);
 | 
			
		||||
                }
 | 
			
		||||
                if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    return "libvpx";
 | 
			
		||||
                }
 | 
			
		||||
                if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    return "wmv2";
 | 
			
		||||
                }
 | 
			
		||||
                if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    return "libtheora";
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return codec.ToLower();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (codec ?? string.Empty).ToLower();
 | 
			
		||||
            return "copy";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal static string GetH264Encoder(EncodingJob state, EncodingOptions options)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                // It's currently failing on live tv
 | 
			
		||||
                if (state.RunTimeTicks.HasValue)
 | 
			
		||||
                {
 | 
			
		||||
                    return "h264_qsv";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return "libx264";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal static bool CanStreamCopyVideo(EncodingJobOptions request, MediaStream videoStream)
 | 
			
		||||
 | 
			
		||||
@ -21,14 +21,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
        protected override string GetCommandLineArguments(EncodingJob state)
 | 
			
		||||
        {
 | 
			
		||||
            // Get the output codec name
 | 
			
		||||
            var videoCodec = state.OutputVideoCodec;
 | 
			
		||||
            var videoCodec = EncodingJobFactory.GetVideoEncoder(state, GetEncodingOptions());
 | 
			
		||||
 | 
			
		||||
            var format = string.Empty;
 | 
			
		||||
            var keyFrame = string.Empty;
 | 
			
		||||
 | 
			
		||||
            if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase) &&
 | 
			
		||||
                state.Options.Context == EncodingContext.Streaming)
 | 
			
		||||
            if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
 | 
			
		||||
                format = " -f mp4 -movflags frag_keyframe+empty_moov";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -53,42 +53,49 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
        /// Gets video arguments to pass to ffmpeg
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="state">The state.</param>
 | 
			
		||||
        /// <param name="codec">The video codec.</param>
 | 
			
		||||
        /// <param name="videoCodec">The video codec.</param>
 | 
			
		||||
        /// <returns>System.String.</returns>
 | 
			
		||||
        private string GetVideoArguments(EncodingJob state, string codec)
 | 
			
		||||
        private string GetVideoArguments(EncodingJob state, string videoCodec)
 | 
			
		||||
        {
 | 
			
		||||
            var args = "-codec:v:0 " + codec;
 | 
			
		||||
            var args = "-codec:v:0 " + videoCodec;
 | 
			
		||||
 | 
			
		||||
            if (state.EnableMpegtsM2TsMode)
 | 
			
		||||
            {
 | 
			
		||||
                args += " -mpegts_m2ts_mode 1";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // See if we can save come cpu cycles by avoiding encoding
 | 
			
		||||
            if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            var isOutputMkv = string.Equals(state.Options.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase);
 | 
			
		||||
 | 
			
		||||
            if (state.RunTimeTicks.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                return state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.Options.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) ?
 | 
			
		||||
                    args + " -bsf:v h264_mp4toannexb" :
 | 
			
		||||
                    args;
 | 
			
		||||
                //args += " -copyts -avoid_negative_ts disabled -start_at_zero";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (state.Options.Context == EncodingContext.Streaming)
 | 
			
		||||
            if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
 | 
			
		||||
                    5.ToString(UsCulture));
 | 
			
		||||
                if (state.VideoStream != null && IsH264(state.VideoStream) &&
 | 
			
		||||
                    (string.Equals(state.Options.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) || isOutputMkv))
 | 
			
		||||
                {
 | 
			
		||||
                    args += " -bsf:v h264_mp4toannexb";
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                args += keyFrameArg;
 | 
			
		||||
                return args;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
 | 
			
		||||
                5.ToString(UsCulture));
 | 
			
		||||
 | 
			
		||||
            args += keyFrameArg;
 | 
			
		||||
 | 
			
		||||
            var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
 | 
			
		||||
 | 
			
		||||
            // Add resolution params, if specified
 | 
			
		||||
            if (!hasGraphicalSubs)
 | 
			
		||||
            {
 | 
			
		||||
                args += GetOutputSizeParam(state, codec);
 | 
			
		||||
                args += GetOutputSizeParam(state, videoCodec);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var qualityParam = GetVideoQualityParam(state, codec, false);
 | 
			
		||||
            var qualityParam = GetVideoQualityParam(state, videoCodec, false);
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(qualityParam))
 | 
			
		||||
            {
 | 
			
		||||
@ -98,7 +105,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            // This is for internal graphical subs
 | 
			
		||||
            if (hasGraphicalSubs)
 | 
			
		||||
            {
 | 
			
		||||
                args += GetGraphicalSubtitleParam(state, codec);
 | 
			
		||||
                args += GetGraphicalSubtitleParam(state, videoCodec);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return args;
 | 
			
		||||
@ -118,11 +125,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Get the output codec name
 | 
			
		||||
            var codec = state.OutputAudioCodec;
 | 
			
		||||
            var codec = EncodingJobFactory.GetAudioEncoder(state);
 | 
			
		||||
 | 
			
		||||
            var args = "-codec:a:0 " + codec;
 | 
			
		||||
 | 
			
		||||
            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                return args;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user