Linux设备驱动之LCD显示摄像图像之二编写V4l2程序
来源:互联网 发布:淘宝卖男童还好做吗 编辑:程序博客网 时间:2024/05/16 02:14
#include <config.h>#include <video_manager.h>#include <disp_manager.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/mman.h>#include <poll.h>#include <sys/ioctl.h>#include <string.h>#include <unistd.h>static int g_aiSupportedFormats[] = {V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_RGB565};static int V4l2GetFrameForReadWrite(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf);static int V4l2PutFrameForReadWrite(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf);static T_VideoOpr g_tV4l2VideoOpr;static int isSupportThisFormat(int iPixelFormat){ int i; for (i = 0; i < sizeof(g_aiSupportedFormats)/sizeof(g_aiSupportedFormats[0]); i++) { if (g_aiSupportedFormats[i] == iPixelFormat) return 1; } return 0;}/* 参考 luvcview *//* 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 停止设备 * */static int V4l2InitDevice(char *strDevName, PT_VideoDevice ptVideoDevice){ int i; int iFd; int iError; struct v4l2_capability tV4l2Cap; struct v4l2_fmtdesc tFmtDesc; struct v4l2_format tV4l2Fmt; struct v4l2_requestbuffers tV4l2ReqBuffs; struct v4l2_buffer tV4l2Buf; int iLcdWidth; int iLcdHeigt; int iLcdBpp; iFd = open(strDevName, O_RDWR); if (iFd < 0) { DBG_PRINTF("can not open %s\n", strDevName); return -1; } ptVideoDevice->iFd = iFd; iError = ioctl(iFd, VIDIOC_QUERYCAP, &tV4l2Cap); memset(&tV4l2Cap, 0, sizeof(struct v4l2_capability)); iError = ioctl(iFd, VIDIOC_QUERYCAP, &tV4l2Cap); if (iError) { DBG_PRINTF("Error opening device %s: unable to query device.\n", strDevName); goto err_exit; } if (!(tV4l2Cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { DBG_PRINTF("%s is not a video capture device\n", strDevName); goto err_exit; } if (tV4l2Cap.capabilities & V4L2_CAP_STREAMING) { DBG_PRINTF("%s supports streaming i/o\n", strDevName); } if (tV4l2Cap.capabilities & V4L2_CAP_READWRITE) { DBG_PRINTF("%s supports read i/o\n", strDevName); } memset(&tFmtDesc, 0, sizeof(tFmtDesc)); tFmtDesc.index = 0; tFmtDesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; while ((iError = ioctl(iFd, VIDIOC_ENUM_FMT, &tFmtDesc)) == 0) { //Garmen:VIDIOC_ENUM_FMT这个操作将Format存在tFmtDesc.pixelformat if (isSupportThisFormat(tFmtDesc.pixelformat)) { ptVideoDevice->iPixelFormat = tFmtDesc.pixelformat; break; } tFmtDesc.index++; } //Garmen:假如这个变量一直没有被设置,即是一直为空的话 if (!ptVideoDevice->iPixelFormat) { DBG_PRINTF("can not support the format of this device\n"); goto err_exit; } /* set format in */ GetDispResolution(&iLcdWidth, &iLcdHeigt, &iLcdBpp); memset(&tV4l2Fmt, 0, sizeof(struct v4l2_format)); tV4l2Fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4l2Fmt.fmt.pix.pixelformat = ptVideoDevice->iPixelFormat; tV4l2Fmt.fmt.pix.width = iLcdWidth; tV4l2Fmt.fmt.pix.height = iLcdHeigt; tV4l2Fmt.fmt.pix.field = V4L2_FIELD_ANY; /* 如果驱动程序发现无法某些参数(比如分辨率), * 它会调整这些参数, 并且返回给应用程序 */ iError = ioctl(iFd, VIDIOC_S_FMT, &tV4l2Fmt); if (iError) { DBG_PRINTF("Unable to set format\n"); goto err_exit; } ptVideoDevice->iWidth = tV4l2Fmt.fmt.pix.width; ptVideoDevice->iHeight = tV4l2Fmt.fmt.pix.height; /* request buffers */ memset(&tV4l2ReqBuffs, 0, sizeof(struct v4l2_requestbuffers)); tV4l2ReqBuffs.count = NB_BUFFER; tV4l2ReqBuffs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4l2ReqBuffs.memory = V4L2_MEMORY_MMAP; iError = ioctl(iFd, VIDIOC_REQBUFS, &tV4l2ReqBuffs); if (iError) { DBG_PRINTF("Unable to allocate buffers.\n"); goto err_exit; } ptVideoDevice->iVideoBufCnt = tV4l2ReqBuffs.count; if (tV4l2Cap.capabilities & V4L2_CAP_STREAMING) { /* map the buffers */ for (i = 0; i < ptVideoDevice->iVideoBufCnt; i++) { memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer)); tV4l2Buf.index = i; tV4l2Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4l2Buf.memory = V4L2_MEMORY_MMAP; iError = ioctl(iFd, VIDIOC_QUERYBUF, &tV4l2Buf); if (iError) { DBG_PRINTF("Unable to query buffer.\n"); goto err_exit; } ptVideoDevice->iVideoBufMaxLen = tV4l2Buf.length; ptVideoDevice->pucVideBuf[i] = mmap(0 /* start anywhere */ , tV4l2Buf.length, PROT_READ, MAP_SHARED, iFd, tV4l2Buf.m.offset); if (ptVideoDevice->pucVideBuf[i] == MAP_FAILED) { DBG_PRINTF("Unable to map buffer\n"); goto err_exit; } } /* Queue the buffers. */ for (i = 0; i < ptVideoDevice->iVideoBufCnt; i++) { memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer)); tV4l2Buf.index = i; tV4l2Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4l2Buf.memory = V4L2_MEMORY_MMAP; //GARMEN:它可以用于mmap iError = ioctl(iFd, VIDIOC_QBUF, &tV4l2Buf); if (iError) { DBG_PRINTF("Unable to queue buffer.\n"); goto err_exit; } } } else if (tV4l2Cap.capabilities & V4L2_CAP_READWRITE) { g_tV4l2VideoOpr.GetFrame = V4l2GetFrameForReadWrite; g_tV4l2VideoOpr.PutFrame = V4l2PutFrameForReadWrite; /* read(fd, buf, size) */ ptVideoDevice->iVideoBufCnt = 1; /* 在这个程序所能支持的格式里, 一个象素最多只需要4字节 */ ptVideoDevice->iVideoBufMaxLen = ptVideoDevice->iWidth * ptVideoDevice->iHeight * 4; ptVideoDevice->pucVideBuf[0] = malloc(ptVideoDevice->iVideoBufMaxLen); } //Garmen:如果成功的话,全局变量g_tV4l2VideoOpr就指向V4l2指向的结构体 ,证明V4l2这个结构体被“征用”了 ptVideoDevice->ptOPr = &g_tV4l2VideoOpr; return 0;err_exit: close(iFd); return -1; }static int V4l2ExitDevice(PT_VideoDevice ptVideoDevice){ int i; for (i = 0; i < ptVideoDevice->iVideoBufCnt; i++) { if (ptVideoDevice->pucVideBuf[i]) { munmap(ptVideoDevice->pucVideBuf[i], ptVideoDevice->iVideoBufMaxLen); ptVideoDevice->pucVideBuf[i] = NULL; } } close(ptVideoDevice->iFd); return 0;}static int V4l2GetFrameForStreaming(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf){ struct pollfd tFds[1]; int iRet; struct v4l2_buffer tV4l2Buf; /* poll */ tFds[0].fd = ptVideoDevice->iFd; tFds[0].events = POLLIN; iRet = poll(tFds, 1, -1); if (iRet <= 0) { DBG_PRINTF("poll error!\n"); return -1; } /* VIDIOC_DQBUF */ memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer)); tV4l2Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4l2Buf.memory = V4L2_MEMORY_MMAP; iRet = ioctl(ptVideoDevice->iFd, VIDIOC_DQBUF, &tV4l2Buf); if (iRet < 0) { DBG_PRINTF("Unable to dequeue buffer.\n"); return -1; } ptVideoDevice->iVideoBufCurIndex = tV4l2Buf.index; ptVideoBuf->iPixelFormat = ptVideoDevice->iPixelFormat; ptVideoBuf->tPixelDatas.iWidth = ptVideoDevice->iWidth; ptVideoBuf->tPixelDatas.iHeight = ptVideoDevice->iHeight; ptVideoBuf->tPixelDatas.iBpp = (ptVideoDevice->iPixelFormat == V4L2_PIX_FMT_YUYV) ? 16 : \ (ptVideoDevice->iPixelFormat == V4L2_PIX_FMT_MJPEG) ? 0 : \ (ptVideoDevice->iPixelFormat == V4L2_PIX_FMT_RGB565) ? 16 : \ 0; ptVideoBuf->tPixelDatas.iLineBytes = ptVideoDevice->iWidth * ptVideoBuf->tPixelDatas.iBpp / 8; ptVideoBuf->tPixelDatas.iTotalBytes = tV4l2Buf.bytesused; ptVideoBuf->tPixelDatas.aucPixelDatas = ptVideoDevice->pucVideBuf[tV4l2Buf.index]; return 0;}static int V4l2PutFrameForStreaming(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf){ /* VIDIOC_QBUF */ struct v4l2_buffer tV4l2Buf; int iError; memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer)); tV4l2Buf.index = ptVideoDevice->iVideoBufCurIndex; tV4l2Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4l2Buf.memory = V4L2_MEMORY_MMAP; iError = ioctl(ptVideoDevice->iFd, VIDIOC_QBUF, &tV4l2Buf); if (iError) { DBG_PRINTF("Unable to queue buffer.\n"); return -1; } return 0;}static int V4l2GetFrameForReadWrite(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf){ int iRet; iRet = read(ptVideoDevice->iFd, ptVideoDevice->pucVideBuf[0], ptVideoDevice->iVideoBufMaxLen); if (iRet <= 0) { return -1; } ptVideoBuf->iPixelFormat = ptVideoDevice->iPixelFormat; ptVideoBuf->tPixelDatas.iWidth = ptVideoDevice->iWidth; ptVideoBuf->tPixelDatas.iHeight = ptVideoDevice->iHeight; ptVideoBuf->tPixelDatas.iBpp = (ptVideoDevice->iPixelFormat == V4L2_PIX_FMT_YUYV) ? 16 : \ (ptVideoDevice->iPixelFormat == V4L2_PIX_FMT_MJPEG) ? 0 : \ (ptVideoDevice->iPixelFormat == V4L2_PIX_FMT_RGB565)? 16 : \ 0; ptVideoBuf->tPixelDatas.iLineBytes = ptVideoDevice->iWidth * ptVideoBuf->tPixelDatas.iBpp / 8; ptVideoBuf->tPixelDatas.iTotalBytes = iRet; ptVideoBuf->tPixelDatas.aucPixelDatas = ptVideoDevice->pucVideBuf[0]; return 0;}static int V4l2PutFrameForReadWrite(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf){ return 0;}static int V4l2StartDevice(PT_VideoDevice ptVideoDevice){ int iType = V4L2_BUF_TYPE_VIDEO_CAPTURE; int iError; iError = ioctl(ptVideoDevice->iFd, VIDIOC_STREAMON, &iType); if (iError) { DBG_PRINTF("Unable to start capture.\n"); return -1; } return 0;}static int V4l2StopDevice(PT_VideoDevice ptVideoDevice){ int iType = V4L2_BUF_TYPE_VIDEO_CAPTURE; int iError; iError = ioctl(ptVideoDevice->iFd, VIDIOC_STREAMOFF, &iType); if (iError) { DBG_PRINTF("Unable to stop capture.\n"); return -1; } return 0;}static int V4l2GetFormat(PT_VideoDevice ptVideoDevice){ return ptVideoDevice->iPixelFormat;}/* 构造一个VideoOpr结构体 */static T_VideoOpr g_tV4l2VideoOpr = { .name = "v4l2", .InitDevice = V4l2InitDevice, .ExitDevice = V4l2ExitDevice, .GetFormat = V4l2GetFormat, .GetFrame = V4l2GetFrameForStreaming, .PutFrame = V4l2PutFrameForStreaming, .StartDevice = V4l2StartDevice, .StopDevice = V4l2StopDevice,};/* 注册这个结构体 */int V4l2Init(void){ return RegisterVideoOpr(&g_tV4l2VideoOpr);}
阅读全文
0 0
- Linux设备驱动之LCD显示摄像图像之二编写V4l2程序
- Linux设备驱动之LCD显示摄像图像之三进行转换
- Linux设备驱动之LCD显示摄像图像之一框架与准备工作
- Linux设备驱动之CRT显示摄像图像之一准备工作
- Linux字符设备驱动之LCD驱动
- linux设备驱动之——V4L2
- linux设备驱动之——V4L2
- linux设备驱动之——V4L2
- linux设备驱动之——V4L2
- linux设备驱动之——V4L2
- 65 linux spi设备驱动之spi LCD屏驱动
- 68 linux framebuffer设备驱动之spi lcd屏驱动
- Linux设备驱动之s3c2440添加LCD驱动
- linux驱动由浅入深系列:显示子系统之二(高通平台lcd驱动代码分析)
- LCD驱动之编写代码
- 设备驱动编写流程之二
- LINUX之LCD驱动
- linux驱动之LCD
- IMWeb提升营Day4 | 训练题22:从上往下打印二叉树
- Linux设备驱动之LCD显示摄像图像之一框架与准备工作
- 2017计蒜之道初赛第四场-商汤科技的安全令牌
- IDEA搭建Spring项目
- 在查找有序排序的时候,无意看到
- Linux设备驱动之LCD显示摄像图像之二编写V4l2程序
- 关于极限小数据!!!
- Centos下安装Scrapy
- hdu1730尼姆博弈
- java基础篇(十三)——三大特性之多态
- Hibernate 核心技术(一)
- spring基础
- 10-排序5 PAT Judge (25分)
- 2017计蒜之道初赛第四场-商汤科技的行人检测(简单)