c MJPG(1)

.读取量化表,全局参数,霍夫曼表,恢复表编码,现在只是实现思路。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static unsigned char h0[100];

int main(void) {
	FILE *f = fopen("/home/wjs/Pictures/1.jpg", "rb");
	if (f == NULL) {
		puts("file_in error");
		exit(-1);
	}
	fseek(f, 0, SEEK_END);
	int len = ftell(f);
	fseek(f, 0, SEEK_SET);

	int fd = fileno(f);
	unsigned char *p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);

	puts("-----------量化表---------------------");
	for (int t = 0; t < len; t++) {
		if ((*(p + t) == 0xff) && (*(p + t + 1) == 0xdb)) {
			//		printf("ffdb:%d\n", t);
		}
	}
	puts("-----------帧全局---------------------");
	for (int t = 0; t < len; t++) {
		if ((*(p + t) == 0xff) && (*(p + t + 1) == 0xc0)) {
			//		printf("ffc0:%d\n", t);
		}
	}
	puts("------------霍夫曼表--------------------");




	for (int t = 0; t < len; t++) {
		if ((*(p + t) == 0xff) && (*(p + t + 1) == 0xc4)) {
			//	printf("ffc4:%d\n",t);   //ff c4 (固定)0 1f(长度-2)0(表id)
			int cd = (*(p + t + 2)) * 256 + *(p + t + 3) - 3;
			unsigned char *hp = malloc(cd * (sizeof(char)));


			for (int n = 0; n < cd; n++) {
				*(hp + n) = *(p + t + 5 + n);
				//	printf("%d ",*(hp+n));

			}

			if (*(p + t + 4) == 0) {          //表1
				unsigned  char hfm0[cd];
			//	memcpy(&h0, hp, cd);

			}
			if (*(p + t + 4) == 16) {         //2
				unsigned  char hfm1[cd];
			//	memcpy(&h0,hp,cd);

			}
			if (*(p + t + 4) == 1) {           //3
				unsigned  char hfm2[cd];
			//	memcpy(&h0,hp,cd);

			}
			if (*(p + t + 4) == 17) {          //4
				unsigned  char hfm3[cd];
				memcpy(&h0,hp,cd);

			}

			printf("\n");

			free(hp);
		}

	}


	puts("------------差分数据--------------------");
	for (int t = 0; t < len; t++) {
		if ((*(p + t) == 0xff) && (*(p + t + 1) == 0xdd)) {
			//		printf("ffdd:%d\n", t);
		}
	}
	puts("------------扫描数据--------------------");
	for (int t = 0; t < len; t++) {
		if ((*(p + t) == 0xff) && (*(p + t + 1) == 0xda)) {
			//		printf("ffda:%d\n", t);
		}
	}
//----------------------------------------------------------------------
	//h0[26]
	// 0 1 2 3 4 5 6 7 8 9 10        15
	//0 1 5 1 1 1 1 0 0 0 0 0 0 0 0 0      0 1 4 5 6 7 3 2 8 9
	int bm[100];
	int t = 0;  //输出数组递增数
	int n = 1;  //内存递增数
	if (h0[n] == 1) {
		bm[t] = 0;

	} else if (h0[n] == 2) {
		bm[t] = 0;             //生成2 位   0,1
		t = t + 1;
		bm[t] = 1;

	}
	
	for(int q=0;q<15;q++){
    	n = n + 1;
    	if (h0[n] != 0) {  //3   2,3,4,5,6
	    	t = t + 1;
	       	bm[t] = 2 * (bm[t - 1] + 1);
	    	for (int z = 0; z < (h0[n] - 1); z++) {
		    	t = t + 1;
		    	bm[t] = bm[t - 1] + 1;
	    	}
    	}
	}
/*	n = n + 1;
	if (h0[n] != 0) {  //4  (6+1)*2=14
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}

	n = n + 1;
	if (h0[n] != 0) {  //5    (14+1)*2=30
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}

	n = n + 1;
	if (h0[n] != 0) {  //6     (30+1)*2=62
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}

	n = n + 1;
	if (h0[n] != 0) {  //7位    (62+1)*2=126
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}

	n = n + 1;
	if (h0[n] != 0) {  //8
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}

	n = n + 1;
	if (h0[n] != 0) {  //9
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}

	n = n + 1;
	if (h0[n] != 0) {  //10
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}
	n = n + 1;
	if (h0[n] != 0) {  //11
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}
	n = n + 1;
	if (h0[n] != 0) {  //12
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}
	n = n + 1;
	if (h0[n] != 0) {  //13
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}
	n = n + 1;
	if (h0[n] != 0) {  //14
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}
	n = n + 1;
	if (h0[n] != 0) {  //15
		t = t + 1;
		bm[t] = 2 * (bm[t - 1] + 1);
		for (int z = 0; z < (h0[n] - 1); z++) {
			t = t + 1;
			bm[t] = bm[t - 1] + 1;
		}
	}
	
*/	
	for (int t = 0; t < 100; t++) {
		printf("%d   ", bm[t]);
	}


	return 0;
}

 Jpeg 用的是范式霍夫曼,可以00 开始推算出码表。

7现在又有一问题,ffda的扫描流中含有Y  和UV两种的交流与直流4个部分,怎样才能区分开这4部分。

搞清楚了码流结构才能试着用上面的码表解码。

一个正常的JPEG码流以SOI(FFD8)标记开始,以EOI(FFD9)标记结束,中间是一帧的图像信息,包括各种数据(如 huffman表FFC4部分,量化表FFC0部分,以及APP和COM等部分)和SCAN部分(FFDA部分)等。JPEG图像包含一个或者多个SCAN(progressive模式包含多个SCAN),一个SCAN下面有一个或者多个RST(Restart Interval),一个RST里有一个或者多个MCU,一个MCU里有一个或者多个Block。

细读rfc2435   jpeg定义标准

c MJPG(1)_第1张图片

 主要找SOS段的详细资料信息

https://www.w3.org/graphics/jpeg/itu-t81.pdf

jpeg  格式  信息技术——
数字压缩和编码
连续的静态图像–
要求和指南

==========================================

交流码表结构
AC  交流表中的每个非零AC数由以下形式的复合8位值RS描述
RS=二进制“RRRRSSSS”

1.RRRR  为2进制表示的10进制数

2.SSSS  为霍夫曼编码数

3. RRRR  表示非零数之间的零的个数。两个特殊值:16个0     RS==15,0==0b11110000

                当块中的所有剩余系数为0,   RS=0

4.SSSS    霍夫曼表

                                     SSSS                 AC系数
                                       1                   -1.              1
                                       2                 -3,-2,         2,3
                                        3                   -7...-4         4...7

                                       4                  -15....-8.        8....15
                                       5                -31...-16,         16....31
                                       6                –63.–32,       32....63
                                       7               –127..–64,     64....127
                                       8              –255..–128        128.....255
                                        9              -511..-256         256.....511
                                         10            -1 023..-512      512.....1 023                

 

到目前为止,梳理一下理解编码的过程,

1.一帧YCbCr信号经过余弦采样后用8*8分为很多小格,每小格叫一个block。这个分block的标准并不一定是8*8 ,还没有搞清楚这个量化小格数量是那个头决定。还有怎样余弦采样。

2.分别用2张量化表量化每个block中的Y和UV.

生成3张量化后的表,就叫它为My,Mu,Mv

3.用Z扫描的顺序重新排列My,Mu,Mv

4.采用RRRRSSSS的二进制形式重新编码z排列My,Mu,Mv,压缩三表中的所有0。

三表中第一数为直流系数 ,其他数为交流.系数

5.再用2张直流,2张交流霍夫曼表分别去编码上面的三张表的直流和交流系数,生成3张表的比特流,sos头有参数规定了yuv分量用那张表编码。所有我认为这4张霍夫曼表是jpeg通用表。肯定不是编码时先统计的。最后把直流放第一,交流放后组合成表,

现在的疑问有:编码时,Y,U,V的三张比特霍夫曼表也是按yuv422的顺序排列存入文件的吗。通俗话说就是:Y1,U,Y2,V的形式。解码时,这三个分量的比特流也是按YCbCr的交错方式拆分后重新组合排列的吗?每两个block的比特流之间是不是用0作为分隔符,还是通过还原计数已有8*8个数完成一个block. 每个block的数据块也是按从左到右,从上到下排列组合成一帧图片吗。更不用说怎样余弦采样。

说实话,小小的一张图片,含有很多知识,这些国际通用标准制定是非常难的。需要很高深的数学知识,真正搞懂了这个编解码过程,应该会很容易理解其他的如h264压缩方法吧。

现在的困难是没有人翻译这些标准协议文件。网上的中文资料很少,有也是内容差不多,而且都是最基本的没有深入了解。

现在我的观点是,如果是遇到协议标准的问题就直接去找英文的标准协议文件,rfc开头的,翻译理解,不用去网上查中文资料。

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(c语言,算法,数据结构)