告诉大家一个关于原子开发板的JPEG解码代码的一个好消息。

2019-10-16 04:36发布

//初始化d_buffer的数据                
int InitTag(void)
{
 BOOL finish=FALSE;
 u8 id;
 short  llength;
 short  i,j,k;
 short  huftab1,huftab2;
 short  huftabindex;
 u8 hf_table_index;
 u8 qt_table_index;
 u8 comnum;//最长为256个字节  unsigned char  *lptemp;  
 short  colorount;
               
 lp=jpg_buffer+2;//跳过两个字节SOI(0xFF,0xD8 Start of Image)
 lp-=P_Cal(lp);           
 while (!finish)
 {   
  id=*(lp+1);//取出低位字节(高位在前,低位在后)
  lp+=2;     //跳过取出的字节
  lp-=P_Cal(lp);   
  switch (id)
  {
   case M_APP0: //JFIF APP0 segment marker (0xE0)
                //标志应用数据段的开始     
    llength=MAKEWORD(*(lp+1),*lp);//得到应用数据段长度 
    lp+=llength; 
    lp-=P_Cal(lp); 
    break;
   case M_DQT: //定义量化表标记(0xFF,0xDB)
    llength=MAKEWORD(*(lp+1),*lp);//(量化表长度)两个字节
    qt_table_index=(*(lp+2))&0x0f;//量化表信息bit 0..3: QT 号(0..3, 否则错误)
             //bit 4..7: QT 精度, 0 = 8 bit, 否则 16 bit
    lptemp=lp+3;        //n 字节的 QT, n = 64*(精度+1)
    //d_buffer里面至少有有512个字节的余度,这里最大用到128个字节
    if(llength<80)      //精度为 8 bit
    {
     for(i=0;i<64;i++)qt_table[qt_table_index]=(short)*(lptemp++); 
    }
    else        //精度为 16 bit
    {
     for(i=0;i<64;i++)qt_table[qt_table_index]=(short)*(lptemp++);  
                 qt_table_index=(*(lptemp++))&0x0f;
       for(i=0;i<64;i++)qt_table[qt_table_index]=(short)*(lptemp++);    
      }   
    lp+=llength;  //跳过量化表
    lp-=P_Cal(lp);  
    break;
   case M_SOF0:             //帧开始 (baseline JPEG 0xFF,0xC0)
     llength=MAKEWORD(*(lp+1),*lp);  //长度 (高字节, 低字节), 8+components*3
     ICINFO.ImgHeight=MAKEWORD(*(lp+4),*(lp+3));//图片高度 (高字节, 低字节), 如果不支持 DNL 就必须 >0
     ICINFO.ImgWidth=MAKEWORD(*(lp+6),*(lp+5)); //图片宽度 (高字节, 低字节), 如果不支持 DNL 就必须 >0
             comp_num=*(lp+7);//components 数量(1 u8), 灰度图是 1, YCbCr/YIQ 彩 {MOD}图是 3, CMYK 彩 {MOD}图是 4                          
    if((comp_num!=1)&&(comp_num!=3))return FUNC_FORMAT_ERROR;// 格式错误 
    if(comp_num==3)      //YCbCr/YIQ 彩 {MOD}图
    {
     comp_index[0]=*(lp+8);     //component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
       SampRate_Y_H=(*(lp+9))>>4; //水平采样系数
       SampRate_Y_V=(*(lp+9))&0x0f;//垂直采样系数
       YQtTable=(short *)qt_table[*(lp+10)];//通过量化表号取得量化表地址
 
     comp_index[1]=*(lp+11);     //component id
     SampRate_U_H=(*(lp+12))>>4;    //水平采样系数
       SampRate_U_V=(*(lp+12))&0x0f;   //垂直采样系数
       UQtTable=(short *)qt_table[*(lp+13)];//通过量化表号取得量化表地址
 
       comp_index[2]=*(lp+14);     //component id
       SampRate_V_H=(*(lp+15))>>4;    //水平采样系数
       SampRate_V_V=(*(lp+15))&0x0f;   //垂直采样系数
     VQtTable=(short *)qt_table[*(lp+16)];//通过量化表号取得量化表地址
      }
    else             //component id
    {
       comp_index[0]=*(lp+8);
     SampRate_Y_H=(*(lp+9))>>4;
       SampRate_Y_V=(*(lp+9))&0x0f;
       YQtTable=(short *)qt_table[*(lp+10)];//灰度图的量化表都一样
 
     comp_index[1]=*(lp+8);
       SampRate_U_H=1;
       SampRate_U_V=1;
       UQtTable=(short *)qt_table[*(lp+10)];
 
     comp_index[2]=*(lp+8);
     SampRate_V_H=1;
       SampRate_V_V=1;
       VQtTable=(short *)qt_table[*(lp+10)];
    }  
    lp+=llength; 
    lp-=P_Cal(lp);         
    break;
   case M_DHT: //定义哈夫曼表(0xFF,0xC4)            
    llength=MAKEWORD(*(lp+1),*lp);//长度 (高字节, 低字节)
    if (llength<0xd0)     // Huffman Table信息 (1 u8)
    {
     huftab1=(short)(*(lp+2))>>4;     //huftab1=0,1(HT 类型,0 = DC 1 = AC)
      huftab2=(short)(*(lp+2))&0x0f;   //huftab2=0,1(HT 号  ,0 = Y  1 = UV)
     huftabindex=huftab1*2+huftab2;  //0 = YDC 1 = UVDC 2 = YAC 3 = UVAC
      lptemp=lp+3;//!!! 
      //在这里可能出现余度不够,多于512字节,则会导致出错!!!!
     for (i=0; i<16; i++)             //16 bytes: 长度是 1..16 代码的符号数
      code_len_table[huftabindex]=(short)(*(lptemp++));//码长为i的码字个数  
     j=0;
     for (i=0; i<16; i++)    //得出HT的所有码字的对应值
     {
      if(code_len_table[huftabindex]!=0)
      {
       k=0;
       while(k<code_len_table[huftabindex])
       {
        code_value_table[huftabindex][k+j]=(short)(*(lptemp++));//最可能的出错地方
        k++;
       }
       j+=k; 
      }
     }
     i=0;
     while (code_len_table[huftabindex]==0)i++;   
     for (j=0;j<i;j++)
     {
      huf_min_value[huftabindex][j]=0;
      huf_max_value[huftabindex][j]=0;
     }
     huf_min_value[huftabindex]=0;
     huf_max_value[huftabindex]=code_len_table[huftabindex]-1;
     for (j=i+1;j<16;j++)
     {
      huf_min_value[huftabindex][j]=(huf_max_value[huftabindex][j-1]+1)<<1;
      huf_max_value[huftabindex][j]=huf_min_value[huftabindex][j]+code_len_table[huftabindex][j]-1;
     }
     code_pos_table[huftabindex][0]=0;
     for (j=1;j<16;j++)
        code_pos_table[huftabindex][j]=code_len_table[huftabindex][j-1]+code_pos_table[huftabindex][j-1];
     lp+=llength;    
     lp-=P_Cal(lp); 
    }//if  
    else
    {   
        hf_table_index=*(lp+2);
     lp+=2; 
     lp-=P_Cal(lp); 
     while (hf_table_index!=0xff)
     {
      huftab1=(short)hf_table_index>>4;     //huftab1=0,1
       huftab2=(short)hf_table_index&0x0f;   //huftab2=0,1
      huftabindex=huftab1*2+huftab2;
      lptemp=lp+1;
      colorount=0;
      for (i=0; i<16; i++)
      {
       code_len_table[huftabindex]=(short)(*(lptemp++));
       colorount+=code_len_table[huftabindex];
      }
      colorount+=17; 
      j=0;
      for (i=0; i<16; i++)
      {
       if(code_len_table[huftabindex]!=0)
       {
        k=0;
        while(k<code_len_table[huftabindex])
        {
         code_value_table[huftabindex][k+j]=(short)(*(lptemp++));//最可能出错的地方,余度不够
         k++;
        }
        j+=k;
       }
      }
      i=0;
      while (code_len_table[huftabindex]==0)i++;
      for (j=0;j<i;j++)
      {
       huf_min_value[huftabindex][j]=0;
       huf_max_value[huftabindex][j]=0;
      }
      huf_min_value[huftabindex]=0;
      huf_max_value[huftabindex]=code_len_table[huftabindex]-1;
      for (j=i+1;j<16;j++)
      {
       huf_min_value[huftabindex][j]=(huf_max_value[huftabindex][j-1]+1)<<1;
       huf_max_value[huftabindex][j]=huf_min_value[huftabindex][j]+code_len_table[huftabindex][j]-1;
      }
      code_pos_table[huftabindex][0]=0;
      for (j=1;j<16;j++)
       code_pos_table[huftabindex][j]=code_len_table[huftabindex][j-1]+code_pos_table[huftabindex][j-1];
      lp+=colorount; 
      lp-=P_Cal(lp); 
      hf_table_index=*lp;
     }  //while
    }  //else
    break;
   case M_DRI://定义差分编码累计复位的间隔
    llength=MAKEWORD(*(lp+1),*lp);
    restart=MAKEWORD(*(lp+3),*(lp+2)); 
    lp+=llength; 
    lp-=P_Cal(lp);
    break;
   case M_SOS:  //扫描开始 12字节
    llength=MAKEWORD(*(lp+1),*lp);
    comnum=*(lp+2);
    if(comnum!=comp_num)return FUNC_FORMAT_ERROR; //格式错误  
    lptemp=lp+3;//这里也可能出现错误
    //这里也可能出错,但是几率比较小了
    for (i=0;i<comp_num;i++)//每组件的信息
    {
     if(*lptemp==comp_index[0])
     {
      YDcIndex=(*(lptemp+1))>>4;   //Y 使用的 Huffman 表
      YAcIndex=((*(lptemp+1))&0x0f)+2;
     }
     else
     {
      UVDcIndex=(*(lptemp+1))>>4;   //U,V
      UVAcIndex=((*(lptemp+1))&0x0f)+2;
     }
     lptemp+=2;//comp_num<256,但是2*comp_num+3可能>=512
    }   
    lp+=llength; 
    lp-=P_Cal(lp); 
    finish=TRUE;
    break;
   case M_EOI:return FUNC_FORMAT_ERROR;//图片结束 标记    
   default:
     if ((id&0xf0)!=0xd0)
    {   
        llength=MAKEWORD(*(lp+1),*lp);
     lp+=llength; 
     lp-=P_Cal(lp);
    }
    else lp+=2;
    break;
    }  //switch
 } //while
 return FUNC_OK;
}
以上黄 {MOD}部分注销的,可以有两个好处:
1.节约代码空间。
2.可以显示更多的图片。(原子提供的原代码只能显示:原子提供的开发板特定图片和BMP图片,到别的地方拷来的图片则不能显示)。如果你注销掉上面的黄 {MOD}代码,可以显示所有的JPG和BMP图片。
3.显示速度变快了。 注销理由:
注销掉的是if内的代码:if内的代码有个Huffman表长度限制。而else内的代码则没有Huffman表长的限制。那么else的代码可以包容if的条件。所以if内的代码多余。 另:我觉得case M-HDT内的下面代码,太啰嗦。原因:huffman树的权值表内,所有的在原子提供的代码处理上,没有和码数表有关系,所以,根本不需要这么啰嗦处理。如下:
 j=0;
 for (i=0; i<16; i++) //得出HT的所有码字的对应值
 {
  if(code_len_table[huftabindex]!=0)
  {
   k=0;
   while(k<code_len_table[huftabindex])
   {
    code_value_table[huftabindex][k+j]=(short)(*(lptemp++));//最可能的出错地方
    k++;
   }
   j+=k; 
  }
 }
我的处理是:
 j=0;
 for(i=0;i<16;i++)
 {
  j+=code_len_table[huftabindex];
 }/*本段也可以让j=【本Tag段的长度-19来实现,更简单:2Byte指本段长度,1B码表类型和编号,16B码数表,这三项是固定的。】*/
 for(i=0;i<j;i++)
 {
  code_value_table[huftabindex]=(short)(*(pTemp++));/*直接全部读入即可。*/
 }
 因为else段内的频繁指针处理,保证了1024的jpg_buffer能足够容纳任意长的Huffman表。(这里的任意长指一个huffman表权值,一般不会太长,即使太长,也可以用指针处理来实现。) 以上修改后,所有的JPG和BMP都能显示,不管他们的像素的宽度是否是1024*768还是什么,都能更快处理并显示出来。 我原来自己拷一些图片用原子代码来显示,结果显示空白。经过上述处理后,所有的JPG和BMP图片都能显示了...........
我的实验做到了,你的呢?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
14条回答
mygod
1楼-- · 2019-10-17 04:52
真正速度快的就是FATFS作者写的那个,以空间换时间的解码方式。感觉比解码BMP还要快
summer
2楼-- · 2019-10-17 09:17
MARK
风溪香士
3楼-- · 2019-10-17 13:28
这是哪个文件里的?
dong
4楼-- · 2019-10-17 16:38
好贴,学习!
默默莱
5楼-- · 2019-10-17 21:52
 精彩回答 2  元偷偷看……
STM32VBT6
6楼-- · 2019-10-17 23:15
mark~~~

一周热门 更多>