本文轉自:http://blog.csdn.net/leixiaohua1020/article/details/12617079
Tiny Jpeg Decoder是一個可以用於嵌入式系統的JPEG解碼器。也可以在Windows上編譯通過。在此分析一下它部分的源代碼,輔助學習JPEG解碼知識。
通過TinyJpeg可以將JPEG(*.jpg)文件解碼為YUV(*.yuv)或者RGB(*.tga)文件。
真正的解碼開始於convert_one_image()函數:
/** * Load one jpeg image, and decompress it, and save the result. */ int convert_one_image(LPVOID lparam,const char *infilename, const char *outfilename, int output_format) { FILE *fp; unsigned int length_of_file; unsigned int width, height; unsigned char *buf; struct jdec_private *jdec; unsigned char *components[3]; /* Load the Jpeg into memory */ fp = fopen(infilename, "rb"); if (fp == NULL) exitmessage("Cannot open filename\n"); length_of_file = filesize(fp); buf = (unsigned char *)malloc(length_of_file + 4); if (buf == NULL) exitmessage("Not enough memory for loading file\n"); fread(buf, length_of_file, 1, fp); fclose(fp); /* Decompress it */ //分配內存 jdec = tinyjpeg_init(); //傳入句柄-------------- jdec->dlg=(CSpecialVIJPGDlg *)lparam; if (jdec == NULL) exitmessage("Not enough memory to alloc the structure need for decompressing\n"); //解頭部 if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0) exitmessage(tinyjpeg_get_errorstring(jdec)); /* Get the size of the image */ //獲得圖像長寬 tinyjpeg_get_size(jdec, &width, &height); snprintf(error_string, sizeof(error_string),"Decoding JPEG image...\n"); //解碼實際數據 if (tinyjpeg_decode(jdec, output_format) < 0) exitmessage(tinyjpeg_get_errorstring(jdec)); /* * Get address for each plane (not only max 3 planes is supported), and * depending of the output mode, only some components will be filled * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane */ tinyjpeg_get_components(jdec, components); /* Save it */ switch (output_format) { case TINYJPEG_FMT_RGB24: case TINYJPEG_FMT_BGR24: write_tga(outfilename, output_format, width, height, components); break; case TINYJPEG_FMT_YUV420P: //開始寫入成YUV420P文件 write_yuv(outfilename, width, height, components); break; case TINYJPEG_FMT_GREY: //開始寫入成灰度文件 write_pgm(outfilename, width, height, components); break; } /* Only called this if the buffers were allocated by tinyjpeg_decode() */ //modify by lei! tinyjpeg_free(jdec); /* else called just free(jdec); */ free(buf); return 0; }
tinyjpeg_init()用於初始化:
/** * Allocate a new tinyjpeg decoder object. * * Before calling any other functions, an object need to be called. */ struct jdec_private *tinyjpeg_init(void) { struct jdec_private *priv; priv = (struct jdec_private *)calloc(1, sizeof(struct jdec_private)); if (priv == NULL) return NULL; priv->DQT_table_num=0; return priv; }
tinyjpeg_parse_header()用於解碼JPEG文件頭,可見函數前幾句主要驗證文件是否為JPEG文件:
/** * Initialize the tinyjpeg object and prepare the decoding of the stream. * * Check if the jpeg can be decoded with this jpeg decoder. * Fill some table used for preprocessing. */ int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size) { int ret; /* Identify the file */ //0x FF D8 //是否是JPEG格式文件? if ((buf[0] != 0xFF) || (buf[1] != SOI)) snprintf(error_string, sizeof(error_string),"Not a JPG file ?\n"); //是 char temp_str[MAX_URL_LENGTH]; sprintf(temp_str,"0x %X %X",buf[0],buf[1]); //JPEG格式文件固定的文件頭 //begin指針前移2字節 priv->stream_begin = buf+2; priv->stream_length = size-2; priv->stream_end = priv->stream_begin + priv->stream_length; //開始解析JFIF ret = parse_JFIF(priv, priv->stream_begin); return ret; }
parse_JFIF()用於解析各種標簽(SOF,SOS,DHT...):
//解各種不同的標簽 static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) { int chuck_len; int marker; int sos_marker_found = 0; int dht_marker_found = 0; const unsigned char *next_chunck; /* Parse marker */ //在Start of scan標簽之前 while (!sos_marker_found) { if (*stream++ != 0xff) goto bogus_jpeg_format; /* Skip any padding ff byte (this is normal) */ //跳過0xff字節 while (*stream == 0xff) stream++; //marker是跳過0xff字節后1個字節的內容 marker = *stream++; //chunk_len是marker后面2個字節的內容(大端模式需要轉換) //包含自身,但不包含0xff+marker2字節 chuck_len = be16_to_cpu(stream); //指向下一個chunk的指針 next_chunck = stream + chuck_len; //各種不同的標簽 switch (marker) { case SOF: //開始解析SOF if (parse_SOF(priv, stream) < 0) return -1; break; //Define quantization table case DQT: //開始解析DQT if (parse_DQT(priv, stream) < 0) return -1; break; case SOS: //開始解析SOS if (parse_SOS(priv, stream) < 0) return -1; sos_marker_found = 1; break; //Define Huffman table case DHT: //開始解析DHT if (parse_DHT(priv, stream) < 0) return -1; dht_marker_found = 1; break; case DRI: //開始解析DRI if (parse_DRI(priv, stream) < 0) return -1; break; default: #if TRACE_PARAM fprintf(param_trace,"> Unknown marker %2.2x\n", marker); fflush(param_trace); #endif break; } //解下一個segment stream = next_chunck; } if (!dht_marker_found) { #if TRACE_PARAM fprintf(param_trace,"No Huffman table loaded, using the default one\n"); fflush(param_trace); #endif build_default_huffman_tables(priv); } #ifdef SANITY_CHECK if ( (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor) || (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor)) snprintf(error_string, sizeof(error_string),"Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n"); if ( (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor) || (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor)) snprintf(error_string, sizeof(error_string),"Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n"); if ( (priv->component_infos[cCb].Hfactor!=1) || (priv->component_infos[cCr].Hfactor!=1) || (priv->component_infos[cCb].Vfactor!=1) || (priv->component_infos[cCr].Vfactor!=1)) snprintf(error_string, sizeof(error_string),"Sampling other than 1x1 for Cr and Cb is not supported"); #endif return 0; bogus_jpeg_format: #if TRACE_PARAM fprintf(param_trace,"Bogus jpeg format\n"); fflush(param_trace); #endif return -1; }
parse_SOF()用於解析SOF標簽:
注意:其中包含了部分自己寫的代碼,形如:
itoa(width,temp_str1,10); priv->dlg->AppendBInfo("SOF0","寬",temp_str1,"圖像的寬度");
這些代碼主要用於在解碼過程中提取一些信息,比如圖像寬,高,顏色分量數等等
static int parse_SOF(struct jdec_private *priv, const unsigned char *stream) { int i, width, height, nr_components, cid, sampling_factor; int Q_table; struct component *c; #if TRACE_PARAM fprintf(param_trace,"> SOF marker\n"); fflush(param_trace); #endif print_SOF(stream); height = be16_to_cpu(stream+3); width = be16_to_cpu(stream+5); nr_components = stream[7]; #if SANITY_CHECK if (stream[2] != 8) snprintf(error_string, sizeof(error_string),"Precision other than 8 is not supported\n"); if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT) snprintf(error_string, sizeof(error_string),"Width and Height (%dx%d) seems suspicious\n", width, height); if (nr_components != 3) snprintf(error_string, sizeof(error_string),"We only support YUV images\n"); if (height%16) snprintf(error_string, sizeof(error_string),"Height need to be a multiple of 16 (current height is %d)\n", height); if (width%16) snprintf(error_string, sizeof(error_string),"Width need to be a multiple of 16 (current Width is %d)\n", width); #endif char temp_str1[MAX_URL_LENGTH]={0}; itoa(width,temp_str1,10); priv->dlg->AppendBInfo("SOF0","寬",temp_str1,"圖像的寬度"); itoa(height,temp_str1,10); priv->dlg->AppendBInfo("SOF0","高",temp_str1,"圖像的高度"); itoa(nr_components,temp_str1,10); priv->dlg->AppendBInfo("SOF0","顏色分量數",temp_str1,"圖像的顏色分量數。一個字節,例如03,代表有三個分量,YCrCb"); itoa(stream[2],temp_str1,10); priv->dlg->AppendBInfo("SOF0","精度",temp_str1,"圖像的精度。一個字節,例如08,即精度為一個字節。"); stream += 8; for (i=0; i<nr_components; i++) { cid = *stream++; sampling_factor = *stream++; Q_table = *stream++; c = &priv->component_infos[i]; #if SANITY_CHECK c->cid = cid; if (Q_table >= COMPONENTS) snprintf(error_string, sizeof(error_string),"Bad Quantization table index (got %d, max allowed %d)\n", Q_table, COMPONENTS-1); #endif c->Vfactor = sampling_factor&0xf; c->Hfactor = sampling_factor>>4; c->Q_table = priv->Q_tables[Q_table]; //------------ char temp_str2[MAX_URL_LENGTH]={0}; sprintf(temp_str2,"垂直采樣因子【%d】",i); itoa(c->Hfactor,temp_str1,10); priv->dlg->AppendBInfo("SOF0",temp_str2,temp_str1,"顏色分量信息:每個分量有三個字節,第一個為分量的ID,01:Y 02:U 03:V;第二個字節高位為水平采樣因子,低位為垂直采樣因子。"); sprintf(temp_str2,"水平采樣因子【%d】",i); itoa(c->Hfactor,temp_str1,10); priv->dlg->AppendBInfo("SOF0",temp_str2,temp_str1,"顏色分量信息:每個分量有三個字節,第一個為分量的ID,01:Y 02:U 03:V;第二個字節高位為水平采樣因子,低位為垂直采樣因子。"); sprintf(temp_str2,"對應量化表ID【%d】",i); itoa((int)Q_table,temp_str1,10); priv->dlg->AppendBInfo("SOF0",temp_str2,temp_str1,"顏色分量信息:第三個字節代表這個分量對應的量化表ID,例如,Y對應的量化表ID索引值為00,而UV對應的量化表ID都為01,即它們共用一張量化表。"); //------------- #if TRACE_PARAM fprintf(param_trace,"Component:%d factor:%dx%d Quantization table:%d\n", cid, c->Hfactor, c->Hfactor, Q_table ); fflush(param_trace); #endif } priv->width = width; priv->height = height; #if TRACE_PARAM fprintf(param_trace,"< SOF marker\n"); fflush(param_trace); #endif return 0; }
parse_DHT()用於解析DHT標簽:
//解析DHT表 static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) { unsigned int count, i,j; unsigned char huff_bits[17]; int length, index; //------------------------------------------ char *temp; FILE *fp; //------------------------------------------ length = be16_to_cpu(stream) - 2; //跳過length字段 stream += 2; /* Skip length */ #if TRACE_PARAM fprintf(param_trace,"> DHT marker (length=%d)\n", length); fflush(param_trace); #endif while (length>0) { //跳過第1字節: //Huffman 表ID號和類型,高 4 位為表的類型,0:DC 直流;1:AC交流 //低四位為 Huffman 表 ID。 index = *stream++; /* We need to calculate the number of bytes 'vals' will takes */ huff_bits[0] = 0; count = 0; //不同長度 Huffman 的碼字數量:固定為 16 個字節,每個字節代表從長度為 1到長度為 16 的碼字的個數 for (i=1; i<17; i++) { huff_bits[i] = *stream++; //count記錄碼字的個數 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_PARAM fprintf(param_trace,"Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, count); fflush(param_trace); #endif #endif if (index & 0xf0 ){ //--------------------- char temp_str1[MAX_URL_LENGTH]={0}; char temp_str2[MAX_URL_LENGTH]={0}; temp=(char *)stream; //fp = fopen("DHT.txt", "a+"); //fwrite(temp, 16, 1, fp); for(j=0;j<16;j++){ //fprintf(fp,"%d ",temp[j]); sprintf(temp_str2,"%d ",temp[j]); strcat(temp_str1,temp_str2); } //fprintf(fp,"\n-----------------------\n"); //fclose(fp); //----------------------------------------------------- priv->dlg->AppendBInfo("DHT","定義霍夫曼表【交流系數表】",temp_str1,"Huffman表ID號和類型:1字節,高4位為表的類型,0:DC直流;1:AC交流 可以看出這里是直流表;低四位為Huffman表ID"); //----------------------------------------------------- //交流霍夫曼表 build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]); } else{ //--------------------- char temp_str1[MAX_URL_LENGTH]={0}; char temp_str2[MAX_URL_LENGTH]={0}; temp=(char *)stream; //fp = fopen("DHT.txt", "a+"); //fwrite(temp, 16, 1, fp); for(j=0;j<16;j++){ //fprintf(fp,"%d ",temp[j]); sprintf(temp_str2,"%d ",temp[j]); strcat(temp_str1,temp_str2); } //fprintf(fp,"\n-----------------------\n"); //fclose(fp); //----------------------------------------------------- priv->dlg->AppendBInfo("DHT","定義霍夫曼表【直流系數表】",temp_str1,"Huffman表ID號和類型:1字節,高4位為表的類型,0:DC直流;1:AC交流 可以看出這里是直流表;低四位為Huffman表ID"); //----------------------------------------------------- //直流霍夫曼表 build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); } length -= 1; length -= 16; length -= count; stream += count; } #if TRACE_PARAM fprintf(param_trace,"< DHT marker\n"); fflush(param_trace); #endif return 0; }
parse_DQT()用於解析DQT標簽:
//解析Define quantization table static int parse_DQT(struct jdec_private *priv, const unsigned char *stream) { int qi; float *table; const unsigned char *dqt_block_end; //------------------------------------------------ int j,k; char *temp; FILE *fp; //------------------------------------------------ #if TRACE_PARAM fprintf(param_trace,"> DQT marker\n"); fflush(param_trace); #endif //該Segment末尾 dqt_block_end = stream + be16_to_cpu(stream); //跳過標簽length(2字節) stream += 2; /* Skip length */ //沒到末尾 while (stream < dqt_block_end) { //跳過該Segment的第1個字節,QT信息 //precision: 00 (Higher 4 bit) //index: 00 (Lower 4 bit) //qi取1,第1張量化表(例如,亮度表),取2,第2張量化表(例如,色度表) 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指向jdec_private的Q_tables數組,為了在其中寫入數據 table = priv->Q_tables[qi]; //注意:一次搞定整張!寫入 //需要對數值進行變換!cos(k*PI/16) * sqrt(2) //這樣才能得到離散余弦變換的系數 build_quantization_table(table, stream); //---------------------------------------------------------- temp=(char *)stream; //fp = fopen("DQT.txt", "a+"); //fwrite(temp, 64, 1, fp); char temp_str1[MAX_URL_LENGTH]={0}; char temp_str2[MAX_URL_LENGTH]={0}; for(j=0;j<64;j++){ sprintf(temp_str2,"%d ",temp[j]); strcat(temp_str1,temp_str2); //fprintf(fp,"%d ",temp[j]); } //計數 char temp_str3[MAX_URL_LENGTH]={0}; sprintf(temp_str3,"量化表【%d】",priv->DQT_table_num); priv->dlg->AppendBInfo("DQT",temp_str3,temp_str1,"JPEG格式文件的量化表,一般來說第一張是亮度的,后面是色度的"); priv->DQT_table_num++; //fprintf(fp,"\n-----------------------\n"); //fclose(fp); #if TRACE_PARAM for(j=0;j<8;j++){ for(k=0;k<8;k++){ fprintf(param_trace,"%d ",temp[j*8+k]); } fprintf(param_trace,"\n"); } fprintf(fp,"\n-----------------------\n"); fflush(param_trace); #endif //---------------------------------------------------------- //完事了! stream += 64; } #if TRACE_PARAM fprintf(param_trace,"< DQT marker\n"); fflush(param_trace); #endif return 0; }
其他標簽的解析不一一列舉。
真正的解碼數據開始於tinyjpeg_decode()函數:
注意:本代碼中包含部分自己寫的代碼,用於提取DCT系數表,解碼后亮度數據表等數據。
/** * Decode and convert the jpeg image into @pixfmt@ image *解碼函數 * Note: components will be automaticaly allocated if no memory is attached. */ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) { unsigned int x, y, xstride_by_mcu, ystride_by_mcu; unsigned int bytes_per_blocklines[3], bytes_per_mcu[3]; decode_MCU_fct decode_MCU; const decode_MCU_fct *decode_mcu_table; const convert_colorspace_fct *colorspace_array_conv; convert_colorspace_fct convert_to_pixfmt; //------------------------------------------- FILE *fp; char *temp; int j,k; //------------------------------------------- if (setjmp(priv->jump_state)) return -1; /* To keep gcc happy initialize some array */ bytes_per_mcu[1] = 0; bytes_per_mcu[2] = 0; bytes_per_blocklines[1] = 0; bytes_per_blocklines[2] = 0; decode_mcu_table = decode_mcu_3comp_table; switch (pixfmt) { case TINYJPEG_FMT_YUV420P: colorspace_array_conv = convert_colorspace_yuv420p; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height); if (priv->components[1] == NULL) priv->components[1] = (uint8_t *)malloc(priv->width * priv->height/4); if (priv->components[2] == NULL) priv->components[2] = (uint8_t *)malloc(priv->width * priv->height/4); bytes_per_blocklines[0] = priv->width; bytes_per_blocklines[1] = priv->width/4; bytes_per_blocklines[2] = priv->width/4; bytes_per_mcu[0] = 8; bytes_per_mcu[1] = 4; bytes_per_mcu[2] = 4; break; case TINYJPEG_FMT_RGB24: colorspace_array_conv = convert_colorspace_rgb24; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3); bytes_per_blocklines[0] = priv->width * 3; bytes_per_mcu[0] = 3*8; break; case TINYJPEG_FMT_BGR24: colorspace_array_conv = convert_colorspace_bgr24; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3); bytes_per_blocklines[0] = priv->width * 3; bytes_per_mcu[0] = 3*8; break; case TINYJPEG_FMT_GREY: decode_mcu_table = decode_mcu_1comp_table; colorspace_array_conv = convert_colorspace_grey; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height); bytes_per_blocklines[0] = priv->width; bytes_per_mcu[0] = 8; break; default: #if TRACE_PARAM fprintf(param_trace,"Bad pixel format\n"); fflush(param_trace); #endif return -1; } xstride_by_mcu = ystride_by_mcu = 8; if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) { decode_MCU = decode_mcu_table[0]; convert_to_pixfmt = colorspace_array_conv[0]; #if TRACE_PARAM fprintf(param_trace,"Use decode 1x1 sampling\n"); fflush(param_trace); #endif } else if (priv->component_infos[cY].Hfactor == 1) { decode_MCU = decode_mcu_table[1]; convert_to_pixfmt = colorspace_array_conv[1]; ystride_by_mcu = 16; #if TRACE_PARAM fprintf(param_trace,"Use decode 1x2 sampling (not supported)\n"); fflush(param_trace); #endif } else if (priv->component_infos[cY].Vfactor == 2) { decode_MCU = decode_mcu_table[3]; convert_to_pixfmt = colorspace_array_conv[3]; xstride_by_mcu = 16; ystride_by_mcu = 16; #if TRACE_PARAM fprintf(param_trace,"Use decode 2x2 sampling\n"); fflush(param_trace); #endif } else { decode_MCU = decode_mcu_table[2]; convert_to_pixfmt = colorspace_array_conv[2]; xstride_by_mcu = 16; #if TRACE_PARAM fprintf(param_trace,"Use decode 2x1 sampling\n"); fflush(param_trace); #endif } resync(priv); /* Don't forget to that block can be either 8 or 16 lines */ bytes_per_blocklines[0] *= ystride_by_mcu; bytes_per_blocklines[1] *= ystride_by_mcu; bytes_per_blocklines[2] *= ystride_by_mcu; bytes_per_mcu[0] *= xstride_by_mcu/8; bytes_per_mcu[1] *= xstride_by_mcu/8; bytes_per_mcu[2] *= xstride_by_mcu/8; /* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */ //縱向 for (y=0; y < priv->height/ystride_by_mcu; y++) { //trace("Decoding row %d\n", y); priv->plane[0] = priv->components[0] + (y * bytes_per_blocklines[0]); priv->plane[1] = priv->components[1] + (y * bytes_per_blocklines[1]); priv->plane[2] = priv->components[2] + (y * bytes_per_blocklines[2]); //橫向(循環的寫法還不一樣?) for (x=0; x < priv->width; x+=xstride_by_mcu) { decode_MCU(priv); convert_to_pixfmt(priv); //DCT系數----------------------------------------------------------- //temp=(char *)priv->component_infos->DCT; //if(y==4&&x==xstride_by_mcu*3){ if(priv->dlg->m_vijpgoutputdct.GetCheck()==1){ fp = fopen("DCT系數表.txt", "a+"); //fwrite(temp,64,1,fp); fprintf(fp,"第%d行,第%d列\n",y,x/xstride_by_mcu); for(j=0;j<64;j++){ fprintf(fp,"%d ",priv->component_infos[cY].DCT[j]); } fprintf(fp,"\n"); fclose(fp); } #if TRACE_PARAM fprintf(param_trace,"\n第3行,第4列\n"); for(j=0;j<8;j++){ for(k=0;k<8;k++){ fprintf(param_trace,"%d ",priv->component_infos[cY].DCT[j*8+k]); } fprintf(param_trace,"\n"); } fprintf(fp,"\n-----------------------\n"); fflush(param_trace); #endif //} //解碼后系數(Y)--------------------------------------------------- //temp=(char *)priv->Y; //if(y==4&&x==xstride_by_mcu*3){ if(priv->dlg->m_vijpgoutputy.GetCheck()==1){ fp = fopen("解碼后Y系數表.txt", "a+"); //fwrite(temp,64*4,1,fp); fprintf(fp,"第%d行,第%d列\n",y,x/xstride_by_mcu); for(j=0;j<64*4;j++){ fprintf(fp,"%d ",priv->Y[j]); } fprintf(fp,"\n"); fclose(fp); } #if TRACE_PARAM fprintf(param_trace,"第3行,第4列\n"); for(j=0;j<8;j++){ for(k=0;k<8;k++){ fprintf(param_trace,"%d ",priv->Y[j*8+k]); } fprintf(param_trace,"\n"); } fprintf(fp,"\n-----------------------\n"); fflush(param_trace); #endif //} //------------------------------------------------------------------ priv->plane[0] += bytes_per_mcu[0]; priv->plane[1] += bytes_per_mcu[1]; priv->plane[2] += bytes_per_mcu[2]; if (priv->restarts_to_go>0) { priv->restarts_to_go--; if (priv->restarts_to_go == 0) { priv->stream -= (priv->nbits_in_reservoir/8); resync(priv); if (find_next_rst_marker(priv) < 0) return -1; } } } } #if TRACE_PARAM fprintf(param_trace,"Input file size: %d\n", priv->stream_length+2); fprintf(param_trace,"Input bytes actually read: %d\n", priv->stream - priv->stream_begin + 2); fflush(param_trace); #endif return 0; }