public async Task TranscodeVideo(Stream outputStream, TranscodeVideoFile options, CancellationToken token) { string cmd; if (options.HwAccelDeviceType != HwAccelDeviceType.None) { cmd = BuildVideoTranscodeCmd(options, 0, 2); _logger.LogInformation($"{nameof(TranscodeVideo)}: Checking if we can use the default cmd for hwAccelType = {options.HwAccelDeviceType}..."); _transcodeProcess.StartInfo.Arguments = cmd; _transcodeProcess.Start(); await using var memStream = new MemoryStream(); var testStream = _transcodeProcess.StandardOutput.BaseStream as FileStream; await testStream.CopyToAsync(memStream, token).ConfigureAwait(false); if (_transcodeProcess.ExitCode != 0) { _logger.LogWarning( $"{nameof(TranscodeVideo)}: We cant use the default cmd = {cmd} for hwAccelType = {options.HwAccelDeviceType}. " + $"Creating a new one with hwAccelType = {HwAccelDeviceType.None}.."); options.HwAccelDeviceType = HwAccelDeviceType.None; } } cmd = BuildVideoTranscodeCmd(options); //https://forums.plex.tv/t/best-format-for-streaming-via-chromecast/49978/6 //ffmpeg - i[inputfile] - c:v libx264 -profile:v high -level 5 - crf 18 - maxrate 10M - bufsize 16M - pix_fmt yuv420p - vf "scale=iw*sar:ih, scale='if(gt(iw,ih),min(1920,iw),-1)':'if(gt(iw,ih),-1,min(1080,ih))'" - x264opts bframes = 3:cabac = 1 - movflags faststart - strict experimental - c:a aac -b:a 320k - y[outputfile] //string cmd = $@"-v quiet -ss {seconds} -y -i ""{filePath}"" -preset superfast -c:v copy -acodec aac -b:a 128k -movflags frag_keyframe+faststart -f mp4 -"; _logger.LogInformation($"{nameof(TranscodeVideo)}: Trying to transcode file with CMD = {cmd}"); _transcodeProcess.StartInfo.Arguments = cmd; _transcodeProcess.Start(); var stream = _transcodeProcess.StandardOutput.BaseStream as FileStream; await stream.CopyToAsync(outputStream, token).ConfigureAwait(false); _logger.LogInformation($"{nameof(TranscodeVideo)}: Transcode completed for file = {options.FilePath}"); }
private static string BuildVideoTranscodeCmd( TranscodeVideoFile options, double?from = null, double?to = null) { var builder = new FFmpegArgsBuilder(); var inputArgs = builder.AddInputFile(options.FilePath) .BeQuiet() .SetVSync(0) .SetAutoConfirmChanges() .SetHwAccel(options.HwAccelDeviceType) .SetVideoCodec(options.HwAccelDeviceType); var outputArgs = builder.AddOutputPipe() .SetPreset(options.HwAccelDeviceType) .AddArg("map_metadata", -1) .AddArg("map_chapters", -1); //for some reason the chromecast doesnt like chapters o.o if (options.VideoStreamIndex >= 0) { outputArgs.SetMap(options.VideoStreamIndex); } if (options.AudioStreamIndex >= 0) { outputArgs.SetMap(options.AudioStreamIndex); } if (options.Seconds > 0 && !from.HasValue && !to.HasValue) { inputArgs.Seek(options.Seconds); } if (from.HasValue) { outputArgs.Seek(from.Value); } if (to.HasValue) { outputArgs.To(to.Value); } if (options.ForceVideoTranscode) { outputArgs.SetVideoCodec(options.HwAccelDeviceType).SetProfileVideo("main").SetLevel(4).SetPixelFormat(options.HwAccelDeviceType); if (options.VideoScaleType != VideoScaleType.Original) { int videoScale = (int)options.VideoScaleType; switch (options.HwAccelDeviceType) { case HwAccelDeviceType.Intel: outputArgs.AddArg("global_quality", 25) .AddArg("look_ahead", 1) .SetFilters($"scale_qsv=trunc(oh*a/2)*2:{videoScale}"); break; case HwAccelDeviceType.Nvidia: string scale = options.VideoScaleType == VideoScaleType.Hd ? "1280x720" : "1920x1080"; if (scale != options.VideoWidthAndHeight && !string.IsNullOrWhiteSpace(options.VideoWidthAndHeight)) { inputArgs.AddArg("resize", scale); } break; case HwAccelDeviceType.None: outputArgs.SetFilters($"scale=trunc(oh*a/2)*2:{videoScale}"); break; case HwAccelDeviceType.AMD: break; default: throw new ArgumentOutOfRangeException(); } } } else { outputArgs.CopyVideoCodec(); } if (options.ForceAudioTranscode) { outputArgs.SetAudioCodec("aac").SetAudioBitrate(128).SetAudioChannels(2); } else { outputArgs.CopyAudioCodec(); } outputArgs.SetMovFlagToTheStart().SetFormat("mp4"); return(builder.GetArgs()); }