diff options
Diffstat (limited to 'com32/lib/jpeg/tinyjpeg.c')
-rw-r--r-- | com32/lib/jpeg/tinyjpeg.c | 243 |
1 files changed, 186 insertions, 57 deletions
diff --git a/com32/lib/jpeg/tinyjpeg.c b/com32/lib/jpeg/tinyjpeg.c index f8e881f0..3c6070f4 100644 --- a/com32/lib/jpeg/tinyjpeg.c +++ b/com32/lib/jpeg/tinyjpeg.c @@ -35,6 +35,7 @@ #include <stdlib.h> #include <string.h> #include <stdint.h> +#include <errno.h> #include "tinyjpeg.h" #include "tinyjpeg-internal.h" @@ -162,7 +163,10 @@ static const unsigned char val_ac_chrominance[] = #define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ while (nbits_in_reservoir<nbits_wanted) \ { \ - const unsigned char c = *stream++; \ + unsigned char c; \ + if (stream >= priv->stream_end) \ + longjmp(priv->jump_state, -EIO); \ + c = *stream++; \ reservoir <<= 8; \ if (c == 0xff && *stream == 0x00) \ stream++; \ @@ -177,7 +181,7 @@ static const unsigned char val_ac_chrominance[] = result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ nbits_in_reservoir -= (nbits_wanted); \ reservoir &= ((1U<<nbits_in_reservoir)-1); \ - if (result < (1UL<<((nbits_wanted)-1))) \ + if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \ result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \ } while(0); @@ -186,8 +190,15 @@ static const unsigned char val_ac_chrominance[] = result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ } while(0); +/* To speed up the decoding, we assume that the reservoir have enough bit + * slow version: + * #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ + * fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ + * nbits_in_reservoir -= (nbits_wanted); \ + * reservoir &= ((1U<<nbits_in_reservoir)-1); \ + * } while(0); + */ #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ - fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ nbits_in_reservoir -= (nbits_wanted); \ reservoir &= ((1U<<nbits_in_reservoir)-1); \ } while(0); @@ -195,6 +206,7 @@ static const unsigned char val_ac_chrominance[] = #define be16_to_cpu(x) (((x)[0]<<8)|(x)[1]) +static void resync(struct jdec_private *priv); /** * Get the next (valid) huffman code in the stream. @@ -215,9 +227,9 @@ static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode); value = huffman_table->lookup[hcode]; - if (value>=0) + if (__likely(value >= 0)) { - int code_size = huffman_table->code_size[value]; + unsigned int code_size = huffman_table->code_size[value]; skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size); return value; } @@ -253,17 +265,19 @@ static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table void tinyjpeg_process_Huffman_data_unit(struct jdec_private *priv, int component) { unsigned char j; - int huff_code; + unsigned int huff_code; unsigned char size_val, count_0; struct component *c = &priv->component_infos[component]; short int DCT[64]; + /* Initialize the DCT coef table */ memset(DCT, 0, sizeof(DCT)); /* DC coefficient decoding */ huff_code = get_next_huffman_code(priv, c->DC_table); + //trace("+ %x\n", huff_code); if (huff_code) { get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]); DCT[0] += c->previous_DC; @@ -277,6 +291,7 @@ void tinyjpeg_process_Huffman_data_unit(struct jdec_private *priv, int component while (j<64) { huff_code = get_next_huffman_code(priv, c->AC_table); + //trace("- %x\n", huff_code); size_val = huff_code & 0xF; count_0 = huff_code >> 4; @@ -291,6 +306,11 @@ void tinyjpeg_process_Huffman_data_unit(struct jdec_private *priv, int component else { j += count_0; /* skip count_0 zeroes */ + if (__unlikely(j >= 64)) + { + snprintf(error_string, sizeof(error_string), "Bad huffman data (buffer overflow)"); + break; + } get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]); j++; } @@ -298,7 +318,6 @@ void tinyjpeg_process_Huffman_data_unit(struct jdec_private *priv, int component for (j = 0; j < 64; j++) c->DCT[j] = DCT[zigzag[j]]; - } /* @@ -311,8 +330,8 @@ void tinyjpeg_process_Huffman_data_unit(struct jdec_private *priv, int component static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table) { unsigned int i, j, code, code_size, val, nbits; - unsigned char huffsize[257], *hz; - unsigned int huffcode[257], *hc; + unsigned char huffsize[HUFFMAN_BITS_SIZE+1], *hz; + unsigned int huffcode[HUFFMAN_BITS_SIZE+1], *hc; int next_free_entry; /* @@ -340,10 +359,11 @@ static void build_huffman_table(const unsigned char *bits, const unsigned char * nbits = *hz; while (*hz) { - while (*hz == nbits) { + while (*hz == nbits) + { *hc++ = code++; hz++; - } + } code <<= 1; nbits++; } @@ -358,7 +378,7 @@ static void build_huffman_table(const unsigned char *bits, const unsigned char * code = huffcode[i]; code_size = huffsize[i]; - trace("val=%2.2x code=%8.8x codesize=%2.2d\n", i, code, code_size); + trace("val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size); table->code_size[val] = code_size; if (code_size <= HUFFMAN_HASH_NBITS) @@ -386,7 +406,6 @@ static void build_huffman_table(const unsigned char *bits, const unsigned char * } } - } static void build_default_huffman_tables(struct jdec_private *priv) @@ -483,14 +502,15 @@ static void build_quantization_table(float *qtable, const unsigned char *ref_tab static int parse_DQT(struct jdec_private *priv, const unsigned char *stream) { - int length, qi; + int qi; float *table; + const unsigned char *dqt_block_end; trace("> DQT marker\n"); - length = be16_to_cpu(stream) - 2; + dqt_block_end = stream + be16_to_cpu(stream); stream += 2; /* Skip length */ - while (length>0) + while (stream < dqt_block_end) { qi = *stream++; #if SANITY_CHECK @@ -502,8 +522,8 @@ static int parse_DQT(struct jdec_private *priv, const unsigned char *stream) table = priv->Q_tables[qi]; build_quantization_table(table, stream); stream += 64; - length -= 65; } + trace("< DQT marker\n"); return 0; } @@ -513,6 +533,7 @@ static int parse_SOF(struct jdec_private *priv, const unsigned char *stream) int Q_table; struct component *c; + trace("> SOF marker\n"); print_SOF(stream); height = be16_to_cpu(stream+3); @@ -521,31 +542,34 @@ static int parse_SOF(struct jdec_private *priv, const unsigned char *stream) #if SANITY_CHECK if (stream[2] != 8) error("Precision other than 8 is not supported\n"); - if (width>2048 || height>2048) + if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT) error("Width and Height (%dx%d) seems suspicious\n", width, height); if (nr_components != 3) error("We only support YUV images\n"); - if (height%16) - error("Height need to be a multiple of 16 (current height is %d)\n", height); - if (width%16) - error("Width need to be a multiple of 16 (current Width is %d)\n", width); #endif stream += 8; for (i=0; i<nr_components; i++) { cid = *stream++; sampling_factor = *stream++; Q_table = *stream++; - c = &priv->component_infos[cid]; + c = &priv->component_infos[i]; +#if SANITY_CHECK + c->cid = cid; + if (Q_table >= COMPONENTS) + error("Bad Quantization table index (got %d, max allowed %d)\n", Q_table, COMPONENTS-1); +#endif c->Vfactor = sampling_factor&0xf; c->Hfactor = sampling_factor>>4; c->Q_table = priv->Q_tables[Q_table]; trace("Component:%d factor:%dx%d Quantization table:%d\n", - cid, c->Hfactor, c->Hfactor, Q_table ); + cid, c->Hfactor, c->Hfactor, Q_table ); } priv->width = width; priv->height = height; + trace("< SOF marker\n"); + return 0; } @@ -570,12 +594,16 @@ static int parse_SOS(struct jdec_private *priv, const unsigned char *stream) error("We do not support more than 2 AC Huffman table\n"); if ((table>>4)>=4) error("We do not support more than 2 DC Huffman table\n"); + if (cid != priv->component_infos[i].cid) + error("SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n", + i, cid, i, priv->component_infos[i].cid); trace("ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4); #endif - priv->component_infos[cid].AC_table = &priv->HTAC[table&0xf]; - priv->component_infos[cid].DC_table = &priv->HTDC[table>>4]; + priv->component_infos[i].AC_table = &priv->HTAC[table&0xf]; + priv->component_infos[i].DC_table = &priv->HTDC[table>>4]; } priv->stream = stream+3; + trace("< SOS marker\n"); return 0; } @@ -601,12 +629,11 @@ static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) count += huff_bits[i]; } #if SANITY_CHECK - if (count > 1024) - error("No more than 1024 bytes is allowed to describe a huffman table"); + if (count >= HUFFMAN_BITS_SIZE) + error("No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE); if ( (index &0xf) >= HUFFMAN_TABLES) - error("No mode than %d Huffman tables is supported\n", HUFFMAN_TABLES); - trace("Huffman table %s n%d\n", (index&0xf0)?"AC":"DC", index&0xf); - trace("Length of the table: %d\n", count); + error("No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index&0xf); + trace("Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, count); #endif if (index & 0xf0 ) @@ -617,11 +644,38 @@ static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) length -= 1; length -= 16; length -= count; + stream += count; } trace("< DHT marker\n"); return 0; } +static int parse_DRI(struct jdec_private *priv, const unsigned char *stream) +{ + unsigned int length; + + trace("> DRI marker\n"); + + length = be16_to_cpu(stream); + +#if SANITY_CHECK + if (length != 4) + error("Length of DRI marker need to be 4\n"); +#endif + + priv->restart_interval = be16_to_cpu(stream+2); + +#if DEBUG + trace("Restart interval = %d\n", priv->restart_interval); +#endif + + trace("< DRI marker\n"); + + return 0; +} + + + static void resync(struct jdec_private *priv) { int i; @@ -632,9 +686,46 @@ static void resync(struct jdec_private *priv) priv->reservoir = 0; priv->nbits_in_reservoir = 0; - + if (priv->restart_interval > 0) + priv->restarts_to_go = priv->restart_interval; + else + priv->restarts_to_go = -1; } +static int find_next_rst_marker(struct jdec_private *priv) +{ + int rst_marker_found = 0; + int marker; + const unsigned char *stream = priv->stream; + + /* Parse marker */ + while (!rst_marker_found) + { + while (*stream++ != 0xff) + { + if (stream >= priv->stream_end) + error("EOF while search for a RST marker."); + } + /* Skip any padding ff byte (this is normal) */ + while (*stream == 0xff) + stream++; + + marker = *stream++; + if ((RST+priv->last_rst_marker_seen) == marker) + rst_marker_found = 1; + else if (marker >= RST && marker <= RST7) + error("Wrong Reset marker found, abording"); + else if (marker == EOI) + return 0; + } + trace("RST Marker %d found at offset %d\n", priv->last_rst_marker_seen, stream - priv->stream_begin); + + priv->stream = stream; + priv->last_rst_marker_seen++; + priv->last_rst_marker_seen &= 7; + + return 0; +} static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) { @@ -676,6 +767,10 @@ static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) return -1; dht_marker_found = 1; break; + case DRI: + if (parse_DRI(priv, stream) < 0) + return -1; + break; default: trace("> Unknown marker %2.2x\n", marker); break; @@ -767,6 +862,7 @@ int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, u priv->stream_begin = buf+2; priv->stream_length = size-2; + priv->stream_end = priv->stream_begin + priv->stream_length; ret = parse_JFIF(priv, priv->stream_begin); @@ -781,18 +877,21 @@ int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, u int tinyjpeg_decode(struct jdec_private *priv, const struct tinyjpeg_colorspace *pixfmt) { - unsigned int x, y, xstride_by_mcu, ystride_by_mcu; + int x, y, sx, sy; + int xshift_by_mcu, yshift_by_mcu; + int xstride_by_mcu, ystride_by_mcu; unsigned int bytes_per_blocklines[3], bytes_per_mcu[3]; decode_MCU_fct decode_MCU; const decode_MCU_fct *decode_mcu_table; convert_colorspace_fct convert_to_pixfmt; + uint8_t *pptr[3]; decode_mcu_table = pixfmt->decode_mcu_table; /* Fix: check return value */ pixfmt->initialize(priv, bytes_per_blocklines, bytes_per_mcu); - xstride_by_mcu = ystride_by_mcu = 8; + xshift_by_mcu = yshift_by_mcu = 3; if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) { decode_MCU = decode_mcu_table[0]; convert_to_pixfmt = pixfmt->convert_colorspace[0]; @@ -800,55 +899,85 @@ int tinyjpeg_decode(struct jdec_private *priv, } else if (priv->component_infos[cY].Hfactor == 1) { decode_MCU = decode_mcu_table[1]; convert_to_pixfmt = pixfmt->convert_colorspace[1]; - ystride_by_mcu = 16; + yshift_by_mcu = 4; trace("Use decode 1x2 sampling (not supported)\n"); } else if (priv->component_infos[cY].Vfactor == 2) { decode_MCU = decode_mcu_table[3]; convert_to_pixfmt = pixfmt->convert_colorspace[3]; - xstride_by_mcu = 16; - ystride_by_mcu = 16; + xshift_by_mcu = 4; + yshift_by_mcu = 4; trace("Use decode 2x2 sampling\n"); } else { decode_MCU = decode_mcu_table[2]; convert_to_pixfmt = pixfmt->convert_colorspace[2]; - xstride_by_mcu = 16; + xshift_by_mcu = 4; trace("Use decode 2x1 sampling\n"); } resync(priv); /* Don't forget to that block can be either 8 or 16 lines */ - bytes_per_blocklines[0] *= ystride_by_mcu; - bytes_per_blocklines[1] *= ystride_by_mcu; - bytes_per_blocklines[2] *= ystride_by_mcu; + bytes_per_blocklines[0] <<= yshift_by_mcu-3; + bytes_per_blocklines[1] <<= yshift_by_mcu-3; + bytes_per_blocklines[2] <<= yshift_by_mcu-3; + + bytes_per_mcu[0] <<= xshift_by_mcu-3; + bytes_per_mcu[1] <<= xshift_by_mcu-3; + bytes_per_mcu[2] <<= xshift_by_mcu-3; - bytes_per_mcu[0] *= xstride_by_mcu/8; - bytes_per_mcu[1] *= xstride_by_mcu/8; - bytes_per_mcu[2] *= xstride_by_mcu/8; + xstride_by_mcu = 1 << xshift_by_mcu; + ystride_by_mcu = 1 << yshift_by_mcu; - /* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */ - for (y=0; y < priv->height/ystride_by_mcu; y++) + pptr[0] = priv->components[0]; + pptr[1] = priv->components[1]; + pptr[2] = priv->components[2]; + + trace("bpbl = %d, bpmcu = %d\n", + bytes_per_blocklines[0], bytes_per_mcu[0]); + + for (y = priv->height; y > 0; y -= ystride_by_mcu) { - //trace("Decoding row %d\n", y); - priv->plane[0] = priv->components[0] + (y * bytes_per_blocklines[0]); - priv->plane[1] = priv->components[1] + (y * bytes_per_blocklines[1]); - priv->plane[2] = priv->components[2] + (y * bytes_per_blocklines[2]); - for (x=0; x < priv->width; x+=xstride_by_mcu) + trace("Decoding row %d\n", priv->height-y); + priv->plane[0] = pptr[0]; pptr[0] += bytes_per_blocklines[0]; + priv->plane[1] = pptr[1]; pptr[1] += bytes_per_blocklines[1]; + priv->plane[2] = pptr[2]; pptr[2] += bytes_per_blocklines[2]; + + sy = min(y, ystride_by_mcu); + + for (x = priv->width; x > 0; x -= xstride_by_mcu) { + sx = min(x, xstride_by_mcu); + trace("Block size: %dx%d\n", sx, sy); + decode_MCU(priv); - convert_to_pixfmt(priv); + convert_to_pixfmt(priv, sx, sy); priv->plane[0] += bytes_per_mcu[0]; priv->plane[1] += bytes_per_mcu[1]; priv->plane[2] += bytes_per_mcu[2]; - + if (priv->restarts_to_go>0) + { + priv->restarts_to_go--; + if (priv->restarts_to_go == 0) + { + priv->stream -= (priv->nbits_in_reservoir/8); + resync(priv); + if (find_next_rst_marker(priv) < 0) + return -1; + } + } } } + trace("Input file size: %d\n", priv->stream_length+2); + trace("Input bytes actually read: %d\n", priv->stream - priv->stream_begin + 2); + return 0; } const char *tinyjpeg_get_errorstring(struct jdec_private *priv) { + /* FIXME: the error string must be store in the context */ + priv = priv; return error_string; } @@ -860,7 +989,7 @@ void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents) { - int i; + unsigned int i; if (ncomponents > COMPONENTS) ncomponents = COMPONENTS; for (i=0; i<ncomponents; i++) @@ -870,7 +999,7 @@ int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **component int tinyjpeg_set_components(struct jdec_private *priv, unsigned char * const *components, unsigned int ncomponents) { - int i; + unsigned int i; if (ncomponents > COMPONENTS) ncomponents = COMPONENTS; for (i=0; i<ncomponents; i++) @@ -882,7 +1011,7 @@ int tinyjpeg_get_bytes_per_row(struct jdec_private *priv, unsigned int *bytes, unsigned int ncomponents) { - int i; + unsigned int i; if (ncomponents > COMPONENTS) ncomponents = COMPONENTS; for (i=0; i<ncomponents; i++) @@ -894,7 +1023,7 @@ int tinyjpeg_set_bytes_per_row(struct jdec_private *priv, const unsigned int *bytes, unsigned int ncomponents) { - int i; + unsigned int i; if (ncomponents > COMPONENTS) ncomponents = COMPONENTS; for (i=0; i<ncomponents; i++) |