bmp转rgb,rgb转yuv420p文件

有几个关键点:首先yuv420p的采样规则一定要明白。代码中注释已经写明了,还有rgb的数据,是不是倒序,还有是rgb排序,还是brg排序,根据rgb数据源的不同,程序处理也会不一样。

#include 
#include 
#include 
#include 

typedef struct                       /**** BMP file header structure (14 bytes) ****/
{
    uint16_t   bfType;           /* file type ,set 0x4d42 */
    uint32_t   bfSize;      /* file size  24位bmp=sizeof(BMPFILEHEADER) + sizeof(BMPINFOHEADER)+width*height*3*/
    uint16_t   bfReserved1;      /* 保留 ,set 0 */
    uint16_t   bfReserved2;      /* 保留 ,set 0 */
    uint32_t   bfOffBits;        /*pos:10  Offset to bitmap data,一般设置为0x36 */
} BMPFILEHEADER;

typedef struct                       /**** BMP file info structure(40 bytes) ****/
{
    uint32_t   biSize;               /* 本信息头的大小 */
    uint32_t            biWidth;          /*pos:18 图像宽度,单位是像素*/
    uint32_t            biHeight;         /*pos:22 图像高度,单位是像素,如果这是一个正数,说明图像数据是从图像左下角到右上角排列的 */
    uint16_t biPlanes;         /* Number of color planes ,set 1*/
    uint16_t biBitCount;       /* pos:28 每个像素占多少bit ,24位bmp值是24*/
    uint32_t   biCompression;    /* 图像的压缩类型,最常用的就是0(BI_RGB),表示不压缩 */
    uint32_t   biSizeImage;      /* pos:32位图数据的大小,当用BI_RGB格式时,可以设置为0 */
    int32_t            biXPelsPerMeter;  /* X pixels per meter ,0x0EC4 */
    int32_t            biYPelsPerMeter;  /* Y pixels per meter ,0x0EC4*/
    uint32_t   biClrUsed;        /* Number of colors used,说明位图使用的调色板中的颜色索引数,为0说明使用所有 */
    uint32_t   biClrImportant;   /* Number of important colors 说明对图像显示有重要影响的颜色索引数,为0说明都重要*/
} BMPINFOHEADER;


void bmp2rgb(const char* filename, uint8_t* rgbbuf){
    FILE* fp = fopen(filename, "rb");
    fseek(fp, 10, SEEK_SET); //跳到偏移量标记处
    int bfOffBits = 0;
    fread(&bfOffBits, 4, 1, fp);

    int biSizeImage = 0;
    fseek(fp, 0, SEEK_END);//文件指针指向文件尾
    long filelen = ftell(fp); //获取文件大小,用于计算rgb数据大小
    int datalen = filelen - bfOffBits;
    rgbbuf = new uint8_t[datalen];
    fseek(fp, bfOffBits, SEEK_SET);
    fread(rgbbuf, 1, datalen, fp);
    fclose(fp);

}

void bmp2rgbstore(const char* filename, char* output_filename){
    FILE* outfp = fopen(output_filename, "wb");
    FILE* fp = fopen(filename, "rb");
    fseek(fp, 10, SEEK_SET); //跳到偏移量标记处
    int bfOffBits = 0;
    fread(&bfOffBits, 4, 1, fp);
    fseek(fp, bfOffBits, SEEK_SET);

    while (!feof(fp)){
        uint8_t* temp = new uint8_t[1];
        if (fread(temp, 1, 1, fp) > 0){
            fwrite(temp, 1, 1, outfp);
        }
        delete[] temp;
    }
    fclose(fp);
    fclose(outfp);

}


int main(int argc, char **argv){
    //uint8_t* rgbbuf = NULL;
    //bmp2rgb("sucai.bmp", rgbbuf);
    //bmp2rgbstore("sucai.bmp", "sucai_rgb.rgb");
    FILE* fp = fopen("sucai_rgb.rgb", "rb");
    FILE* fpyuv = fopen("out.yuv", "wb");

    int w = 400, h = 400;
    unsigned char b, g, r;
    unsigned char* ybuf = new unsigned char[w*h];
    unsigned char* ubuf = new unsigned char[w*h / 4];
    unsigned char* vbuf = new unsigned char[w*h / 4];


    unsigned char*y = ybuf;
    unsigned char* u = ubuf;
    unsigned char *v = vbuf;

    for (int i = 0; i 1 - i) * 3, SEEK_SET); //图像数据是左下角为图像第一个像素,从左往右,从下往上排列的。所以要反向读取。


        for (int j = 0; j1, 1, fp);
            fread(&g, 1, 1, fp);
            fread(&r, 1, 1, fp); //图像是以BGR排序的


            unsigned char Y = (unsigned char)((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;


            *y = Y;
            y++;

            /*
            yuv420的采样规则:
            一行一行的扫描采样,第一行采集u,不采集v。且y和u比例,2:1(即偶数位才采集u)
            第二行采集v,不采集u,且y和v比例,2:1(即偶数位才采集v)
            以此递推...
            故整体采样比例y:u:v=8:2:2=4:1:1
            */
            if (j % 2 == 0){//列数为偶素行才采集U或V
                if (i % 2 == 0){//行数位偶数行采集U
                    unsigned char  U = (unsigned char)((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;

                    *(u++) = U;
                }
                else{
                    unsigned char V = (unsigned char)((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;

                    *(v++) = V;
                }

            }


        }
    }
    //yuv420p,先写y,再写u,在写v
    fwrite(ybuf, 1, w*h, fpyuv);
    fwrite(ubuf, 1, w*h / 4, fpyuv);
    fwrite(vbuf, 1, w*h / 4, fpyuv);
    fclose(fp);
    fclose(fpyuv);
    getchar();
    return 0;
}

转出的yuv图片效果:
bmp转rgb,rgb转yuv420p文件_第1张图片

你可能感兴趣的:(ffmpeg)