试验环境:s5pv210(smart210) linux3.9.7
usb cam(C270) --->640X480 YUYV数据---->fimc0--->800x480RGB32---->lcd framebuffer.
这里 fimc0主要用来颜色空间和分辨率转换。
cam CAPTURE memory类型为V4L2_MEMORY_MMAP
fimc0 OUTPUT memory类型为V4L2_MEMORY_USERPTR
当cam采集完数据之后,从cam的buffer里面 复制到 fimc0的 OUTPUT的buffer里面。
下面是一个测试,测试fimc0处理完数据,复制到一个临时buffer需要花费的时间。
int fimc0_cap_dbuf(int *index) { unsigned int i; enum v4l2_buf_type type; int ret; struct v4l2_buffer b, buf; struct v4l2_plane plane[3]; static int count = 0; clock_t startTime, finishTime; struct timeval start; struct timeval end; int time_use=0; /* enqueue buffer to fimc0 output */ CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; b.memory = V4L2_MEMORY_MMAP; // b.index = index; b.m.planes = plane; b.length = 1; // plane[0].m.userptr = (unsigned long)fimc0_out_buf[index].start; // plane[0].length = (unsigned long)fimc0_out_buf[index].length; // planes[0].bytesused = fimc0_out_buf[buf.index].length; ret = ioctl(fimc0_fd, VIDIOC_DQBUF, &b); *index = b.index; if (ERR_ON(ret < 0, "fimc0: VIDIOC_DQBUF: %s\n", ERRSTR)) return -errno; sem_post(&lcd_sem); fimc0_cap_index = b.index; count ++; gettimeofday(&start,NULL); memcpy((void *)temp_buf, (void *)fimc0_cap[b.index], 800*480*4); gettimeofday(&end,NULL); time_use=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec); printf("%s,time_use:%d\n",__func__, time_use); return 0; }主要计算的是利用memcpy copy 800*480*4的数据话费的时间:
fimc0_cap_dbuf,time_use:76542 fimc0_cap_dbuf,time_use:75996 fimc0_cap_dbuf,time_use:78408 fimc0_cap_dbuf,time_use:79656 fimc0_cap_dbuf,time_use:79891 fimc0_cap_dbuf,time_use:78900 fimc0_cap_dbuf,time_use:78400 fimc0_cap_dbuf,time_use:78384 fimc0_cap_dbuf,time_use:77857 fimc0_cap_dbuf,time_use:77672 fimc0_cap_dbuf,time_use:76691 fimc0_cap_dbuf,time_use:79270 fimc0_cap_dbuf,time_use:75980 fimc0_cap_dbuf,time_use:76634 fimc0_cap_dbuf,time_use:80195
解决这个问题,采取一个思路是,
在用户空间只分配一块大内存,cam和fimc0共享这个内存,
cam和fimc0同时采用V4L2 之V4L2_MEMORY_USERPTR方式,
当cam采集完数据,就把这块内存入队到fimc0的OUTPUTbuf里面,这样就避免了memcpy。
fimc0 request buffer的时候,来开辟这块内存
CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; b.memory = V4L2_MEMORY_USERPTR; b.index = 0; b.m.planes = plane; b.length = 1; fimc0_out_buf_length = 640*480*2;//for yuyv 422 printf("%s, line:%d,fimc0_out_buf_length:%d\n",__func__,__LINE__, fimc0_out_buf_length); unsigned int page_size; page_size = getpagesize(); fimc0_out_buf_length = (fimc0_out_buf_length + page_size - 1) & ~(page_size - 1); printf("%s, line:%d,page_size:%d,fimc0_out_buf_length:%d\n",__func__, __LINE__, page_size, fimc0_out_buf_length); for (n = 0; n < ReqButNum; ++n) { fimc0_out_buf[n].start = (void *)memalign(/* boundary */(size_t)page_size, (size_t)fimc0_out_buf_length);//malloc(fimc0_out_buf_length); fimc0_out_buf[n].length= 640*480*2; if(fimc0_out_buf[n].start != NULL) printf("fimc0_out userptr reqbuf start:0x%08x,length:%d\n",fimc0_out_buf[n].start,fimc0_out_buf_length); }cam也会共享这个内存,
下面是完整代码
#include <stdio.h> #include <stdarg.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <time.h> #include <sys/mman.h> #include <assert.h> #include <linux/videodev2.h> #include <linux/fb.h> #include <pthread.h> #include <poll.h> #include <semaphore.h> #define TimeOut 5 #define CapNum 10 #define CapWidth 640 #define CapHeight 480 #define ReqButNum 3 #define IsRearCamera 0 #define FPS 10 #define PIXELFMT V4L2_PIX_FMT_YUYV #define CapDelay 100*1000 #define CLEAR(x) memset(&(x), 0, sizeof(x)) #define MIN(x,y) ((x) < (y) ? (x) : (y)) #define MAX(x,y) ((x) > (y) ? (x) : (y)) #define CLAMP(x,l,h) ((x) < (l) ? (l) : ((x) > (h) ? (h) : (x))) #define ERRSTR strerror(errno) #define LOG(...) fprintf(stderr, __VA_ARGS__) #define ERR(...) __info("Error", __FILE__, __LINE__, __VA_ARGS__) #define ERR_ON(cond, ...) ((cond) ? ERR(__VA_ARGS__) : 0) #define CRIT(...) \ do { \ __info("Critical", __FILE__, __LINE__, __VA_ARGS__); \ exit(EXIT_FAILURE); \ } while(0) #define CRIT_ON(cond, ...) do { if (cond) CRIT(__VA_ARGS__); } while(0) typedef struct { void *start; int length; int bytesused; }BUFTYPE; char lcd_path[] = "/dev/fb0"; char fimc0_path[] = "/dev/video0"; char cam_path[] = "/dev/video13"; static sem_t lcd_sem; BUFTYPE *fimc0_out_buf; BUFTYPE *buffers; static int n_buffer = 0; void *fimc_in = NULL; void *fimc_out = NULL; int fimc0_out_buf_length; int fimc0_cap_buf_length; void *fimc0_out[16]; void *fimc0_cap[16]; static struct fb_var_screeninfo vinfo; static struct fb_fix_screeninfo finfo; static int lcd_buf_size; static char *fb_buf = NULL; static int tsp_fd; static int fimc0_fd; static pthread_t capture_tid; static pthread_t display_tid; int lcd_fd; int cam_fd; int display_x = 0; int display_y = 0; static int fimc0_cap_index = 0; char *temp_buf=NULL; int display_format(int pixelformat) { printf("{pixelformat = %c%c%c%c}\n", pixelformat & 0xff,(pixelformat >> 8)&0xff, (pixelformat >> 16) & 0xff,(pixelformat >> 24)&0xff ); } static inline int __info(const char *prefix, const char *file, int line, const char *fmt, ...) { int errsv = errno; va_list va; va_start(va, fmt); fprintf(stderr, "%s(%s:%d): ", prefix, file, line); vfprintf(stderr, fmt, va); va_end(va); errno = errsv; return 1; } struct format { unsigned long fourcc; unsigned long width; unsigned long height; }; void dump_format(char *str, struct v4l2_format *fmt) { if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { struct v4l2_pix_format_mplane *pix = &fmt->fmt.pix_mp; LOG("%s: width=%u height=%u format=%.4s bpl=%u\n", str, pix->width, pix->height, (char*)&pix->pixelformat, pix->plane_fmt[0].bytesperline); } else { struct v4l2_pix_format *pix = &fmt->fmt.pix; LOG("%s: width=%u height=%u format=%.4s bpl=%u\n", str, pix->width, pix->height, (char*)&pix->pixelformat, pix->bytesperline); } } int open_camera_device() { int fd; if((fd = open(cam_path,O_RDWR | O_NONBLOCK)) < 0) { perror("Fail to open"); exit(EXIT_FAILURE); } cam_fd = fd; if((fimc0_fd = open(fimc0_path,O_RDWR | O_NONBLOCK)) < 0) { perror("Fail to open"); exit(EXIT_FAILURE); } printf("open cam success %d\n",fd); return fd; } //打开摄像头设备 int open_lcd_device() { int fd; int err; int ret; if((fd = open(lcd_path, O_RDWR | O_NONBLOCK)) < 0) { perror("Fail to open"); exit(EXIT_FAILURE); } printf("open lcd success %d\n",fd); if(-1 == ioctl(fd, FBIOGET_FSCREENINFO,&finfo)) { perror("Fail to ioctl:FBIOGET_FSCREENINFO\n"); exit(EXIT_FAILURE); } if (-1==ioctl(fd, FBIOGET_VSCREENINFO, &vinfo)) { perror("Fail to ioctl:FBIOGET_VSCREENINFO\n"); exit(EXIT_FAILURE); } lcd_buf_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; printf("vinfo.xres:%d, vinfo.yres:%d, vinfo.bits_per_pixel:%d, lcd_buf_size:%d, finfo.line_length:%d\n",vinfo.xres, vinfo.yres, vinfo.bits_per_pixel, lcd_buf_size, finfo.line_length); lcd_fd = fd; vinfo.activate = FB_ACTIVATE_FORCE; vinfo.yres_virtual = vinfo.yres; ret = ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo ); if( ret < 0 ) { printf( "ioctl FBIOPUT_VSCREENINFO failed\n"); return -1; } //mmap framebuffer fb_buf = (char *)mmap( NULL, lcd_buf_size, PROT_READ | PROT_WRITE,MAP_SHARED , lcd_fd, 0); if(NULL == fb_buf) { perror("Fail to mmap fb_buf"); exit(EXIT_FAILURE); } ret = ioctl( lcd_fd, FBIOBLANK, FB_BLANK_UNBLANK ); if( ret < 0 ) { printf( "ioctl FBIOBLANK failed\n"); return -1; } return fd; } int fb_wait_for_vsync(int lcd_fd) { int ret; unsigned long temp; ret = ioctl(lcd_fd, FBIO_WAITFORVSYNC, &temp); if (ret < 0) { err("Wait for vsync failed"); return -1; } return 0; } int cam_reqbufs() { struct v4l2_requestbuffers req; int i; printf("%s: +\n", __func__); int n_buffers = 0; CLEAR(req); req.count = ReqButNum; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_USERPTR; if (-1 == ioctl(cam_fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf(stderr, "%s does not support " "user pointer i/o\n", "campture"); exit(EXIT_FAILURE); } else { printf("VIDIOC_REQBUFS"); exit(EXIT_FAILURE); } } buffers = calloc(ReqButNum, sizeof(*buffers)); if (!buffers) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } for (n_buffers = 0; n_buffers < ReqButNum; ++n_buffers) { buffers[n_buffers].length = fimc0_out_buf_length; buffers[n_buffers].start = fimc0_out_buf[n_buffers].start; if (!buffers[n_buffers].start) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } } /* for (i = 0; i < 3; ++i) { fimc0_out_buf[i].length = fimc0_out_buf_length; fimc0_out_buf[i].start = fimc0_out[i]; if (!fimc0_out_buf[i].start) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } }*/ printf("%s: -\n", __func__); } int fimc0_reqbufs() { int i = 0; int err; int ret; struct v4l2_control ctrl; struct v4l2_requestbuffers reqbuf; struct v4l2_requestbuffers rb; CLEAR(rb); /* enqueue the dmabuf to vivi */ struct v4l2_buffer b; CLEAR(b); printf("%s: +\n", __func__); /* request buffers for FIMC0 */ rb.count = ReqButNum; rb.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; rb.memory = V4L2_MEMORY_USERPTR; ret = ioctl(fimc0_fd, VIDIOC_REQBUFS, &rb); if (ERR_ON(ret < 0, "fimc0: VIDIOC_REQBUFS: %s\n", ERRSTR)) return -errno; printf("fimc0 output_buf_num:%d\n",rb.count); int n; n_buffer = rb.count; fimc0_out_buf = calloc(rb.count,sizeof(BUFTYPE)); if(fimc0_out_buf == NULL){ fprintf(stderr,"Out of memory\n"); exit(EXIT_FAILURE); } printf("%s, fimc0_out_buf request successfully\n",__func__); /* mmap DMABUF */ struct v4l2_plane plane[2]; #if 1 CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; b.memory = V4L2_MEMORY_USERPTR; b.index = 0; b.m.planes = plane; b.length = 1; fimc0_out_buf_length = 640*480*2;//for yuyv 422 printf("%s, line:%d,fimc0_out_buf_length:%d\n",__func__,__LINE__, fimc0_out_buf_length); unsigned int page_size; page_size = getpagesize(); fimc0_out_buf_length = (fimc0_out_buf_length + page_size - 1) & ~(page_size - 1); printf("%s, line:%d,page_size:%d,fimc0_out_buf_length:%d\n",__func__, __LINE__, page_size, fimc0_out_buf_length); for (n = 0; n < ReqButNum; ++n) { //b.index = n; //printf("line:%d, buffers[n].start:0x%08x\n",buffers[n].start); // void *addr = malloc(fimc0_out_buf_length + 64); // addr = (void *)(((unsigned long)addr + 63)&(~63)); fimc0_out_buf[n].start = (void *)memalign(/* boundary */(size_t)page_size, (size_t)fimc0_out_buf_length);//malloc(fimc0_out_buf_length); fimc0_out_buf[n].length= 640*480*2; if(fimc0_out_buf[n].start != NULL) printf("fimc0_out userptr reqbuf start:0x%08x,length:%d\n",fimc0_out_buf[n].start,fimc0_out_buf_length); } #if 0 for (n = 0; n < ReqButNum; ++n) { b.index = n; ret = ioctl(fimc0_fd, VIDIOC_QUERYBUF, &b); if (ERR_ON(ret < 0, "fimc0: VIDIOC_REQBUFS: %s\n", ERRSTR)) exit(EXIT_FAILURE); // printf("fimc0 querybuf:%d,%d\n", b.m.planes[0].length, b.m.planes[0].m.mem_offset); fimc0_out_buf[n].start = mmap(NULL, b.m.planes[0].length, PROT_READ | PROT_WRITE, MAP_SHARED, fimc0_fd, b.m.planes[0].m.mem_offset); // fimc0_out_buf[n].start = fimc0_out[n]; fimc0_out_buf[n].length = b.m.planes[0].length; if (fimc0_out[n] == MAP_FAILED) { printf("Failed mmap buffer %d for %d\n", n, fimc0_fd); return -1; } fimc0_out_buf_length = b.m.planes[0].length; printf("fimc0 querybuf:0x%08lx,%d,%d\n", fimc0_out_buf[n], fimc0_out_buf_length, b.m.planes[0].m.mem_offset); // printf("fimc0 output:plane.length:%d\n",fimc0_out_buf_length); } #endif #endif CLEAR(plane); CLEAR(b); rb.count = ReqButNum; rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; rb.memory = V4L2_MEMORY_MMAP; ret = ioctl(fimc0_fd, VIDIOC_REQBUFS, &rb); if (ERR_ON(ret < 0, "fimc0: VIDIOC_REQBUFS: %s\n", ERRSTR)) return -errno; for (n = 0; n < ReqButNum; ++n) { b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; b.memory = V4L2_MEMORY_MMAP; b.index = n; b.m.planes = plane; b.length = 1; b.index = n; ret = ioctl(fimc0_fd, VIDIOC_QUERYBUF, &b); if (ERR_ON(ret < 0, "fimc0: VIDIOC_QUERYBUF: %s\n", ERRSTR)) return -errno; fimc0_cap[n] = mmap(NULL, b.m.planes[0].length, PROT_READ | PROT_WRITE, MAP_SHARED, fimc0_fd, b.m.planes[0].m.mem_offset); if (fimc0_cap[n] == MAP_FAILED) { printf("Failed mmap buffer %d for %d\n", n, fimc0_fd); return -1; } fimc0_cap_buf_length = b.m.planes[0].length; printf("fimc0 capture:plane.length:%d\n",fimc0_cap_buf_length); } printf("%s -\n", __func__); return 0; } int cam_setfmt() { int err; int ret; struct v4l2_fmtdesc fmt; struct v4l2_capability cap; struct v4l2_format stream_fmt; struct v4l2_input input; struct v4l2_control ctrl; struct v4l2_streamparm stream; memset(&fmt,0,sizeof(fmt)); fmt.index = 0; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; while((ret = ioctl(cam_fd,VIDIOC_ENUM_FMT,&fmt)) == 0) { fmt.index ++ ; printf("{pixelformat = %c%c%c%c},description = '%s'\n", fmt.pixelformat & 0xff,(fmt.pixelformat >> 8)&0xff, (fmt.pixelformat >> 16) & 0xff,(fmt.pixelformat >> 24)&0xff, fmt.description); } ret = ioctl(cam_fd,VIDIOC_QUERYCAP,&cap); if(ret < 0){ perror("FAIL to ioctl VIDIOC_QUERYCAP"); exit(EXIT_FAILURE); } if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { printf("The Current device is not a video capture device\n"); exit(EXIT_FAILURE); } if(!(cap.capabilities & V4L2_CAP_STREAMING)) { printf("The Current device does not support streaming i/o\n"); exit(EXIT_FAILURE); } CLEAR(stream_fmt); stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; stream_fmt.fmt.pix.width = CapWidth; stream_fmt.fmt.pix.height = CapHeight; stream_fmt.fmt.pix.pixelformat = PIXELFMT; stream_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if(-1 == ioctl(cam_fd,VIDIOC_S_FMT,&stream_fmt)) { printf("Can't set the fmt\n"); perror("Fail to ioctl\n"); exit(EXIT_FAILURE); } printf("VIDIOC_S_FMT successfully\n"); printf("%s: -\n", __func__); return 0; } int cam_setrate() { int err; int ret; struct v4l2_streamparm stream; CLEAR(stream); stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; stream.parm.capture.capturemode = 0; stream.parm.capture.timeperframe.numerator = 1; stream.parm.capture.timeperframe.denominator = FPS; err = ioctl(cam_fd, VIDIOC_S_PARM, &stream); if(err < 0) printf("FimcV4l2 start: error %d, VIDIOC_S_PARM", err); return 0; } int fimc0_setfmt() { int err; int ret; struct v4l2_fmtdesc fmt; struct v4l2_capability cap; struct v4l2_format stream_fmt; struct v4l2_input input; struct v4l2_control ctrl; struct v4l2_streamparm stream; printf("%s: +\n", __func__); CLEAR(stream_fmt); stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; stream_fmt.fmt.pix.width = CapWidth; stream_fmt.fmt.pix.height = CapHeight; stream_fmt.fmt.pix.pixelformat = PIXELFMT; stream_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; /* get format from VIVI */ ret = ioctl(cam_fd, VIDIOC_G_FMT, &stream_fmt); if (ERR_ON(ret < 0, "vivi: VIDIOC_G_FMT: %s\n", ERRSTR)) return -errno; dump_format("cam_fd-capture", &stream_fmt); /* setup format for FIMC 0 */ /* keep copy of format for to-mplane conversion */ struct v4l2_pix_format pix = stream_fmt.fmt.pix; CLEAR(stream_fmt); stream_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; struct v4l2_pix_format_mplane *pix_mp = &stream_fmt.fmt.pix_mp; pix_mp->width = pix.width; pix_mp->height = pix.height; pix_mp->pixelformat = pix.pixelformat; pix_mp->num_planes = 1; pix_mp->plane_fmt[0].bytesperline = pix.bytesperline; dump_format("fimc0-output", &stream_fmt); ret = ioctl(fimc0_fd, VIDIOC_S_FMT, &stream_fmt); if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_FMT: %s\n", ERRSTR)) return -errno; dump_format("fimc0-output", &stream_fmt); /* set format on fimc0 capture */ stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; /* try cmdline format, or use fimc0-output instead */ struct v4l2_pix_format_mplane *pix_mp_f = &stream_fmt.fmt.pix_mp; CLEAR(*pix_mp_f); pix_mp_f->pixelformat = V4L2_PIX_FMT_RGB32; pix_mp_f->width = 800; pix_mp_f->height = 480; pix_mp_f->plane_fmt[0].bytesperline = 0; dump_format("pre-fimc0-capture", &stream_fmt); ret = ioctl(fimc0_fd, VIDIOC_S_FMT, &stream_fmt); if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_FMT: %s\n", ERRSTR)) return -errno; printf("%s -\n", __func__); } int init_device() { cam_setfmt(); fimc0_setfmt(); fimc0_reqbufs(); cam_reqbufs(); cam_setrate(); printf("%s -\n", __func__); } int start_capturing(int cam_fd) { unsigned int i; enum v4l2_buf_type type; int ret; struct v4l2_buffer b; struct v4l2_plane plane; printf("%s +\n", __func__); for(i = 0;i < n_buffer;i ++) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; buf.index = i; buf.m.userptr = (unsigned long)buffers[i].start; buf.length = buffers[i].length; printf("cam qbuf:%d,userptr:0x%08x,length:%d\n",i, buf.m.userptr, buf.length); if(-1 == ioctl(cam_fd,VIDIOC_QBUF,&buf)) { perror("cam Fail to ioctl 'VIDIOC_QBUF'"); exit(EXIT_FAILURE); } } CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; b.memory = V4L2_MEMORY_MMAP; b.index = 0; b.m.planes = &plane; b.length = 1; for(i = 0;i < n_buffer;i ++) { b.index = i; ret = ioctl(fimc0_fd, VIDIOC_QBUF, &b); if (ERR_ON(ret < 0, "fimc0: VIDIOC_QBUF: %s\n", ERRSTR)) return -errno; } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(-1 == ioctl(cam_fd,VIDIOC_STREAMON,&type)) { printf("i = %d.\n",i); perror("cam_fd Fail to ioctl 'VIDIOC_STREAMON'"); exit(EXIT_FAILURE); } /* start processing */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ret = ioctl(fimc0_fd, VIDIOC_STREAMON, &type); if (ERR_ON(ret < 0, "fimc0: VIDIOC_STREAMON: %s\n", ERRSTR)) return -errno; /* type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ret = ioctl(fimc0_fd, VIDIOC_STREAMON, &type); if (ERR_ON(ret < 0, "fimc0: VIDIOC_STREAMON: %s\n", ERRSTR)) return -errno; */ type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ret = ioctl(fimc0_fd, VIDIOC_STREAMON, &type); if (ERR_ON(ret < 0, "fimc0: VIDIOC_STREAMON: %s\n", ERRSTR)) return -errno; printf("%s -\n", __func__); return 0; } int cam_cap_dbuf(int *index) { unsigned int i; enum v4l2_buf_type type; int ret; struct v4l2_buffer buf; bzero(&buf,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; if(-1 == ioctl(cam_fd,VIDIOC_DQBUF,&buf)) { perror("Fail to ioctl 'VIDIOC_DQBUF'"); exit(EXIT_FAILURE); } buffers[buf.index].bytesused = buf.bytesused; printf("%s,Line:%d,bytesused:%d\n",__func__, __LINE__, buf.bytesused); *index = buf.index; // printf("%s -\n", __func__); return 0; } int cam_cap_qbuf(int index) { struct v4l2_buffer buf; bzero(&buf,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; buf.index = index; buf.m.userptr = (unsigned long)buffers[index].start; buf.length = buffers[index].length; // printf("cam qbuf:%d,userptr:0x%08x,length:%d\n",i, buf.m.userptr, buf.length); if(-1 == ioctl(cam_fd,VIDIOC_QBUF,&buf)) { perror("cam Fail to ioctl 'VIDIOC_QBUF'"); exit(EXIT_FAILURE); } // printf("%s -\n", __func__); return 0; } int fimc0_out_qbuf(int index) { unsigned int i; enum v4l2_buf_type type; int ret; struct v4l2_buffer b, buf; struct v4l2_plane plane[3]; /* enqueue buffer to fimc0 output */ CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; b.memory = V4L2_MEMORY_USERPTR; b.index = index; b.m.planes = plane; b.length = 1; if(b.memory == V4L2_MEMORY_USERPTR) { plane[0].m.userptr = (unsigned long)fimc0_out_buf[index].start; plane[0].length = (unsigned long)fimc0_out_buf[index].length; plane[0].bytesused = fimc0_out_buf[index].length; } else { memcpy(fimc0_out_buf[index].start, buffers[index].start, buffers[index].length); } // printf("fimc0_out_buf:0x%08lx,length:%d,byteused:%d\n",fimc0_out_buf[index].start, fimc0_out_buf[index].length, fimc0_out_buf[index].bytesused); //process_image(fimc0_out_buf[index].start,0); ret = ioctl(fimc0_fd, VIDIOC_QBUF, &b); if (ERR_ON(ret < 0, "fimc0: VIDIOC_QBUF: %s\n", ERRSTR)) return -errno; // printf("%s -\n", __func__); } int fimc0_out_dbuf(int *index) { unsigned int i; enum v4l2_buf_type type; int ret; struct v4l2_buffer b, buf; struct v4l2_plane plane[3]; /* enqueue buffer to fimc0 output */ CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; b.memory = V4L2_MEMORY_USERPTR; // b.index = index; b.m.planes = plane; b.length = 1; // plane[0].m.userptr = (unsigned long)fimc0_out_buf[index].start; // plane[0].length = (unsigned long)fimc0_out_buf[index].length; // planes[0].bytesused = fimc0_out_buf[buf.index].length; ret = ioctl(fimc0_fd, VIDIOC_DQBUF, &b); *index = b.index; if (ERR_ON(ret < 0, "fimc0: VIDIOC_DQBUF: %s\n", ERRSTR)) return -errno; } int fimc0_cap_dbuf(int *index) { unsigned int i; enum v4l2_buf_type type; int ret; struct v4l2_buffer b, buf; struct v4l2_plane plane[3]; static int count = 0; /* enqueue buffer to fimc0 output */ CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; b.memory = V4L2_MEMORY_MMAP; // b.index = index; b.m.planes = plane; b.length = 1; // plane[0].m.userptr = (unsigned long)fimc0_out_buf[index].start; // plane[0].length = (unsigned long)fimc0_out_buf[index].length; // planes[0].bytesused = fimc0_out_buf[buf.index].length; ret = ioctl(fimc0_fd, VIDIOC_DQBUF, &b); *index = b.index; if (ERR_ON(ret < 0, "fimc0: VIDIOC_DQBUF: %s\n", ERRSTR)) return -errno; sem_post(&lcd_sem); fimc0_cap_index = b.index; count ++; //memcpy((void *)temp_buf, (void *)fimc0_cap[b.index], 800*480*4); printf("%s,%d\n",__func__, count); return 0; } #if 0 int fimc0_cap_qbuf(int index) { unsigned int i; enum v4l2_buf_type type; int ret; struct v4l2_buffer b, buf; struct v4l2_plane plane[3]; /* enqueue buffer to fimc0 output */ CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; b.memory = V4L2_MEMORY_MMAP; b.index = index; b.m.planes = plane; b.length = 1; if(b.memory == V4L2_MEMORY_USERPTR) { plane[0].m.userptr = (unsigned long)fimc0_out_buf[index].start; plane[0].length = (unsigned long)fimc0_out_buf[index].length; plane[0].bytesused = fimc0_out_buf[buf.index].length; } // printf("fimc0_out_buf:0x%08lx,length:%d,byteused:%d\n",fimc0_out_buf[index].start, fimc0_out_buf[index].length, fimc0_out_buf[index].bytesused); // process_image(fimc0_out_buf[index].start,0); ret = ioctl(fimc0_fd, VIDIOC_QBUF, &b); if (ERR_ON(ret < 0, "fimc0: VIDIOC_QBUF: %s\n", ERRSTR)) return -errno; // printf("%s -\n", __func__); } #endif int fimc0_cap_qbuf(int index) { // int *pdata = (int *)addr; int ret; struct v4l2_buffer b; struct v4l2_plane plane; static unsigned int count = 0; //sleep(0); printf("%s +\n", __func__); CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; b.memory = V4L2_MEMORY_MMAP; b.m.planes = &plane; b.length = 1; b.index = index; ret = ioctl(fimc0_fd, VIDIOC_QBUF, &b); if (ERR_ON(ret < 0, "fimc0: VIDIOC_QBUF: %s\n", ERRSTR)) return -errno; // printf("%s -\n", __func__); } void process_cam_to_fimc0() { int index; printf("%s +\n", __func__); cam_cap_dbuf(&index); fimc0_out_qbuf(index); printf("%s -,index:%d\n",__func__, index); } void process_fimc0_to_cam() { int index; printf("%s +\n", __func__); fimc0_out_dbuf(&index); cam_cap_qbuf(index); printf("%s -,index:%d\n",__func__, index); } int process_fimc0_capture() { // int *pdata = (int *)addr; int ret; struct v4l2_buffer b; struct v4l2_plane plane; static unsigned int count = 0; //sleep(0); // printf("%s +\n", __func__); CLEAR(plane); CLEAR(b); b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; b.memory = V4L2_MEMORY_MMAP; b.m.planes = &plane; b.length = 1; /* grab processed buffers */ ret = ioctl(fimc0_fd, VIDIOC_DQBUF, &b); if (ERR_ON(ret < 0, "fimc0: VIDIOC_DQBUF: %s\n", ERRSTR)) return -errno; count ++; printf("%s,%d\n",__func__, count); //memcpy((void *)fb_buf, (void *)fimc0_cap[b.index], 800*480*4); //process_rgb32(fimc0_cap[b.index]); //temp_buf = (char *)fimc0_cap[b.index]; /* enqueue buffer to fimc0 capture */ // CLEAR(plane); // CLEAR(b); // b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; // b.memory = V4L2_MEMORY_MMAP; // b.index = 0; // b.m.planes = &plane; // b.length = 1; ret = ioctl(fimc0_fd, VIDIOC_QBUF, &b); if (ERR_ON(ret < 0, "fimc0: VIDIOC_QBUF: %s\n", ERRSTR)) return -errno; // printf("%s -\n", __func__); //memcpy(fb_buf, fimc_out, 640) } int mainloop(int cam_fd) { int count = 1;//CapNum; clock_t startTime, finishTime; double selectTime, frameTime; struct pollfd fds[2]; int nfds = 0; while(count++ > 0) { { struct timeval tv; int r; struct timeval start; struct timeval end; int time_use=0; gettimeofday(&start,NULL); fds[0].events |= POLLIN | POLLPRI; fds[0].fd = cam_fd; fds[1].events |= POLLIN | POLLPRI | POLLOUT; fds[1].fd = fimc0_fd; //++nfds; r = poll(fds, 2, -1); if(-1 == r) { if(EINTR == errno) continue; perror("Fail to select"); exit(EXIT_FAILURE); } if(0 == r) { fprintf(stderr,"select Timeout\n"); exit(EXIT_FAILURE); } if (fds[0].revents & POLLIN) { process_cam_to_fimc0(); gettimeofday(&end,NULL); time_use=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec); // printf("time_use is %dms\n",time_use/1000); } if (fds[1].revents & POLLIN) { // printf("fimc0 has data to read\n"); int index; fimc0_cap_dbuf(&index); // fimc0_cap_qbuf(fimc0_cap_index); } if (fds[1].revents & POLLOUT) { int index; process_fimc0_to_cam(); } } } return 0; } void stop_capturing(int cam_fd) { enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(-1 == ioctl(cam_fd,VIDIOC_STREAMOFF,&type)) { perror("Fail to ioctl 'VIDIOC_STREAMOFF'"); exit(EXIT_FAILURE); } return; } void uninit_camer_device() { unsigned int i; for(i = 0;i < n_buffer;i ++) { if(-1 == munmap(fimc0_out_buf[i].start, fimc0_out_buf[i].length)) { exit(EXIT_FAILURE); } } if (-1 == munmap(fb_buf, lcd_buf_size)) { perror(" Error: framebuffer device munmap() failed.\n"); exit (EXIT_FAILURE) ; } free(fimc0_out_buf); return; } void close_camer_device(int lcd_fd, int cam_fd) { if(-1 == close(lcd_fd)) { perror("Fail to close lcd_fd"); exit(EXIT_FAILURE); } if(-1 == close(cam_fd)) { perror("Fail to close cam_fd"); exit(EXIT_FAILURE); } return; } static void *cam_thread(void *pVoid) { mainloop(cam_fd); } static void *display_thread(void *pVoid) { static unsigned int count = 0; printf("display_thread start\n"); int num = 800*480*4; while(1) { sem_wait(&lcd_sem); count ++; memcpy((void *)fb_buf, (void *)fimc0_cap[fimc0_cap_index], num); //fb_wait_for_vsync(lcd_fd); fimc0_cap_qbuf(fimc0_cap_index); } } int main() { sem_init(&lcd_sem, 0, 0); temp_buf =(char *)malloc(800*480*4); open_lcd_device(); open_camera_device(); init_device(lcd_fd, cam_fd); start_capturing(cam_fd); pthread_create(&capture_tid,NULL,cam_thread,(void *)NULL); pthread_create(&display_tid,NULL,display_thread,(void *)NULL); while(1) { sleep(10); } stop_capturing(cam_fd); uninit_camer_device(); close_camer_device(lcd_fd, cam_fd); return 0; }
open lcd success 3 vinfo.xres:800, vinfo.yres:480, vinfo.bits_per_pixel:32, lcd_buf_size:1536000, finfo.line_length:3200 open cam success 4 {pixelformat = YUYV},description = 'YUV 4:2:2 (YUYV)' {pixelformat = MJPG},description = 'MJPEG' VIDIOC_S_FMT successfully cam_setfmt: - fimc0_setfmt: + cam_fd-capture: width=640 height=480 format=YUYV bpl=1280 fimc0-output: width=640 height=480 format=YUYV bpl=1280 fimc0-output: width=640 height=480 format=YUYV bpl=1280 pre-fimc0-capture: width=800 height=480 format=RGB4 bpl=0 fimc0_setfmt - fimc0_reqbufs: + fimc0 output_buf_num:3 fimc0_reqbufs, fimc0_out_buf request successfully fimc0_reqbufs, line:331,fimc0_out_buf_length:614400 fimc0_reqbufs, line:336,page_size:4096,fimc0_out_buf_length:614400 fimc0_out userptr reqbuf start:0xb6ab8000,length:614400 fimc0_out userptr reqbuf start:0xb6a20000,length:614400 fimc0_out userptr reqbuf start:0xb6988000,length:614400 fimc0 capture:plane.length:1536000 fimc0 capture:plane.length:1536000 fimc0 capture:plane.length:1536000 fimc0_reqbufs - cam_reqbufs: + cam_reqbufs: - init_device - start_capturing + cam qbuf:0,userptr:0xb6ab8000,length:614400 cam qbuf:1,userptr:0xb6a20000,length:614400 cam qbuf:2,userptr:0xb6988000,length:614400 start_capturing - display_thread start process_cam_to_fimc0 + cam_cap_dbuf,Line:665,bytesused:614400[ 282.690700] contiguous mapping is too small 4096/614400 [ 282.690759] lj:qbuf: failed acquiring userspace memory for plane 0,ret:-14:userptr:0xb6ab8000 [ 282.690827] lj:__qbuf_userptr:q->memory:2,ret:-14 [ 282.690867] lj:qbuf: buffer preparation failed: -14 Error(cam.c:726): fimc0: VIDIOC_QBUF: Bad address process_cam_to_fimc0 -,index:0 process_cam_to_fimc0 + cam_cap_dbuf,Line:665,bytesused:614400[ 282.790940] contiguous mapping is too small 483328/614400 [ 282.790994] lj:qbuf: failed acquiring userspace memory for plane 0,ret:-14:userptr:0xb6a20000 [ 282.791061] lj:__qbuf_userptr:q->memory:2,ret:-14 [ 282.791161] lj:qbuf: buffer preparation failed: -14 Error(cam.c:726): fimc0: VIDIOC_QBUF: Bad address process_cam_to_fimc0 -,index:1 process_cam_to_fimc0 + cam_cap_dbuf,Line:665,bytesused:614400 process_cam_to_fimc0 -,index:2 fimc0_cap_dbuf,1 process_fimc0_to_cam + process_fimc0_to_cam -,index:2 fimc0_cap_qbuf + process_cam_to_fimc0 + cam_cap_dbuf,Line:665,bytesused:614400 process_cam_to_fimc0 -,index:2 fimc0_cap_dbuf,2 process_fimc0_to_cam + process_fimc0_to_cam -,index:2 fimc0_cap_qbuf +
[liujia@210]#cat /proc/pagetypeinfo Page block order: 10 Pages per block: 1024 Free pages count per migrate type at order 0 1 2 3 4 5 6 7 8 9 10 Node 0, zone Normal, type Unmovable 1 4 2 3 1 0 1 0 0 0 0 Node 0, zone Normal, type Reclaimable 1 1 0 0 1 0 1 1 1 0 0 Node 0, zone Normal, type Movable 17 10 6 2 1 2 3 1 1 1 54 Node 0, zone Normal, type Reserve 0 0 0 0 0 0 0 0 0 0 1 Node 0, zone Normal, type CMA 6 1 0 6 1 1 0 6 1 0 39 Node 0, zone Normal, type Isolate 0 0 0 0 0 0 0 0 0 0 0 Number of blocks type Unmovable Reclaimable Movable Reserve CMA Isolate Node 0, zone Normal 1 1 59 1 42 0 [liujia@210]#cat /proc/bu buddyinfo bus/ [liujia@210]#cat /proc/buddyinfo Node 0, zone Normal 25 16 8 11 4 3 5 8 3 1 94
关于“contiguous mapping is too small", 还没有解决的思路。