V4L2 框架分析

这一篇幅旨在续上一篇V4L2框架分析的内容,其中包括了主函数的实现例子,以及帧图像的获并且JPEG图片的转换生成的方法。

4、mainloop

这个模块主要的工作就是你获得数据后如何处理,可以直接存储,也可以实时显示在屏幕上。

static void mainLoop(void)//main capture control
        {
                unsigned int count;
                count = 1;
                while (count-- > 0) {
                        for (;;) {
                                fd_set fds;
                                struct timeval tv;
                                int r;
                                FD_ZERO(&fds);
                                FD_SET(fd, &fds);
                                /* Timeout. */
                                tv.tv_sec = 2;
                                tv.tv_usec = 0;
                                r = select(fd + 1, &fds, NULL, NULL, &tv);
                                if (-1 == r) {
                                         if (EINTR == errno)
                                         continue;
                                         errno_exit("select");
                                 }
                                if (0 == r) {
                                        fprintf (stderr, "select timeout\n");
                                        exit(EXIT_FAILURE);
                                        }
                                if (frameRead())
                                break;
                                /* EAGAIN - continue select loop. */
                        }
                }
        }

上面的frameRead函数很亮。请看:

static int frameRead(void)
        {
                struct v4l2_buffer buf;
                CLEAR (buf);
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                 buf.memory = V4L2_MEMORY_MMAP;
                if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
                         switch (errno) {
                                case EAGAIN:
                                 return 0;
                                 case EIO:
                                 default:
                                 errno_exit("VIDIOC_DQBUF");
                                 }
                 }
                assert(buf.index < n_buffers);//反logic
                imageProcess(buffers[buf.index].start);
                if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
                 errno_exit("VIDIOC_QBUF");
         }

上面的imageProcess函数,我采用的是存储的做法。也可以转换为RGB,再转换为jpg

算法如下:
        static void jpegWrite(unsigned char* img)
        {
                struct jpeg_compress_struct cinfo;
                struct jpeg_error_mgr jerr;
                JSAMPROW row_pointer[1];
                //char name[4]={'a','b','c','x'};
                FILE *outfile = fopen( jpegFilename, "wb" );
                // try to open file for saving
                 if (!outfile) {
                          errno_exit("jpeg");
                 }
                 // create jpeg data
                cinfo.err = jpeg_std_error( &jerr );
                jpeg_create_compress(&cinfo);
                  jpeg_stdio_dest(&cinfo, outfile);
                // set image parameters
                 cinfo.image_width = width;
                cinfo.image_height = height;
                 cinfo.input_components = 3;
                 cinfo.in_color_space = JCS_RGB;
                 // set jpeg compression parameters to default
                 jpeg_set_defaults(&cinfo);
                // and then adjust quality setting
                 jpeg_set_quality(&cinfo, jpegQuality, TRUE);
                 // start compress
                 jpeg_start_compress(&cinfo, TRUE);
                 // feed data
                 while (cinfo.next_scanline < cinfo.image_height) {
                        row_pointer[0] = &img[cinfo.next_scanline * cinfo.image_width *
                        cinfo.input_components];
                        jpeg_write_scanlines(&cinfo, row_pointer, 1);
                        }
                 // finish compression
                 jpeg_finish_compress(&cinfo);
                // destroy jpeg data
                jpeg_destroy_compress(&cinfo);
                 // close output file
                 fclose(outfile);
         }
        /**
        process image read
        */
        static void imageProcess(const void* p)
        {
                unsigned char* src = (unsigned char*)p;
                unsigned char* dst = malloc(width*height*3*sizeof(char));
                // convert from YUV422 to RGB888
                YUV422toRGB888(width,height,src,dst);
                // write jpeg
                jpegWrite(dst);
        }
        static void YUV422toRGB888(int width, int height, unsigned char *src, unsigned char *dst)
        {
                int line, column;
                unsigned char *py, *pu, *pv;
                 unsigned char *tmp = dst;
                 /* In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb
                and a Cr.Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels. */
                py = src;
                 pu = src + 1;
                pv = src + 3;
                #define CLIP(x) ( (x)>=0xFF ? 0xFF : ( (x) <= 0x00 ? 0x00 : (x) ) )
                for (line = 0; line < height; ++line) {
                        for (column = 0; column < width; ++column) {
                                *tmp++ = CLIP((double)*py + 1.402*((double)*pv-128.0));
                                *tmp++ = CLIP((double)*py - 0.344*((double)*pu-128.0) - 0.714*((double)*pv-128.0));
                                *tmp++ = CLIP((double)*py + 1.772*((double)*pu-128.0));
                                // increase py every time
                                py += 2;
                                // increase pu,pv every second time
                                if ((column & 1)==1) {
                                        pu += 4;
                                        pv += 4;
                                 }
                         }
                 }
        }

5、关闭捕捉数据流代码,重点在与ioctl()函数的参数:VIDIOC_STREAMOFF,这个和capture_start中的VIDIOC_STREAMON成对使用。

static void captureStop(void)
        {
                enum v4l2_buf_type type;
                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                 if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
                 errno_exit("VIDIOC_STREAMOFF");
         }

6、设备关闭相关

static void deviceUninit(void)
        {
                unsigned int i;
                for (i = 0; i < n_buffers; ++i)
                if (-1 == munmap (buffers[i].start, buffers[i].length))
                errno_exit("munmap");
                for (i = 0; i < n_buffers; ++i)
                 free (buffers[i].start);
                free(buffers);
        }

7、关闭设备文件

static void deviceClose(void)
        {
                if (-1 == close (fd))
                 errno_exit("close");
                 fd = -1;
         }


转自:http://www.embedu.org/Column/Column527.htm

你可能感兴趣的:(V4L2 框架分析)