这一篇幅旨在续上一篇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