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

C# 如何让FFMPEG使用与输入相同的时间构建视频?,c#,video,ffmpeg,screenshot,C#,Video,Ffmpeg,Screenshot,我试图通过从C#console应用程序将屏幕截图传输到FFMPEG,来创建用户的屏幕动作视频。我每秒发送10帧。最后一段视频的帧数与我发送的帧数完全相同(即:10秒视频有100帧)。但是,视频的时间不匹配。通过下面的代码,我从490751毫秒的输入中获得了价值7米47秒的视频。我发现PTS让我更接近,但感觉我做错了什么 private const int VID_FRAME_FPS = 10; private const double PTS = 2.4444; ///

我试图通过从C#console应用程序将屏幕截图传输到FFMPEG,来创建用户的屏幕动作视频。我每秒发送10帧。最后一段视频的帧数与我发送的帧数完全相同(即:10秒视频有100帧)。但是,视频的时间不匹配。通过下面的代码,我从490751毫秒的输入中获得了价值7米47秒的视频。我发现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();
    }
private const int VID_FRAME_FPS=10;
私人常数双点=2.4444;
/// 
///通过采集帧并通过FFMPEG进行处理来生成视频。
///成功编译视频后删除生成的帧图像。
/// 
公共静态无效记录屏幕(字符串路径输出)
{
Logger.log.Info(“启动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\”+路径输出+“\\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\”+路径输出+“\\VidOut.mp4\”;
进程启动FFMPEG=新进程
{
StartInfo=新流程StartInfo
{
FileName=“ffmpeg”,
参数=arg,
UseShellExecute=false,
CreateNoWindow=true,
重定向标准输入=true
}
};
启动ffmpeg.Start();
系统图、图像img;
Stopwatch Stopwatch=Stopwatch.StartNew();//创建并启动Stopwatch实例
智力睡眠;
秒表vidTime=Stopwatch.StartNew();
做
{
img=Capture.GetScreen();
保存(启动ffmpeg.StandardInput.BaseStream,System.Drawing.Imaging.ImageFormat.Bmp);
img.Dispose();
睡眠=10*VID_FRAME_FPS-(int)秒表。延时百万秒;
如果(睡眠>0)
{
Logger.log.Info(“捕获帧,休眠”+休眠+“毫秒”);
睡眠;
}
stopWatch.Restart();
}while(workerThread.IsAlive);
Logger.log.Debug(“视频时间:+vidTime.elapsedmillyses”);
启动FFMPEG.StandardInput.Flush();
启动FFMPEG.StandardInput.Close();
启动ffmpeg.Close();
}
没有PTS有没有办法做到这一点?如果我需要PTS,正确的值是多少?2.5656的PTS似乎接近正确

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


注意:我只使用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\"";
这假设发送帧之间的间隔是固定的,即每个帧在前一帧之后发送100ms。如果存在可变定时或帧速率,则需要不同的方法


顺便说一句,libx264将忽略
-qscale:v
,因此最好使用
-crf N
,其中18到28是N的一个良好范围。

它起作用了。接受一件事,我忘了在我的问题中提到,我使用的是webm而不是H.264。我已经切换到H.264进行测试,因为ffprobe无法从webm读取帧。事实上,任何非专利格式都很好。对webm有什么想法吗?同样的方法也适用于webm。谢谢@Mulvya,你是对的,事实证明,对于webm来说,我能在一秒钟内录制的帧数要慢得多。叹息