一、回忆下V4L2驱动操作流程
1.查询驱动功能
struct v4l2_capability cap; ioctl(fd,VIDIOC_QUERYCAP,&cap); printf("TK---------->>>>>Driver Name:%s\nCard Name:%s\nBus info:%s\n",cap.driver,cap.card,cap.bus_info);
2.获取当前驱动支持的视频格式
struct v4l2_fmtdesc fmtdesc; fmtdesc.index = 0; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) != -1){ printf("TK-------->>>>>fmtdesc.description is %s\n",fmtdesc.description); fmtdesc.index ++; }
3.设置当前驱动的频捕获格式
struct v4l2_format fmt; memset(&fmt,0,sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 1280; fmt.fmt.pix.height = 720; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; fmt.fmt.pix.field = V4L2_FIELD_NONE;//V4L2_FIELD_INTERLACED; fmt.fmt.pix.colorspace = 8; int fmtreslt = ioctl(fd,VIDIOC_S_FMT,&fmt); printf("TK--------_>>>>fmtreslt is %d\n",fmtreslt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //重新获取,看是否设置成功 ioctl(fd,VIDIOC_G_FMT,&fmt); printf("TK----------->>>>>fmt.fmt.width is %d\nfmt.fmt.pix.height is %d\nfmt.fmt.pix.colorspace is %d\n",fmt.fmt.pix.width,fmt.fmt.pix.height,fmt.fmt.pix.colorspace);
4.分配内存(一般不超过5个)并转换成物理地址,将物理地址映射到用户空间
struct v4l2_requestbuffers req; req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; //分配内存 ioctl(fd,VIDIOC_REQBUFS,&req); struct buffer{ void *start; unsigned int length; }*buffers; buffers = (struct buffer*)calloc (req.count, sizeof(*buffers)); unsigned int n_buffers = 0; for(n_buffers = 0; n_buffers < req.count; ++n_buffers){ struct v4l2_buffer buf; memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; //转换成物理地址 if(ioctl(fd,VIDIOC_QUERYBUF,&buf) == -1){ printf("TK---------_>>>>>>error\n"); close(fd); exit(-1); } buffers[n_buffers].length = buf.length; //映射到用户空间 buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset); if(MAP_FAILED == buffers[n_buffers].start){ printf("TK--------__>>>>>error 2\n"); close(fd); exit(-1); } }
5.把数据放入缓存队列
unsigned int i; enum v4l2_buf_type type; for(i = 0; i < 4; i++){ struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; ioctl(fd,VIDIOC_QBUF,&buf); }
6.开启视频流
type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(fd,VIDIOC_STREAMON,&type);7.把数据从缓存队列中读取出来
unsigned int j; for(j = 0; j < 4; j++){ struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = 0; ioctl(fd,VIDIOC_DQBUF,&buf); char path[30]; snprintf(path,sizeof(path),"./v4l2test/720pmjpeg%d",buf.index); int fdyuyv = open(path,O_WRONLY|O_CREAT,00700); printf("TK--------->>>>fdyuyv is %d\n",fdyuyv); int resultyuyv = write(fdyuyv,buffers[buf.index].start,1280*720*2); printf("TK--------->>>resultyuyv is %d\n",resultyuyv); close(fdyuyv); }
8.关闭视频流
ioctl(fd,VIDIOC_STREAMOFF,&type);
二、修改
原来如下——
ioctl(fd,VIDIOC_QBUF,&buf); ioctl(fd,VIDIOC_STREAMON,&type); ioctl(fd,VIDIOC_DQBUF,&buf);
现在改为——
ioctl(fd,VIDIOC_STREAMON,&type); usleep(800000); ioctl(fd,VIDIOC_QBUF,&buf); ioctl(fd,VIDIOC_DQBUF,&buf);
其实就是刚打开时的数据不能要!!!!!
三、工程实例
status_t V4LCameraAdapter::startPreview() { ...... /* change by tankai nQueued = 0; for (int i = 0; i < mPreviewBufferCount; i++) { frame_count = -1; frame_buf = (void *)mPreviewBufs.keyAt(i); if((ret_c = getFrameRefCount(frame_buf,CameraFrame::PREVIEW_FRAME_SYNC))>=0) frame_count = ret_c; //if((ret_c = getFrameRefCount(frame_buf,CameraFrame::VIDEO_FRAME_SYNC))>=0) // frame_count += ret_c; CAMHAL_LOGDB("startPreview--buffer address:0x%x, refcount:%d",(uint32_t)frame_buf,frame_count); if(frame_count>0) continue; //mVideoInfo->buf.index = i; mVideoInfo->buf.index = mPreviewBufs.valueFor((uint32_t)frame_buf); mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; #ifdef AMLOGIC_USB_CAMERA_SUPPORT if(mIsDequeuedEIOError){ CAMHAL_LOGEA("DQBUF EIO error has occured!\n"); return -EINVAL; } #endif ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); if (ret < 0) { CAMHAL_LOGEA("VIDIOC_QBUF Failed"); return -EINVAL; } CAMHAL_LOGDB("startPreview --length=%d, index:%d", mVideoInfo->buf.length,mVideoInfo->buf.index); nQueued++; } *///end tankai enum v4l2_buf_type bufType; if (!mVideoInfo->isStreaming) { bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; #ifdef AMLOGIC_CAMERA_NONBLOCK_SUPPORT gettimeofday( &previewTime1, NULL); #endif ret = ioctl (mCameraHandle, VIDIOC_STREAMON, &bufType); if (ret < 0) { CAMHAL_LOGEB("StartStreaming: Unable to start capture: %s", strerror(errno)); return ret; } mVideoInfo->isStreaming = true; } if( mEnableContiFocus && (CAM_FOCUS_MODE_AUTO != cur_focus_mode_for_conti) && (CAM_FOCUS_MODE_INFINITY != cur_focus_mode_for_conti)){ struct v4l2_control ctl; ctl.id = V4L2_CID_FOCUS_AUTO; ctl.value = CAM_FOCUS_MODE_CONTI_VID; if(ioctl(mCameraHandle, VIDIOC_S_CTRL, &ctl)<0){ CAMHAL_LOGDA("failed to set CAM_FOCUS_MODE_CONTI_VID!\n"); } cur_focus_mode_for_conti = CAM_FOCUS_MODE_CONTI_VID; } //add by tankai usleep(800000); nQueued = 0; for (int i = 0; i < mPreviewBufferCount; i++) { frame_count = -1; frame_buf = (void *)mPreviewBufs.keyAt(i); if((ret_c = getFrameRefCount(frame_buf,CameraFrame::PREVIEW_FRAME_SYNC))>=0) frame_count = ret_c; //if((ret_c = getFrameRefCount(frame_buf,CameraFrame::VIDEO_FRAME_SYNC))>=0) // frame_count += ret_c; CAMHAL_LOGDB("startPreview--buffer address:0x%x, refcount:%d",(uint32_t)frame_buf,frame_count); if(frame_count>0) continue; //mVideoInfo->buf.index = i; mVideoInfo->buf.index = mPreviewBufs.valueFor((uint32_t)frame_buf); mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; #ifdef AMLOGIC_USB_CAMERA_SUPPORT if(mIsDequeuedEIOError){ CAMHAL_LOGEA("DQBUF EIO error has occured!\n"); return -EINVAL; } #endif ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); if (ret < 0) { CAMHAL_LOGEA("VIDIOC_QBUF Failed"); return -EINVAL; } CAMHAL_LOGDB("startPreview --length=%d, index:%d", mVideoInfo->buf.length,mVideoInfo->buf.index); nQueued++; } //end tankai ...... }
补充:
看看preview线程:
int V4LCameraAdapter::previewThread() { uint8_t* ptr = (uint8_t*) mPreviewBufs.keyAt(mPreviewIdxs.valueFor(index)); //gralloc显存 if(mVideoInfo->buf.length != mVideoInfo->buf.bytesused){ fillThisBuffer( ptr, CameraFrame::PREVIEW_FRAME_SYNC); /* status_t V4LCameraAdapter::fillThisBuffer(void* frameBuf, CameraFrame::FrameType frameType) { ret = ioctl(mCameraHandle, VIDIOC_QBUF, &hbuf_query);//入队列 nQueued++; } */ } char *fp = this->GetFrame(index); /* char * V4LCameraAdapter::GetFrame(int &index) { ret = ioctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf); //出队列 } */ uint8_t* src = (uint8_t*) fp; //Camera原始数据 private_handle_t* gralloc_hnd = (private_handle_t*)ptr; dest = (uint8_t*)gralloc_hnd->base; if(DEFAULT_PREVIEW_PIXEL_FORMAT == V4L2_PIX_FMT_YUYV){ // 422I frame.mLength = width*height*2; memcpy(dest,src,frame.mLength); } }