JPEG81 coefficient decoder

History

I've made a progressive JPEG decoder available many years ago (FireRainbow), but when I looked at my code after 5 years, well... it hit me by the classical programmer's saying: "Hm.. that's not my code". I've decided to re-write and extend a little bit. Back then, my motivation was to simply blit an uncomressed image into the frame buffer in my hobby OS. For others this might be not the case, although I tried to make the code as general as I could.

JPEG coefficient decoder

In JPEG81 I have focused on decoder conformance. In the T.83 package there are several compressed test data streams (JPEG sample image files). For the DCT-based process, reference test data is in the form of 16-bit signed coefficients for each 8x8 block per image component in a separate file. During decoding, this is the stage right before de-quantization (then IDCT).

Therefore, JPEG81 is a 'coefficient decoder'.

It allowed me to test:

The following files were successfully decoded with no error against encoder reference data (files of EREF.DCT):

DATA     JPEG   Precision   Entropy    Code       Nf   Inter-    DRI
STREAM   mode    (bits)     Coder      Tables          leave
----------------------------------------------------------------------- 
A1       S(B)       8       Huff       sample      4     yes     yes 
C1       S(E)       8       Huff       custom      4     yes     yes 
C2       S(E)       8       Huff       custom      4      no     yes 
D1       S(E)       8       arith      custom      4     yes     yes 
D2       S(E)       8       arith      custom      4      no     yes 
E1       S(E)      12       Huff       custom      4     yes     yes 
E2       S(E)      12       Huff       custom      4      no     yes 
F1       S(E)      12       arith      custom      4     yes     yes 
F2       S(E)      12       arith      custom      4      no     yes 
G1       P(SS)      8       Huff       custom      4     yes     yes  
H1       P(SS)      8       arith      custom      4     yes     yes  
J1       P(SS)     12       arith      custom      4     yes     yes  
K1       P(Full)    8       Huff       custom      4     yes     yes  
L1       P(Full)    8       arith      custom      4     yes     yes  
N1       P(Full)   12       arith      custom      4     yes     yes  
O1       LL         8       Huff       sample      4     yes     yes  
O2       LL        16       Huff       sample      4      no     yes  
P1       LL         8       arith      default     4     yes     yes  
P2       LL        16       arith      custom      4      no     yes  

Those T.83 test images have 4 image components and a crazy sub-sampling (output from Analyzer):

0000021B: FFC2 SOF2 (Huffman Progressive DCT)
  P=8 Y=257 X=255
  Nf=4
    Ci=200 HV=1x1 Qi=0
    Ci=150 HV=1x2 Qi=1
    Ci=100 HV=3x1 Qi=2
    Ci= 50 HV=1x4 Qi=3

  0
    Sample: x=85+3 (1:3) y=65+7 (1:4)
    8x8 Data Unit: 99 (X=11 Y=9)
    MCU Data Unit: 99 (X=11 Y=9)
  1
    Sample: x=85+3 (1:3) y=129+7 (1:2)
    8x8 Data Unit: 187 (X=11 Y=17)
    MCU Data Unit: 198 (X=11 Y=18)
  2
    Sample: x=255+1 (1:1) y=65+7 (1:4)
    8x8 Data Unit: 288 (X=32 Y=9)
    MCU Data Unit: 297 (X=33 Y=9)
  3
    Sample: x=85+3 (1:3) y=257+7 (1:1)
    8x8 Data Unit: 363 (X=11 Y=33)
    MCU Data Unit: 396 (X=11 Y=36)

  99 MCU (11 x 9)

  Malloc for 990 Data Units (126720 bytes)

  MCU: 3 x 4 (24 x 32 pixels)
  DU: 0 1 1 2 2 2 3 3 3 3  (10 DU/MCU)
  Subsampling:
  +---------+---------+---------+---------+
  | 0  -  - | 1  -  - | 2  2  2 | 3  -  - |
  | -  -  - | 1  -  - | -  -  - | 3  -  - |
  | -  -  - | -  -  - | -  -  - | 3  -  - |
  | -  -  - | -  -  - | -  -  - | 3  -  - |
  +---------+---------+---------+---------+

During testing, no matter how hard I tried, I got +/- 1 decoded coefficient differences comparing my output with the Decoder reference test data. It made me crazy, at this stage there should be a match. Especially disturbing, because as in the last successive scan, when the lsb of the coefficient gets decoded, this error cannot detect decoding error. Then, I just tried the Encoder reference test data - and there were no errors, the two fully matched. The Encoder reference test data is different from the Decoder reference test data in +/- 1 at certain places.

Input

Through two statically linked functions by the moment:

This interface fits both common scenarios:

Output

For the DCT-based mode, memory structure is (almost) the same as defined in T.83. After reading the SOF header, the decoder allocates buffer for all Data Units of all components, preparing to receive partial MCU-s in one, big interleaved scan. This is the maximum number of DU-s for the image.

Here is the structure for one image component: 'X' are possible extensions in partial MCU-s.

for single scans, only DU-s marked by '-' are in encoded in the data stream
for interleaved scans, there is a possibility for 'dummy' DU-s, marked by 'X'

- - - - - - - X X
- - - - - - - X X 
- - - - - - - X X 
- - - - - - - X X 
- - - - - - - X X 
- - - - - - - X X 
- - - - - - - X X 
- - - - - - - X X 
- - - - - - - X X 
X X X X X X X X X

What is it good for?

So this version is a stripped-down decoder. It's a one-file-lib, with very simple I/O interface. I used it with modifications for a small jpeg-to-bmp decoder, a jpeg-analyzer console application, and a jpeg-analyzer Windows GUI application. As I mentioned, it really depends what we want from a JPEG decoder.

Source code

Can be found on BitBucket in a tiny Mercurial repo - soon.