c# - 如何让 FFMPEG 使用与输入相同的时间来构建视频?

标签 c# video ffmpeg screenshot

我正在尝试通过将屏幕截图从 C# 控制台应用程序传送到 FFMPEG 来创建用户采取的屏幕操作视频。我每秒发送 10 帧。最终视频的帧数与我发送的帧数完全相同(即:10 秒的视频有 100 帧)。但是,视频的时间不匹配。使用下面的代码,我从 490751 ms 的输入中获得了 7m 47s 的视频。我发现 PTS 让我更接近了一点,但感觉就像我做错了什么。

    private const int VID_FRAME_FPS = 10;
    private const double PTS = 2.4444;

    /// <summary>
    /// Generates the Videos by gathering frames and processing via FFMPEG.
    /// Deletes the generated Frame images after successfully compiling the video.
    /// </summary>
    public static void RecordScreen(string pathToOutput)
    {
        Logger.log.Info("Launching FFMPEG ....");
        String arg = "-f image2pipe -i pipe:.bmp -filter:v \"setpts = " + PTS + " * PTS\" -r " + VID_FRAME_FPS + " -pix_fmt yuv420p -qscale:v 5 -vcodec libvpx -bufsize 30000k -y \"" + pathToOutput + "\\VidOut.webm\"";
        //String arg = "-f image2pipe -i pipe:.bmp -filter:v \"setpts = " + PTS + " * PTS\" -r " + VID_FRAME_FPS + " -pix_fmt yuv420p -qscale:v 5 -vcodec libx264 -bufsize 30000k -y \"" + pathToOutput + "\\VidOut.mp4\"";
        Process launchingFFMPEG = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "ffmpeg",
                Arguments = arg,
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardInput = true
            }
        };
        launchingFFMPEG.Start();

        System.Drawing.Image img;
        Stopwatch stopWatch = Stopwatch.StartNew(); //creates and start the instance of Stopwatch
        int sleep;

        Stopwatch vidTime = Stopwatch.StartNew();

        do
        {
            img = Capture.GetScreen();
            img.Save(launchingFFMPEG.StandardInput.BaseStream, System.Drawing.Imaging.ImageFormat.Bmp);
            img.Dispose();

            sleep = 10 * VID_FRAME_FPS - (int)stopWatch.ElapsedMilliseconds;
            if (sleep > 0)
            {
                Logger.log.Info("Captured frame, sleeping " + sleep + " milliseconds.");
                Thread.Sleep(sleep);
            }
            stopWatch.Restart();
        } while (workerThread.IsAlive);
        Logger.log.Debug("Video Time: " + vidTime.ElapsedMilliseconds);
        launchingFFMPEG.StandardInput.Flush();
        launchingFFMPEG.StandardInput.Close();
        launchingFFMPEG.Close();
    }

有没有办法在没有 PTS 的情况下做到这一点?如果我需要 PTS,正确的值是多少?似乎 2.565656 的 PTS 接近正确。

所有相关文档都指向仅使用 -r (帧速率命令),但这不起作用(因为我正在使用它)。

注意:我只使用 H.264 进行 ffprobe 调试,我计划在解决此问题后切换回 webm。我试图避免 H.256 和 MP4 专利。

最佳答案

我建议使用以下语法:

String arg = "-f image2pipe -framerate " + VID_FRAME_FPS + " -i pipe:.bmp -pix_fmt yuv420p -qscale:v 5 -vcodec libx264 -bufsize 30000k -y \"" + pathToOutput + "\\VidOut.mp4\"";

这假设发送帧之间的间隔是固定的,即每一帧在前一帧之后 100 毫秒发送。如果有可变的时序或帧速率,则需要使用不同的方法。

顺便说一句,libx264 将忽略 -qscale:v , 所以最好使用 -crf N相反,其中 18 到 28 是 N 的一个很好的范围。

关于c# - 如何让 FFMPEG 使用与输入相同的时间来构建视频?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36635141/

相关文章:

c# - 可以使用 XmlAttributes 有选择地 XmlIgnore 吗?

c# - Xaml,按钮的click事件在命令之前运行?

PHP : How check movie format is MKV or WMV

ios - 使用ffmpeg,函数 av_find_input_format ("avfoundation")返回 null

c++ - 将来自 MacOS X 10.9 的 ffmpeg 的 libswresample 与 C++ 链接起来

c# - 如何使用 Project Oxford 的语音 API 将解决方案实现到 WPF 应用程序中?

c# - 在单元测试中使用 RowTest 是一个好习惯吗

video - CKEditor:允许视频嵌入代码

php - 发布带有youtube嵌入式视频的网站的网址时未显示缩略图

ffmpeg - 使用 ffmpeg 如何将 dv pal 格式转换为 mp4 而不会出现隔行扫描问题?