转:Tiny Jpeg Decoder (JPEG解码程序) 源代码分析

本文转自: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;   
}

你可能感兴趣的:(decode)