这次是学习怎么创建一个控制台的滚动条,并且使用它控制视频的播放。为了测试一些东西,改编了视频教程中的代码。
#include "stdafx.h" #include "highgui.h" #include "cv.h" CvCapture* g_capture = NULL; //记录滚动条的当前位置 int g_slider_pos = 0; //对视频帧进行计数的变量 int frame_count = 0; void onTrackbarSlider(int pos)//回调函数 { //设置g_capture的属性,从位置pos开始播放视频 cvSetCaptureProperty( g_capture, CV_CAP_PROP_POS_FRAMES,//单位为帧数的位置 pos//当前滚动条的位置 ); frame_count =pos; //printf("frame_count is %dpos is %d\n-------\n",frame_count,pos); } int main(int argc, char* argv[]) { IplImage* frame; cvNamedWindow("show"); CvCapture* tmp = cvCreateFileCapture("E:\\狸窝转换结果\\oldfriends.avi"); printf("使用代码1.2,屏蔽代码1.1和代码2.1\n"); /*-----------------1、获取总帧数---------*/ frame = cvQueryFrame(tmp); //获取视频的总帧数 int frames = 0; /*-----------------代码1.1---------*/ /*frames =(int)cvGetCaptureProperty( tmp, CV_CAP_PROP_FRAME_COUNT ); */ /*-----------------代码1.1end---------*/ /*-----------------代码1.2---------*/ while(frame != NULL ){ frame = cvQueryFrame(tmp); frames++; } cvReleaseCapture(&tmp); /*-----------------代码1.2end---------*/ printf("总帧数 is %3d\n",frames); /*-----------------获取总帧数-----------*/ g_capture = cvCreateFileCapture("E:\\狸窝转换结果\\oldfriends.avi"); if(frames>0) { cvCreateTrackbar( "Position",//创建的名字 "show",//窗口名字 &g_slider_pos,//整数指针,它的值将反应滑块位置 frames,//滑块位置的最大值 onTrackbarSlider//每次滑块位置被改变的时候,被调用的指针 ); } int count = 0; while(1) { frame = cvQueryFrame(g_capture);//返回视频文件的下一帧 if(!frame){ printf("NULL\n"); break; } cvShowImage("show",frame); char c = cvWaitKey(33); if(c==27)//Esc按键 { cvWaitKey(0);//break; } /*-----------------2、设置滚动条位置---------*/ /*-----------------代码2.1---------*/ //cvSetTrackbarPos("Position","show",frame_count);//通过单步调试,发现执行这一步时会调用到onTrackbarSlider()函数 /*-----------------代码2.1end---------*/ /*-----------------设置滚动条位置-----------*/ frame_count++; count++; } printf("累加值:frame_count is %3d,count is %3d\n",frame_count,count); cvReleaseCapture(&g_capture); cvDestroyWindow("show"); return 0; }
上述代码中有几个函数值得深入研究
1、double cvGetCaptureProperty(CvCapture* capture, int property_id)//获取摄像头属性的函数
capture:源文件指针
property_id: 控制返回的属性,其中
CV_CAP_PROP_POS_MSEC - 影片目前位置,为毫秒数或者视频获取时间戳
CV_CAP_PROP_POS_FRAMES - 将被下一步解压/获取的帧索引,以0为起点
CV_CAP_PROP_POS_AVI_RATIO - 视频文件的相对位置(0 - 影片的开始,1 - 影片的结尾)
CV_CAP_PROP_FRAME_WIDTH - 视频流中的帧宽度
CV_CAP_PROP_FRAME_HEIGHT - 视频流中的帧高度
CV_CAP_PROP_FPS - 帧率
CV_CAP_PROP_FOURCC - 表示codec的四个字符
CV_CAP_PROP_FRAME_COUNT视频文件中帧的总数(本课时需要使用的属性)
注:1.有时调用函数cvGetCaptureProperty需要调用cvQueruFrame一次后才返回正确的值。这是软件存在的一个bug.
2.cvGetCaptureProperty函数实际是通过读取视频文件头信息返回数据,不是真正读取视频文件。因此不同格式视频文件转换成opencv所支持的avi格式后,使用该函数去读取时,会造成信息的不准确。(主要参考http://blog.sina.com.cn/s/blog_4b0020f301012dbz.html)
2、cvCreateTrackbar()创建滚动条
定义:
CV_EXTERN_C_FUNCPTR(void(*CvTrackbarCallback)(int pos));//回调函数的格式,返回值是void,参数是int。不能随意定义
int cvCreateTrackbar(const char* trackbar_name,//创建的名字
const char* window_name,//窗口名字
int* value,//整数指针,它的值将反应滑块位置
int count,//滑块位置的最大值
CvTrackbarCallback on_change//每次滑块位置被改变的时候,被调用的指针,回调函数
);
回调函数就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。
3、int cvSetCaptureProperty( CvCapture* capture, int property_id, double value );//设置视频获取属性
4、cvSetTrackbarPos设置滚动条的值
根据cvGetCaptureProperty函数中提到的获取值不正确问题,我做了一个实验。
使用狸窝工具,将一个rmvb视频转成avi然后进行测试。测试数据如下:
对于这样的结果,我表示深深的疑惑。
首先图1图3和图2图4的对比可以看出,之前说到的cvGetCaptureProperty函数获取的值不正确这个问题是存在的。
其次,看到图3,为什么获取的总帧数是734,后来运行的时候帧数却可以达到879?对比了图1图2和图3图4之后,可以发现这个问题和cvSetTrackbarPos()、cvSetCaptureProperty()这两个函数有关。
是不是在使用函数的时候修改了什么东西,具体的还需要找到这两个函数的源代码看看才知道。