public async Task <bool> Detect(MediaInfo mediaInfo) { if (mediaInfo == null) { throw new ArgumentNullException(nameof(mediaInfo)); } if (string.IsNullOrWhiteSpace(mediaInfo.FileName)) { throw new ArgumentException($"{nameof(mediaInfo)}.FileName must not be empty or whitespace.", nameof(mediaInfo)); } if (mediaInfo.Duration <= TimeSpan.Zero) { throw new ArgumentException($"{nameof(mediaInfo)}.Duration is invalid.", nameof(mediaInfo)); } var job = new FFmpegJob() { HideBanner = true, StartTime = TimeSpan.FromMilliseconds(mediaInfo.Duration.TotalMilliseconds / 2), InputFileName = mediaInfo.FileName, FrameCount = FRAME_COUNT, Filters = new IFilter[] { new Filter("idet") } }; var arguments = _argumentGenerator.GenerateArguments(job); FrameStatistics statistics = null; try { var processResult = await _processRunner.Run(_ffmpegFileName, arguments, _timeout); //The interlace detection data is written to standard error. if (!string.IsNullOrWhiteSpace(processResult.ErrorData)) { statistics = Parse(processResult.ErrorData); } else { Trace.WriteLine("No ffmpeg data on stderr to parse."); } } catch (ArgumentException ex) { Trace.WriteLine(ex.Message); Debug.WriteLine(ex.StackTrace); } catch (InvalidOperationException ex) { Trace.WriteLine(ex.Message); Debug.WriteLine(ex.StackTrace); } return(statistics != null && (statistics.TffCount + statistics.BffCount) > (statistics.ProgressiveCount + statistics.UndeterminedCount)); }
public async Task GenerateCallsProcessRunner() { var args = "generated arguments"; _argumentGenerator.GenerateArguments(Arg.Any <FFmpegJob>()).Returns(args); await _imageGenerator.Generate(_transcodeJob); await _processRunner.Received(_imageCount).Run(_ffmpegFileName, args, _timeout); }
public async Task DetectRunsProcess() { string arguments = "generated"; _argumentGenerator.GenerateArguments(Arg.Any <FFmpegJob>()).Returns(arguments); await _detector.Detect(_mediaInfo); await _processRunner.Received().Run(_ffmpegFileName, arguments, _timeout); }
public void StartPassesCorrectProcessStartInfo() { string arguments = "transcode arguments"; ProcessStartInfo startInfo = null; _argumentGenerator.GenerateArguments(Arg.Any <FFmpegJob>()).Returns(arguments); _process.Start(Arg.Any <ProcessStartInfo>()).Returns(x => { startInfo = x[0] as ProcessStartInfo; return(true); }); _transcoder.Start(_transcodeJob); Assert.IsNotNull(startInfo); Assert.IsTrue(startInfo.CreateNoWindow); Assert.AreEqual(_ffmpegFileName, startInfo.FileName); Assert.AreEqual(arguments, startInfo.Arguments); Assert.IsTrue(startInfo.RedirectStandardOutput); Assert.IsTrue(startInfo.RedirectStandardError); Assert.IsFalse(startInfo.UseShellExecute); }
public async Task <CropParameters> Detect(MediaInfo mediaInfo) { if (mediaInfo == null) { throw new ArgumentNullException(nameof(mediaInfo)); } if (string.IsNullOrWhiteSpace(mediaInfo.FileName)) { throw new ArgumentException($"{nameof(mediaInfo)}.FileName must not be empty or whitespace.", nameof(mediaInfo)); } if (mediaInfo.Duration <= TimeSpan.Zero) { throw new ArgumentException($"{nameof(mediaInfo)}.Duration is invalid.", nameof(mediaInfo)); } CropParameters result = null; IEnumerable <double> positions = GetSeekSeconds(mediaInfo.Duration); FFmpegConfig config = _configManager.Config; string options = string.Empty; if (!string.IsNullOrWhiteSpace(config?.Video?.CropDetectOptions)) { options = "=" + config.Video.CropDetectOptions; } var lockTarget = new object(); int?minX = null, minY = null, maxWidth = null, maxHeight = null; var tasks = positions.Select(async seconds => { var job = new FFmpegJob() { HideBanner = true, StartTime = TimeSpan.FromSeconds(seconds), InputFileName = mediaInfo.FileName, FrameCount = 2, Filters = new IFilter[] { new CustomFilter($"cropdetect{options}") } }; var arguments = _argumentGenerator.GenerateArguments(job); try { var processResult = await _processRunner.Run(_ffmpegFileName, arguments, _timeout); //The crop detection data is written to standard error. if (!string.IsNullOrWhiteSpace(processResult.ErrorData)) { var crop = Parse(processResult.ErrorData); if (crop != null) { lock (lockTarget) { minX = minX.HasValue ? Math.Min(crop.Start.X, minX.Value) : crop.Start.X; minY = minY.HasValue ? Math.Min(crop.Start.Y, minY.Value) : crop.Start.Y; maxWidth = maxWidth.HasValue ? Math.Max(crop.Size.Width, maxWidth.Value) : crop.Size.Width; maxHeight = maxHeight.HasValue ? Math.Max(crop.Size.Height, maxHeight.Value) : crop.Size.Height; } } } else { Trace.WriteLine("No ffmpeg data on stderr to parse."); } } catch (ArgumentException ex) { Trace.WriteLine(ex.Message); Debug.WriteLine(ex.StackTrace); } catch (InvalidOperationException ex) { Trace.WriteLine(ex.Message); Debug.WriteLine(ex.StackTrace); } }); await Task.WhenAll(tasks); if (minX.HasValue && minY.HasValue && maxWidth.HasValue && maxHeight.HasValue) { result = new CropParameters() { Start = new Coordinate <int>(minX.Value, minY.Value), Size = new Dimensions(maxWidth.Value, maxHeight.Value) }; } return(result); }
protected virtual string GenerateArguments(TranscodeJob job) { var ffmpegJob = Map(job, _configManager.Config); return(_argumentGenerator.GenerateArguments(ffmpegJob)); }