JPEG原理分析及JPEG解码器的调试
程序员文章站
2022-07-14 22:08:47
...
实验内容
实验步骤
理解三个结构体的设计目的
-
struct huffman_table
-
struct component
包括AC、DC哈夫曼码表,量化指针,DCT变换系数表,前一幅图像的直流分量
-
struct jdec_private
包括图像的参数:宽高比;码流的参数:开始、结束位置,持续时间;量化表,哈夫曼码表;y、u、v分量;最小单元MUC;中间变量
层次分析如上图:正如编解码流程框图所示,输入码流jdec_private
包含包含不同的分量component
(比如y、u、v),对component
进行编解码需要用到哈夫曼码表huffman_table
(AC、DC),当然这知道概况的结构框图,每个层次具体的细节都在不同结构体中有详细的声明。
程序设计的整体框架
-
文件读取
-
程序处理
-
进入到程序内部观察:发现边进行解码便对上述结构体构造
-
-
文件关闭
、
TRACE的目的和含义
系统提供一系列特殊的函数或者宏来处理Debug版本相关的信息,如下:
宏名/函数名 | 说明 |
---|---|
TRACE | 使用方法和printf 完全一致,他在output 框中输出调试信息 |
-
例如:输出哈夫曼码表
#if TRACE fprintf(p_trace,"val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size); fflush(p_trace); #endif
通过
TRACE
的TURE
或者FALSE
可以很容易的开关这些数据的输出#define snprintf _snprintf//add by nxn #define TRACE 1//add by nxn #define TRACEFILE "trace_jpeg.txt"//add by nxn
逐步调试JPEG解码器程序
-
直接执行程序,发现报错,没有指定
arg[]
参数int main(int argc, char *argv[])
-
观察文件中出现的
arg[]
参数
-
输入文件
arg[1]
current_argument = 1; input_filename = argv[current_argument];
-
输出文件
arg[2]
if (strcmp(argv[current_argument+1],"yuv420p")==0) output_format = TINYJPEG_FMT_YUV420P; else if (strcmp(argv[current_argument+1],"rgb24")==0) output_format = TINYJPEG_FMT_RGB24; else if (strcmp(argv[current_argument+1],"bgr24")==0) output_format = TINYJPEG_FMT_BGR24; else if (strcmp(argv[current_argument+1],"grey")==0) output_format = TINYJPEG_FMT_GREY; else exitmessage("Bad format: need to be one of yuv420p, rgb24, bgr24, grey\n");
-
输出文件名
arg[3]
output_filename = argv[current_argument+2];
-
重新运行,发现生成了相应的Y、U、V图像文件和
TRACE
中的信息
经过对代码大体框架的梳理,通过调试很容易找到所需文件的位置,进行输出即可
##输出YUV文件
- 调整命令行参数
-
调整
write_yuv
函数/** * Save a buffer in three files (.Y, .U, .V) useable by yuvsplittoppm */ static void write_yuv(const char *filename, int width, int height, unsigned char **components) { FILE *F; char temp[1024]; snprintf(temp, 1024, "%s.Y", filename); F = fopen(temp, "wb"); fwrite(components[0], width, height, F); fclose(F); snprintf(temp, 1024, "%s.U", filename); F = fopen(temp, "wb"); fwrite(components[1], width*height/4, 1, F); fclose(F); snprintf(temp, 1024, "%s.V", filename); F = fopen(temp, "wb"); fwrite(components[2], width*height/4, 1, F); fclose(F); //生成可观看的YUV文件 snprintf(temp, 1024, "%s.YUV", filename); F = fopen(temp, "wb"); fwrite(components[0], width, height, F); fwrite(components[1], width * height / 4, 1, F); fwrite(components[2], width * height / 4, 1, F); fclose(F); #if TRACE printf("%d,%d",width,height); #endif }
以txt文件输出所有的量化矩阵和所有的HUFFMAN码表
- 定义输出文件
FILE *p1_trace;//add by nxn
#if TRACE
p_trace=fopen(TRACEFILE,"w");
if (p_trace==NULL)
{
printf("trace file open error!");
}
//输出文件
p1_trace=fopen("QandH_tables.txt","w");
if (p1_trace==NULL)
{
printf("QandH_tables.txt open error!");
}
#endif
- 输出量化矩阵
static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
{
int qi;
float *table;
const unsigned char *dqt_block_end;
#if TRACE
fprintf(p_trace,"> DQT marker\n");
fflush(p_trace);
#endif
dqt_block_end = stream + be16_to_cpu(stream);
stream += 2; /* Skip length */
while (stream < dqt_block_end)
{
qi = *stream++;
#if SANITY_CHECK
if (qi>>4)
snprintf(error_string, sizeof(error_string),"16 bits quantization table is not supported\n");
if (qi>4)
snprintf(error_string, sizeof(error_string),"No more 4 quantization table is supported (got %d)\n", qi);
#endif
table = priv->Q_tables[qi];
//量化矩阵输出
#if TRACE
fprintf(p_trace, "Quantization_table [%d]:\n", qi);
fflush(p_trace);
#endif
build_quantization_table(table, stream);
stream += 64;
}
#if TRACE
fprintf(p_trace,"< DQT marker\n");
fflush(p_trace);
#endif
return 0;
}
-
输出哈夫曼码表
static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) { unsigned int count, i; unsigned char huff_bits[17]; int length, index; length = be16_to_cpu(stream) - 2; stream += 2; /* Skip length */ #if TRACE fprintf(p_trace,"> DHT marker (length=%d)\n", length); fflush(p_trace); #endif while (length>0) { index = *stream++; /* We need to calculate the number of bytes 'vals' will takes */ huff_bits[0] = 0; count = 0; for (i=1; i<17; i++) { huff_bits[i] = *stream++; count += huff_bits[i]; } #if SANITY_CHECK if (count >= HUFFMAN_BITS_SIZE) snprintf(error_string, sizeof(error_string),"No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE); if ( (index &0xf) >= HUFFMAN_TABLES) snprintf(error_string, sizeof(error_string),"No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index&0xf); #if TRACE fprintf(p_trace,"Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, count); fflush(p_trace); #endif #if TRACE //码表输出 fprintf(p1_trace,"Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, count); fflush(p1_trace); #endif #endif if (index & 0xf0 ) build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]); else build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); length -= 1; length -= 16; length -= count; stream += count; }
static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table)
{
unsigned int i, j, code, code_size, val, nbits;
unsigned char huffsize[HUFFMAN_BITS_SIZE+1], *hz;
unsigned int huffcode[HUFFMAN_BITS_SIZE+1], *hc;
int next_free_entry;
/*
* Build a temp array
* huffsize[X] => numbers of bits to write vals[X]
*/
hz = huffsize;
for (i=1; i<=16; i++)
{
for (j=1; j<=bits[i]; j++)
*hz++ = i;
}
*hz = 0;
memset(table->lookup, 0xff, sizeof(table->lookup));
for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++)
table->slowtable[i][0] = 0;
/* Build a temp array
* huffcode[X] => code used to write vals[X]
*/
code = 0;
hc = huffcode;
hz = huffsize;
nbits = *hz;
while (*hz)
{
while (*hz == nbits)
{
*hc++ = code++;
hz++;
}
code <<= 1;
nbits++;
}
/*
* Build the lookup table, and the slowtable if needed.
*/
next_free_entry = -1;
for (i=0; huffsize[i]; i++)
{
val = vals[i];
code = huffcode[i];
code_size = huffsize[i];
//输出哈夫曼码表
#if TRACE
fprintf(p_trace,"val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
fflush(p_trace);
fprintf(p1_trace,"val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
fflush(p1_trace);
#endif
table->code_size[val] = code_size;
if (code_size <= HUFFMAN_HASH_NBITS)
{
/*
* Good: val can be put in the lookup table, so fill all value of this
* column with value val
*/
int repeat = 1UL<<(HUFFMAN_HASH_NBITS - code_size);
code <<= HUFFMAN_HASH_NBITS - code_size;
while ( repeat-- )
table->lookup[code++] = val;
}
else
{
/* Perhaps sorting the array will be an optimization */
uint16_t *slowtable = table->slowtable[code_size-HUFFMAN_HASH_NBITS-1];
while(slowtable[0])
slowtable+=2;
slowtable[0] = code;
slowtable[1] = val;
slowtable[2] = 0;
/* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */
}
}
}
输出AC、DC图像并统计其概率分布
-
保存AC、DC
void save_DC_AC(struct jdec_private *priv,int component) { int DC = (priv->component_infos[component]).DCT[0]; int AC = (priv->component_infos[component]).DCT[5]; DC_buffer[component][conut[component]]= DC; AC_buffer[component][conut[component]]= AC; //printf("%d\n",DC_buffer[component][conut[component]]); conut[component]++; DC_max[component] = DC_max[component] < DC ? DC : DC_max[component]; DC_min[component] = DC_min[component] < DC ? DC_min[component] : DC; AC_max[component] = DC_max[component] < AC ? AC : DC_max[component]; AC_min[component] = DC_min[component] < AC ? DC_min[component] : AC; }
-
初始化
void inti_DC_AC(struct jdec_private *priv) { for (i = 0; i < 3; i++) { AC_buffer[i] = (int*)malloc(priv->width * priv->height ); DC_buffer[i] = (int*)malloc(priv->width * priv->height ); conut[i] = 0; AC_max[i] = 0; AC_min[i] = 0; DC_max[i] = 0; DC_min[i] = 0; } }
实验结果
-
YUV文件
-
量化表及哈夫曼码表
-
DC、AC图像及概率分布
上一篇: ROS基础,创建工作空间,创建功能包