JPEG Microcode

Introduction
The N64 JPEG library is an adapted version of the useful elements of the JPEG compression method customized for use in N64 game development.

Compression
The N64 JPEG library uses the Huffman entropy encoding method for data compression.

The Huffman method stores redundancy information, so it uses fewer bits to express data that appears frequently. As a result, the size of the compressed data is kept very small. Typically you can compress the original file down to 10% of its original size. Depending on the image, you may even be able to compress the file down to 5% of its original size. However, the speed of decompressing the compressed data slows things down. It typically takes more than 80 ms to decompress a 320x240 compressed image. Of course, the decompressing speed will vary depending on the image.

N64 JPEG Library
The N64 JPEG library consists of library functions, microcode, and tools.

Library Functions
There are two library functions that you can use for entropy encoding and decoding.

- Use the njpgHuffEncode function to encode using the Huffman method.

- Use the njpgHuffDecode function to decode data that was encoded using the Huffman method.

Microcode
There are two microcode object files that you can use for encoding and decoding.

- Use the njpgespMain.o microcode to complete the YUV conversion, culling, DCT, quantization, and zigzag scanning processes on RGBA-formatted image data. It outputs entropy encodable data.

- Use the njpgdspMain.o microcode to do reverse-zigzag scanning, reverse-quantization, and reverse-DCT to create entropy decoded (decompressed) data. It outputs data in YUV form.

Tools
There are three tools that you can use to compress an image to the proper form.

- Use the njpgCompress tool compresses an image to the N64 JPEG form.

- Use the njpgMakeSlide tool compresses one or more images to the N64 JPEG form, and puts them into a file.

Library Functions
There are two N64 JPEG library functions, njpgHuffEncode and njpgHuffDecode.

njpgHuffEncode Function
Use the njpgHuffEncode function to encode and compress data using Huffman encoding.

Syntax

    #include
    u32 njpgHuffEncode (u8 *indata, u8 *outdata, u32 size);

Arguments

- indata
  The pointer to the input data buffer.

- outdata
  The pointer to the output data buffer.

- size
  The size of the encoding data.

Remarks
The Huffman method encodes the output data by using the njpgespMain microcode. The address of the input/output data buffer must be 4 bytes-alignment. Also, the input data size needs to be a multiple of 768 bytes (8x8 (unit process matrix) x 2 (bytes) x 6). The output data from the njpgespMain microcode is usually this size.

Note that the output data size of the njpgespMain microcode is one-and-a-half times the size of the original image. The value should be (the width of the original image) x (the height of the original image) x 2 (bytes) x 1.5.

Return Value
Data size after compression.

njpgHuffDecode Function
Use the njpgHuffDecode function to decompress data that was compressed by the Huffman encoding method.

Syntax

    #include
    s32 njpgHuffDecode (u8 *indata, u8 *outdata);

Arguments

- indata
  The pointer to the input data buffer.

- outdata
  The pointer to the output data buffer.

Remarks
This function decompresses the Huffman-encoded compression data. The address of the input/output buffer must be 4 byte-alignment.

If a function is called successfully, 0 is returned. If the call was unsuccessful, -1 is returned. The data which was output will be decoded again using the njpgdsMain microcode.

You should check the return value to see if the decoding process failed because the original data (the compressed data) may have been destroyed; for example, you could have saved the compression data on a disk or Controller Pak that was later destroyed. To be sure the file is valid, check to see if the top 4 bytes of the compression data is the recognition header “HUFF” (ASCII: 0x48554646), and check the data in the following 16 x 16 dot macro block.

Please see Section 27.5.4.1, "njpgCompress Tool," for details about the data format.

Example Code

    if (* ( (u32*) indata)  !=  0x4e485546) {
       /* Error process */
       }

    if (* ( (u32*) (indata + 4) )  != IMAGE_SIZE) {
       /* Error process */
       }

    njpgHuffDecode (indata, outdata);
    /* Decoding by njpgdspMain microcode */

Microcode
N64 JPEG microcode does the high-speed compression and decompression of N64 JPEG files from the N64 original format.

There are the two kinds of microcode:

- njpgdspMain.o decompresses the compressed images

- njpgespMain.o compresses images

As the application programmer, you can choose the microcode appropriate for your game application.

The Decompression Microcode (njpgdspMain)
The decompression microcode processes the image files that have been compressed.

The Decompression Microcode’s Input Data
The N64 JPEG format has two operation blocks for image compression, a sub-block (SB) and a macro block (MB).

- A sub-block (SB) is an 8x8 dot square. For both compression and decompression of the JPEG file, discrete cosine transformation (reverse-discrete cosine transformation), quantization (reverse-quantization), zigzag scanning, and the Huffman encode (decode) are done in a sub-block.

- A macro block (MB) is a 16x16 dot square. It is a group of four sub-blocks. The N64 JPEG color space uses the YUV format as does standard JPEG, not RGB format which is frequently used in N64 development. N64 JPEG culls the color differences in a macro block after converting the color space from RGB to YUV (4:1:1). As a result, RSP output during the compression (or RSP input during decompression) keeps the YUV data in the macro block. The final drawing during the decompression is also done in the macro block (please see Section 27.3.1.3, "Decompression Microcode's Output Data," for more information). The following diagram shows the relationship between the sub-blocks and macro blocks:

The following diagram shows the RSP output data format during compression (or RSP input data format during decompression):

How to Activate the Decompression Microcode
The procedure for starting the expansion microcode, njpgdsMain, is described below.

First, include the header-file n64jpeg.h in the source code for your game application, and include njpgdspMain.o in the spec file for makerom. Then establish the OSTask structure as follows:

    type                      M_NJPEGTASK
    flags                     0x0
    *ucode_boot               (u64 *) rspbootTextStart
    ucode_boot_size           SP_BOOT_UCODE_SIZE
    *ucode                    (u64 *) njpgdspMainTextStart
    ucode_size                SP_UCODE_SIZE
    *ucode_data               (u64 *) njpgdspMainDataStart
    ucode_data_size           SP_UCODE_DATA_SIZE
    *dram_stack               NULL
    dram_stack_size           0
    *output_buf               NULL
    *output_buff_size         NULL
    *data_ptr                 Pointer to the NJPEGDParam parameter structure
    data_size                 NJPEGD_PARAM_SIZE
    *yield_data_ptr           Pointer to the yield buffer
    yield_data_size           NJPEGD_YIELD_SIZE

The address of the yield buffer must conform to 16-byte alignment, and it must be 272 bytes in size.

The NJPEGDParam structure is defined as follows:

    typedef struct {
       u64 *buffer;     /* input/output data buffer address */
       u32 mbs;         /* number of all the macro blocks */
       u32 scale;       /* quantization scale (-2, -2, 0, 1, 2) */
       u32 dummy;
    } NJPEGDParam;

In the header address of the input/output data buffer, enter the output address for the CPU decoding process that will be done by njpgHuffDecode function. Microcode overwrites the decompressed input data in RAM, so you don’t have to specify the output address for the microcode.

The microcode processes and outputs the image data with a macro block of 16x16 (length x width) dots (pixels). For the mbs argument (the number of all macro blocks), enter the number macro blocks in the original image data. For example, if the size of the original image data is 240x 320 (length x width) dots, the total number of macro blocks should be 300, which is 15 (length) x 20 (width).

For the scale argument (the quantization scale value), enter the specified quantization scale value during the compression. The larger this value is, the higher the compression rate becomes and the shorter the decompression time. But the image quality becomes worse. Choose a value appropriate for your image.

You can specify any value in the range from -2 to 2 as the quantization scale value. Any other value may cause unexpected results. If you specify 0, the reverse-quantization is not done.

After the CPU decoding process ends and the OSTask structure is prepared, you can start to use the microcode. Call the osSpTaskStart function. It works in the same way as graphics or audio microcode.

Example Code

    OSTask njpgdtlist;
          .
          .
          .

    /* OSTask structure njpgdtlist set /*
          .
          .
          .

    /* Start RSP Processing */
    osWritebackDCacheAll();
    osSpTaskStart(&njpgdtlist);
          .
          .
          .

    /* Wait for the end of RSP processing */
    osRecvMesg(&rspMessageQ, NULL, OS_MESG_BLOCK);

The Decompression Microcode’s Output Data
Data output by the decompression microcode has a format such that each graphics microcode is usable for the YUV texture. For more information about the 16-bit YUV texel format, please see Section 13.8, "Texture Memory" (figure 13.8.6).

The decompression microcode’s output data overwrites the input data of each macro block, so you don’t have to prepare another microcode output buffer.

The following diagram shows the format of the data output by the decompression microcode. To render a graphic image, you simply paste the microcode’s output data (YUV texels) shown in the following diagram into the proper places on the screen in each macro block. There are many rendering methods you can use. For example, you can use this output data with the sprite microcode.

The Compression Microcode (njpgespMain)
The compression microcode compresses 16-bit RGBA formatted images into N64 JPEG format.

The Compression Microcode’s Input Data
This microcode can only encode (compress) 16-bit RGBA formatted image data format. No other format can be encoded. With regard to the size of the graphic data, the only restriction is that the length and width each conform to a dot multiple of 16. For example, 320 x 240 dots will work because both the length and width are evenly divisible by 16.

The microcode directly divides and encodes the image data into 16x16 dot macro blocks (MBs), so it’s impossible to cut and process a piece of a large image. For example, it’s impossible to cut out a 240x160 piece from a drawn 320x 240 dot image in a frame buffer to use directly as input data for the microcode without erasing it from the frame buffer. However, after first cutting out the piece for another buffer in the application, you can then use the cut-out data as the input data for the microcode.

How to Activate the Compression Microcode
First, include the n64jpeg.h header file in the source code for your game application, and include the njpgespMain.o file in the spec file for makerom. Then set the OSTask structure as follows:

    type                      M_NJPEGTASK
    flags                     0x0
    *ucode_boot               (u64 *) rspbootTextStart
    ucode_boot_size           SP_BOOT_UCODE_SIZE
    *ucode                    (u64 *) njpgespMainTextStart
    ucode_size                SP_UCODE_SIZE
    *ucode_data               (u64 *) njpgespMainDataStart
    ucode_data_size           SP_UCODE_DATA_SIZE
    *dram_stack               NULL
    dram_stack_size           0
    *output_buf               NULL
    *output_buff_size         NULL
    *data_ptr                 Pointer to the NJPEGEParam parameter structure
    data_size                 NJPEGE_PARAM_SIZE
    *yield_data_ptr           Pointer to the yield buffer
    yield_data_size           NJPEGE_YIELD_SIZE

The OSTask structure is used to transfer the data to the RCP. The address of the yield buffer must conform to 16-byte alignment, and it must be 288 bytes in size for encoding.

The NJPEGEParam structure is defined as follows:

    typedef struct {
       u64 *input;      /* input data buffer address */
       u64 *output;     /* output data buffer address */
       u32 mbs_x;       /* number of macro blocks in the x direction - 1 */
       u32 mbs_y;       /* number of macro blocks in the y direction - 1 */
       u32 scale;       /* quantization scale (-2, -2, 0, 1, 2) */
       u32 dummy1;
       u32 dummy2;
       u32 dummy3;
    } NJPEGEParam;

The quantization scale value is a coefficient to be multiplied by each value in a quantization table when quantizing. There are five possible scale values: -2, -1, 0, 1, and 2 which represent ¼, ½, don’t use the quantization table, 1, and 2 respectively. When the quantization table isn’t used, the output value of the discrete cosine transformation is used only for zigzag scanning.

After completing each setup item outlined above, call the osSpTaskStart function to activate the compression microcode in the same way you would activate graphics or audio microcode.

Example Code

    OSTask njpgetlist;
          .
          .
          .

    /* OSTask structure njpgetlist set */
          .
          .
          .

    /* Start RSP Processing */
    osWritebackDCacheAll();
    osSpTaskStart(&njpgetlist);
          .
          .
          .

    /* Wait for the end of RSP processing */
    osRecvMesg(&rspMessageQ, NULL, OS_MESG_BLOCK);

The Compression Microcode’s Output Data
In each macro block (MB), the microcode converts the data from RGB to YUV format, reduces (culls) the data, performs discrete cosine transformation, quantizes the data, and zigzag scans the data.

You can use culling (in the ratio of 4:1:1) and the quantization table to make necessary modifications to the data. You can change the quantization table by changing the quantization scale factor.

Each macro block must be 768 bytes in size to hold the output data buffer. For example, an image of 320 x 240 dots is divided into a total of 300 MBs. Therefore, a 230,400-byte region is required for the output buffer. Each application must prepare this buffer.

Tools

njpgCompress Tool
Use the njpgCompress tool to compress a 16-bit RGBA-format graphic image into N64 JPEG format.

Syntax

    njpgCompress [-w width] [-h height] [-s scale] [-v] inFile outFile

Command Line Options
The following command line options are available for the njpgCompress tool:

- -w width
  The width of the image (default is 320). It must be a multiple of 16.

- -h height
  The height of the image (default is 240). It must be a multiple of 16.

- -s scale
  The scale of the quantization table (-2 scale2, default is 1). If this value is small, the image quality is improved but the compression ratio goes down. Conversely, if this value is large, the image quality falls but the compression ratio goes up. If the scale is set to 0, there is no quantization.

- -v
  Switches on verbose mode. When this option is included, information about the image, such as the compression rate, is shown during the compression process.

- inFile
  The name of the 16-bit RGBA graphic image file. (Use the rgb2u64 tool to put your input file into 16-bit RGBA format if necessary.)

- outFile
  The name of the N64 JPEG output file.

njpgMakeSlide Tool
Use the njpgMakeSlide tool to compress one or more 16-bit RGBA-format graphic images into N64 JPEG format and place the result into a single file. This is useful for making a file of all background images or for using images continuously as slides or flip animation pictures.

Syntax

    njpgMakeSlide [-w width] [-h height] [-s scale] [-v] inFile outFile

Command Line Options
The following command line options are available for the njpgMakeSlide tool:

- -w width
  The width of the image (default is 320). It must be a multiple of 16.

- -h height is
  The height of the image (default is 240). It must be a multiple of 16.

- -s scale
  The scale of the quantization table (-2 scale2, default is 1). If this value is small, the image quality is improved but the compression ratio goes down. Conversely, if this value is large, the image quality falls but the compression ratio goes up. If the scale is set to 0, there is no quantization.

- -v
  Switches on the verbose mode. When this option is included, information about the image, such as the compression rate, is shown during the compression process.

- inFile
  The name of a text file that lists the names of all the 16-bit RGBA graphic image files.

- outFile
  The name of the N64 JPEG output file.

rgb2u64 Tool
Each original image file must be in the 16-bit RGBA format before it can be compressed into the N64 JPEG format. You can use this rgb2u64 tool to convert an image from RGB format into 16-bit RGBA format.

This tool must be used on an SGI workstation.

Syntax

    rgb2u64  [x_size y_size]>

Explanation
This tool converts images in RGB format to 16-bit RGBA format.

Type the command from the console to use this tool.

- <infile>
  he name of the original RGB-formatted file.

- <outfile>
  The name of the output file that will hold the new 16-bit RGBA formatted file.

- x_size y_size
  An optional specification that you can use to specify the image size in the x and y directions. It cuts the original image to the specified size and converts it to 16-bit RGBA format. The image is shaped by cutting off all four sides (top, bottom, left, and right).

Be sure to use the redirection symbol (>) to send the output to the output file.

General Reference Material

N64 JPEG Compression Process
The N64 JPEG compression method is based on the standard JPEG process. See the JPEG standard for a complete description of the exact process. Following is a brief explanation of the N64 JPEG compression process. The procedure for decompressing compressed data is basically the opposite of this.

1. Convert to the YUV Format
   The N64 compression process first converts data from 16-bit RGBA format to YUV format. During this process, less essential visual data (data that is less important in human vision) is culled. The resulting YUV data format is easier to compress.

   First the data is converted from RGB to YCrCb format. The Y value holds the luminance (brightness) information and Cr and Cb values hold the chrominance (color) information:

       r = R/255, g = G/255, b = B/255
              (0 £ R £ 255, 0 £ G £ 255, 0 £ B £ 255)
              (0 £ r £ 1, 0 £ g £ 1, 0 £ b £ 1)

       Y  = 0.299r + 0.587g + 0.114b
       Cr = 0.713(r - Y)
       Cb = 0.564(b - Y)
              (0 £ Y £ 1, -0.5 £ Cr £ 0.5, -0.5 £ Cb £ 0.5)

   Then the YCrCb formatted data is converted to the YUV format:

       y = 219Y + 16
       u = 224Cb + 128
       v = 224Cr + 128
              (0 £ y £ 255, 0 £ u £ 255, 0 £ v £ 255)

2. Cull Less Essential Data
   Human eyes are relatively insensitive to UV components compared to the Y component. Thus, culling the UV components can decrease the amount of data without a large noticeable change. This process extracts four 8x8 blocks of the Y component and one 8x8 block of each UV (U and V) component from the 16x16 dots (macro block).

3. Perform DCT
   DCT (discrete cosine transformation) regulates the apparently random image to ease the compression process.

   When processing an 8x8 matrix, DCT calculates an average value (the DC coefficient) of the data elements in the matrix and places it in the [0][0] position of the transformed matrix. Then it calculates the variance (the AC coefficient) from that DC coefficient for each of the other 63 cells of the 8x8 matrix. The farther the AC element is from the position of the DC element, the higher the displayed frequency element is.

4. Reduce the Data Range Through Quantization
   The range of data after DCT is wide, and the wider the range the less compression, so you need to reduce the range. To reduce the range, divide each value by a specific value. Human vision is less sensitive to high frequency components than it is to low frequency components, so you should divide high frequency components by a large value and divide low frequency components by a small value.

5. Perform Zigzag Scanning
   The DCT and quantization processes concentrate on the DC components and low frequency components. The high frequency components don’t change much and the data concentrates around 0. That is, large changes in data concentrate around cell [0][0] of the 8x8 pixel matrix after DCT, and many zeros concentrate around cell [7][7]. The continuous appearance of these zeros is profitable for compression, so this step rearranges the data to take advantage of the large concentration of zeros. One way to do this is to apply zigzag scanning to the data from [0][0] to [8][8] like this: [0][0] Æ [1][0] Æ [0][1] Æ [0][2] Æ [1][1] Æ [2][1]... and so on.

   DC components have differential data of DC components in the previous block so that the range of data values becomes smaller.

   Note that the N64 JPEG process does the scanning after first inverting the matrix. This is different from normal JPEG zigzag scanning. It is done this way to ease microcode decompression of compressed data.

6. Do the Huffman Entropy Encoding
   The previous five steps converted the random image into a compressible form. Now this final step completes the Huffman entropy encoding to compress the image data.

Output Data Formats

njpgMakeSlide
To move data output by this tool into the game application, first use DMA to load all images into RAM until numImages (the number of included images) is reached. After checking the necessary information following numImages, use DMA again to transfer frame[] into RAM. Then if you also need the image data, use DMA again to transfer data[] into RAM.

    typedef struct{
       s32     size;
       s32     offset;
    } MVFrame;

    struct{
       u8 headerID[] = 'NJPG'
       s32 version;
       s16      width;
       s16      height;
       u8       rawMode;
       u8       compressType;
       s16      qScale;
       s32      numImages;
       MVFrame  frame[];
       u8       data[];
    };

- headerID[]
  Recognition header of the N64 JPEG format data.

- version
  N64 JPEG version. The current version is 002.

- width
  Width of the image expressed in pixel (dot) units.

- height
  Height of the image expressed in pixel (dot) units.

- rawMode
  Raw data mode. It is 1 if the raw data mode is ON or 0 if it is OFF.

- compressType
  Entropy encoding method. A value of 0 indicates Huffman encoding.

- numImages
  Number of included images.

- frame[]
  Frame size and the offset address as an MVFrame structure:
  - size - Image size
  - offset - The offset address for the image data.

- data[]
  The compressed image data.

njpgCompress
The data output by the njpgCompress tool is suited to only a part of the data output by the njpgMakeSlide tool. Be careful that the special supplemented header is not changed. Note that the minimum header required for data decompressing has been supplemented. The following is the data format. Refer to it to check the data when decompressing:

    struct{
       u8 headerID[] = "HUFF";
       s16      numMB;       /* number of macro blocks */
       u8       compData[];
    };

Quantization Table
The quantization table for both luminance (brightness) and chrominance (color) is adapted to the luminosity quantization table of quantization table in the attachment K (reference) “Examples and guide line” of ITU-T advice, T.81 “The digital compression and coding of continuous-tone still images.” The quantization table has been organized to make RSP calculation faster when decompressing the compressed data. The following is the table:

    static short QTable[64] = {
    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
    };

As a practical matter, this table is used by multiples of ¼, ½, 1, and 2 (these correspond to the scale values -2, -1, 1 and 2). When the value of the quantization table is small, the image quality goes up but the size after compression is larger. On the other hand, when the value of the quantization table is large, the size after the compression is small but the image quality is worse.

Huffman Encoding Table
The Huffman encoding table is the one in the attachment K (reference) “Examples and Guidelines” of the ITU-T advice, T.81 “Digital compression and encoding of continuous-tone still images.”

Following are the four tables. The first and second show the possible DC codes for luminance and chrominance, and the third and fourth show the possible AC codes for luminance and chrominance.

Table of DC Codes for Luminance (Brightness)

Classification | Code Length | Code Word
0 | 2 | 0x0000
1 | 1 | 0x0002
2 | 3 | 0x0003
3 | 3 | 0x0004
4 | 3 | 0x0005
5 | 3 | 0x0006
6 | 6 | 0x000e
7 | 5 | 0x001e
8 | 6 | 0x003e
9 | 7 | 0x007e
10 | 8 | 0x00fe
11 | 9 | 0x01fe

Table of DC Codes for Chrominance (Color)

Classification | Code Length | Code Word
0 | 2 | 0x0000
1 | 1 | 0x0001
2 | 2 | 0x0002
3 | 3 | 0x0006
4 | 4 | 0x000e
5 | 5 | 0x001e
6 | 6 | 0x003e
7 | 7 | 0x007e
8 | 8 | 0x00fe
9 | 9 | 0x01fe
10 | 10 | 0x03fe
11 | 11 | 0x07fe

Table of AC Codes for Luminance (Brightness)

Run Size | Code Length | Code Word
0/0 (EOB) | 4 | 0x000a
0/1 | 2 | 0x0000
0/2 | 2 | 0x0003
0/3 | 3 | 0x0004
0/4 | 4 | 0x000b
0/5 | 5 | 0x001a
0/6 | 7 | 0x0078
0/7 | 8 | 0x00f8
0/8 | 10 | 0x03f6e
0/9 | 16 | 0xff82
0/A | 16 | 0xff83
1/1 | 4 | 0x000c
1/2 | 5 | 0x001b
1/3 | 7 | 0x0079
1/5 | 11 | 0x07f6
1/6 | 16 | 0xff84
1/7 | 16 | 0xff85
1/8 | 16 | 0xff86
1/9 | 16 | 0xff87
1/A | 16 | 0xff88
2/1 | 5 | 0x001c
2/2 | 8 | 0x00f9
2/3 | 10 | 0x03f7
2/4 | 12 | 0x0ff4
2/5 | 16 | 0xff89
2/6 | 16 | 0xff8a
2/7 | 16 | 0xff8b
2/8 | 16 | 0xff8c
2/9 | 16 | 0xff8d
2/A | 16 | 0xff8e
3/1 | 6 | 0x003a
3/2 | 9 | 0x01f7
3/3 | 12 | 0x0ff5
3/4 | 16 | 0xff8f
3/5 | 16 | 0xff90
3/6 | 16 | 0xff91
3/7 | 16 | 0xff92
3/8 | 16 | 0xff93
3/9 | 16 | 0xff94
3/A | 16 | 0xff95
4/1 | 6 | 0x003b
4/2 | 10 | 0x03f8
4/3 | 16 | 0xff96
4/4 | 16 | 0xff97
4/5 | 16 | 0xff98
4/6 | 16 | 0xff99
4/7 | 16 | 0xff9a
4/8 | 16 | 0xff9b
4/9 | 16 | 0xff9c
4/A | 16 | 0xff9d
5/1 | 7 | 0x007a
5/2 | 11 | 0x07f7
5/3 | 16 | 0xff9e
5/4 | 16 | 0xff9f
5/5 | 16 | 0xffa0
5/6 | 16 | 0xffa1
5/7 | 16 | 0xffa2
5/8 | 16 | 0xffa3
5/9 | 16 | 0xffa4
5/A | 16 | 0xffa5
6/1 | 7 | 0x007b
6/2 | 12 | 0x0ff6
6/3 | 16 | 0xffa6
6/4 | 16 | 0xffa7
6/5 | 16 | 0xffa8
6/6 | 16 | 0xffa9
6/7 | 16 | 0xffaa
6/8 | 16 | 0xffab
6/9 | 16 | 0xffac
6/A | 16 | 0xffad
7/1 | 8 | 0x00fa
7/2 | 12 | 0x0ff7
7/3 | 16 | 0xffae
7/4 | 16 | 0xffaf
7/5 | 16 | 0xffb0
7/6 | 16 | 0xffb1
7/7 | 16 | 0xffb2
7/8 | 16 | 0xffb3
7/9 | 16 | 0xffb4
7/A | 16 | 0xffb5
8/1 | 9 | 0x01f8
8/2 | 15 | 0x7fc0
8/3 | 16 | 0xffb6
8/4 | 16 | 0xffb7
8/5 | 16 | 0xffb8
8/6 | 16 | 0xffb9
8/7 | 16 | 0xffba
8/8 | 16 | 0xffbb
8/9 | 16 | 0xffbc
8/A | 16 | 0xffbd
9/1 | 9 | 0x01f9
9/2 | 9 | 0xffbe
9/3 | 9 | 0xffbf
9/4 | 9 | 0xffc0
9/5 | 9 | 0xffc1
9/6 | 9 | 0xffc2
9/7 | 9 | 0xffc3
9/8 | 9 | 0xffc4
9/9 | 9 | 0xffc5
9/A | 9 | 0xffc6
A/1 | 9 | 0x01fa
A/2 | 16 | 0xffc7
A/3 | 16 | 0xffc8
A/4 | 16 | 0xffc9
A/5 | 16 | 0xffca
A/6 | 16 | 0xffcb
A/7 | 16 | 0xffcc
A/8 | 16 | 0xffcd
A/9 | 16 | 0xffce
A/A | 16 | 0xffcf
B/1 | 10 | 0x03f9
B/2 | 16 | 0xffd0
B/3 | 16 | 0xffd1
B/4 | 16 | 0xffd2
B/5 | 16 | 0xffd3
B/6 | 16 | 0xffd4
B/7 | 16 | 0xffd5
B/8 | 16 | 0xffd6
B/9 | 16 | 0xffd7
B/A | 16 | 0xffd8
C/1 | 10 | 0x03fa
C/2 | 16 | 0xffd9
C/3 | 16 | 0xffda
C/4 | 16 | 0xffdb
C/5 | 16 | 0xffdc
C/6 | 16 | 0xffdd
C/7 | 16 | 0xffde
C/8 | 16 | 0xffdf
C/9 | 16 | 0xffe0
C/A | 16 | 0xffe1
D/1 | 11 | 0x07f8
D/2 | 11 | 0xffe2
D/3 | 11 | 0xffe3
D/4 | 16 | 0xffe4
D/5 | 16 | 0xffe5
D/6 | 16 | 0xffe6
D/7 | 16 | 0xffe7
D/8 | 16 | 0xffe8
D/9 | 16 | 0xffe9
D/A | 16 | 0xffea
E/1 | 16 | 0xffeb
E/2 | 16 | 0xffec
E/3 | 16 | 0xffed
E/4 | 16 | 0xffee
E/5 | 16 | 0xffef
E/6 | 16 | 0xfff0
E/7 | 16 | 0xfff1
E/8 | 16 | 0xfff2
E/9 | 16 | 0xfff3
E/A | 16 | 0xfff4
F/0(ZRL) | 11 | 0x07f9
F/1 | 16 | 0xfff5
F/2 | 16 | 0xfff6
F/3 | 16 | 0xfff7
F/4 | 16 | 0xfff8
F/5 | 16 | 0xfff9
F/6 | 16 | 0xfffa
F/7 | 16 | 0xfffb
F/8 | 16 | 0xfffc
F/9 | 16 | 0xfffd
F/A | 16 | 0xfffe

Table of AC Codes for Chrominance (Color)

Run Size | Code Length | Code Word
0/0(EOB) | 2 | 0x0000
0/1 | 2 | 0x0001
0/2 | 3 | 0x0004
0/3 | 4 | 0x000a
0/4 | 5 | 0x0018
0/5 | 5 | 0x0019
0/6 | 6 | 0x0038
0/7 | 7 | 0x0078
0/8 | 9 | 0x01f4
0/9 | 10 | 0x03f6
0/A | 12 | 0x0ff4
1/1 | 4 | 0x000b
1/2 | 6 | 0x0039
1/3 | 8 | 0x00f6
1/4 | 9 | 0x01f5
1/5 | 11 | 0x07f6
1/6 | 12 | 0x0ff5
1/7 | 16 | 0xff88
1/8 | 16 | 0xff89
1/9 | 16 | 0xff8a
1/A | 16 | 0xff8b
2/1 | 5 | 0x001a
2/2 | 8 | 0x00f7
2/3 | 10 | 0x03f7
2/4 | 12 | 0x0ff6
2/5 | 15 | 0x7fc2
2/6 | 16 | 0xff8c
2/7 | 16 | 0xff8d
2/8 | 16 | 0xff8e
2/9 | 16 | 0xff8f
2/A | 16 | 0xff90
3/1 | 5 | 0x001b
3/2 | 8 | 0x00f8
3/3 | 10 | 0x03f8
3/4 | 12 | 0x0ff7
3/5 | 16 | 0xff91
3/6 | 16 | 0xff92
3/7 | 16 | 0xff93
3/8 | 16 | 0xff94
3/9 | 16 | 0xff95
3/A | 16 | 0xff96
4/1 | 6 | 0x003a
4/2 | 9 | 0x01f6
4/3 | 16 | 0xff97
4/4 | 16 | 0xff98
4/5 | 16 | 0xff99
4/6 | 16 | 0xff9a
4/7 | 16 | 0xff9b
4/8 | 16 | 0xff9c
4/9 | 16 | 0xff9d
4/A | 16 | 0xff9e
5/1 | 16 | 0x003b
5/2 | 16 | 0x03f9
5/3 | 16 | 0xff9f
5/4 | 16 | 0xffa0
5/5 | 16 | 0xffa1
5/6 | 16 | 0xffa2
5/7 | 16 | 0xffa3
5/8 | 16 | 0xffa4
5/9 | 16 | 0xffa5
5/A | 16 | 0xffa6
6/1 | 7 | 0x0079
6/2 | 11 | 0x07f7
6/3 | 16 | 0xffa7
6/4 | 16 | 0xffa8
6/5 | 16 | 0xffa9
6/6 | 16 | 0xffaa
6/7 | 16 | 0xffab
6/8 | 16 | 0xffac
6/9 | 16 | 0xffad
6/A | 16 | 0xffae
7/1 | 7 | 0x007a
7/2 | 11 | 0x07f8
7/3 | 16 | 0xffaf
7/4 | 16 | 0xffb0
7/5 | 16 | 0xffb1
7/6 | 16 | 0xffb2
7/7 | 16 | 0xffb3
7/8 | 16 | 0xffb4
7/9 | 16 | 0xffb5
7/A | 16 | 0xffb6
8/1 | 8 | 0x00f9
8/2 | 16 | 0xffb7
8/3 | 16 | 0xffb8
8/4 | 16 | 0xffb9
8/5 | 16 | 0xffba
8/6 | 16 | 0xffbb
8/7 | 16 | 0xffbc
8/8 | 16 | 0xffbd
8/9 | 16 | 0xffbe
8/A | 16 | 0xffbf
9/1 | 9 | 0x01f7
9/2 | 16 | 0xffc0
9/3 | 16 | 0xffc1
9/4 | 16 | 0xffc2
9/5 | 16 | 0xffc3
9/6 | 16 | 0xffc4
9/7 | 16 | 0xffc5
9/8 | 16 | 0xffc6
9/9 | 16 | 0xffc76
9/A | 16 | 0xffc8
A/1 | 9 | 0x01f8
A/2 | 16 | 0xffc9
A/3 | 16 | 0xffca
A/4 | 16 | 0xffcb
A/5 | 16 | 0xffcc
A/6 | 16 | 0xffcd
A/7 | 16 | 0xffce
A/8 | 16 | 0xffcf
A/9 | 16 | 0xffd0
A/A | 16 | 0xffd1
B/1 | 9 | 0x01f9
B/2 | 16 | 0xffd2
B/3 | 16 | 0xffd3
B/4 | 16 | 0xffd4
B/5 | 16 | 0xffd5
B/6 | 16 | 0xffd6
B/7 | 16 | 0xffd7
B/8 | 16 | 0xffd8
B/9 | 16 | 0xffd9
B/A | 16 | 0xffda
C/1 | 9 | 0x01fa
C/2 | 16 | 0xffdb
C/3 | 16 | 0xffdc
C/4 | 16 | 0xffdd
C/5 | 16 | 0xffde
C/6 | 16 | 0xffdf
C/7 | 16 | 0xffe0
C/8 | 16 | 0xffe1
C/9 | 16 | 0xffe2
C/A | 16 | 0xffe3
D/1 | 11 | 0x07f9
D/2 | 16 | 0xffe4
D/3 | 16 | 0xffe5
D/4 | 16 | 0xffe6
D/5 | 16 | 0xffe7
D/6 | 16 | 0xffe8
D/7 | 16 | 0xffe9
D/8 | 16 | 0xffea
D/9 | 16 | 0xffeb
D/A | 16 | 0xffec
E/1 | 14 | 0x3fe0
E/2 | 16 | 0xffed
E/3 | 16 | 0xffee
E/4 | 16 | 0xffef
E/5 | 16 | 0xfff0
E/6 | 16 | 0xfff1
E/7 | 16 | 0xfff2
E/8 | 16 | 0xfff3
E/9 | 16 | 0xfff4
E/A | 16 | 0xfff5
F/0 (ZRL) | 10 | 0x03fa
F/1 | 15 | 0x7fc3
F/2 | 16 | 0xfff6
F/3 | 16 | 0xfff7
F/4 | 16 | 0xfff8
F/5 | 16 | 0xfff9
F/6 | 16 | 0xfffa
F/7 | 16 | 0xfffb
F/8 | 16 | 0xfffc
F/9 | 16 | 0xfffd
F/A | 16 | 0xfffe

The standard JPEG format distinguishes between the marker for defining the image information and the regular data when outputting the data after Huffman encoding. Therefore, if it encounters the same code (0xFF) as the data, it inserts 0x00 to indicate that this code is not the marker. However, N64 JPEG doesn’t provide this process since it doesn’t use the marker.

Programming Cautions

Image Quality
N64 JPEG raises the compression rate by slightly reducing the image quality. Therefore, if you repeatedly compress and decompress the compressed image, image quality can become noticeably worse.

Also, the N64 JPEG process includes errors, so you must be particularly careful when culling the UV data in the YUV space. For example, if you make an N64 drawing tool for use over and over in the N64 JPEG library for the purpose of image storage and retrieval, image encoding and decoding are provided whenever you repeat the storage and retrieval process. This means that if the drawing is done in the RGBA space (in the regular N64 image process space), UV data in the macro block is culled again and again based on the drawing. In short, an application that repeatedly compresses and decompresses a compressed image provides data culling over and over which can cause a noticeable deterioration in image quality.

If you make such an application, you should store the regular RGBA data without using compression or store the compressed data (for example, by the run length encoding as in the compression used in a BMP file), and use N64 JPEG as the final storage method.

Data Form after Decompression
Data decoded by the njpgdspMain microcode is output in YUV format, not RGBA format. Therefore, you need to be aware that the image won’t be displayed normally, even if you directly specify the output data buffer to the frame buffer.

Also, data output in YUV format needs to be expressed as a 16x16 dot texture. Both input and output data regions are divided into 768-byte macro blocks, and each macro block processed completes in its region. As a result, the size of the output data becomes 512 byte for the 768 byte (Y4, U1, and V1 are each 128 bytes) after input to the macro block region. The 256-byte empty region (suitable for the unnecessary UV component region) is produced.

When you get the texture from the data buffer, add the pointer to the buffer at each 768-byte boundary. Please see Section 27.3.1.3, "Decompression Microcode's Output Data."

Please see the sample program for the specific methods.

Copyright © 1999 Nintendo of America Inc. All Rights Reserved Nintendo and N64 are registered trademarks of Nintendo Last Updated January, 1999