生成的yuv420p 文件,用ffplay -i 16*16.yuv -pix_fmt yuv420p -s 16*16 打开正确显示
特别注意:yuv420p 格式是先存所有的256个Y分量,再存64个U分量,最后存64个V分量。UV可以任选4个Y中的一个读取,本程序选的是每组的第一个。
所以霍夫曼解码遇到yuv420格式时,是先解码所有的Y分量,再解所有的U,最后再解所有的V。怪不得前面对自编程序的解码总有问题。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#define pic_width 16 //水平16个像素
#define pic_heigth 16 //垂直16个像素
#define file "/home/wzpc/Pictures/16*16.rgb"
#define file1 "/home/wzpc/Pictures/16*16.yuv"
int sp[pic_width*pic_heigth];
int sp1[pic_width*pic_heigth];
static struct fb_var_screeninfo var;
int main(void)
{
int t=0;
for(int a=0;a<pic_heigth/4;a++){
for(int b=0;b<pic_width;b++){
sp1[t]=0xff<<16|0x0<<8|0x0; //生成红色水平条
t++;
}
}
for(int a=0;a<pic_heigth/4;a++){
for(int b=0;b<pic_width;b++){
sp1[t]=0x0<<16|0xff<<8|0x0; //生成绿色水平条
t++;
}
}
for(int a=0;a<pic_heigth/4;a++){
for(int b=0;b<pic_width;b++){ //生成蓝色水平条
sp1[t]=0x0<<16|0x0<<8|0xff;
t++;
}
}
for(int a=0;a<pic_heigth/4;a++){
for(int b=0;b<pic_width;b++){
sp1[t]=0xff<<16|0xff<<8|0xff; //生成白色条
t++;
}
}
FILE *f=fopen(file,"w+b"); //生成文件存储
fwrite(sp1,t*4,1,f); //fwrite fread 操作的单位是字节,sp是int 必须乘以4
fclose(f);
int sp2[16*16]={};
FILE *fo=fopen(file,"rb"); //读rgb文件
fread(sp2,t*4,1,fo);
fclose(fo);
//--------------------------------------------------------
/* RGB 转换成 YUV
Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 //Y,U,V, B,G,R 取值范围0-0xff 之间的整数
Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -( 0.148 * R) - (0.291 * G) + (0.439 * B) + 128
YUV 转换成 RGB
B = 1.164(Y - 16) + 2.018(U - 128)
G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
R = 1.164(Y - 16) + 1.596(V - 128)
*/
//------提起RGB 再转为YUV--------------------------------------
unsigned char o_yuv[3*16*16]={};
for(int a=0;a<t;a++){
int Y=0,U=0,V=0,B=0,G=0,R=0;
R=(sp2[a])>>16;
G=(sp2[a]&0b1111111100000000)>>8;
B=(sp2[a])&0b11111111;
Y=(0.257*R)+(0.504*G)+(0.098*B)+16;
V=(0.439*R)-(0.368*G)-(0.071*B)+128;
U=-(0.148*R)-(0.291*G)+(0.439*B)+128;
if(Y>0xff) Y=0xff;
if(Y<0) Y=0;
if(V>0xff) V=0xff;
if(V<0) V=0;
if(U>0xff) U=0xff;
if(U<0) U=0;
o_yuv[a]=(unsigned char)Y; //先存16×16个Y
}
int nu=0;
for(int a=0;a<16;a=a+2){
for(int c=0;c<16;c=c+2){
int Y=0,U=0,V=0,B=0,G=0,R=0;
R=(sp2[a*16+c])>>16;
G=(sp2[a*16+c]&0b1111111100000000)>>8;
B=(sp2[a*16+c])&0b11111111;
Y=(0.257*R)+(0.504*G)+(0.098*B)+16;
V=(0.439*R)-(0.368*G)-(0.071*B)+128;
U=-(0.148*R)-(0.291*G)+(0.439*B)+128;
if(Y>0xff) Y=0xff;
if(Y<0) Y=0;
if(V>0xff) V=0xff;
if(V<0) V=0;
if(U>0xff) U=0xff;
if(U<0) U=0;
o_yuv[256+nu]=(unsigned char)U; //存8×8个U
nu++;
}
}
int nv=0;
for(int a=0;a<16;a=a+2){
for(int c=0;c<16;c=c+2){
int Y=0,U=0,V=0,B=0,G=0,R=0;
R=(sp2[a*16+c])>>16;
G=(sp2[a*16+c]&0b1111111100000000)>>8;
B=(sp2[a*16+c])&0b11111111;
Y=(0.257*R)+(0.504*G)+(0.098*B)+16;
V=(0.439*R)-(0.368*G)-(0.071*B)+128;
U=-(0.148*R)-(0.291*G)+(0.439*B)+128;
if(Y>0xff) Y=0xff;
if(Y<0) Y=0;
if(V>0xff) V=0xff;
if(V<0) V=0;
if(U>0xff) U=0xff;
if(U<0) U=0;
o_yuv[256+64+nv]=(unsigned char)V; //存8×8个V
nv++;
}
}
FILE *of=fopen(file1,"w+b");
fwrite(o_yuv,256+128,1,of);
fclose(of);
return 0;
}