使用std :: chrono :: high_resolution_clock每秒写一次帧30次

isA*_*Don 3 c++ c++11 c++-chrono

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

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();
Run Code Online (Sandbox Code Playgroud)

我不确定这是否是正确的方法,或者是否有更有效的方法.还有什么比投射持续时间更好的long long difference?

How*_*ant 12

有一个基本租户可以使用chrono,它类似于:

如果你使用count(),和/或你的chrono代码中有转换因子 ,那么你就是在努力.

这不是你的错.确实没有好的chrono教程,这是我的不好,我最近决定我需要做些什么.

在您的情况下,我建议您按照以下方式重写代码:

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

using frame_period = std::chrono::duration<long long, std::ratio<1, 30>>;
Run Code Online (Sandbox Code Playgroud)

现在,当你说frame_period{1},这意味着正好 1/30秒.

接下来要注意的是,只要你留在计时系统中,chrono比较总是精确的. count()是逃离计时系统的"陷阱门".只有在别无选择时才能逃脱.所以...

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();
Run Code Online (Sandbox Code Playgroud)

一旦你得到计时,上面的评论就过于冗长了.评论比上面的代码更多.但是上面的工作正如你想象的那样,不需要"逃出"计时系统.

更新

如果你想初始化difference,以便第一次不执行内部循环,你可以将它初始化为刚刚超过 frame_period{1} 0的东西.为此,这里找到的实用程序派上用场.特别是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;
}
Run Code Online (Sandbox Code Playgroud)

ceilduration_cast当转换不精确时,它将取代它,而不是截断为零.现在你可以说:

auto difference = ceil<hr_duration>(frame_period{1});
Run Code Online (Sandbox Code Playgroud)

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