搞linux下音视频是不能离开v4l2的。前段时候想自己写个利用v4l2 API直接抓取图像的测试程序。网上一查有很多相关的程序。我下载下来编译后运行,发现图片是抓取到了,可是不能打开,摄像头抓取的一般都是YUYV格式的,直接存成文件缺乏相应头文件信息肯定打不开。下面是我写的一个简单的转换成rgb24,再存成ppm格式,图片正常打开。
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <malloc.h>
#if 0
#define TO_R(y, u, v) floor((float)y + 1.140 *((float)v))
#define TO_G(y, u, v) floor((float)y - 0.394 * (float)u - 0.581 * (float)v)
#define TO_B(y, u, v) floor((float)y + 2.032 * (float)u)
#else
#define TO_R(y, u, v) floor(1.164 * (y - 16) + 1.159 * (v - 128))
#define TO_G(y, u, v) floor(1.164 * (y - 16) - 0.38 * (u - 128) - 0.813 * (v - 128))
#define TO_B(y, u, v) floor(1.164 * (y - 16) + 2.018 * (u - 128))
#endif
#define CLIP(x) if (x > 255) x = 255; \
else if (x < 0) x = 0;
// need free rgb by user;
int YuyvToRgb24(const char * const yuv, const int in_size,
char **const rgb, int * const out_size, int w, int h)
{
const unsigned char *pyuv = yuv;
char *prgb = NULL;
int pix = w * h;
prgb = malloc(pix * 3);
if (prgb == NULL)
{
perror("malloc:");
return -1;
}
float R, G, B, Y, U, V;
int i, j;
for (i = 0, j = 0; i < pix * 2; i += 4)
{
// pixe0
Y = pyuv[i];
U = pyuv[i + 1];
V = pyuv[i + 3];
R = TO_R(Y, U, V);
G = TO_G(Y, U, V);
B = TO_B(Y, U, V);
CLIP(R);
CLIP(G);
CLIP(B);
prgb[j++] = (unsigned char)R;
prgb[j++] = (unsigned char)G;
prgb[j++] = (unsigned char)B;
// pixe1
Y = pyuv[i + 2];
R = TO_R(Y, U, V);
G = TO_G(Y, U, V);
B = TO_B(Y, U, V);
CLIP(R);
CLIP(G);
CLIP(B);
prgb[j++] = (unsigned char)R;
prgb[j++] = (unsigned char)G;
prgb[j++] = (unsigned char)B;
}
*out_size = pix * 3;
*rgb = prgb;
return 0;
}
如果图片颜色不对,可以试着换下TO_R,TO_G,TO_B的公式。
存成ppm文件函数
int WriteToPpm(const char * const data, int size, int w, int h)
{
static int frame = 0;
char name[64] = {0};
snprintf(name, sizeof(name), "frame%d.ppm\0", frame++);
FILE *fp = fopen(name, "wb");
if (fp < 0)
{
printf("open frame data file failed\n");
return -1;
}
fprintf(fp, "P6\n%d %d\n255\n", w, h);
char *rgb;
int rgb_size;
YuyvToRgb24(data, size, &rgb, &rgb_size, w, h);
fwrite(rgb, rgb_size, 1, fp);
free(rgb);
printf("Capture one frame saved in %s\n", CAPTURE_FILE);
fclose(fp);
return 0;
}