龙空技术网

Android 音视频入门01 RGB、YUV像素数据处理

人生笑笑迩 127

前言:

眼前看官们对“java设置屏幕亮度”大体比较珍视,兄弟们都想要了解一些“java设置屏幕亮度”的相关知识。那么小编在网上网罗了一些关于“java设置屏幕亮度””的相关知识,希望各位老铁们能喜欢,姐妹们快快来了解一下吧!

这段时间学习音视频,在网上找了很多资料,翻看到雷神的博客,说的很是详细,准备按照雷神博客走一遍。感谢前人的栽树。

本文记录RGB/YUV视频像素数据的处理方法,不使用任何第三方库,完全用C实现。视频像素数据在视频播放器的解码流程中的位置如下图所示,RGB/YUV查看用yuvplayer.exe,已上传到项目git中。

包括如下几个处理函数:

分离YUV420P像素数据中的Y、U、V分量分离YUV444P像素数据中的Y、U、V分量将YUV420P像素数据去掉颜色,变成灰度图将YUV420P像素数据的亮度减半将YUV420P像素数据的周围加上边框生成YUV420P格式的灰阶测试图计算两个YUV420P像素数据的PSNR分离RGB24像素数据中的R、G、B分量将RGB24格式像素数据封装为BMP图像将RGB24格式像素数据转换为YUV420P格式像素数据生成RGB24格式的彩条测试图

1) 分离YUV420P像素数据中的Y、U、V分量

/** * Split Y, U, V planes in YUV420P file. * @param jstr_url Location of Input YUV file. * @param w    Width of Input YUV file. * @param h    Height of Input YUV file. * @param num  Number of frames to process. * 分离YUV420P像素数据中的Y、U、V分量 * 如果视频帧的宽和高分别为w和h,那么一帧YUV420P像素数据一共占用w*h*3/2 Byte的数据。其中前w*h Byte存储Y,接着的w*h*1/4 Byte存储U,最后w*h*1/4 Byte存储V */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_yuv420Split(        JNIEnv *env,jobject /* this */,        jstring jstr_url, jint w, jint h, jint num) {    char input_url[100] = {0};    const char *str = env->GetStringUTFChars(jstr_url, NULL);    sprintf(input_url,"%s",str);    env->ReleaseStringUTFChars(jstr_url,str);    FILE *fp = fopen(input_url,"rb+");    if(fp == NULL) return -1;    strcpy(input_url+strlen(input_url)-4,"_y.y");    FILE *fp1 = fopen(input_url,"wb+");     strcpy(input_url+strlen(input_url)-4,"_u.y");    FILE *fp2 = fopen(input_url,"wb+");     strcpy(input_url+strlen(input_url)-4,"_v.y");    FILE *fp3 = fopen(input_url,"wb+");     unsigned char *pic = (unsigned char *)malloc(w*h*3/2);    for(int i = 0;i < num;i++) {        fread(pic, 1, w * h * 3 / 2, fp);        //Y        fwrite(pic, 1, w * h, fp1);        //U        fwrite(pic + w * h, 1, w * h / 4, fp2);        //V        fwrite(pic + w * h * 5 / 4, 1, w * h / 4, fp3);    }    free(pic);    fclose(fp);    fclose(fp1);    fclose(fp2);    fclose(fp3);    return 0;}

函数调用

AVUtils.getInstance().yuv420Split(ROOT+"lena_256x256_yuv420p.yuv",256,256,1);

运行上面代码后会在同目录下生成y、u、v三个文件,工具查看要改为对应格式和分辨率大小查看

lena_256x256_yuv420p_y.y: Y数据, 分辨率为256x256lena_256x256_yuv420p_u.y: U数据, 分辨率为128x128lena_256x256_yuv420p_v.y: V数据, 分辨率为128x128

原始图片:

lena_256x256_yuv420p.yuv

生成的y、u、v分量图片如下:

lena_256x256_yuv420p_y.y

lena_256x256_yuv420p_u.y

lena_256x256_yuv420p_v.y

2) 分离YUV444P像素数据中的Y、U、V分量

/** * Split Y, U, V planes in YUV444P file. * @param jstr_url Location of YUV file. * @param w    Width of Input YUV file. * @param h    Height of Input YUV file. * @param num  Number of frames to process. * 分离YUV444P像素数据中的Y、U、V分量 * 如果视频帧的宽和高分别为w和h,那么一帧YUV444P像素数据一共占用w*h*3 Byte的数据。其中前w*h Byte存储Y,接着的w*h Byte存储U,最后w*h Byte存储V */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_yuv444Split(        JNIEnv *env,jobject /* this */,        jstring jstr_url, jint w, jint h, jint num) {    char input_url[100] = {0};    const char *str = env->GetStringUTFChars(jstr_url, NULL);    sprintf(input_url,"%s",str);    env->ReleaseStringUTFChars(jstr_url,str);    FILE *fp = fopen(input_url,"rb+");    if(fp == NULL) return -1;    strcpy(input_url+strlen(input_url)-4,"_y.y");    FILE *fp1 = fopen(input_url,"wb+");    strcpy(input_url+strlen(input_url)-4,"_u.y");    FILE *fp2 = fopen(input_url,"wb+");    strcpy(input_url+strlen(input_url)-4,"_v.y");    FILE *fp3 = fopen(input_url,"wb+");    unsigned char *pic = (unsigned char *) malloc(w * h * 3);    for(int i = 0;i < num;i++) {        fread(pic, 1, w * h * 3, fp);        //Y        fwrite(pic, 1, w * h, fp1);        //U        fwrite(pic + w * h, 1, w * h, fp2);        //V        fwrite(pic + w * h * 2, 1, w * h, fp3);    }    free(pic);    fclose(fp);    fclose(fp1);    fclose(fp2);    fclose(fp3);    return 0;}

函数调用

AVUtils.getInstance().yuv444Split(ROOT+"lena_256x256_yuv444p.yuv",256,256,1);

运行上面代码后会在同目录下生成y、u、v三个文件

lena_256x256_yuv444p_u.y: Y数据, 分辨率为256x256lena_256x256_yuv444p_u.y: U数据, 分辨率为256x256lena_256x256_yuv444p_v.y: V数据, 分辨率为256x256

原始图片

lena_256x256_yuv444p.yuv

生成的y、u、v分量图片如下:

lena_256x256_yuv444p_y.y

lena_256x256_yuv444p_u.y

lena_256x256_yuv444p_v.y

3) 将YUV420P像素数据去掉颜色,变成灰度图

/** * Convert YUV420P file to gray picture * @param jstr_url Location of Input YUV file. * @param w       Width of Input YUV file. * @param h       Height of Input YUV file. * @param num     Number of frames to process. * 将YUV420P像素数据去掉颜色,变成灰度图 * 如果想把YUV格式像素数据变成灰度图像,只需要将U、V分量设置成128即可。 * 这是因为U、V是图像中的经过偏置处理的色度分量。色度分量在偏置处理前的取值范围是-128至127,这时候的无色对应的是0值。经过偏置后色度分量取值变成了0至255,因而此时的无色对应的就是128了 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_yuv420Gray(        JNIEnv *env,jobject /* this */,        jstring jstr_url, jint w, jint h, jint num) {    char input_url[100] = {0};    const char *str = env->GetStringUTFChars(jstr_url, NULL);    sprintf(input_url,"%s",str);    env->ReleaseStringUTFChars(jstr_url,str);    FILE *fp = fopen(input_url,"rb+");    if(fp == NULL) return -1;    strcpy(input_url+strlen(input_url)-4,"_gray.yuv");    FILE *fp1 = fopen(input_url,"wb+");    unsigned char *pic=(unsigned char *)malloc(w*h*3/2);    for(int i = 0;i < num;i++) {        fread(pic, 1, w * h * 3 / 2, fp);        //Gray        memset(pic + w * h, 128, w * h / 2);        fwrite(pic, 1, w * h * 3 / 2, fp1);    }    free(pic);    fclose(fp);    fclose(fp1);    return 0;}

函数调用

AVUtils.getInstance().yuv420Gray(ROOT+"lena_256x256_yuv420p.yuv",256,256,1);

原始图片

lena_256x256_yuv420p.yuv

生成的灰度图如下:

lena_256x256_yuv420p_gray.yuv

4) 将YUV420P像素数据的亮度减半

/** * Halve Y value of YUV420P file * @param jstr_url Location of Input YUV file. * @param w       Width of Input YUV file. * @param h       Height of Input YUV file. * @param num     Number of frames to process. * 将YUV420P像素数据的亮度减半 * 如果打算将图像的亮度减半,只要将图像的每个像素的Y值取出来分别进行除以2就可以了 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_yuv420Halfy(        JNIEnv *env,jobject /* this */,        jstring jstr_url, jint w, jint h, jint num) {    char input_url[100] = {0};    const char *str = env->GetStringUTFChars(jstr_url, NULL);    sprintf(input_url,"%s",str);    env->ReleaseStringUTFChars(jstr_url,str);    FILE *fp = fopen(input_url,"rb+");    if(fp == NULL) return -1;    strcpy(input_url+strlen(input_url)-4,"_halfy.yuv");    FILE *fp1 = fopen(input_url,"wb+");    unsigned char *pic=(unsigned char *)malloc(w*h*3/2);    for(int i = 0;i < num;i++) {        fread(pic, 1, w * h * 3 / 2, fp);        //Half        for (int j = 0; j < w * h; j++) {            unsigned char temp = pic[j] / 2;            pic[j] = temp;        }        fwrite(pic, 1, w * h * 3 / 2, fp1);    }    free(pic);    fclose(fp);    fclose(fp1);    return 0;}

函数调用

AVUtils.getInstance().yuv420Halfy(ROOT+"lena_256x256_yuv420p.yuv",256,256,1);

原始图片

lena_256x256_yuv420p.yuv

生成的亮度减半图如下:

lena_256x256_yuv420p_halfy.yuv

5) 将YUV420P像素数据的周围加上边框

/** * Add border for YUV420P file * @param jstr_url Location of Input YUV file. * @param w       Width of Input YUV file. * @param h       Height of Input YUV file. * @param border  Width of Border. * @param num     Number of frames to process. * 将YUV420P像素数据的周围加上边框 * 图像的边框的宽度为border,本程序将距离图像边缘border范围内的像素的亮度分量Y的取值设置成了亮度最大值255 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_yuv420Border(        JNIEnv *env,jobject /* this */,        jstring jstr_url, jint w, jint h, jint border, jint num) {    char input_url[100] = {0};    const char *str = env->GetStringUTFChars(jstr_url, NULL);    sprintf(input_url,"%s",str);    env->ReleaseStringUTFChars(jstr_url,str);    FILE *fp = fopen(input_url,"rb+");    if(fp == NULL) return -1;    strcpy(input_url+strlen(input_url)-4,"_border.yuv");    FILE *fp1 = fopen(input_url,"wb+");    unsigned char *pic=(unsigned char *)malloc(w*h*3/2);    for(int i = 0;i < num;i++){        fread(pic,1,w*h*3/2,fp);        //Y        for(int j = 0;j < h;j++){            for(int k = 0;k < w;k++){                if(k < border || k >= (w-border) || j < border || j >= (h-border)){                    pic[j*w+k]=255;                    //pic[j*w+k]=0;                }            }        }        fwrite(pic,1,w*h*3/2,fp1);    }    free(pic);    fclose(fp);    fclose(fp1);    return 0;}

函数调用

AVUtils.getInstance().yuv420Border(ROOT+"lena_256x256_yuv420p.yuv",256,256,20,1);

原始图片

lena_256x256_yuv420p.yuv

生成的周围加上边框图如下:

lena_256x256_yuv420p_border.yuv

6) 生成YUV420P格式的灰阶测试图

/** * Generate YUV420P gray scale bar. * @param width    Width of Output YUV file. * @param height   Height of Output YUV file. * @param ymin     Max value of Y * @param ymax     Min value of Y * @param barnum   Number of bars * @param jstr_url_out Location of Output YUV file. * 生成YUV420P格式的灰阶测试图 * 通过灰阶测试图的亮度最小值ymin,亮度最大值ymax,灰阶数量barnum确定每一个灰度条中像素的亮度分量Y的取值。 * 还要根据图像的宽度width和图像的高度height以及灰阶数量barnum确定每一个灰度条的宽度 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_yuv420GrayBar(        JNIEnv *env,jobject /* this */,        jstring jstr_url_out, jint width, jint height, jint ymin,jint ymax,jint barnum) {    int barwidth;    float lum_inc;    unsigned char lum_temp;    int uv_width,uv_height;    FILE *fp=NULL;    unsigned char *data_y = NULL;    unsigned char *data_u = NULL;    unsigned char *data_v = NULL;    int t = 0,i = 0,j = 0;    barwidth = width/barnum;    lum_inc = ((float)(ymax-ymin))/((float)(barnum-1));    uv_width = width/2;    uv_height = height/2;    data_y = (unsigned char *)malloc(width*height);    data_u = (unsigned char *)malloc(uv_width*uv_height);    data_v = (unsigned char *)malloc(uv_width*uv_height);    char input_url[100] = {0};    const char *str = env->GetStringUTFChars(jstr_url_out, NULL);    sprintf(input_url,"%s",str);    env->ReleaseStringUTFChars(jstr_url_out,str);    if((fp=fopen(input_url,"wb+")) == NULL){        LOGE("Error: Cannot create file!");        return -1;    }    //Output Info    LOGI("Y, U, V value from picture's left to right:\n");    for(t = 0;t < barnum;t++){        lum_temp = ymin+(char)(t*lum_inc);        LOGI("%3d, 128, 128\n",lum_temp);    }    //Gen Data    for(j = 0;j < height;j++){        for(i = 0;i < width;i++){            t = i/barwidth;            lum_temp = ymin+(char)(t*lum_inc);            data_y[j*width+i] = lum_temp;        }    }    for(j = 0;j < uv_height;j++){        for(i = 0;i < uv_width;i++){            data_u[j*uv_width+i] = 128;        }    }    for(j = 0;j < uv_height;j++){        for(i = 0;i < uv_width;i++){            data_v[j*uv_width+i] = 128;        }    }    fwrite(data_y,width*height,1,fp);    fwrite(data_u,uv_width*uv_height,1,fp);    fwrite(data_v,uv_width*uv_height,1,fp);    fclose(fp);    free(data_y);    free(data_u);    free(data_v);    return 0;}

函数调用

AVUtils.getInstance().yuv420GrayBar(ROOT+"graybar_640x360_yuv420p.yuv",640, 360,0,255,10);

生成的灰阶测试图如下:

graybar_640x360_yuv420p.yuv

7) 计算两个YUV420P像素数据的PSNR

/** * Calculate PSNR between 2 YUV420P file * @param jstr_url1     Location of first Input YUV file. * @param jstr_url2     Location of another Input YUV file. * @param w        Width of Input YUV file. * @param h        Height of Input YUV file. * @param num      Number of frames to process. * 计算两个YUV420P像素数据的PSNR * PSNR是最基本的视频质量评价方法 * 程序计算后得到的PSNR取值为26.693。PSNR取值通常情况下都在20-50的范围内,取值越高,代表两张图像越接近,反映出受损图像质量越好 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_yuv420Psnr(        JNIEnv *env,jobject /* this */,        jstring jstr_url1,jstring jstr_url2, jint w, jint h,jint num) {    const char *str1 = env->GetStringUTFChars(jstr_url1, NULL);    FILE *fp1 = fopen(str1,"rb+");    env->ReleaseStringUTFChars(jstr_url1,str1);    if(fp1 == NULL)        return  -1;    const char *str2 = env->GetStringUTFChars(jstr_url2, NULL);    FILE *fp2 = fopen(str2,"rb+");    env->ReleaseStringUTFChars(jstr_url2,str2);    if(fp2 == NULL)        return  -1;    unsigned char *pic1 = (unsigned char *)malloc(w*h);    unsigned char *pic2 = (unsigned char *)malloc(w*h);    for(int i = 0;i < num;i++){        fread(pic1,1,w*h,fp1);        fread(pic2,1,w*h,fp2);        double mse_sum = 0,mse = 0,psnr = 0;        for(int j = 0;j < w*h;j++){            mse_sum += pow((double)(pic1[j]-pic2[j]),2);        }        mse = mse_sum/(w*h);        psnr = 10*log10(255.0*255.0/mse);        LOGI("%5.3f\n",psnr);        fseek(fp1,w*h/2,SEEK_CUR);        fseek(fp2,w*h/2,SEEK_CUR);    }    free(pic1);    free(pic2);    fclose(fp1);    fclose(fp2);    return 0;}

函数调用

AVUtils.getInstance().yuv420Psnr(ROOT+"lena_256x256_yuv420p.yuv",ROOT+"lena_distort_256x256_yuv420p.yuv",256,256,1);

对于8bit量化的像素数据来说,PSNR的计算公式

PSNR的计算公式

原始图和受损图如下:

程序计算后得到的PSNR取值为26.693。PSNR取值通常情况下都在20-50的范围内,取值越高,代表两张图像越接近,反映出受损图像质量越好。

8) 分离RGB24像素数据中的R、G、B分量

/** * Split R, G, B planes in RGB24 file. * @param jstr_url  Location of Input RGB file. * @param w    Width of Input RGB file. * @param h    Height of Input RGB file. * @param num  Number of frames to process. * 分离RGB24像素数据中的R、G、B分量 * RGB24格式的每个像素的三个分量是连续存储的。一帧宽高分别为w、h的RGB24图像一共占用w*h*3 Byte的存储空间。 * RGB24格式规定首先存储第一个像素的R、G、B,然后存储第二个像素的R、G、B…以此类推。 * 类似于YUV420P的存储方式称为Planar方式,而类似于RGB24的存储方式称为Packed方式 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_rgb24Split(        JNIEnv *env,jobject /* this */,        jstring jstr_url, jint w, jint h,jint num) {    char input_url[100] = {0};    const char *str = env->GetStringUTFChars(jstr_url, NULL);    sprintf(input_url,"%s",str);    env->ReleaseStringUTFChars(jstr_url,str);    FILE *fp = fopen(input_url,"rb+");    if(fp == NULL) return -1;    strcpy(input_url+strlen(input_url)-4,"_r.y");    FILE *fp1 = fopen(input_url,"wb+");    strcpy(input_url+strlen(input_url)-4,"_g.y");    FILE *fp2 = fopen(input_url,"wb+");    strcpy(input_url+strlen(input_url)-4,"_b.y");    FILE *fp3 = fopen(input_url,"wb+");    unsigned char *pic=(unsigned char *)malloc(w*h*3);    for(int i = 0;i < num;i++){        fread(pic,1,w*h*3,fp);        for(int j = 0;j < w*h*3;j = j+3){            //R            fwrite(pic+j,1,1,fp1);            //G            fwrite(pic+j+1,1,1,fp2);            //B            fwrite(pic+j+2,1,1,fp3);        }    }    free(pic);    fclose(fp);    fclose(fp1);    fclose(fp2);    fclose(fp3);    return 0;}

函数调用

AVUtils.getInstance().rgb24Split(ROOT+"cie1931_500x500.rgb",500,500,1);

运行上面代码后会在同目录下生成r、g、b三个文件

cie1931_500x500_r.y: R数据,分辨率为500x500cie1931_500x500_g.y:G数据,分辨率为500x500cie1931_500x500_b.y:B数据,分辨率为500x500

输入的原图是一张标准的CIE 1931色度图。该色度图右下为红色,上方为绿色,左下为蓝色

cie1931_500x500.rgb

生成的r、g、b分量图片如下:

cie1931_500x500_r.y

cie1931_500x500_g.y

cie1931_500x500_b.y

9) 将RGB24格式像素数据封装为BMP图像

/** * Convert RGB24 file to BMP file * @param jstr_rgb24path    Location of input RGB file. * @param width        Width of input RGB file. * @param height       Height of input RGB file. * @param jstr_bmppath      Location of Output BMP file. * 将RGB24格式像素数据封装为BMP图像 * BMP采用的是小端(Little Endian)存储方式。这种存储方式中“RGB24”格式的像素的分量存储的先后顺序为B、G、R。由于RGB24格式存储的顺序是R、G、B,所以需要将“R”和“B”顺序作一个调换再进行存储 * 该程序完成了主要完成了两个工作: * 1)将RGB数据素的“B”和“前面加上文件头。 * 2)将RGB数据中每个像R”的位置互换。 *  BMP文件是由BITMAPFILEHEADER、BITMAPINFOHEADER、RGB像素数据共3个部分构成,它的结构如下所示。 * BITMAPFILEHEADER * BITMAPINFOHEADER * RGB像素数据 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_rgb24ToBmp(        JNIEnv *env,jobject /* this */,        jstring jstr_rgb24path, jint width, jint height,jstring jstr_bmppath) {    typedef struct    {        long imageSize;        long blank;        long startPosition;    }BmpHead;    typedef struct    {        long  Length;        long  width;        long  height;        unsigned short  colorPlane;        unsigned short  bitColor;        long  zipFormat;        long  realSize;        long  xPels;        long  yPels;        long  colorUse;        long  colorImportant;    }InfoHead;    int i = 0,j = 0;    BmpHead m_BMPHeader={0};    InfoHead  m_BMPInfoHeader={0};    char bfType[2] = {'B','M'};    int header_size = sizeof(bfType)+sizeof(BmpHead)+sizeof(InfoHead);    unsigned char *rgb24_buffer = NULL;    FILE *fp_rgb24 = NULL,*fp_bmp = NULL;    const char *rgb24path = env->GetStringUTFChars(jstr_rgb24path, NULL);    if((fp_rgb24=fopen(rgb24path,"rb")) == NULL){        LOGE("Error: Cannot open input RGB24 file.\n");        env->ReleaseStringUTFChars(jstr_rgb24path,rgb24path);        return -1;    }    env->ReleaseStringUTFChars(jstr_rgb24path,rgb24path);    const char *bmppath = env->GetStringUTFChars(jstr_bmppath, NULL);    if((fp_bmp=fopen(bmppath,"wb")) == NULL){        LOGE("Error: Cannot open output BMP file.\n");        env->ReleaseStringUTFChars(jstr_bmppath,bmppath);        return -1;    }    rgb24_buffer = (unsigned char *)malloc(width*height*3);    fread(rgb24_buffer,1,width*height*3,fp_rgb24);    m_BMPHeader.imageSize = 3*width*height+header_size;    m_BMPHeader.startPosition = header_size;    m_BMPInfoHeader.Length = sizeof(InfoHead);    m_BMPInfoHeader.width = width;    //BMP storage pixel data in opposite direction of Y-axis (from bottom to top).    m_BMPInfoHeader.height = -height;    m_BMPInfoHeader.colorPlane = 1;    m_BMPInfoHeader.bitColor = 24;    m_BMPInfoHeader.realSize = 3*width*height;    fwrite(bfType,1,sizeof(bfType),fp_bmp);    fwrite(&m_BMPHeader,1,sizeof(m_BMPHeader),fp_bmp);    fwrite(&m_BMPInfoHeader,1,sizeof(m_BMPInfoHeader),fp_bmp);    //BMP save R1|G1|B1,R2|G2|B2 as B1|G1|R1,B2|G2|R2    //It saves pixel data in Little Endian    //So we change 'R' and 'B'    for(j = 0;j < height;j++){        for(i = 0;i < width;i++){            char temp = rgb24_buffer[(j*width+i)*3+2];            rgb24_buffer[(j*width+i)*3+2] = rgb24_buffer[(j*width+i)*3+0];            rgb24_buffer[(j*width+i)*3+0] = temp;        }    }    fwrite(rgb24_buffer,3*width*height,1,fp_bmp);    fclose(fp_rgb24);    fclose(fp_bmp);    free(rgb24_buffer);    LOGI("Finish generate %s!\n",bmppath);    env->ReleaseStringUTFChars(jstr_bmppath,bmppath);    return 0;}

函数调用

AVUtils.getInstance().rgb24ToBmp(ROOT+"lena_256x256_rgb24.rgb",256,256,ROOT+"lena_256x256.bmp");

原始图片

lena_256x256_rgb24.rgb

生成的bmp可以用自带看图软件打开:

lena_256x256.bmp

10) 将RGB24格式像素数据转换为YUV420P格式像素数据

unsigned char clip_value(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;    }}//RGB to YUV420bool RGB24_TO_YUV420(unsigned char *RgbBuf,int w,int h,unsigned char *yuvBuf){    unsigned char*ptrY, *ptrU, *ptrV, *ptrRGB;    LOGI("pic_rgb24 [ ");    ptrRGB = RgbBuf;    for(int ll = 0;ll < w*h*3;ll++){        LOGI("%c ",ptrRGB++);        if(ll%50 == 0){LOGI("\n");}    }    LOGI("]\n");    memset(yuvBuf,0,w*h*3/2);    ptrY = yuvBuf;    ptrU = yuvBuf + w*h;    ptrV = ptrU + (w*h*1/4);    unsigned char y, u, v, r, g, b;    for (int j = 0; j < h;j++){        ptrRGB = RgbBuf + w*j*3 ;        //ptrRGB = RgbBuf + w * (h - 1 - j) * 3 ;        for (int i = 0;i < w;i++){            r = *(ptrRGB++);            g = *(ptrRGB++);            b = *(ptrRGB++);            /*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 ;*/            y = (unsigned char)( ( 66 * r + 129 * g +  25 * b) >> 8) + 16  ;            u = (unsigned char)( ( -38 * r -  74 * g + 112 * b) >> 8) + 128 ;            v = (unsigned char)( ( 112 * r -  94 * g -  18 * b) >> 8) + 128 ;            *(ptrY++) = clip_value(y,0,255);            if (j%2==0 && i%2 ==0){                *(ptrU++) = clip_value(u,0,255);            }            else{                if (i%2==0){                    *(ptrV++) = clip_value(v,0,255);                }            }        }    }    return true;}/** * Convert RGB24 file to YUV420P file * @param url_in  Location of Input RGB file. * @param w       Width of Input RGB file. * @param h       Height of Input RGB file. * @param num     Number of frames to process. * @param url_out Location of Output YUV file. * RGB24格式像素数据转换为YUV420P格式像素数据 * RGB到YUV的转换公式: *           Y = 0.257*R' + 0.504*G' + 0.098*B' + 16 *           U = -0.148*R' - 0.291*G' + 0.439*B' + 128 *           V = 0.439*R' - 0.368*G' - 0.071*B' + 128 * 转换的过程中有以下几点需要注意: * 1) RGB24存储方式是Packed,YUV420P存储方式是Planar。 * 2) U,V在水平和垂直方向的取样数是Y的一半 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_rgb24ToYuv420(        JNIEnv *env,jobject /* this */,        jstring jstr_urlin, jint w, jint h, jint num,jstring jstr_urlout) {    const char *url_in = env->GetStringUTFChars(jstr_urlin, NULL);    LOGI("url_in : %s\n",url_in);    FILE *fp = fopen(url_in,"rb+");    env->ReleaseStringUTFChars(jstr_urlin,url_in);    if(fp == NULL){        return -1;    }    const char *urlout = env->GetStringUTFChars(jstr_urlout, NULL);    LOGI("urlout : %s\n",urlout);    FILE *fp1 = fopen(urlout,"wb+");    env->ReleaseStringUTFChars(jstr_urlout,urlout);    if(fp1 == NULL){        return -1;    }    unsigned char *pic_rgb24 = (unsigned char *)malloc(w*h*3);    unsigned char *pic_yuv420 = (unsigned char *)malloc(w*h*3/2);    for(int i = 0;i < num;i++){        fread(pic_rgb24,1,w*h*3,fp);        RGB24_TO_YUV420(pic_rgb24,w,h,pic_yuv420);        fwrite(pic_yuv420,1,w*h*3/2,fp1);    }    free(pic_rgb24);    free(pic_yuv420);    fclose(fp);    fclose(fp1);    return 0;}

函数调用

AVUtils.getInstance().rgb24ToYuv420(ROOT+"lena_256x256_rgb24.rgb",256,256,1,ROOT+"lena_256x256_rgb24ToYuv420.yuv");

原始图片

lena_256x256_rgb24.rgb

转换后的YUV420P格式的图片:

lena_256x256_rgb24ToYuv420.yuv

11) 生成RGB24格式的彩条测试图

/** * Generate RGB24 colorbar. * @param width    Width of Output RGB file. * @param height   Height of Output RGB file. * @param url_out  Location of Output RGB file. * 生成RGB24格式的彩条测试图 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_rgb24ColorBar(        JNIEnv *env,jobject /* this */,        jint width, jint height,jstring jstr_urlout) {    unsigned char *data = NULL;    int barwidth;    FILE *fp = NULL;    int i = 0,j = 0;    data = (unsigned char *)malloc(width*height*3);    barwidth = width/8;    const char *url_out = env->GetStringUTFChars(jstr_urlout, NULL);    fp = fopen(url_out,"wb+");    env->ReleaseStringUTFChars(jstr_urlout,url_out);    if(fp == NULL){        return -1;    }    for(j = 0;j < height;j++){        for(i = 0;i < width;i++){            int barnum = i/barwidth;            switch(barnum){                case 0:{                    data[(j*width+i)*3+0] = 255;                    data[(j*width+i)*3+1] = 255;                    data[(j*width+i)*3+2] = 255;                    break;                }                case 1:{                    data[(j*width+i)*3+0] = 255;                    data[(j*width+i)*3+1] = 255;                    data[(j*width+i)*3+2] = 0;                    break;                }                case 2:{                    data[(j*width+i)*3+0] = 0;                    data[(j*width+i)*3+1] = 255;                    data[(j*width+i)*3+2] = 255;                    break;                }                case 3:{                    data[(j*width+i)*3+0] = 0;                    data[(j*width+i)*3+1] = 255;                    data[(j*width+i)*3+2] = 0;                    break;                }                case 4:{                    data[(j*width+i)*3+0] = 255;                    data[(j*width+i)*3+1] = 0;                    data[(j*width+i)*3+2] = 255;                    break;                }                case 5:{                    data[(j*width+i)*3+0] = 255;                    data[(j*width+i)*3+1] = 0;                    data[(j*width+i)*3+2] = 0;                    break;                }                case 6:{                    data[(j*width+i)*3+0] = 0;                    data[(j*width+i)*3+1] = 0;                    data[(j*width+i)*3+2] = 255;                    break;                }                case 7:{                    data[(j*width+i)*3+0] = 0;                    data[(j*width+i)*3+1] = 0;                    data[(j*width+i)*3+2] = 0;                    break;                }            }        }    }    fwrite(data,width*height*3,1,fp);    fclose(fp);    free(data);    return 0;}

函数调用

AVUtils.getInstance().rgb24ColorBar(640, 360,ROOT+"rgb24colorbar_640x360.rgb");

生成“白黄青绿品红蓝黑”8种颜色的彩条,如下图:

rgb24colorbar_640x360.rgb

参考文章:

雷神文章

RGB到YUV的转换公式

项目git地址:

中的FFMpeg1

标签: #java设置屏幕亮度