赞
踩
点击上方“LiveVideoStack”关注我们
▲扫描图中二维码或点击阅读原文▲
了解音视频技术大会更多信息
作者:王伟
编辑:Alex
引 言
我们有一个平台来周期性地对线上的直播流数据进行某些检测,例如黑/白屏检测、静态画面检测……在检测中,我们会根据提取到的直播流的帧率来预估要计算的帧数量,例如,如果要检测5s的直播流,而该直播流的帧率为20fps,需要计算的帧数量则为100。忽然有一天,我们发现,平台开始大面积的超时,之前只需要2s就能完成的计算,现在却需要30+分钟。查了之后,我们发现,之所以计算超时是因为OpenCV计算的帧率为2000,从而导致需要计算的帧数量从之前的100变为了10000,进而引起了计算超时。
1
OpenCV 如何计算帧率
这个问题的具体描述可以参见 OpenCV Issues 21006[1]。该问题的模拟直播流片段test.ts可以点击链接下载:
https://pan.baidu.com/share/init?surl=RY0Zk5C_DOEwTXYe2SLFEg,下载提取码为x87m。
如果用如下的代码获取test.ts的fps,
- const double FPS = cap.get(cv::CAP_PROP_FPS);
- std::cout << "fps: " << FPS << std::endl;
可以得到:
$ fps: 2000
用ffprobe对视频进行分析,可以得到:
- codec_name=h264
- r_frame_rate=30/1
- avg_frame_rate=0/0
- ……
从 opencv/modules/videoio/src/cap_ffmpeg_impl.hpp[2]中,我们发现fps由CvCapture_FFMPEG::get
计算而来,其计算逻辑如下:
- double fps = r2d(ic->streams[video_stream]->avg_frame_rate);
- if (fps < eps_zero) {
- fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base);
- }
2
为什么OpenCV得到的帧率是错的
利用test_time_base.cpp[3],我们可以得到:
- time_base: 1/2000
- framerate: 0/0
- avg_framerate: 0/0
- r2d(ic->streams[video_stream]->avg_frame_rate) = 0
所以OpenCV采用了:
1.0 / r2d(ic->streams[video_stream]->codec->time_base)
来计算该视频的fps。而此处的time_base = 1/2000,因此,最终得到的fps是2000。
也就是说,AVStream->codec->time_base的值导致了OpenCV得到一个看起来是错误的fps。那么,AVStream->codec->time_base为什么是这个值呢?FFmpeg是怎么计算这个字段的呢?
3
FFmpeg 如何计算
AVCodecContext.time_base
AVStream->codec->time_base是AVCodecContext中定义的 time_base字段,根据libavcodec/avcodec.h[4] 中的定义可知,对于解码而言,time_base已经被废弃,需要使用framerate来替换 time_base。并且,对于固定帧率而言,time_base = 1/framerate,但并非总是如此。
利用H264Naked[5]对test.ts对应的H.264码流进行分析,我们得到SPS.Vui信息:
- timing_info_present_flag :1
- num_units_in_tick :1
- time_scale :2000
- fixed_frame_rate_flag :0
<
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。