************************** * THE ATARI JPEG DECODER * ************************** Developer's guide ----------------- I) Introduction II) The JPD cookie III) What calls to decode? IV) A look at the JPEG decoder structure V) Official calling protocol JPEGOpenDriver JPEGCloseDriver JPEGGetStructSize JPEGGetImageInfo JPEGGetImageSize JPEGDecodeImage VI) User definable functions UserRoutinePtr CreateOutputPtr WriteOutputPtr CloseOutputPtr SigTermOutputPtr VII) JPEG decoder return codes VIII) Notes IX) Questions and answers Atari and Brainstorm has developed the fastest JPEG decoder, specifically designed for Falcon030. It uses both DSP and 68030 simultaneously. JPEG is a compression/decompression format based on a DCT which allows very high compression rates. Note that it is a lossy compression which means that there is some loss between the original picture and the compressed picture. But this loss may not be visible... =============== I) Introduction =============== Currently, the Atari JPEG decoder can decompress a 24 bits 320x200 picture in less than one second, which allows use of JPEG in games for example. This decoder is faster on the Falcon030 than the one we have tested on PC 486 DX2 66Mhz. This JPEG decoder is currently provided by Atari as an AUTO programmer which installs a specific cookie and JPEG decoding functions. In the future, it might be integrated in the ROMS and MultiTOS. Of course, the cookie will remain the same. When you are programming a software you first have to check if the JPEG cookie is installed. If NO, you will have to disable JPEG loading or use your own routines (the C source code of JPEG is freeware). If YES, use it and your picture loading will be amazingly fast. For the moment, only the JPEG decoder exists... ================== II) The JPD cookie ================== When launched, the JPEG driver install a cookie in the Cookie jar. It's name is '_JPD'. Following the cookie magic is a pointer to the cookie structure. This structure is: 1 long: 'CookieVersion' (Currently $00000001) 1 long: 'JPGDOpenDriver' routine pointer 1 long: 'JPGDCloseDriver' routine pointer 1 long: 'JPGDGetStructSize' routine pointer 1 long: 'JPGDGetImageInfo' routine pointer 1 long: 'JPGDGetImageSize' routine pointer 1 long: 'JPGDDecodeImage' routine pointer Warning: The driver should be called in user mode. At that point, it works also in super mode, but future versions may not. Note that all user routines are called in the same mode as the driver. ========================== III) What calls to decode? ========================== The following calls must be performed in order to decode a JPEG file: 1: Call 'JPGDGetStructSize'. No input parameters are required. This function return the size (in bytes) of the JPEG decoder structure in register D0. 2: Allocate the structure, and CLEAR IT. 3: Call 'JPGDOpenDriver', with the JPEG structure in register A0. This function locks the DSP, and perform some internal initializations. 4: Call 'JPGDGetImageInfo', with the JPEG structure in register A0. This function return the image size and some other useful informations on the JPEG structure. 5: Set some internal information in the JPEG structure: The output image colorspace (Luma, RGB), and the size of the output image pixels (1 byte for Luma, 2,3, or 4 bytes for RGB). 6: Call 'JPGDGetImageSize', with the JPEG structure in register A0. This function return the size of the decoded image in the JPEG structure. If you only want to uncompress the image to disk, you don't have to take care of this size but: YOU ALWAYS HAVE TO CALL THIS FUNCTION. 7: If you want to uncompress the image in RAM, allocate a buffer of the size returned by the previous function call. NEVER CALCULATE THE OUTPUT BUFFER SIZE YOURSELF, since it's not exactly 'Width*Height*BytesPerPixel' of the image. 8: Call 'JPGDDecodeImage', with the JPEG structure in register A0. The image is now decoded in the buffer, on in the disk. 9: Call 'JPGDCloseDriver'. The DSP is unlocked, and some internal buffers are freed. NOTE: You should always check the 'CookieVersion' number. A number other than 1 means that the decoder structure has changed. In this case, you should warn the user that calling the decoder may cause a crash. Of course, we will try to always keep this structure unchanged. ======================================== IV) A look at the JPEG decoder structure ======================================== Now, take a look at the JPEG decoder structure: 1 long: InPointer ; JPEG image pointer 1 long: OutPointer ; Output buffer/filename pointer (see OutFlag) 1 long: InSize ; JPEG image size (bytes) 1 long: OutSize ; Output image size (bytes) 1 word: InComponents ; JPEG image components number (1->4) 1 word: OutComponents ; Output components number (1->4) 1 word: OutPixelSize ; Output pixel size (1->4) 1 word: OutFlag ; 0 (RAM output) / -1 (Disk output) 1 word: XLoopCounter ; Number of MCUs per row 1 word: YLoopCounter ; Number of MCUs per column 1 long: CreateOutputPtr ; Pointer to user routine / 0 1 long: WriteOutputPtr ; Pointer to user routine / 0 1 long: CloseOutputPtr ; Pointer to user routine / 0 1 long: SigTermOutputPtr ; Pointer to user routine / 0 1 long: Comp1GammaPtr ; Component 1 gamma table / 0 1 long: Comp2GammaPtr ; Component 2 gamma table / 0 1 long: Comp3GammaPtr ; Component 3 gamma table / 0 1 long: Comp4GammaPtr ; Component 4 gamma table / 0 1 long: UserRoutinePtr ; Pointer to user routine (called during decompression) / 0 1 long: OutTmpPointer ; Current OutPointer / Temporary disk buffer pointer (see OutFlag) 1 word: MCUsCounter ; Number of MCUs not decoded 1 word: OutTmpHeight ; Number of lines in OutTmpPointer 1 long: UserLong1 ; Free, available for user 1 long: UserLong2 ; Free, available for user 1 word: OutHandle ; 0 / Output file handle (see OutFlag) 1 long: MFDBAddress 1 word: MFDBPixelWidth 1 word: MFDBPixelHeight 1 word: MFDBWordSize 1 word: MFDBFormatFlag 1 word: MFDBBitPlanes 1 word: MFDBReserved1 1 word: MFDBReserved2 1 word: MFDBReserved3 Now let us explain the exact meaning of each element of the structure: - InPointer: Pointer to the JPEG datas. - OutPointer: Pointer to the output buffer (RAM output), or to the filename of the output file (Disk output). In case of disk output, if OutPointer is 0, the decoder will save a file called OUTPUT.TGA in the current directory. - InSize: JPEG datas size in bytes. - OutSize: Output image size. - InComponents: Number of components in the JPEG datas (usually 1 for Y datas or 3 for YCbCr datas). - OutComponents: Number components in the output image (usually 1 for Y image or 3 for RGB image). - OutPixelSize: Size (in bytes) of a pixel in the output image. It can be: 1: Y output 2: RGB 15 bits format (ATARI true colour) 3: RGB 24 bits format (24 bits true colour) 4: RGB 32 bits format (32 bits true colour, MATRIX Gmbh format) - OutFlag: 0 means RAM output, -1 means disk output. - XLoopCounter: Number of MCU per row in the image. MCU width is 16 pixels in most JPEG files. - YLoopCounter: Number of MCU per column in the image. MCU height is 16 pixels in most JPEG files. - CreateOutputPtr: Pointer to a routine called when creating the output file, in case of disk output. - WriteOutputPtr: Pointer to a routine called when writing the output file, in case of disk output. - CloseOutputPtr: Pointer to a routine called when closing the output file, in case of disk output. - SigTermOutputPtr: Pointer to a routine called when an error is found during JPEG decompression and disk output is specified. NOTE: If you specify 'DiskOutput' (OutFlag = -1) and the above 4 pointers are 0, the driver writes the file in uncompressed TARGA format. - Comp1GammaPtr: Pointer to a 256 bytes table, used by the decoder as a color correction table for the first image component. - Comp2GammaPtr: Pointer to a 256 bytes table, used by the decoder as a color correction table for the second image component. - Comp3GammaPtr: Pointer to a 256 bytes table, used by the decoder as a color correction table for the third image component. - Comp4GammaPtr: Pointer to a 256 bytes table, used by the decoder as a color correction table for the fourth image component. NOTE: If one or more of the above 4 pointers is 0, the decoder uses the following linear table 0, 1, 2, 3, ..., 254, 255 for the component(s). - UserRoutinePtr: Pointer to a routine called during decompression, after decoding one row of the image (XLoopCounter MCUs). You can use it for displaying something on the screen during decompression. - OutTmpPointer: Current OutPointer (if RAM output), or temporary disk buffer pointer (if disk output). - MCUsCounter: Number of MCUs not decoded. - OutTmpHeight: Number of lines in OutTmpPointer. - UserLong1: Free, available for the user. - UserLong2: Free, available for the user. - OutHandle: Output file handle (if OutFlag = -1). - MFDBAddress: Output MFDB - MFDBPixelWidth: Output MFDB - MFDBPixelHeight: Output MFDB - MFDBWordSize: Output MFDB - MFDBFormatFlag: Output MFDB - MFDBReserved1: Output MFDB - MFDBReserved2: Output MFDB - MFDBReserved3: Output MFDB NOTE: The real JPEG decoder structure is longer than the official JPEG decoder structure: there are a lot of internal variables following the MFDB. That's why you should ALWAYS call 'JPGDGetStructSize' function before allocating the structure. ============================ V) Official calling protocol ============================ You will now discover the list of parameters for each functions. In each case, input parameters are passed using A0 register. Each function returns an error code via D0 register. JPEGOpenDriver: --------------- This function locks the DSP, performs internal initialisations, allocates internal buffers. IN: A0 = JPEG structure pointer OUT: D0 = 0 / Error JPEGCloseDriver: ---------------- This function unlocks the DSP (so if your program is also using the DSP you can reload your LOD file after this call), and frees the internal buffers. IN: A0 = JPEG structure pointer OUT: D0 = 0 / Error JPEGGetStructSize: ---------------- This functions has to be called. It returns the exact size of the JPEG decoder structure. Note that this structure is bigger than the normal JPEG structure. So don't forget to call it to allocate the right structure size. IN: Nothing OUT: D0 = JPEG decoder structure size (bytes) JPEGGetImageInfo: ---------------- This function returns a structure which contains lot of useful informations. For more informations please read chapter IV (a look at the JPEG structure)... IN: A0 = JPEG structure pointer Input parameters: InPointer InSize Output parameters: InComponents MFDBPixelWidth MFDBPixelHeight OUT: D0 = 0 / Error JPEGGetImageSize: ---------------- ALWAYS CALL THIS FUNCTION! NEVER FORGET TO CALL IT! EVEN IF YOU DON'T CARE ABOUT THE SIZE! It returns the size of the picture in bytes inside the 'OutSize' element of the structure. IN: A0 = JPEG structure pointer Input parameters: OutComponents OutPixelSize Output parameters: OutSize MFDBWordSize OUT: D0 = 0 / Error JPEGDecodeImage: ---------------- Incredible but true! This call decodes at an amazing speed your JPEG file... IN: A0 = JPEG structure pointer Input parameters: OutFlag CreateOutputPtr (optional) WriteOutputPtr (optional) CloseOutputPtr (optional) SigTermOutputPtr (optional) Comp1GammaPtr (optional) Comp2GammaPtr (optional) Comp3GammaPtr (optional) Comp4GammaPtr (optional) Output parameters: MFDBAddress MFDBPixelWidth MFDBPixelHeight MFDBWordSize MFDBFormatFlag MFDBBitPlanes MFDBReserved1 MFDBReserved2 MFDBReserved3 OUT: D0 = 0 / Error ============================ VI) User definable functions ============================ The developer can enhance the functionalities of the JPEG decoder by adding his own routines to force the decoder to save the picture in a specific format for example. If you have yet created a program with a specific way to manage screen in the memory, it is very easy to implement the JPEG cookie in it without modifying anything, thanks to the user definable routines. UserRoutinePtr: --------------- It is called by the JPEG decoder each time one row has been decoded. It allows you to display something during compression (a status bar for example). IN: A0 = JPEG structure pointer OUT: D0 = 0 (continue decoding) / -1 (abord decoding) CreateOutputPtr: --------------- If you have decided to decompress the JPEG image into a file, you can use this functino to create your own file format. It is called by the JPEG decoder when it creates the file. IN: A0 = JPEG structure pointer OUT: D0 = 0 (continue decoding) / Error WriteOutputPtr: --------------- If you have decided to decompress the JPEG image into a file, you can use this functino to create your own file format. It is called by the JPEG decoder when it writes datas. IN: A0 = JPEG structure pointer OUT: D0 = 0 (continue decoding) / Error CloseOutputPtr: --------------- If you have decided to decompress the JPEG image into a file, you can use this functino to create your own file format. It is called by the JPEG decoder when it closes the file. IN: A0 = JPEG structure pointer OUT: D0 = 0 (continue decoding) / Error SigTermOutputPtr: --------------- This function is called by the decoder if a JPEG error happens during file saving. IN: A0 = JPEG structure pointer =============================== VII) JPEG decoder return codes: =============================== Here is a complete list with meanings of the error codes returned by the functions of the JPEG decoder. Don't forget to manage them in your program... Note that the decoder can return a negative code. It's a GEMDOS error. 0 NOERROR File correctly uncompressed 1 UNKNOWNFORMAT Error, file is not JFIF compatible 2 INVALIDMARKER Error, reserved CCITT marker found 3 SOF1MARKER Error, marker not handled by the decoder 4 SOF2MARKER Error, marker not handled by the decoder 5 SOF3MARKER Error, marker not handled by the decoder 6 SOF5MARKER Error, marker not handled by the decoder 7 SOF6MARKER Error, marker not handled by the decoder 8 SOF7MARKER Error, marker not handled by the decoder 9 SOF9MARKER Error, marker not handled by the decoder 10 SOF10MARKER Error, marker not handled by the decoder 11 SOF11MARKER Error, marker not handled by the decoder 12 SOF13MARKER Error, marker not handled by the decoder 13 SOF14MARKER Error, marker not handled by the decoder 14 SOF15MARKER Error, marker not handled by the decoder 15 RSTmMARKER Error, unexpected RSTm marker 16 BADDHTMARKER Error, buggy DHT marker 17 DACMARKER Error, marker not handled by the decoder 18 BADDQTMARKER Error, buggy DQT marker 19 BADDNLMARKER Error, unexpected/invalid DNL marker 20 BADDRIMARKER Error, invalid DRI marker size 21 DHPMARKER Error, marker not handled by the decoder 22 EXPMARKER Error, marker not handled by the decoder 23 BADSUBSAMPLING Error, invalid components subsampling 24 NOTENOUGHMEMORY Error, not enough memory 25 DECODERBUSY Error, decoder is busy 26 DSPBUSY Error, DSP is locked 27 BADSOFnMARKER Error, buggy SOFn marker 28 BADSOSMARKER Error, buggy SOS marker 29 HUFFMANERROR Error, buggy Huffman stream 30 BADPIXELFORMAT Error, invalid output pixel format 31 DISKFULL Error, hard/floppy disk full 32 MISSINGMARKER Error, marker expected but not found 33 IMAGETRUNCATED Error, more bytes needed 34 EXTRABYTES Warning, dummy bytes after EOI marker 35 USERABORT User routine signaled 'Abort' 36 DSPMEMORYERROR Error, not enough DSP RAM available 37 NORSTmMARKER Error, RSTm marker expected but not found 38 BADRSTmMARKER Error, invalid RSTm marker number 39 DRIVERCLOSED Error, driver is already closed In future versions of the decoder, some new return codes will be probably added. ============ VIII) Notes: ============ The current version of the JPEG decoder (0.85) is completely compatible with MultiTOS. It allows you to decode ut to 32 files at the same time. Note that decoding two files at the same time is slower than decoding the two files one after the other because some DSP context switch is needed. If you are working under TOS, the decoder can be run from the desktop, or from the AUTO folder. If you are working under MultiTOS, it's better to launch the decoder from the AUDIO folder, AFTER MINT.PRG (it's then impossible to kill it). Currently, killing the decoder is a very bad idea, specially while decoding a file. THis will be fixed in future versions. When processing a file, the decoder tests if the the end of the file has been reached or not, in order to avoid memory violation problems when decompressing a truncated JPEG file. But, in the Huffman decoder, this test is not performed, for speed reasons. So, you should always allocate JPEG file size +10, and fill the last ten bytes with: $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00. This sequence will generate a Huffman error, and memory violation will be avoided. Note that the 'InSize' value in the JPEG structure should contain the real JPEG file size, not the size + 10. ========================= IX) Question and answers: ========================= - How to decode just one channel (i.e RED)? ------------------------------------------- There are several ways to do it. The easier (and the worst) is simply to decode the complete image, and then discard the GREEN and BLUE information. This is a bad way to do it since a lot of memory will be required, i.e. for a 320x200 image the decoder will need 320x200x3 bytes, and the application itself will need 320x200 bytes (a total of 256000 bytes!). A better approach is to specify disk output. The decoder then allocates just one row of MCUs (typically 16 lines of pixels). Then, you install your own disk routines: The create routine just performs a RTS. The write routine copy the current MCU row into the application's internal buffer, copying only the RED components. The close routine just performs a RTS. A third way to do it is to use the gamma pointers. On GREEN and BLUE gamma pointers (second and third pointers), put a pointer to an empty array of 256 bytes. In this case, the decoder will output a RGB image with all GREEN and BLUE components null. The best way to decode files in a format not handled by the decoder (i.e. CMY) is to patch the standard disk output routines, and put a conversion routine in the write output routine. In this case, don't forget to patch the create, close and sigterm routnies. They can point to a RTS instruction. You should always keep in mind this rule: Use the user routine for perform some graphic effect, like an animated mouse or a bar, and the disk output routines for everything else. - Is this driver 100% JPEG compatible? -------------------------------------- No. Currently, we have never seen a 100% JPEG compatible program. But decoding files created by the JPSRC package from the Independant JPEG Group, the PVRG JPEG codec, Alchemy, ... should work with NO problem. What is currently not implemented is: - Multiscan images (non interleaved input stream) - Some strange and not useful subsampling modes - Fractional subsampling Note that Apple Quicktime JPEG files are not standard JPEG files. If you want to decode such files on the Falcon, you will have first to convert them in standard JPEG files using an utility program called PictPixie, written by Apple inc.