http://blog.csdn.net/tankai19880619/article/details/16983627
一、回忆下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);
- 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);
- }
- }