MTK Android 8.1 的camera实现部分并没有走标准Camera3 dev实现,而是自行实现了 v1 的 hal层内容。
具体的代码模块位于 vendor/mediatek/proprietary/hardware/mtkcam/middleware 目录下。
在 mtk6763这个低端平台上,采用了 v1 的版本。预览的代码位于 DisplayClient.BufOps.cpp 这里,在 handleReturnBuffers 函数中提供了要向上层提供的原始数据。
在预览、录像模式下,数据格式都不同,有 yuv422的,还有 yuv420p的,还有yuv420sp的。
yuv422 格式介绍见 https://blog.csdn.net/xjhhjx/article/details/80291465
yuv420p, yuv420sp格式介绍见 https://blog.csdn.net/zhong29/article/details/83508106
如果要贴一张效果图到视频流里,需要转换成对应的格式,然后再插入数据。
首先使用 ffmpeg 转换 jpg图片为 rgb24格式:
ffmpeg -i 1080x1440.jpg -s 1080x1440 -pix_fmt rgb24 1080x1440.rgb
然后将rgb文件转为对应的格式文件:
#include
#include
#include
unsigned char ClipValue(unsigned char x, unsigned char min_val, unsigned char max_val) {
if (x > max_val) {
return max_val;
} else if (x < min_val) {
return min_val;
} else {
return x;
}
}
void RGB2YUV420SP(unsigned char *rgb24, int width, int height, unsigned char *yuv420p) {
unsigned char *ptrY, *ptrUV;
memset(yuv420p, 0, width * height * 3 / 2);
ptrY = yuv420p;
ptrUV = yuv420p + width * height;
unsigned char y, u, v, r, g, b;
int index = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
index = width * j * 3 + i * 3;
r = rgb24[index];
g = rgb24[index + 1];
b = rgb24[index + 2];
y = (unsigned char) ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = (unsigned char) ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
v = (unsigned char) ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
*(ptrY++) = ClipValue(y, 0, 255);
if (j % 2 == 0 && i % 2 == 0) {
*(ptrUV++) = ClipValue(u, 0, 255);
*(ptrUV++) = ClipValue(v, 0, 255);
}
}
}
}
// 3bytes -> 1.5bytes
void rgb24_to_yuv420sp(char *rgbPath, char *yuvPath, int width, int height) {
FILE *fp_rgb = fopen(rgbPath, "rb+");
FILE *fp_yuv = fopen(yuvPath, "wb+");
if(fp_rgb == NULL) {
printf("file no found %s\n", rgbPath);
return;
}
unsigned char *rgb24_data = (unsigned char *) malloc(width * height * 3);
unsigned char *yuv420_data = (unsigned char *) malloc(width * height * 3 / 2);
fread(rgb24_data, 1, width * height * 3, fp_rgb);
RGB2YUV420SP(rgb24_data, width, height, yuv420_data);
fwrite(yuv420_data, 1, width * height * 3 / 2, fp_yuv);
free(rgb24_data);
free(yuv420_data);
fclose(fp_rgb);
fclose(fp_yuv);
printf("done %s\n", yuvPath);
}
void RGB2YUV420P(unsigned char *rgb24, int width, int height, unsigned char *yuv420p) {
unsigned char *ptrY, *ptrU, *ptrV;
memset(yuv420p, 0, width * height * 3 / 2);
ptrY = yuv420p;
ptrU = yuv420p + width * height;
ptrV = ptrU + (width * height * 1 / 4);
unsigned char y, u, v, r, g, b;
int index = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
index = width * j * 3 + i * 3;
r = rgb24[index];
g = rgb24[index + 1];
b = rgb24[index + 2];
y = (unsigned char) ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = (unsigned char) ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
v = (unsigned char) ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
*(ptrY++) = ClipValue(y, 0, 255);
if (j % 2 == 0 && i % 2 == 0) {
*(ptrU++) = ClipValue(u, 0, 255);
} else if (i % 2 == 0) {
*(ptrV++) = ClipValue(v, 0, 255);
}
}
}
}
// 3bytes -> 1.5bytes
void rgb24_to_yuv420p(char *rgbPath, char *yuvPath, int width, int height) {
FILE *fp_rgb = fopen(rgbPath, "rb+");
FILE *fp_yuv = fopen(yuvPath, "wb+");
if(fp_rgb == NULL) {
printf("file no found %s\n", rgbPath);
return;
}
unsigned char *rgb24_data = (unsigned char *) malloc(width * height * 3);
unsigned char *yuv420_data = (unsigned char *) malloc(width * height * 3 / 2);
fread(rgb24_data, 1, width * height * 3, fp_rgb);
RGB2YUV420P(rgb24_data, width, height, yuv420_data);
fwrite(yuv420_data, 1, width * height * 3 / 2, fp_yuv);
free(rgb24_data);
free(yuv420_data);
fclose(fp_rgb);
fclose(fp_yuv);
printf("done %s\n", yuvPath);
}
void RGB2YUV422(unsigned char *rgb24, int width, int height, unsigned char *yuv422, unsigned char *yuv444_data) {
unsigned char y, u, v, r, g, b;
int index = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
index = (width * j + i) * 3;
r = rgb24[index];
g = rgb24[index + 1];
b = rgb24[index + 2];
y = (unsigned char) ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = (unsigned char) ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
v = (unsigned char) ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
yuv444_data[index] = y&0xff;
yuv444_data[index + 1] = u&0xff;
yuv444_data[index + 2] = v&0xff;
}
}
// conver yuv444 -> yuv 422
//YUV444: Y0 U0 V0 Y1 U1 V1
//YUV422: Y0 U0 Y1 V0
int cnt = (width * height*3)/6;
unsigned char *ptr444 = yuv444_data;
unsigned char *ptr422 = yuv422;
for(int i=0; i 2bytes
void rgb24_to_yuv422(char *rgbPath, char *yuvPath, int width, int height) {
FILE *fp_rgb = fopen(rgbPath, "rb+");
FILE *fp_yuv = fopen(yuvPath, "wb+");
if(fp_rgb == NULL) {
printf("file no found %s\n", rgbPath);
return;
}
printf("stage1\n");
unsigned char *rgb24_data = (unsigned char *) malloc(width * height * 3);
unsigned char *yuv444_data = (unsigned char *) malloc(width * height * 3);
unsigned char *yuv422_data = (unsigned char *) malloc(width * height * 2);
printf("stage2\n");
fread(rgb24_data, 1, width * height * 3, fp_rgb);
printf("stage3\n");
RGB2YUV422(rgb24_data, width, height, yuv422_data, yuv444_data);
printf("stage4\n");
fwrite(yuv422_data, 1, width * height * 2, fp_yuv);
printf("stage5\n");
fclose(fp_rgb);
fclose(fp_yuv);
printf("stage6\n");
free(rgb24_data);
printf("stage7\n");
free(yuv422_data);
printf("stage8\n");
free(yuv444_data);
printf("done %s\n", yuvPath);
}
static void merge_yuv420sp(unsigned char *logo_p, int logo_w, int logo_h, unsigned char *buf, int dst_w, int dst_h) {
int size = dst_w * dst_h * 3/2;
int stride0 = dst_w;
int ybytes = stride0 * dst_h; // y parts bytes
// clear all white
memset(buf, 0xeb, ybytes);
memset(&buf[ybytes], 0x80, size-ybytes);
int xoff = (dst_w - logo_w )/2;
int yoff = (dst_h-logo_h)/2;
int yline_bytes = stride0;
int offset_bytes = yoff*yline_bytes + xoff; // Y cost 1 byte
int logo_stride_bytes = logo_w;
int logo_offset_bytes = 0;
// copy Y bytes
for(int i=0; i> 8) + 16;
int u = (unsigned char) ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
int v = (unsigned char) ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
printf("y=%x, u=%x, v=%x\n", y, u, v);
char buf[16];
memset(buf, 0xeb80, sizeof(buf));
for(int i=0;i<16;i++){
printf("buf[%d]=%x\n", i, buf[i]&0xff);
}
#endif
return 0;
}
最后将输出的 yuv422或者yuv420p原始文件转换成 c 数组,放到输出流里即可。
想要本地验证yuv422或者yuv420p原始文件,下载这个工程:https://github.com/figgis/yuv-viewer 然后编译执行yv程序即可。
这个程序依赖 libsdl所以需要安装libsdl: sudo apt-get install libsdl1.2-dev
执行查看程序:./yv 300x400.yuv422 300 400 YV12
弹出的查看窗口是 libsdl的,可以上下方向键缩放图片,按 q 退出显示。