本文将会详细分析项目二中的Video2Lcd
首先,要有一个感性的认识,从摄像头捕获视频数据,到显示在lcd屏幕上,经历了以下几个步骤:
摄像头读取图像数据--->图像数据格式转换--->图像缩放--->图像合并进framebuffer--->图像显示
现在我将按步骤来分析
我们可以把所想想到的环节都抽象出来,比如,摄像头就抽象为VideoDevice结构体,获取图像等过程抽象为VideoOpr结构体。摄像头包含获取图像等功能,现在我们的任务是来细化这些结构体,怎么样才能实现我们的目的呢?
以下代码段为抽象出的摄像头设备结构体,包含文件句柄、像素格式、分辨率、申请buffer数目、大小、索引等,最后还有个成员是操作函数
struct VideoDevice {
int iFd;
int iPixelFormat;
int iWidth;
int iHeight;
int iVideoBufCnt;
int iVideoBufMaxLen;
int iVideoBufCurIndex;
unsigned char *pucVideBuf[NB_BUFFER];
/* 函数 */
PT_VideoOpr ptOPr;
};
以下代码段为操作函数的抽象结构体,包含获取图像过程中用到的各种操作、属性等
struct VideoOpr {
char *name;
int (*InitDevice)(char *strDevName, PT_VideoDevice ptVideoDevice);
int (*ExitDevice)(PT_VideoDevice ptVideoDevice);
int (*GetFrame)(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf);
int (*GetFormat)(PT_VideoDevice ptVideoDevice);
int (*PutFrame)(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf);
int (*StartDevice)(PT_VideoDevice ptVideoDevice);
int (*StopDevice)(PT_VideoDevice ptVideoDevice);
struct VideoOpr *ptNext;
};
摄像头数据的获取流程如下:
/* open
* VIDIOC_QUERYCAP 确定它是否视频捕捉设备,支持哪种接口(streaming/read,write)
* VIDIOC_ENUM_FMT 查询支持哪种格式
* VIDIOC_S_FMT 设置摄像头使用哪种格式
* VIDIOC_REQBUFS 申请buffer
对于 streaming:
* VIDIOC_QUERYBUF 确定每一个buffer的信息 并且 mmap
* VIDIOC_QBUF 放入队列
* VIDIOC_STREAMON 启动设备
* poll 等待有数据
* VIDIOC_DQBUF 从队列中取出
* 处理....
* VIDIOC_QBUF 放入队列
* ....
对于read,write:
read
处理....
read
* VIDIOC_STREAMOFF 停止设备
*
*/
通过分配、设置、注册全局变量g_tV4l2VideoOpr,实现了结构体与功能函数间的串联。将V4L2.c注册进video_manager.c中
有几个ioctl起了至关重要的作用:
iError = ioctl(iFd, VIDIOC_QUERYCAP, &tV4l2Cap);tV4l2Cap.capabilities & V4L2_CAP_VIDEO_CAPTURE; //确定是否为视频捕获设备
iError = ioctl(iFd, VIDIOC_ENUM_FMT, &tFmtDesc); //枚举摄像头支持的格式
iError = ioctl(iFd, VIDIOC_S_FMT, &tV4l2Fmt); //设置格式
iError = ioctl(iFd, VIDIOC_REQBUFS, &tV4l2ReqBuffs);//请求buffer
iError = ioctl(iFd, VIDIOC_QUERYBUF, &tV4l2Buf); //查询buffer
iError = ioctl(iFd, VIDIOC_QBUF, &tV4l2Buf); //将buffer放入队列
iError = ioctl(ptVideoDevice->iFd, VIDIOC_QBUF, &tV4l2Buf); //取出队列中的buffer
5 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!