Jaypeg module
$Id$
Introduction
General description
Jaypeg is a jpeg decoder used in core-2 based versions of Opera and some
core-1 based versions. It is intended as a replacement for libjpeg which was
previously used.
Use-case: decode a jpeg from a web page or a skin
When Opera needs to decode a jpeg, either from a web page or a skin, Jaypeg is
invoked from the image module.
Design goals
The design goals of Jaypeg are:
- Decode all jpegs supported by libjpeg
- Keep the footprint small
- Use little memory
- Handle OOM
- Allocate as small chunks of memory as possible
- Make it easy to add jpeg 2000 support in the future
Supported standards
JPEG ISO/IEC 10918-1
Jaypeg supports a subset of the jpeg specification. Supported parts are:
- Huffman coding
- Sequential DCT-based mode of operation
- Progressive DCT-based mode of operation
- 8-bit sample precision
Unsupported parts are:
- Arithmetic coding
- Hierarchical mode of operation
- Lossless mode of operation
- 12-bit sample precision (might be supported, it is untested until a file actually using it can be found)
JFIF
JPEG File Interchange Format 1.02 is supported.
Adobe
Adobes file interchange format is supported. Modes with alpha support are not supported.
EXIF
EXIF version 2.2 is supported. Support for it is optional.
Not yet supported standards
JPEG 2000
JPEG 2000 support is planned, but not yet started.
API documentation
The API documentation is generated by Doxygen.
Memory handling
OOM handling
OOM is signaled through OP_STATUS. TRAP/LEAVE is not used in this module. When
an OOM occurs the OP_STATUS will be propagated back to the entry point. It is
assumed that the caller handles the OOM and does not try to call jaypeg again
after an OOM has occured. OOM can also be signaled from the image listener.
That case is handled the same way as any other OOM.
Memory usage
Stack
Jaypeg contains no recursive functions. The only allocation except a few
simple types is the IDCT which allocates an array of 64 ints on the stack.
Heap
One scanline in RGB format is always allocated. In the case of linear
interpolation two scanlines are allocated.
Tables for dequantization and huffman decoded are also always stored in memory.
The size of these is specified in the jpeg image. The upper bound is 4 arrays
of 64 shorts each for dequantization and 4 arrays of up to 16*255 bytes for
huffman decoding.
For sequential jpegs, only one MCU row will be allocated. The size of an MCU
row depends on the image being decoded. It is the maximum component resolution
multiplied by eight multiplied by the width of the image scaled up to an even
multiplier of 8. The size also depends on how many components the jpeg
contains (the most common is 3 components, Ycrcb).
For progressive jpegs, one MCU row will be kept. In addition all blocks of DCT
coefficients will be kept in memory. The amount required for this is the size
of the image multiplied by the number of components multiplied by 2. This is
divided into one memory block per 8 lines and per component.
Static
Jaypeg contains a clamping table and two tables for color transforms. Total
size of these tables is 1.5 kbytes. There is also 192 bytes of table data for
IDCT.
Freeing
When the decoder is deleted all allocated memory will be freed. Memory can
also be freed if a new image is decoded using the same decoder. There is no way
for force all memory to be freed without deleteing the decoder.
Future improvements
The memory allocations could, and should, be modified to always allocate 16k
blocks.
Implementation details
Main decoding loop
A jpeg is decoded by jaypeg through calling the decode loop repetedly until
all data has been sent or the image has been completly decoded.
When the decode loop is called, jaypeg will fill an internal buffer which is
used to keep track of how much data needs to be resent the next time, and then
call the apropriate internal decode (currently only standard jpeg, but jpeg
2000 will probably be supported later on).
Jpeg decoding loop
The jpeg decoder will look for the next marker in the code stream. When such a
marker is found it is parsed and the state changes are stored in the internal
state.
The maker causing the actual decoding is start of scan. When this is
encountered jaypeg will start decoding huffman tables and in the case of
sequential jpegs perform an IDCT.
In the case of progressive jpegs the coefficients are simply stored without
being transformed. This is done to avoid transforming unused values. The
precission might be increased before the image is actually drawn, and it that
case it is a vaste of resources to perform the IDCT for these values.
When a complete MCU row is decoded a sequential jpeg will send this to the
image listener. A progressive jpeg does not do this for the reasons mentioned
above.
To send the image data to the image in the case of Progressive jpegs the
flushProgressive method must be called.
IDCT
The IDCT algortihm used transforms the coefficients from DCT to fourier and the
performs an IDFT transform instead.
Writing image data
When the image data is copied to the image it is first interpolated to the
correct resolution since if some of the components have lower resolution.
This is usually done with a linear interpolation.
When all components have the same resolution the samples are transformed into
the RGB colorspace and sent to the image listener.