nengel@0: /* nengel@0: * Small jpeg decoder library nengel@0: * nengel@0: * Copyright (c) 2006, Luc Saillard nengel@0: * All rights reserved. nengel@0: * Redistribution and use in source and binary forms, with or without nengel@0: * modification, are permitted provided that the following conditions are met: nengel@0: * nengel@0: * - Redistributions of source code must retain the above copyright notice, nengel@0: * this list of conditions and the following disclaimer. nengel@0: * nengel@0: * - Redistributions in binary form must reproduce the above copyright notice, nengel@0: * this list of conditions and the following disclaimer in the documentation nengel@0: * and/or other materials provided with the distribution. nengel@0: * nengel@0: * - Neither the name of the author nor the names of its contributors may be nengel@0: * used to endorse or promote products derived from this software without nengel@0: * specific prior written permission. nengel@0: * nengel@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" nengel@0: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE nengel@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE nengel@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE nengel@0: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR nengel@0: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF nengel@0: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS nengel@0: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN nengel@0: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) nengel@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE nengel@0: * POSSIBILITY OF SUCH DAMAGE. nengel@0: * nengel@0: */ nengel@0: nengel@0: #include nengel@0: #include nengel@0: #include nengel@0: #include nengel@0: #include nengel@0: nengel@0: #include "tinyjpeg.h" nengel@0: #include "tinyjpeg-internal.h" nengel@0: nengel@0: /* Global variable to return the last error found while deconding */ nengel@0: char error_string[256]; nengel@0: nengel@0: static const unsigned char zigzag[64] = nengel@0: { nengel@0: 0, 1, 5, 6, 14, 15, 27, 28, nengel@0: 2, 4, 7, 13, 16, 26, 29, 42, nengel@0: 3, 8, 12, 17, 25, 30, 41, 43, nengel@0: 9, 11, 18, 24, 31, 40, 44, 53, nengel@0: 10, 19, 23, 32, 39, 45, 52, 54, nengel@0: 20, 22, 33, 38, 46, 51, 55, 60, nengel@0: 21, 34, 37, 47, 50, 56, 59, 61, nengel@0: 35, 36, 48, 49, 57, 58, 62, 63 nengel@0: }; nengel@0: nengel@0: /* nengel@0: * 4 functions to manage the stream nengel@0: * nengel@0: * fill_nbits: put at least nbits in the reservoir of bits. nengel@0: * But convert any 0xff,0x00 into 0xff nengel@0: * get_nbits: read nbits from the stream, and put it in result, nengel@0: * bits is removed from the stream and the reservoir is filled nengel@0: * automaticaly. The result is signed according to the number of nengel@0: * bits. nengel@0: * look_nbits: read nbits from the stream without marking as read. nengel@0: * skip_nbits: read nbits from the stream but do not return the result. nengel@0: * nengel@0: * stream: current pointer in the jpeg data (read bytes per bytes) nengel@0: * nbits_in_reservoir: number of bits filled into the reservoir nengel@0: * reservoir: register that contains bits information. Only nbits_in_reservoir nengel@0: * is valid. nengel@0: * nbits_in_reservoir nengel@0: * <-- 17 bits --> nengel@0: * Ex: 0000 0000 1010 0000 1111 0000 <== reservoir nengel@0: * ^ nengel@0: * bit 1 nengel@0: * To get two bits from this example nengel@0: * result = (reservoir >> 15) & 3 nengel@0: * nengel@0: */ nengel@0: nengel@0: #define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ nengel@0: while (nbits_in_reservoir= priv->stream_end) \ nengel@0: return -1; \ nengel@0: c = *stream++; \ nengel@0: reservoir <<= 8; \ nengel@0: if (c == 0xff && *stream == 0x00) \ nengel@0: stream++; \ nengel@0: reservoir |= c; \ nengel@0: nbits_in_reservoir+=8; \ nengel@0: } \ nengel@0: } while(0); nengel@0: nengel@0: nengel@0: /* Signed version !!!! */ nengel@0: #define get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \ nengel@0: fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ nengel@0: result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ nengel@0: nbits_in_reservoir -= (nbits_wanted); \ nengel@0: reservoir &= ((1U<>(nbits_in_reservoir-(nbits_wanted))); \ nengel@0: } while(0); nengel@0: nengel@0: /* To speed up the decoding, we assume that the reservoir has enough bits */ nengel@0: #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ nengel@0: nbits_in_reservoir -= (nbits_wanted); \ nengel@0: reservoir &= ((1U<reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode); nengel@0: value = huffman_table->lookup[hcode]; nengel@0: if (__likely(value >= 0)) nengel@0: { nengel@0: unsigned int code_size = huffman_table->code_size[value]; nengel@0: skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size); nengel@0: return value; nengel@0: } nengel@0: nengel@0: /* Decode more bits each time ... */ nengel@0: for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++) nengel@0: { nengel@0: nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits; nengel@0: nengel@0: look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode); nengel@0: slowtable = huffman_table->slowtable[extra_nbits]; nengel@0: /* Search if the code is in this array */ nengel@0: while (slowtable[0]) { nengel@0: if (slowtable[0] == hcode) { nengel@0: skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits); nengel@0: return slowtable[1]; nengel@0: } nengel@0: slowtable+=2; nengel@0: } nengel@0: } nengel@0: return 0; nengel@0: } nengel@0: nengel@0: /** nengel@0: * nengel@0: * Decode a single block that contains the DCT coefficients. nengel@0: * The table coefficients is already dezigzaged at the end of the operation. nengel@0: * nengel@0: */ nengel@0: static int process_Huffman_data_unit(struct jdec_private *priv, int component) nengel@0: { nengel@0: unsigned char j; nengel@0: unsigned int huff_code; nengel@0: int retcode; nengel@0: unsigned char size_val, count_0; nengel@0: nengel@0: struct component *c = &priv->component_infos[component]; nengel@0: short int DCT[64]; nengel@0: nengel@0: /* Initialize the DCT coef table */ nengel@0: memset(DCT, 0, sizeof(DCT)); nengel@0: nengel@0: /* DC coefficient decoding */ nengel@0: retcode = get_next_huffman_code(priv, c->DC_table); nengel@0: // End of stream nengel@0: if(retcode == -1) nengel@0: return -1; nengel@0: else nengel@0: huff_code = (unsigned int)retcode; nengel@0: //trace("+ %x\n", huff_code); nengel@0: if (huff_code) { nengel@0: get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]); nengel@0: DCT[0] += c->previous_DC; nengel@0: c->previous_DC = DCT[0]; nengel@0: } else { nengel@0: DCT[0] = c->previous_DC; nengel@0: } nengel@0: nengel@0: /* AC coefficient decoding */ nengel@0: j = 1; nengel@0: while (j<64) nengel@0: { nengel@0: huff_code = get_next_huffman_code(priv, c->AC_table); nengel@0: //trace("- %x\n", huff_code); nengel@0: nengel@0: size_val = huff_code & 0xF; nengel@0: count_0 = huff_code >> 4; nengel@0: nengel@0: if (size_val == 0) nengel@0: { /* RLE */ nengel@0: if (count_0 == 0) nengel@0: break; /* EOB found, go out */ nengel@0: else if (count_0 == 0xF) nengel@0: j += 16; /* skip 16 zeros */ nengel@0: } nengel@0: else nengel@0: { nengel@0: j += count_0; /* skip count_0 zeroes */ nengel@0: if (__unlikely(j >= 64)) nengel@0: { nengel@0: snprintf(error_string, sizeof(error_string), "Bad huffman data (buffer overflow)"); nengel@0: break; nengel@0: } nengel@0: get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]); nengel@0: j++; nengel@0: } nengel@0: } nengel@0: nengel@0: for (j = 0; j < 64; j++) nengel@0: c->DCT[j] = DCT[zigzag[j]]; nengel@0: return 0; nengel@0: } nengel@0: nengel@0: /******************************************************************************* nengel@0: * nengel@0: * Colorspace conversion routine nengel@0: * nengel@0: * Note: nengel@0: * YCbCr is defined per CCIR 601-1, except that Cb and Cr are nengel@0: * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. nengel@0: * The conversion equations to be implemented are therefore nengel@0: * R = Y + 1.40200 * Cr nengel@0: * G = Y - 0.34414 * Cb - 0.71414 * Cr nengel@0: * B = Y + 1.77200 * Cb nengel@0: * nengel@0: ******************************************************************************/ nengel@0: nengel@0: static unsigned char clamp(int i) nengel@0: { nengel@0: if (i<0) nengel@0: return 0; nengel@0: else if (i>255) nengel@0: return 255; nengel@0: else nengel@0: return i; nengel@0: } nengel@0: nengel@0: #define SCALEBITS 10 nengel@0: #define ONE_HALF (1UL << (SCALEBITS-1)) nengel@0: #define FIX(x) ((int)((x) * (1UL< RGB24 (2x2) nengel@0: * .-------. nengel@0: * | 1 | 2 | nengel@0: * |---+---| nengel@0: * | 3 | 4 | nengel@0: * `-------' nengel@0: */ nengel@0: static void YCrCB_to_RGB24_2x2(struct jdec_private *priv) nengel@0: { nengel@0: const unsigned char *Y, *Cb, *Cr; nengel@0: unsigned char *p, *p2; nengel@0: int i,j; nengel@0: int offset_to_next_row; nengel@0: nengel@0: p = priv->plane; nengel@0: p2 = priv->plane + priv->width*3; nengel@0: Y = priv->Y; nengel@0: Cb = priv->Cb; nengel@0: Cr = priv->Cr; nengel@0: offset_to_next_row = (priv->width*3*2) - 16*3; nengel@0: for (i=0; i<8; i++) { nengel@0: nengel@0: for (j=0; j<8; j++) { nengel@0: nengel@0: int y, cb, cr; nengel@0: int add_r, add_g, add_b; nengel@0: int r, g , b; nengel@0: nengel@0: cb = *Cb++ - 128; nengel@0: cr = *Cr++ - 128; nengel@0: add_r = FIX(1.40200) * cr + ONE_HALF; nengel@0: add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; nengel@0: add_b = FIX(1.77200) * cb + ONE_HALF; nengel@0: nengel@0: y = (*Y++) << SCALEBITS; nengel@0: r = (y + add_r) >> SCALEBITS; nengel@0: *p++ = clamp(r); nengel@0: g = (y + add_g) >> SCALEBITS; nengel@0: *p++ = clamp(g); nengel@0: b = (y + add_b) >> SCALEBITS; nengel@0: *p++ = clamp(b); nengel@0: nengel@0: y = (*Y++) << SCALEBITS; nengel@0: r = (y + add_r) >> SCALEBITS; nengel@0: *p++ = clamp(r); nengel@0: g = (y + add_g) >> SCALEBITS; nengel@0: *p++ = clamp(g); nengel@0: b = (y + add_b) >> SCALEBITS; nengel@0: *p++ = clamp(b); nengel@0: nengel@0: y = (Y[16-2]) << SCALEBITS; nengel@0: r = (y + add_r) >> SCALEBITS; nengel@0: *p2++ = clamp(r); nengel@0: g = (y + add_g) >> SCALEBITS; nengel@0: *p2++ = clamp(g); nengel@0: b = (y + add_b) >> SCALEBITS; nengel@0: *p2++ = clamp(b); nengel@0: nengel@0: y = (Y[16-1]) << SCALEBITS; nengel@0: r = (y + add_r) >> SCALEBITS; nengel@0: *p2++ = clamp(r); nengel@0: g = (y + add_g) >> SCALEBITS; nengel@0: *p2++ = clamp(g); nengel@0: b = (y + add_b) >> SCALEBITS; nengel@0: *p2++ = clamp(b); nengel@0: } nengel@0: Y += 16; nengel@0: p += offset_to_next_row; nengel@0: p2 += offset_to_next_row; nengel@0: } nengel@0: } nengel@0: nengel@0: /* nengel@0: * Decode a 2x2 nengel@0: * .-------. nengel@0: * | 1 | 2 | nengel@0: * |---+---| nengel@0: * | 3 | 4 | nengel@0: * `-------' nengel@0: */ nengel@0: static int decode_MCU_2x2_3planes(struct jdec_private *priv) nengel@0: { nengel@0: // Y nengel@0: if(process_Huffman_data_unit(priv, cY)) nengel@0: return -1; nengel@0: IDCT(&priv->component_infos[cY], priv->Y, 16); nengel@0: if(process_Huffman_data_unit(priv, cY)) nengel@0: return -1; nengel@0: IDCT(&priv->component_infos[cY], priv->Y+8, 16); nengel@0: if(process_Huffman_data_unit(priv, cY)) nengel@0: return -1; nengel@0: IDCT(&priv->component_infos[cY], priv->Y+64*2, 16); nengel@0: if(process_Huffman_data_unit(priv, cY)) nengel@0: return -1; nengel@0: IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16); nengel@0: nengel@0: // Cb nengel@0: if(process_Huffman_data_unit(priv, cCb)) nengel@0: return -1; nengel@0: IDCT(&priv->component_infos[cCb], priv->Cb, 8); nengel@0: nengel@0: // Cr nengel@0: if(process_Huffman_data_unit(priv, cCr)) nengel@0: return -1; nengel@0: IDCT(&priv->component_infos[cCr], priv->Cr, 8); nengel@0: nengel@0: return 0; nengel@0: } nengel@0: nengel@0: static void resync(struct jdec_private *priv) nengel@0: { nengel@0: int i; nengel@0: nengel@0: /* Init DC coefficients */ nengel@0: for (i=0; icomponent_infos[i].previous_DC = 0; nengel@0: nengel@0: priv->reservoir = 0; nengel@0: priv->nbits_in_reservoir = 0; nengel@0: } nengel@0: nengel@0: static int find_next_rst_marker(struct jdec_private *priv) nengel@0: { nengel@0: int rst_marker_found = 0; nengel@0: int marker; nengel@0: const unsigned char *stream = priv->stream; nengel@0: nengel@0: /* Parse marker */ nengel@0: while (!rst_marker_found) nengel@0: { nengel@0: while (*stream++ != 0xff) nengel@0: { nengel@0: if (stream >= priv->stream_end) nengel@0: error("EOF while search for a RST marker."); nengel@0: } nengel@0: /* Skip any padding ff byte (this is normal) */ nengel@0: while (*stream == 0xff) nengel@0: stream++; nengel@0: nengel@0: marker = *stream++; nengel@0: if ((RST+priv->last_rst_marker_seen) == marker) nengel@0: rst_marker_found = 1; nengel@0: else if (marker >= RST && marker <= RST7) nengel@0: error("Wrong Reset marker found, abording"); nengel@0: else if (marker == EOI) nengel@0: return 0; nengel@0: } nengel@0: trace("RST Marker %d found at offset %ld\n", priv->last_rst_marker_seen, stream - priv->stream_begin); nengel@0: nengel@0: priv->stream = stream; nengel@0: priv->last_rst_marker_seen++; nengel@0: priv->last_rst_marker_seen &= 7; nengel@0: nengel@0: return 0; nengel@0: } nengel@0: nengel@0: /******************************************************************************* nengel@0: * nengel@0: * Functions exported of the library. nengel@0: * nengel@0: * Note: Some applications can access directly to internal pointer of the nengel@0: * structure. It's is not recommended, but if you have many images to nengel@0: * uncompress with the same parameters, some functions can be called to speedup nengel@0: * the decoding. nengel@0: * nengel@0: ******************************************************************************/ nengel@0: nengel@0: /** nengel@0: * Allocate a new tinyjpeg decoder object. nengel@0: * nengel@0: * Before calling any other functions, an object need to be called. nengel@0: */ nengel@0: struct jdec_private *tinyjpeg_init(void) nengel@0: { nengel@0: struct jdec_private *priv; nengel@0: nengel@2: priv = (struct jdec_private *)VMS_App__malloc(1* sizeof(struct jdec_private)); nengel@0: if (priv == NULL) nengel@0: return NULL; nengel@2: memset(priv,0,sizeof(struct jdec_private)); nengel@0: return priv; nengel@0: } nengel@0: nengel@0: /** nengel@0: * Free a tinyjpeg object. nengel@0: * nengel@0: * No others function can be called after this one. nengel@0: */ nengel@0: void tinyjpeg_free(struct jdec_private *priv) nengel@0: { nengel@2: VMS_App__free(priv); nengel@0: } nengel@0: nengel@0: nengel@0: /** nengel@0: * Create a new JPEG decode task nengel@0: * nengel@0: */ nengel@0: struct jdec_private *create_jdec_priv_task(struct jdec_private *priv, int tasknum) nengel@0: { nengel@0: struct jdec_private *jdec_task; nengel@0: nengel@0: jdec_task = tinyjpeg_init(); nengel@0: resync(priv); nengel@0: if (tasknum > 0){ nengel@0: find_next_rst_marker(priv); nengel@0: } nengel@0: memcpy(jdec_task, priv, sizeof(struct jdec_private)); nengel@0: nengel@0: jdec_task->mcus_posx = (tasknum * priv->restart_interval) % priv->mcus_in_width; nengel@0: jdec_task->mcus_posy = (tasknum * priv->restart_interval) / priv->mcus_in_width; nengel@0: nengel@0: return jdec_task; nengel@0: } nengel@0: nengel@0: /** nengel@0: * Initialize the tinyjpeg object and prepare the decoding of the stream. nengel@0: * nengel@0: * Check if the jpeg can be decoded with this jpeg decoder. nengel@0: * Fill some table used for preprocessing. nengel@0: */ nengel@0: int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size) nengel@0: { nengel@0: int ret; nengel@0: nengel@0: /* Identify the file */ nengel@0: if ((buf[0] != 0xFF) || (buf[1] != SOI)) nengel@0: error("Not a JPG file ?\n"); nengel@0: nengel@0: priv->stream_begin = buf+2; nengel@0: priv->stream_length = size-2; nengel@0: priv->stream_end = priv->stream_begin + priv->stream_length; nengel@0: nengel@0: ret = parse_JFIF(priv, priv->stream_begin); nengel@0: nengel@0: return ret; nengel@0: } nengel@0: nengel@0: /** nengel@0: * Decode and convert the jpeg image nengel@0: * nengel@0: * Note: components will be automaticaly allocated if no memory is attached. nengel@0: */ nengel@0: void tinyjpeg_decode_task(void *data, SlaveVP *animatingSlv ) nengel@0: { nengel@0: //struct jdec_private *priv, uint8_t* context nengel@0: tinyjpeg_decode_task_args* args = (tinyjpeg_decode_task_args*) data; nengel@0: nengel@0: struct jdec_private *priv = args->priv; nengel@0: uint8_t* context = args->context; nengel@0: nengel@0: // Make OmpSs not complain while compiling nengel@0: //(void) context; nengel@0: nengel@0: unsigned int x, xstride_by_mcu, ystride_by_mcu; nengel@0: unsigned int bytes_per_blocklines, bytes_per_mcu; nengel@0: decode_MCU_fct decode_MCU; nengel@0: convert_colorspace_fct convert_to_pixfmt; nengel@0: nengel@0: bytes_per_blocklines = priv->width * RGB_DEPTH; nengel@0: bytes_per_mcu = RGB_DEPTH*8; nengel@0: nengel@0: // Only 2x2 CU sizes are supported in this simple decoder nengel@0: decode_MCU = decode_MCU_2x2_3planes; nengel@0: convert_to_pixfmt = YCrCB_to_RGB24_2x2; nengel@0: xstride_by_mcu = MCU_X_STRIDE; nengel@0: ystride_by_mcu = MCU_Y_STRIDE; nengel@0: nengel@0: bytes_per_blocklines *= ystride_by_mcu; nengel@0: bytes_per_mcu *= xstride_by_mcu/8; nengel@0: nengel@0: /* Just the decode the image by macroblock */ nengel@0: nengel@0: priv->plane = priv->components[0] + (priv->mcus_posy * bytes_per_blocklines) + (priv->mcus_posx * bytes_per_mcu); nengel@0: nengel@0: for (x=0; x < priv->restart_interval; x++) { nengel@0: if(decode_MCU(priv)) { nengel@0: fprintf(stderr, "%s\n", error_string); nengel@0: } nengel@0: convert_to_pixfmt(priv); nengel@0: nengel@0: priv->plane += bytes_per_mcu; nengel@0: priv->mcus_posx++; nengel@0: if (priv->mcus_posx >= priv->mcus_in_width){ nengel@0: priv->mcus_posy++; nengel@0: priv->mcus_posx = 0; nengel@0: priv->plane += (bytes_per_blocklines - priv->width*3); nengel@0: } nengel@0: } seanhalle@1: VSs__end_task(animatingSlv); nengel@0: } nengel@0: nengel@0: const char *tinyjpeg_get_errorstring() nengel@0: { nengel@0: return error_string; nengel@0: } nengel@0: nengel@0: void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height) nengel@0: { nengel@0: *width = priv->width; nengel@0: *height = priv->height; nengel@0: } nengel@0: nengel@0: int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components) nengel@0: { nengel@0: int i; nengel@0: for (i=0; priv->components[i] && icomponents[i]; nengel@0: return 0; nengel@0: }