Chinaunix首页 | 论坛 | 博客
  • 博客访问: 517616
  • 博文数量: 187
  • 博客积分: 3011
  • 博客等级: 中校
  • 技术积分: 2092
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-28 17:08
文章分类

全部博文(187)

文章存档

2011年(1)

2010年(8)

2009年(178)

我的朋友

分类: LINUX

2009-10-07 22:53:46

xtalker????  
  JPEG   简易文档  
     
     
  JPEG   简易文档   V2.0    
  ------------------------------  
  最后修订   2000.3.4  
  作者:   云风  
  Email:   cloudwu@263.net  
  Homepage:   ~cloudwu  
   
  写在前面  
  --------  
  1.   为什么写这个文档?  
  云风想对   JPEG/MPEG   有一个系统的研究,   但是苦于找到好的资料.   而英文  
  水平又不怎样,   所以在学习的过程,   将已经了解了的东西记录下来.   方便  
  自己在编写代码的时候查阅.   而且正式的   JPEG   文档非常复杂,   打印出来  
  也有厚厚一本,   就是英文底子比较好的朋友,   看起来也会头痛的.   这里写  
  一份精简版本,   对大家都有好处的.   同时希望   inet   上中文资料越来越丰富.  
   
  2.   通过阅读这份文档期望达到的目的.  
  能够对   JPEG   图形压缩有一定感性的认识,   但其数学原理不需要搞清.   能够  
  通过这,   开始写自己的编码/解码程序.   或者看懂以有的代码.   提高对有损图  
  形压缩有进一步了解.   自己能够改良   JPEG,   比如增加透明色的支持,   加快    
  JPEG   的解码速度.  
   
  3.   为什么用文本格式写,   而不用   HTML?  
  个人喜好.   不喜欢有格式编排的电子文档.   纯文本能够更广泛的使用,   而不  
  需要HTML   浏览器.  
   
  4.   读者需要为这个文档付出什么吗?  
  您可以自由使用它.   但是由于您是无偿使用,   所以作者不对可能出现的错误  
  和问题担负任何责任.   关于相关问题,可以来   email   探讨,   但由于精力有限,    
  不保证回信.   如果你对这有不满意的地方,   云风不接受任何批评.  
   
  5.   能够转载这篇文档吗?  
  欢迎您随意转载,   但不得用它赢利.   而且转载请保留其内容完整.   如果您为它  
  制作了诸如   HTML   等别的格式的版本,   也必须同时保留一份纯文本版在一起.  
   
  JPEG   压缩简介  
  -------------  
   
  1.   色彩模型  
   
  JPEG   的图片使用的是   YCrCb   颜色模型,   而不是计算机上最常用的   RGB.   关于  
  色彩模型,   这里不多阐述.   只是说明,   YCrCb   模型更适合图形压缩.   因为人眼  
  对图片上的亮度   Y   的变化远比色度   C   的变化敏感.   我们完全可以每个点保存  
  一个   8bit   的亮度值,   每   2x2   个点保存一个   Cr   Cb   值,   而图象在肉眼中的感  
  觉不会起太大的变化.   所以,   原来用   RGB   模型,   4   个点需要   4x3=12   字节.    
  而现在仅需要   4+2=6   字节;   平均每个点占   12bit.   当然   JPEG   格式里允许每  
  个点的   C   值都记录下来;   不过   MPEG   里都是按   12bit   一个点来存放的,   我们  
  简写为   YUV12.  
   
  [R   G   B]   ->   [Y   Cb   Cr]   转换  
  -------------------------  
   
  (R,G,B   都是   8bit   unsigned)  
   
  |   Y   |   |   0.299   0.587   0.114   |   |   R   |   |   0   |  
  |   Cb   |   =   |-   0.1687   -   0.3313   0.5   |   *   |   G   |   +   |128|  
  |   Cr   |   |   0.5   -   0.4187   -   0.0813|   |   B   |   |128|  
   
  Y   =   0.299*R   +   0.587*G   +   0.114*B   (亮度)  
  Cb   =   -   0.1687*R   -   0.3313*G   +   0.5   *B   +   128  
  Cr   =   0.5   *R   -   0.4187*G   -   0.0813*B   +   128  
   
  [Y,Cb,Cr]   ->   [R,G,B]   转换  
  -------------------------  
   
  R   =   Y   +   1.402   *(Cr-128)  
  G   =   Y   -   0.34414*(Cb-128)   -   0.71414*(Cr-128)  
  B   =   Y   +   1.772   *(Cb-128)  
   
  一般,   C   值   (包括   Cb   Cr)   应该是一个有符号的数字,   但这里被处理过了,    
  方法是加上了   128.   JPEG   里的数据都是无符号   8bit   的.  
   
  2.   DCT   (离散余弦变换)  
   
  JPEG   里,   要对数据压缩,   先要做一次   DCT   变换.   DCT   变换的原理,   涉及到  
  数学知识,   这里我们不必深究.   反正和傅立叶变换(学过高数的都知道)   是差  
  不多了.   经过这个变换,   就把图片里点和点间的规律呈现出来了,   更方便压缩  
  .JPEG   里是对每   8x8   个点为一个单位处理的.   所以如果原始图片的长宽不是    
  8   的倍数,   都需要先补成   8   的倍数,   好一块块的处理.   另外,   记得刚才我说的  
    Cr   Cb   都是   2x2   记录一次吗?   所以大多数情况,   是要补成   16x16   的整数块.  
  按从左到右,   从上到下的次序排列   (和我们写字的次序一样).   JPEG   里是对  
    Y   Cr   Cb   分别做   DCT   变换的.   这里进行   DCT   变换  
  的   Y,   Cr,   Cb   值的范围都是   -128~127.   (Y   被减去   128)  
   
  JPEG   编码时使用的是   Forward   DCT   (FDCT)   解码时使用的   Inverse   DCT    
  (IDCT)下面给出公式:  
   
  FDCT:  
  7   7   2*x+1   2*y+1  
  F(u,v)   =   alpha(u)*alpha(v)*   sum   sum   f(x,y)   *   cos   (-------   *u*PI)*   cos   (------   *v*PI)  
  x=0   y=0   16   16  
   
  u,v   =   0,1,...,7  
   
  {   1/sqrt(8)   (u==0)  
  alpha(u)   =   {  
  {   1/2   (u!=0)  
   
  IDCT:  
  7   7   2*x+1   2*y+1  
  f(x,y)   =   sum   sum   alpha(u)*alpha(v)*F(u,v)*cos   (-------   *u*PI)*   cos   (------   *v*PI)  
  u=0   v=0   16   16  
   
  x,y=0,1...7  
   
  这个步骤很花时间,   另外有种   AA&N   优化算法,   大家可以去   inet   自己找  
  一下.   在   Intel   主页上可以找到   AA&N   IDCT   的   MMX   优化代码.   (   Intel    
  主页上的代码,输入数据为   12.4   的定点数,   输入矩阵需要转置   90   度)  
   
  3.   重排列   DCT   结果  
  DCT   将一个   8x8   的数组变换成另一个   8x8   的数组.   但是内存里所有数据都  
  是线形存放的,   如果我们一行行的存放这   64   个数字,   每行的结尾的点和下  
  行开始的点就没有什么关系,   所以   JPEG   规定按如下次序整理   64   个数字.  
   
  0,   1,   5,   6,14,15,27,28,  
  2,   4,   7,13,16,26,29,42,  
  3,   8,12,17,25,30,41,43,  
  9,11,18,24,31,40,44,53,  
  10,19,23,32,39,45,52,54,  
  20,22,33,38,46,51,55,60,  
  21,34,37,47,50,56,59,61,  
  35,36,48,49,57,58,62,63  
   
  这样数列里的相邻点在图片上也是相邻的了.  
   
  4.   量化  
  对于前面得到的   64   个空间频率振幅值,   我们将对它们作幅度分层量化操作.  
  方法就是分别除以量化表里对应值并四舍五入.  
   
  for   (i   =   0   ;   i<=63;   i++   )  
  vector[i]   =   (int)   (vector[i]   /   quantization_table[i]   +   0.5)  
   
  下面有张   JPEG   标准量化表.   (按上面同样的弯曲次序排列)  
   
  16   11   10   16   24   40   51   61  
  12   12   14   19   26   58   60   55  
  14   13   16   24   40   57   69   56  
  14   17   22   29   51   87   80   62  
  18   22   37   56   68   109   103   77  
  24   35   55   64   81   104   113   92  
  49   64   78   87   103   121   120   101  
  72   92   95   98   112   100   103   99  
   
  这张表依据心理视觉阀制作,   对   8bit   的亮度和色度的图象的处理效果不错.  
  当然我们可以使用任意的量化表.   量化表是定义在   jpeg   的   DQT   标记后.   一  
  般为   Y   值定义一个,   为   C   值定义一个.    
  量化表是控制   JPEG   压缩比的关键.   这个步骤除掉了一些高频量,   损失了很高  
  细节.   但事实上人眼对高空间频率远没有低频敏感.所以处理后的视觉损失很小.  
  另一个重要原因是所有的图片的点与点之间会有一个色彩过渡的过程.   大量的图  
  象信息被包含在低空间频率中.   经过量化处理后,   在高空间频率段,   将出现大量  
  连续的零.  
  注意,   量化后的数据有可能超过   2   byte   有符号整数的处理范围.  
   
  5.   0   RLC   编码  
  现在我们矢量中有许多连续的   0.   我们可以使用   RLC   来压缩掉这些   0.   这里我们  
  将跳过第一个矢量   (后面将解释为什么)   因为它的编码比较特别.   假设有一组矢量  
  (64   个的后   63   个)   是57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0,   0   ,   0   ,0   ,   0,..,0  
  经过   RLC   压缩后就是(0,57)   ;   (0,45)   ;   (4,23)   ;   (1,-30)   ;   (0,-16)   ;   (2,1)   ;  
    EOBEOB   是一个结束标记,   表示后面都是   0   了.   实际上,   我们用   (0,0)   表示   EOB  
  但是,   如果这组数字不以   0   结束,   那么就不需要   EOB.由于后面   huffman   编码的要求,    
  每组数字前一个表示   0   的数量的必须是   4   bit,就是说,   只能是   0~15,   所以我们实际  
  这样编码:  
  (0,57)   ;   (15,0)   (2,3)   ;   (4,2)   ;   (15,0)   (15,0)   (1,895)   ,   (0,0)  
  注意   (15,0)   表示了   16   个连续的   0.  
   
  6.   huffman   编码  
  为了提高储存效率,   JPEG   里并不直接保存数值,   而是将数值按位数分成   16   组:  
   
  数值   组   实际保存值  
  0   0   -  
  -1,1   1   0,1  
  -3,-2,2,3   2   00,01,10,11  
  -7,-6,-5,-4,4,5,6,7   3   000,001,010,011,100,101,110,111  
  -15,..,-8,8,..,15   4   0000,..,0111,1000,..,1111  
  -31,..,-16,16,..,31   5   00000,..,01111,10000,..,11111  
  -63,..,-32,32,..,63   6   .  
  -127,..,-64,64,..,127   7   .  
  -255,..,-128,128,..,255   8   .  
  -511,..,-256,256,..,511   9   .  
  -1023,..,-512,512,..,1023   10   .  
  -2047,..,-1024,1024,..,2047   11   .  
  -4095,..,-2048,2048,..,4095   12   .  
  -8191,..,-4096,4096,..,8191   13   .  
  -16383,..,-8192,8192,..,16383   14   .  
  -32767,..,-16384,16384,..,32767   15   .  
   
  还是来看前面的例子:  
  (0,57)   ;   (0,45)   ;   (4,23)   ;   (1,-30)   ;   (0,-8)   ;   (2,1)   ;   (0,0)  
  只处理每对数右边的那个:  
  57   是第   6   组的,   实际保存值为   111001   ,   所以被编码为   (6,111001)  
  45   ,   同样的操作,   编码为   (6,101101)  
  23   ->   (5,10111)  
  -30   ->   (5,00001)  
  -8   ->   (4,0111)  
  1   ->   (1,1)  
   
  前面的那串数字就变成了:  
  (0,6),   111001   ;   (0,6),   101101   ;   (4,5),   10111;   (1,5),   00001;   (0,4)   ,   0111   ;  
  (2,1),   1   ;   (0,0)  
   
  括号里的数值正好合成一个字节.   后面被编码的数字表示范围是   -32767..32767.合  
  成的字节里,   高   4   位是前续   0   的个数,   低   4   位描述了后面数字的位数.  
   
  继续刚才的例子,   如果   06   的   huffman   编码为   111000  
  69   =   (4,5)   ---   1111111110011001  
  21   =   (1,5)   ---   11111110110  
  4   =   (0,4)   ---   1011  
  33   =   (2,1)   ---   11011  
  0   =   EOB   =   (0,0)   ---   1010  
   
  那么最后对于前面的例子表示的   63   个系数   (记得我们将第一个跳过了吗?)   按位流  
  写入   JPG   文件中就是这样的:  
  111000   111001   111000   101101   1111111110011001   10111   11111110110   00001  
  1011   0111   11011   1   1010  
   
  DC   的编码  
  ---------  
  记得刚才我们跳过了每组   64   个数据的第一个吧,   DC   就是指的这个数字   (后面   63  
    个简称   AC)   代入前面的   FDCT   公式可以得到  
  c(0,0)   7   7    
  DC   =   F(0,0)   =   ---------   *   sum   sum   f(x,y)   *   cos   0   *   cos   0   其中   c(0,0)   =   1/2  
  4   x=0   y=0    
   
  1   7   7    
  =   ---   *   sum   sum   f(x,y)    
  8   x=0   y=0    
   
  即一块图象样本的平均值.   就是说,   它包含了原始   8x8   图象块里的很多能量.    
  (通常会得到一个很大的数值)  
   
  JPEG   的作者指出连续块的   DC   率之间有很紧密的联系,   因此他们决定对   8x8  
    块的DC   值的差别进行编码.   (Y,   Cb,   Cr   分别有自己的   DC)  
   
  Diff   =   DC(i)   -   DC(i-1)  
   
  所以这一块的   DC(i)   就是:   DC(i)   =   DC(i-1)   +   Diff  
   
  JPG   从   0   开始对   DC   编码,   所以   DC(0)=0.   然后再将当前   Diff   值加在上一个值  
  上得到当前值.  
   
  下面再来看看上面那个例子:   (记住我们保存的   DC   是和上一块   DC   的差值   Diff)  
   
  例如上面例子中,   Diff   是   -511,   就编码成(9,   000000000)  
   
  如果   9   的   Huffman   编码是   1111110   (在   JPG   文件中,   一般有两个   Huffman   表,    
  一个是   DC   用,   一个是   AC   用)   那么在   JPG   文件中,   DC   的   2   进制表示为  
   
  1111110   000000000  
   
  它将放在   63   个   AC   的前面,   上面上个例子的最终   BIT   流如下:  
   
  1111110   000000000   111000   111001   111000   101101   1111111110011001   10111  
  11111110110   00001   1011   0111   11011   1   1010  
   
  下面简单叙述一下针对一个数据单元的图片   Y   的解码  
  -----------------------------------------------  
   
  在整个图片解码的开始,   你需要先初始化   DC   值为   0.  
   
  1)   先解码   DC:  
  a)   取得一个   Huffman   码   (使用   Huffman   DC   表)  
  b)   Huffman解码,   看看后面的数据位数   N  
  c)   取得   N   位,   计算   Diff   值  
  d)   DC   +   =   Diff  
  e)   写入   DC   值:   "   vector[0]=DC   "  
   
  2)   解码   63   个   AC:  
   
  -------   循环处理每个   AC   直到   EOB   或者处理到   64   个   AC  
   
  a)   取得一个   Huffman   码   (使用   Huffman   AC   表)  
  b)   Huffman   解码,   得到   (前面   0   数量,   组号)  
  [记住:   如果是(0,0)   就是   EOB   了]  
   
  c)   取得   N   位(组号)   计算   AC  
  d)   写入相应数量的   0  
  e)   接下来写入   AC  
  -----------------  
   
  下一步的解码  
  ------------  
  上一步我们得到了   64   个矢量.   下面我们还需要做一些解码工作:  
   
  1)   反量化   64   个矢量   :   "for   (i=0;i<=63;i++)   vector[i]*=quant[i]"   (注意防止溢出)  
  2)   重排列   64   个矢量到   8x8   的块中  
  3)   对   8x8   的块作   IDCT  
   
  对   8x8   块的   (Y,Cb,Cr)   重复上面的操作   [Huffman   解码,   步骤   1),   2),   3)]  
   
  4)   将所有的   8bit   数加上   128  
  5)   转换   YCbCr   到   RGB  
   
  JPG   文件(Byte   级)里怎样组织图片信息  
  -----------------------------------  
  注意   JPEG/JFIF   文件格式使用   Motorola   格式,   而不是   Intel   格式,    
  就是说,   如果是一个字的话,   高字节在前,   低字节在后.  
   
  JPG   文件是由一个个段   (segments)   构成的.   每个段长度   <=65535.   每个段从  
  一个标记字开始.   标记字都是   0xff   打头的,   以非   0   字节和   0xFF   结束.   例如    
  'FFDA'   ,   'FFC4',   'FFC0'.   每个标记有它特定意义,   这是由第2字节指明的.    
  例如,   SOS   (StartOf   Scan   =   'FFDA')   指明了你应该开始解码.   另一个标记  
    DQT   (Define   QuantizationTable   =   0xFFDB)   就是说它后面有   64   字节的  
    quantization   表  
   
  在处理   JPG   文件时,   如果你碰到一个   0xFF,   而它后面的字节不是   0,   并且这个  
  字节没有意义.   那么你遇到的   0xFF   字节必须被忽略.   (一些   JPG   里,   常用用    
  0xFF   做某些填充用途)   如果你在做   huffman   编码时碰巧产生了一个   0xFF,   那  
  么就用   0xFF   0x00   代替.   就是说在   jpeg   图形解码时碰到   FF00   就把它当作   FF   处理.  
   
  另外在   huffman   编码区域结束时,   碰到几个   bit   没有用的时候,   应该用   1   去填充.  
  然后后面跟   FF.  
   
  下面是几个重要的标记  
  --------------------  
   
  SOI   =   Start   Of   Image   =   'FFD8'  
  这个标记只在文件开始出现一次  
  EOI   =   End   Of   Image   =   'FFD9'  
  JPG   文件都以   FFD9   结束  
   
  RSTi   =   FFDi   (   i   =   0..7)   [   RST0   =   FFD0,   RST7=FFD7]  
  =   复位标记  
  通常穿插在数据流里,   我想是担心   JPG   解码出问题吧(应该配合   DRI   使用).  
    不过很多   JPG   都不使用它  
   
  (SOS   ---   RST0   ---   RST1   --   RST2   --...  
  ...--   RST6   ---   RST7   --   RST0   --...)  
   
  ----  
  标记  
  ----  
  下面是必须处理的标记  
   
  SOF0   =   Start   Of   Frame   0   =   FFC0  
  SOS   =   Start   Of   Scan   =   FFDA  
  APP0   =   it's   the   marker   used   to   identify   a   JPG   file   which   uses   the   JFIF  
  specification   =   FFE0  
  COM   =   Comment   =   FFFE  
  DNL   =   Define   Number   of   Lines   =   FFDC  
  DRI   =   Define   Restart   Interval   =   FFDD  
  DQT   =   Define   Quantization   Table   =   FFDB  
  DHT   =   Define   Huffman   Table   =   FFC4  
   
  JPG   文件中   Haffman   表的储存  
  ---------------------------  
  JPEG   里定义了一张表来描述   Haffman   树.   定义在   DHT   标记后面.   注意:    
  Haffman   代码的长度限制在   16bit   内.  
   
  一般一个   JPG   文件里会有   2   类   Haffman   表:   一个用于   DC   一个用于   AC    
  (实际有   4个表,   亮度的   DC,AC   两个,   色度的   DC,AC   两个)  
   
  这张表是这样保存的:  
  1)   16   字节:  
  第   i   字节表示了   i   位长的   Huffman   代码的个数   (i=   1   到   16)  
   
  2)   这表的长度   (字节数)   =   这   16   个数字之和  
  现在你可以想象这张表怎么存放的吧?   对应字节就是对应   Haffman   代码  
  等价数字.   我不多解释,   这需要你先了解   Haffman   算法.   这里只举一个例子:  
   
  Haffman   表的表头是   0,2,3,1,1,1,0,1,0,0,0,0,0,0,0,0  
  就是说长度为   1   的代码没有长度为   2   的代码为   00  
  01  
  长度为   3   的代码是   100  
  101  
  110  
  长度为   4   的代码是   1110  
  长度为   5   的代码是   11110  
  长度为   6   的代码是   111110  
  长度为   7   的代码没有   (如果有一个的话应该是   1111110)  
  长度为   8   的代码是   11111100  
  .....  
  后面都没有了.  
   
  如果表下面的数据是  
  45   57   29   17   23   25   34   28  
   
  就是说  
  45   =   00  
  57   =   01  
  29   =   100  
  17   =   101  
  23   =   110  
  等等...  
   
  如果你懂   Haffman   编码,   这些不难理解  
   
  采样系数  
  --------  
  下面讲解的都是真彩   JPG   的解码,   灰度   JPG   的解码很简单,   因为图形中  
  只有亮度信息.   而彩色图形由   (Y,   Cr,   Cb)   构成,   前面提到过,   Y   通常是  
  每点采样一次,   而   Cr,Cb   一般是   2x2   点采样一次,   当然也有的   JPG   是逐  
  点采样,   或者每两点采样   (横向两点,   纵向一点)   采样系数均被定义成对  
  比最高采样系数的相对值.    
   
  一般情况   (即:   Y   逐点采样,   Cr   Cb   每   2x2   点一次)   下:   Y   有最高的采样  
  率,   横向采样系数HY=2   纵向采样系数   VY=2;   Cb   的横向采样系数   HCb=1,    
  纵向采样系数   VCb=1;同样   HCr=1,   VCr=1  
   
  在   Jpeg   里,   8x8   个原始数据,   经过   RLC,   Huffman   编码后的一串数据流称为一个    
  Data   Unit   (DU)   JPG   里按   DU   为单位的编码次序如下:  
   
  1)   for   (counter_y=1;counter_y<=VY;counter_y++)  
  for   (counter_x=1;counter_x<=HY;counter_x++)  
  {   对   Y   的   Data   Unit   编码   }  
   
  2)   for   (counter_y=1;counter_y<=VCb   ;counter_y++)  
  for   (counter_x=1;counter_x<=HCb;counter_x++)  
  {   对   Cb   的   Data   Unit   编码   }  
   
  3)   for   (counter_y=1;counter_y<=VCr;counter_y++)  
  for   (counter_x=1;counter_x<=HCr;counter_x++)  
  {   对   Cr   的   Data   Unit   编码   }  
   
  按我上面的例子:   (HY=2,   VY=2   ;   HCb=VCb   =1,   HCr,VCr=1)   就是这样一个次  
  序YDU,YDU,YDU,YDU,CbDU,CrDU  
  这些就描述了一块   16x16   的图形.   16x16   =   (Hmax*8   x   Vmax*8)   这里    
  Hmax=HY=2   Vmax=VY=2  
   
  一个   (Hmax*8,Vmax*8)   的块被称作   MCU   (Minimun   Coded   Unix)   前面例子  
  中一个   MCU   =   YDU,YDU,YDU,YDU,CbDU,CrDU  
   
  如果   HY   =1,   VY=1  
  HCb=1,   VCb=1  
  HCr=1,   VCr=1  
  这样   (Hmax=1,Vmax=1),   MCU   只有   8x8   大,   MCU   =   YDU,CbDU,CrDU  
   
  对于灰度   JPG,   MCU   只有一个   DU   (MCU   =   YDU)  
   
  JPG   文件里,   图象的每个组成部分的采样系数定义在   SOF0   (FFC0)   标记后  
   
  简单说一下   JPG   文件的解码  
  -------------------------  
  解码程序先从   JPG   文件中读出采样系数,   这样就知道了   MCU   的大小,   算出整  
  个图象有几个   MCU.   解码程序再循环逐个对   MCU   解码,   一直到检查到   EOI   标  
  记.   对于每个MCU,   按正规的次序解出每个   DU,   然后组合,   转换成   (R,G,B)   就   OK   了  
   
  附:JPEG   文件格式  
  ~~~~~~~~~~~~~~~~  
   
  -   文件头   (2   bytes):   $ff,   $d8   (SOI)   (JPEG   文件标识)  
  -   任意数量的段   ,   见后面  
  -   文件结束   (2   bytes):   $ff,   $d9   (EOI)  
   
  段的格式:  
  ~~~~~~~~~  
   
  -   header   (4   bytes):  
  $ff   段标识  
  n   段的类型   (1   byte)  
  sh,   sl   该段长度,   包括这两个字节,   但是不包括前面的   $ff   和   n.  
  注意:   长度不是   intel   次序,   而是   Motorola   的,   高字节在前,  
  低字节在后!  
  -   该段的内容,   最多   65533   字节  
   
  注意:  
  -   有一些无参数的段   (下面那些前面注明星号的)  
  这些段没有长度描述   (而且没有内容),   只有   $ff   和类型字节.  
  -   段之间无论有多少   $ff   都是合法的,   必须被忽略掉.  
   
  段的类型:  
  ~~~~~~~~~  
   
  *TEM   =   $01   可以忽略掉  
   
  SOF0   =   $c0   帧开始   (baseline   JPEG),   细节附后  
  SOF1   =   $c1   dito  
  SOF2   =   $c2   通常不支持  
  SOF3   =   $c3   通常不支持  
   
  SOF5   =   $c5   通常不支持  
  SOF6   =   $c6   通常不支持  
  SOF7   =   $c7   通常不支持  
   
  SOF9   =   $c9   arithmetic   编码(Huffman   的一种扩展算法),   通常不支持  
  SOF10   =   $ca   通常不支持  
  SOF11   =   $cb   通常不支持  
   
  SOF13   =   $cd   通常不支持  
  SOF14   =   $ce   通常不支持  
  SOF14   =   $ce   通常不支持  
  SOF15   =   $cf   通常不支持  
   
  DHT   =   $c4   定义   Huffman   Table,   细节附后  
  JPG   =   $c8   未定义/保留   (引起解码错误)  
  DAC   =   $cc   定义   Arithmetic   Table,   通常不支持  
   
  *RST0   =   $d0   RSTn   用于   resync,   通常被忽略  
  *RST1   =   $d1  
  *RST2   =   $d2  
  *RST3   =   $d3  
  *RST4   =   $d4  
  *RST5   =   $d5  
  *RST6   =   $d6  
  *RST7   =   $d7  
   
  SOI   =   $d8   图片开始  
  EOI   =   $d9   图片结束  
  SOS   =   $da   扫描行开始,   细节附后  
  DQT   =   $db   定义   Quantization   Table,   细节附后  
  DNL   =   $dc   通常不支持,   忽略  
  DRI   =   $dd   定义重新开始间隔,   细节附后  
  DHP   =   $de   忽略   (跳过)  
  EXP   =   $df   忽略   (跳过)  
   
  APP0   =   $e0   JFIF   APP0   segment   marker   (细节略)  
  APP15   =   $ef   忽略  
   
  JPG0   =   $f0   忽略   (跳过)  
  JPG13   =   $fd   忽略   (跳过)  
  COM   =   $fe   注释,   细节附后  
   
  其它的段类型都保留必须跳过  
   
  SOF0:   Start   Of   Frame   0:  
  ~~~~~~~~~~~~~~~~~~~~~~~  
   
  -   $ff,   $c0   (SOF0)  
  -   长度   (高字节,   低字节),   8+components*3  
  -   数据精度   (1   byte)   每个样本位数,   通常是   8   (大多数软件不支持   12   和   16)  
  -   图片高度   (高字节,   低字节),   如果不支持   DNL   就必须   >0  
  -   图片宽度   (高字节,   低字节),   如果不支持   DNL   就必须   >0  
  -   components   数量(1   byte),   灰度图是   1,   YCbCr/YIQ   彩色图是   3,   CMYK   彩色图  
  是   4  
  -   每个   component:   3   bytes  
  -   component   id   (1   =   Y,   2   =   Cb,   3   =   Cr,   4   =   I,   5   =   Q)  
  -   采样系数   (bit   0-3   vert.,   4-7   hor.)  
  -   quantization   table   号  
   
  DRI:   Define   Restart   Interval:  
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
   
  -   $ff,   $dd   (DRI)  
  -   长度   (高字节,   低字节),   必须是   4  
  -   MCU   块的单元中的重新开始间隔   (高字节,   低字节),  
  意思是说,   每   n   个   MCU   块就有一个   RSTn   标记.  
  第一个标记是   RST0,   然后是   RST1   等,   RST7   后再从   RST0   重复    
   
  DQT:   Define   Quantization   Table:  
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
   
  -   $ff,   $db   (DQT)  
  -   长度   (高字节,   低字节)  
  -   QT   信息   (1   byte):  
  bit   0..3:   QT   号(0..3,   否则错误)  
  bit   4..7:   QT   精度,   0   =   8   bit,   否则   16   bit  
  -   n   字节的   QT,   n   =   64*(精度+1)  
   
  评论:  
  -   一个单独的   DQT   段可以包含多个   QT,   每个都有自己的信息字节  
  -   当精度=1   (16   bit),   每个字都是高位在前低位在后  
   
  DAC:   Define   Arithmetic   Table:  
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
  法律原因,   现在的软件不支持   arithmetic   编码.  
  不能生产使用   arithmetic   编码的   JPEG   文件  
   
  DHT:   Define   Huffman   Table:  
  ~~~~~~~~~~~~~~~~~~~~~~~~~~  
   
  -   $ff,   $c4   (DHT)  
  -   长度   (高字节,   低字节)  
  -   HT   信息   (1   byte):  
  bit   0..3:   HT   号   (0..3,   否则错误)  
  bit   4   :   HT   类型,   0   =   DC   table,   1   =   AC   table  
  bit   5..7:   必须是   0  
  -   16   bytes:   长度是   1..16   代码的符号数.   这   16   个数的和应该   <=256  
  -   n   bytes:   一个包含了按递增次序代码长度排列的符号表  
  (n   =   代码总数)  
   
  评论:  
  -   一个单独的   DHT   段可以包含多个   HT,   每个都有自己的信息字节  
   
  COM:   注释:  
  ~~~~~~~~~~  
   
  -   $ff,   $fe   (COM)  
  -   注释长度   (高字节,   低字节)   =   L+2  
  -   注释为长度为   L   的字符流  
   
  SOS:   Start   Of   Scan:  
  ~~~~~~~~~~~~~~~~~~~  
   
  -   $ff,   $da   (SOS)  
  -   长度   (高字节,   低字节),   必须是   6+2*(扫描行内组件的数量)  
  -   扫描行内组件的数量   (1   byte),   必须   >=   1   ,   <=4   (否则是错的)   通常是   3  
  -   每个组件:   2   bytes  
  -   component   id   (1   =   Y,   2   =   Cb,   3   =   Cr,   4   =   I,   5   =   Q),   见   SOF0  
  -   使用的   Huffman   表:  
  -   bit   0..3:   AC   table   (0..3)  
  -   bit   4..7:   DC   table   (0..3)  
  -   忽略   3   bytes   (???)  
   
  评论:  
  -   图片数据   (一个个扫描行)   紧接着   SOS   段.
阅读(501) | 评论(0) | 转发(0) |
0

上一篇:C语言中sizeof的用法

下一篇:Video4linux 编程

给主人留下些什么吧!~~