MTK Android Camera 录像、预览格式。

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 退出显示。

 

你可能感兴趣的:(Android开发)