usb廉价摄像头抓取实时视频数据,呵呵,这可是一个非常不错视频开发试验。通过这个试验,可以在学习中体验视频给我们带来的乐趣。网上常用的是CCaptureVideo类,来处理usb摄像头数据捕获和读取。我也用的是这个类来在win32环境下面做做试验。很好用,而且很轻松就得到了usb摄像头的实时数据。但是这个类就是十全十美的吗?我看不见得。比如说,我直接定义CCaptureVideo的一个对象,没有调用它的init()函数,即没有调用它来获取视频数据,程序退出的时候会抛出异常。经过检查才发现原来m_pBF要不就是m_pGB没有初始化成NULL。这是一个很低级的错误拉,不过很容易就可以修改过来。这样哪怕你不使用这个类,只是声明一个对象,那么程序推出的时候也不会出现什么异常。
刚刚那个是比较明显的bug了,还有一些不太明显的。不知道大家在使用CCaptureVideo类的时候是否遇见过。例如,我们可能希望按下某个按钮的时候开始摄像头视频捕捉,再按一次,就停止视频捕捉;然后如果需要,那么再次重复按下该按钮,再次重新启动视频捕捉,这就好比qq的视频聊天一样,qq主程序没有关掉,但是你可以在不同的时间段和不同的人视频聊天。简单的描述就是在不关闭主程序的前提下进行:
打开摄像头--->关闭摄像头--->再打开摄像头--->再关闭摄像头--->再打开摄像头...等等以此类推。
对于网上流传的CCaptureVideo类而言,它是有问题的,假设我们声明了一个CCaptureVideo类的指针
CCaptureVideo * m_cap ;
然后,在OnInitDialog函数中创建该对象,
m_cap = new CCaptureVideo() ;
然后就是例牌的枚举可用摄像头(m_cap->EnumDevices (m_cam_lst);),或者直接调用init函数
(m_cap->Init(m_cam_lst.GetCurSel (),hWnd);),开始捕获视频数据。
对于缺省的CCaptureVideo而言,第一次这么用是完全没有问题的,可以很容易的把usb摄像头的数据得到。
假定,现在我们按下了“stop”按钮,此时,我们可以用delete m_cap ;可以看到实时显示的那个窗口不见了。这也是正确的。
当我们再次开启摄像头的时候,问题就出现了。我们还是按照刚刚一样的顺序初始化m_cap对象,但是这次调用init函数的时候确弹出一个对话框“can't build graph”错误。区区怪事!
后来仔细跟踪才知道问题出在:
CComPtr<ISampleGrabber> m_pGrabber;
这个智能指针上面。它第一次工作是正常的,但是第二次就有问题了,似乎是资源没有释放掉。
修改的方法也很简单,直接手工定义:
ISampleGrabber * m_pGrabber ;
...
使用这个指针的代码也需要修改:
原来的初始化代码是:
hr = m_pGrabber.CoCreateInstance( CLSID_SampleGrabber );
我们可以改为:
hr = CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_ISampleGrabber, (void**)&m_pGrabber );
当然,在析构的时候千万不要忘记了:
SAFE_RELEASE(m_pGrabber);
这样,我们想要开关摄像头多少次都没问题了