V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mikewang
V2EX  ›  算法

JPEG 需要给所有可能的 Run/Size 进行 Huffman 编码吗

  •  
  •   mikewang · 2022-04-07 15:03:10 +08:00 · 1017 次点击
    这是一个创建于 963 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前情概要(/t/835906):
      本科毕设,用 Java 从零开始写一个 JPEG 编码器,v 友们的回答使我受益匪浅。


    目前转换 YCC 、DCT 、量化已经完成,用 ISO/IEC 10918-1:1993 中 K.3 推荐的 Huffman 表,可以完美运行。
    然而,用固定的 Huffman 表压缩效果不一定是最好的,所以我打算根据单个图片本身生成一个新的表。

    单个图片中,并不是所有 Run/Size 值都用得到,所以我只打算给用到的值分配 Huffman 编码。
    (虽是变长编码,由于 JPEG 限制码长不得超过 16bit ,分配过多会导致权重大的值码长增加)

    解码测试结果:

    1. macOS 预览(错误:它可能已损坏,或者可能使用了“预览”无法识别的文件格式。)
    2. libjpeg (错误:Bogus Huffman table definition )
    3. ffmpeg (成功,使用 ffplay 图片可以正常显示)

    疑问:

    1. 可不可以,对没有出现的值,不分配 Huffman 编码;
    2. 如果可以不分配编码,是不是 libjpeg 解码器的 bug ;
      (如果 libjpeg 没问题,就是我的 bug )

    和 libjpeg 比,我这个只是一个小玩具。但是本着敢于质疑的精神,提出了这个问题,希望有懂 JPEG 的大神解惑,非常感谢!

    第 1 条附言  ·  2022-04-07 19:31:29 +08:00

    折腾了一下午,问题解决,在此记录一下:

    答案:
      可以不给没用到的值分配编码。我这么做是对的。
      所以libjpeg报错,是我另外的问题。


    既然libjpeg报错了,我就查了libjpeg源码,看看哪里判错了。
    “Bogus Huffman table definition”,是在jdhuff.c第381行,

    /* Figure C.2: generate the codes themselves */
    /* We also validate that the counts represent a legal Huffman code tree. */
    
    code = 0;
    si = huffsize[0];
    p = 0;
    while (huffsize[p]) {
      while (((int) huffsize[p]) == si) {
        huffcode[p++] = code;
        code++;
      }
      /* code is now 1 more than the last code used for codelength si; but
        * it must still fit in si bits, since no code is allowed to be all ones.
        */
      if (((INT32) code) >= (((INT32) 1) << si))
        ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
      code <<= 1;
      si++;
    }
    

    然后我把报错的代码注释掉:

    // if (((INT32) code) >= (((INT32) 1) << si))
    //  ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
    

    竟然能解码了!没有任何问题。(事实证明,ffmpeg能够解码的原因,是因为ffmpeg没有做这个验证。)


    那 libjpeg 为什么要拦住我呢。
    再看了眼注释:no code is allowed to be all ones.
    原来JPEG里面用的Huffman编码,不能全为1。
    所以将全1的编码长度往后推一个就行。

    问题解决。

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3575 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 00:16 · PVG 08:16 · LAX 16:16 · JFK 19:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.