c# - 将视频渲染到帧速率可能不一致的文件

标签 c# video aforge

我以不一致的速率从源(可视为黑盒)获取原始视频帧。我正在尝试将视频源录制到磁盘。我正在使用 AForge 的 VideoRecorder 这样做,并且正在写入 MP4 文件。

但是,我接收帧的速率不一致导致视频显示速度加快。似乎我只能创建具有固定帧速率的视频文件,即使源没有固定帧速率。

渲染到屏幕时这不是问题,因为我们可以尽可能快地渲染。我无法在写入文件时执行此操作,因为播放文件时会以固定帧速率播放。

有哪些解决方案?输出不必是相同的视频格式,只要有一些合理的方法可以稍后转换它(不一定是实时的)。视频源可能会很长,所以我不能将所有内容都存储在内存中,然后再进行编码。

我的代码目前看起来是这样的:

VideoFileWriter writer = new VideoFileWriter();
Stopwatch stopwatch = new Stopwatch();

public override void Start() {
    writer.Open("output.mp4", videoWidth, videoHeight, frameRate, AForge.Video.FFMPEG.VideoCodec.MPEG4);
    stopwatch.Start();
}

public override void End() {
    writer.Close();
}

public override void Draw(Frame frame) {
    double elapsedTimeInSeconds = stopwatch.ElapsedTicks / (double) Stopwatch.Frequency;
    double timeBetweenFramesInSeconds = 1.0 / FrameRate;
    if (elapsedTimeInSeconds >= timeBetweenFramesInSeconds) {
        stopwatch.Restart();
        writer.WriteVideoFrame(frame.ToBitmap());
    }
}

我们的黑盒调用StartEndDraw 方法的地方。我在 Draw 中进行的当前检查可防止我们绘制得太快,但不会采取任何措施来处理绘制太慢的情况。

最佳答案

原来 WriteVideoFrame 被重载了,函数的一个变体是 WriteVideoFrame(Bitmap frame, TimeSpan timestamp) .您可以猜到,时间戳用于使帧出现在视频中的特定时间。

因此,通过跟踪实时时间,我们可以将每一帧设置为使用它应该在视频中出现的时间。当然,如果渲染速度不够快,视频质量会变差,但这可以解决手头的问题。

这是我用于Draw 函数的代码:

// We can provide a frame offset so that each frame has a time that it's supposed to be
// seen at. This ensures that the video looks correct if the render rate is lower than
// the frame rate, since these times will be used (it'll be choppy, but at least it'll
// be paced correctly -- necessary so that sound won't go out of sync).
long currentTick = DateTime.Now.Ticks;
StartTick = StartTick ?? currentTick;
var frameOffset = new TimeSpan(currentTick - StartTick.Value);

// Figure out if we need to render this frame to the file (ie, has enough time passed
// that this frame will be in the file?). This prevents us from going over the
// desired frame rate and improves performance (assuming that we can go over the frame
// rate).
double elapsedTimeInSeconds = stopwatch.ElapsedTicks / (double) Stopwatch.Frequency;
double timeBetweenFramesInSeconds = 1.0 / FrameRate;
if (elapsedTimeInSeconds >= timeBetweenFramesInSeconds)
{
    stopwatch.Restart();

    Writer.WriteVideoFrame(frame.ToBitmap(), frameOffset);
}

StartTick 是对象的 long? 成员。

关于c# - 将视频渲染到帧速率可能不一致的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30225716/

相关文章:

c# - 如何在 C# 中返回静态类实例

android - Cordova 3.4 Android 本地视频文件无法播放

video - 即使录制意外中断(例如电源断开),如何在 gstreamer 中录制可播放的视频文件?

c# - VS 2008 C# 将焦点设置为仅一种形式

javascript - 无法让 Javascript 函数从 gridview 中的文本框触发

c# - 为什么 Windows 服务中的打印屏幕返回黑色图像?

ios - MPMoviePlayerController 不在 iOS7 上播放视频

c# - 在图片框中显示/读取 8 位灰度(未压缩)TIFF 并使用 AForge.net c# 进行操作

robotics - 机器人、立体视觉、驾驶和AForge