使用std :: chrono :: high_resolution_clock每秒写入一帧30次 [英] using std::chrono::high_resolution_clock to write a frame 30 times per second

查看:1924
本文介绍了使用std :: chrono :: high_resolution_clock每秒写入一帧30次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用OpenCV来编写视频文件。对于 cv :: VideoWriter 工作正常对write()函数的调用必须每秒正好发生30次(对于30fps视频)。
我找到了这个代码,使用boost库来实现这一点。我想要相同,但在我的程序中使用 std :: chrono 。这是我的实现:

I'm using OpenCV to write a video file. For cv::VideoWriter to work correctly the call to the write() function has to happen exactly 30 times per second (for a 30fps video). I found this code which uses the boost library to achieve this. I want to to the same but using std::chrono in my program. This is my implementation:

std::chrono::high_resolution_clock::time_point prev = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point current = prev;
long long difference = std::chrono::duration_cast<std::chrono::microseconds>(current-prev).count();

while(recording){

    while (difference < 1000000/30){
        current = std::chrono::high_resolution_clock::now();
        difference = std::chrono::duration_cast<std::chrono::microseconds>(current-prev).count();
    }                   

    theVideoWriter.write(frameToRecord);

    prev = prev + std::chrono::high_resolution_clock::duration(1000000000/30);
    difference = std::chrono::duration_cast<std::chrono::microseconds>(current-prev).count();                  
}

theVideoWriter.release();

我不知道这是否正确的方法,或者如果有更有效的方式。有什么比投射持续时间到长的差异吗?

I'm not sure if thats the correct way to do this or if there is a more efficient way. Is there anything better than casting the duration to long long difference?

推荐答案

使用 chrono 的基本租户有:


如果您使用 count()和/或您的
chrono 代码中有转换因子,那么你太费力了。

If you use count(), and/or you have conversion factors in your chrono code, then you're trying too hard.

这不是你的错。真的没有好的 chrono 教程,这是我的坏,我最近决定我需要做一些事情。

This is not your fault. There really is no good chrono tutorial and that is my bad, and I've recently decided I need to do something about that.

在这种情况下,我建议按照以下内容重写代码:

In your case, I recommend rewriting your code along the lines of the following:

首先创建一个表示帧速率周期的持续时间单位:

First create a duration unit which represents the period of your frame rate:

using frame_period = std::chrono::duration<long long, std::ratio<1, 30>>;

现在当你说 frame_period {1}

接下来要注意的是 chrono 比较始终精确,只要你留在计时系统。 count()是一个陷阱门,逃出计时系统。只有当你没有别的选择逃脱。所以...

The next thing to note is that chrono comparisons are always exact, as long as you stay in the chrono system. count() is a "trap door" for escaping out of the chrono system. Only escape out when you have no other choice. So...

auto prev = std::chrono::high_resolution_clock::now();
auto current = pref;
// Just get the difference, and don't worry about the units for now
auto difference = current-prev;
while(recording)
{
    // Find out if the difference is less than one frame period
    // This comparison will do all the conversions for you to get an exact answer
    while (difference < frame_period{1})
    {
        current = std::chrono::high_resolution_clock::now();
        // stay in "native units"...
        difference = current-prev;
    }                   
    theVideoWriter.write(frameToRecord);
    // This is a little tricky...
    // prev + frame_period{1} creates a time_point with a complicated unit
    // Use time_point_cast to convert (via truncation towards zero) back to
    // the "native" duration of high_resolution_clock
    using hr_duration = std::chrono::high_resolution_clock::duration;
    prev = std::chrono::time_point_cast<hr_duration>(prev + frame_period{1});
    // stay in "native units"...
    difference = current-prev;                  
}
theVideoWriter.release();

一旦你得到了chrono,上面的注释过于冗长。有比上面的代码更多的评论。

The comments above are overly verbose once you get chrono. There's more comment than code above. But the above just works as you intended, with no need for "escaping out" of the chrono system.

更新

如果你想初始化 difference ,这样内循环将不会被第一次执行,你可以初始化它只需 frame_period {1} 而不是0.为此,这里找到的实用程序派上用场。具体 ceil

If you would want to initialize difference such that the inner loop won't be executed the first time, you could initialize it to something just over frame_period{1} instead of to 0. To do this, the utilities found here come in handy. Specifically ceil:

// round up
template <class To, class Rep, class Period>
To
ceil(const std::chrono::duration<Rep, Period>& d)
{
    To t = std::chrono::duration_cast<To>(d);
    if (t < d)
        ++t;
    return t;
}

ceil 替换 duration_cast ,当转换不准确时向上舍入,而不是向零舍入。现在您可以说:

ceil is a replacement for duration_cast that will round up when the conversion is inexact, as opposed to truncate towards zero. Now you can say:

auto difference = ceil<hr_duration>(frame_period{1});

您可以保证 difference> = frame_period {1} code>。此外,在实践中已知high_resolution_clock的持续时间是纳秒,因此,您可以推导(或测试) difference 实际上被初始化为33,333,334ns,这是2/3大于1/30秒,等于 frame_period {1} ,其等于33,333,333 + 1 / 3ns。

And you are guaranteed that difference >= frame_period{1}. Furthermore, it is known in practice that the duration of high_resolution_clock is nanoseconds, thus you can deduce (or test) that difference is actually initialized to 33,333,334ns, which is 2/3 of a nanosecond greater than 1/30 of a second, which equals frame_period{1}, which equals 33,333,333+1/3ns.

这篇关于使用std :: chrono :: high_resolution_clock每秒写入一帧30次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆