本文共 2715 字,大约阅读时间需要 9 分钟。
从上一篇可以看出opencv播放视频很是简单,我的环境是VS2010+opencv2.49.这篇文章中我们就一起学习了如何在OpenCV中用createTrackbar函数创建和使用轨迹条,以视频进度的调整。废话少说,先上代码和结果截图再说。
#include#include #include #include using namespace std;using namespace cv;//进度条控制void onTrackbarSlide(int pos,void* capture){ (*((VideoCapture*)capture)).set(CV_CAP_PROP_POS_FRAMES,pos);}int main(void){ //打开视频文件 VideoCapture capture("海贼王.avi"); //isOpen判断视频是否打开成功 if(!capture.isOpened()) { cout<<"Movie open Error"<
运行结果如下:
这个结果界面比原来增加一个进度条。通过进度条我们可以调节播放的的进度。和上一篇的代码相比,这次在代码里面我们就添加了几行代码。来吧,我们先来看看进度条的创建与使用。
我们先来看看这个函数的原型:
C++: int createTrackbar(conststring& trackbarname, conststring& winname, int* value, int count, TrackbarCallback onChange=0,void* userdata=0);
这个createTrackbar函数,为我们创建一个具有特定名称和范围的进度条,并且指定一个和进度条位置同步的变量。而且要指定回调函数onChange(第五个参数),在轨迹条位置改变的时候来调用这个回调函数。可能有些朋友看完上述解释还是有点模糊,还是搞不懂进度条怎么和视频联系到一块呢?首先是进度条通过窗口的名字(第二个参数)绑定到了指定的窗口上,再通过一个整形变量(第三个参数)记录进度条所滑动到达的位置。当进度条滑动时候,会触发回调掉函数(第五个参数),而第六个参数是正是回调函数的一个参数。
下面我们看到自己写的一个回调函数onTrackbarSlide(int pos,void* capture),他的作用就是当进度条被触发时候,设置读取视频帧的位置。里面的set函数上篇博客已经有所介绍,这里就不多说啦。但是当我们在播放时候,我们移动进度条,该进度条总是定位不准,比如说我们想滑动进度条到500帧,结果是很难滑到该帧处的,会出现跳跃的现象。因为我的是opencv2.0版本,同样的代码在opencv1.0里面可能完全没错。可是这是为什么?在网上搜了一些资料,把他贴到这里供大家参考()。
原因在于opencv2.0以后,采用ffmpeg采集视频,而在opencv1.0采用vfw采集视频。而opencv在定位时候,调用的ffmpeg的av_seek_frame()函数,此函数原型为:
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
其中,最后一个参数有
AVSEEK_FLAG_BACKWARD = 1; ///< seek backward
AVSEEK_FLAG_BYTE = 2; ///< seeking based on position >in bytes AVSEEK_FLAG_ANY = 4; ///< seek to any frame, even non >key-framesffmpeg默认的是选取关键帧(这个概念需要具体定义)。opencv里面这个函数的参数flag是0,
int ret = av_seek_frame(ic, video_stream, timestamp, 0);
也就是按照默认的读取关键帧。因此,视频跳跃就出现了。
解决这个问题需要将0改为 AVSEEK_FLAG_ANY ,即:
int ret = av_seek_frame(ic, video_stream, timestamp, AVSEEK_FLAG_ANY );
之后重新编译opencv库,就可以了。
视频播放的例程就讲解到这里,在关于进度条的只是还有几个函数也是经常用到的如获取当前进度条的位置——getTrackbarPos函数,以及设置当前进度条的位置函数setTrackbarPos()等等,这些函数都定义在opencv2/highgui/highgui.hpp路径的highgui.hpp里面,有需要的可以去里面查看。这些函数也是很容易理解的。