c 试水解码jpeg图片比特流(已成功解码)

c 试水解码jpeg图片比特流(已成功解码)_第1张图片找到一张采用霍夫曼通用DC,AC编码表的图片,提取出此图片的比特流准备对它解码,再反推怎样编码。

下图是此图片比特流前100个字节。解码是每次读一字节,对这8比特解码,如8比特不能解码,再读入一字节。因为霍夫曼表最多是16比特位编码,意思是说超过16位比特还没有被解码就是错误的。当然不一定都是8比特,有时候是2比特等,这就涉及到比特的移位等操作。但操作单位是1字节8比特。

75a09a2e3d96400a96bb9e896184c227.jpeg

图1

上传此图片文件

下面是霍夫曼4张通用表;

c 试水解码jpeg图片比特流(已成功解码)_第2张图片

此图片帧全局(0xffc0)

ff ,c0 ,0 ,11 ,8 ,1 ,67 ,1 ,da ,3 ,1 ,22 ,0 ,2 ,11 ,1 ,3 ,11 ,1 ,

对全局头分析:

总长0x11=17位,8 代表采样精度是8位,1,67  是图片行数=1×256+0 x67=359行,1,da 代表图片列数:1x256+0xda=474,    3 代表图片的分量数:亮度Y,色度U,V 三个。

后9字节分为3组,每组3字节,第一组id为1(Y),第二为2(U),第三3(V),id号为第一字节,第3字节为每个分量采样的量化表id,第二个字节高4位代表水平采样个数,低4位垂直采样个数。

1,22,0    表示Y  在MCU中水平垂直各有2个

2, 11 ,1   U 各一次

3, 11,  1         V 各一次 

意思就是说:此图片采样的是YUV 420 格式,有4个Y,1个U,1个V。

------------------------------------------------

此图片扫描头 SOS (0xffda)

ff ,da ,0 ,c ,3 ,1 ,0 ,2 ,11 ,3 ,11 ,0 ,3f ,0 ,

0,c:   扫描头长度 0×256+0xc=12 字节

 3: 3分量 ,Y,U,V

1,0,2,11,3,11  分位三组,每组2字节,第一个是id号

第二字节高4位是DC 号,低4位为AC 号

0 :代表Z排序是从0开始编号

3f: 0x3f=63   表示Z排序是63结束,最后一字节默认是0

有这些信息就可以解码了。

因为采用的是yuv420格式,那比特流开始就是4个Y,.紧跟1个U  ,1个V,组成一个MCU。比特流以此MCU格式为单位循环直到结束。

首先是亮度DC解码,马上是亮度AC解码,再是第二个亮度DC解码,再是第二个亮度AC解码。

现在在验证转换的方法是否正确:对,正确!现在解码出亮度DC=94,马上就是对亮度AC解码。

其实最简单粗暴的方法是把每一个比特位用一个char数组元素存储,这样就可连续读取。

特别要注意存入char数组时,读入的比特位是存储在数组的最高位。换一句话说,比特流是反序排列的,比如编码后是2字节,是先写入高字节,再写入低字节。8位二进制数是先读入高位,最后读入低位。
  下一步把另外3张表加入,完整解码看还遇到什么问题

已加入Y_AC  表,遇到0xff 0  报错

太绕了,还有各种判断要加,如0xff 0.     0.0

虽然报错,也解出4对:

94,(9, 1),(0 ,-17),(0,3)

现在有点麻烦,不能验证这些数据是否正确。感觉不理想,咋DC过后是9个0。只有一个办法验证了,手算,把前几位data数据全部用二进制位表示后手算验证程序是否正确。如正确再往下进行。

c 试水解码jpeg图片比特流(已成功解码)_第3张图片                                                                                                                                                                                                                    

I上图是验证数据,程序正确解码。证明ALI,霍夫曼解码部分正确。

​
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include   
#include 
#include 
#include 
#include 

int main(void) {
//	unsigned char dc0[28]={0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0xa,0xb};
	
	char y_dc(unsigned char len,int bit ){   //亮度DC
		if((len==2)&&(bit==0b00)){
			return 0;	
		}	
		if((len==3)&&(bit==0b010)){
			return 1;
		}
		if((len==3)&&(bit==0b011)){
			return 2;
		}
		if((len==3)&&(bit==0b100)){
			return 3;
		}
		if((len==3)&&(bit==0b101)){
			return 4;
		}
		if((len==3)&&(bit==0b110)){
			return 5;
		}
		if((len==4)&&(bit==0b1110)){
			return 6;
		}
		if((len==5)&&(bit==0b11110)){
			return 7;
		}
		if((len==6)&&(bit==0b111110)){
			return 8;
		}
		if((len==7)&&(bit==0b1111110)){
			return 9;
		}
		if((len==8)&&(bit==0b11111110)){
			return 10;
		}
		if((len==9)&&(bit==0b111111110)){
			return 11;
		}
		else return -1;
	}
	//----------------------------------
	
	char ali(char len,char i){            //ALI   
		char o;
		
		if (len == 0) {
			o = 0;
		}
		if ((len == 1) && (i == 0)) {
			o = -1;
		}
		if ((len == 1) && (i == 1)) {
			o = 1;
		}
		//--------------------------
		if ((i >= pow(2, len - 1)) && (i <= pow(2, len))) {
			o = i;
		}
		if ((i >= 0) && (i < pow(2, len - 1))) {
			o = i - pow(2, len) + 1;
		}
		return o;
	}	
	//-------Y——AC-----------------
	​
	int  y_ac(unsigned char cd,unsigned int i,unsigned char out[2]){
		
		int bb=1;
		unsigned int i_bit=i;
		unsigned char i_len=cd;
		
		unsigned char len;
		unsigned char o;
		
		unsigned char  ws[16]={0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};
		unsigned char zh[162]={0x1, 0x2, 0x3, 0x0, 0x4, 0x11, 0x5,0x12,0x21,0x31,0x41,0x6, 0x13,0x51,0x61,0x7,
			0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
			0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
			0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
			0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
			0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
			0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
			0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
			0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
			0xe3,0xe4,0xe5,0xe6,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
			0xf9,0xfa
		};
		unsigned char  cx_ws,cx_b;
		
		unsigned char hfm[17][0x7d]={};
		int t=0;
		for(int a=0;a<16;a++){             
			if(ws[a]==0){
				continue;
			}
			
			for(int b=0;b=0){         //得到位数len,此位数是马上要从data[]读取的二进制位,此o位二进制的值假如是c,不用解码
					jb=jb+a;      // ali 利用len 和 c  推算出DC值
					//	y=1;          
					break;
				}
			}else{             //处理 Y_AC
				o=y_ac(a,ls,yac_o);
				if(o>=0){         //得到位数len,此位数是马上要从data[]读取的二进制位,此o位二进制的值假如是c,不用解码
					jb=jb+a;      // ali 利用len 和 c  推算出DC值
					break;
				}
			}
			if(a==16){
				puts("hfm error");
				exit(-1);
			}
		}
		
		
//--------------------
//	
//-----读len 二进制 c-------------
		if(y==1){
			n0=yac_o[0];
			o=yac_o[1];
		}
		
		int ls=0;
		for(int b=0;b

为了简单,读比特流采用char数组,一个比特存入一个char.连续读取。

终于解码出亮度DC,AC。下三条也是亮度数据,但它的DC头是与首DC(94)的差。后面紧跟的是U与V,这6条组成一个MCU。此解码数据和手算的相同,如遇到0xff,0,则舍弃0。意思就是跳过0读下一字节。

到目前为止,已攻克了jpeg编码,解码的所有环节,完整编解码就是把这些环节串联起来。

c 试水解码jpeg图片比特流(已成功解码)_第4张图片

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(c语言)