.读取量化表,全局参数,霍夫曼表,恢复表编码,现在只是实现思路。
#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定义标准
主要找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开头的,翻译理解,不用去网上查中文资料。