From 74da4eee9a9c7c34a986e4a559627acd12b49a9b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 5 Aug 2009 08:42:59 -0700 Subject: [PATCH] tinyjpeg: update to revision 20070609 Update tinyjpeg to upstream version 20070609. Signed-off-by: H. Peter Anvin --- com32/lib/jpeg/jidctflt.c | 22 ++--- com32/lib/jpeg/tinyjpeg-internal.h | 33 +++++-- com32/lib/jpeg/tinyjpeg.c | 183 ++++++++++++++++++++++++++++++------- com32/lib/jpeg/yuv420p.c | 35 ++++--- 4 files changed, 210 insertions(+), 63 deletions(-) diff --git a/com32/lib/jpeg/jidctflt.c b/com32/lib/jpeg/jidctflt.c index e5e66ed..6f0df77 100644 --- a/com32/lib/jpeg/jidctflt.c +++ b/com32/lib/jpeg/jidctflt.c @@ -80,7 +80,7 @@ #define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) -#if defined(__GNUC__) && defined(__i686__) || defined(__x86_64__) +#if 1 && defined(__GNUC__) && (defined(__i686__) || defined(__x86_64__)) static inline unsigned char descale_and_clamp(int x, int shift) { @@ -92,7 +92,7 @@ static inline unsigned char descale_and_clamp(int x, int shift) "\tcmpl %4,%1\n" "\tcmovg %4,%1\n" : "=r"(x) - : "0"(x), "i"(shift), "i"(1UL<<(shift-1)), "r" (0xff), "r" (0) + : "0"(x), "Ir"(shift), "ir"(1UL<<(shift-1)), "r" (0xff), "r" (0) ); return x; } @@ -120,7 +120,7 @@ static inline unsigned char descale_and_clamp(int x, int shift) */ void -jpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride) +tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride) { FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; FAST_FLOAT tmp10, tmp11, tmp12, tmp13; @@ -269,14 +269,14 @@ jpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride) /* Final output stage: scale down by a factor of 8 and range-limit */ - outptr[0] = descale_and_clamp(tmp0 + tmp7, 3); - outptr[7] = descale_and_clamp(tmp0 - tmp7, 3); - outptr[1] = descale_and_clamp(tmp1 + tmp6, 3); - outptr[6] = descale_and_clamp(tmp1 - tmp6, 3); - outptr[2] = descale_and_clamp(tmp2 + tmp5, 3); - outptr[5] = descale_and_clamp(tmp2 - tmp5, 3); - outptr[4] = descale_and_clamp(tmp3 + tmp4, 3); - outptr[3] = descale_and_clamp(tmp3 - tmp4, 3); + outptr[0] = descale_and_clamp((int)(tmp0 + tmp7), 3); + outptr[7] = descale_and_clamp((int)(tmp0 - tmp7), 3); + outptr[1] = descale_and_clamp((int)(tmp1 + tmp6), 3); + outptr[6] = descale_and_clamp((int)(tmp1 - tmp6), 3); + outptr[2] = descale_and_clamp((int)(tmp2 + tmp5), 3); + outptr[5] = descale_and_clamp((int)(tmp2 - tmp5), 3); + outptr[4] = descale_and_clamp((int)(tmp3 + tmp4), 3); + outptr[3] = descale_and_clamp((int)(tmp3 - tmp4), 3); wsptr += DCTSIZE; /* advance pointer to next row */ diff --git a/com32/lib/jpeg/tinyjpeg-internal.h b/com32/lib/jpeg/tinyjpeg-internal.h index 78cb042..b04a302 100644 --- a/com32/lib/jpeg/tinyjpeg-internal.h +++ b/com32/lib/jpeg/tinyjpeg-internal.h @@ -35,14 +35,21 @@ #ifndef __TINYJPEG_INTERNAL_H_ #define __TINYJPEG_INTERNAL_H_ +#include + +#define SANITY_CHECK 1 + struct jdec_private; +#define HUFFMAN_BITS_SIZE 256 #define HUFFMAN_HASH_NBITS 9 #define HUFFMAN_HASH_SIZE (1UL< .. */ + RST7 = 0xD7, /* Reset Marker .. -> d7 */ EOI = 0xD9, /* End of Image */ + DRI = 0xDD, /* Define Restart Interval */ APP0 = 0xE0, }; -#define cY 1 -#define cCb 2 -#define cCr 3 +#define cY 0 +#define cCb 1 +#define cCr 2 #define BLACK_Y 0 #define BLACK_U 127 diff --git a/com32/lib/jpeg/tinyjpeg.c b/com32/lib/jpeg/tinyjpeg.c index f8e881f..657ff6e 100644 --- a/com32/lib/jpeg/tinyjpeg.c +++ b/com32/lib/jpeg/tinyjpeg.c @@ -35,6 +35,7 @@ #include #include #include +#include #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= 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-(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<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,40 @@ 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 0 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 +#endif stream += 8; for (i=0; icomponent_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 +600,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 +635,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 +650,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 +692,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 +773,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 +868,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); @@ -840,15 +942,30 @@ int tinyjpeg_decode(struct jdec_private *priv, 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 +977,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 COMPONENTS) ncomponents = COMPONENTS; for (i=0; i COMPONENTS) ncomponents = COMPONENTS; for (i=0; i COMPONENTS) ncomponents = COMPONENTS; for (i=0; i YUV420P (1x1) * .---. @@ -61,7 +76,7 @@ static void YCrCB_to_YUV420P_1x1(struct jdec_private *priv) { memcpy(p, y, 8); p += priv->bytes_per_row[0]; - y += 8; + y+=8; } p = priv->plane[1]; @@ -95,7 +110,7 @@ static void YCrCB_to_YUV420P_2x1(struct jdec_private *priv) { unsigned char *p; const unsigned char *s, *y1; - int i,j; + unsigned int i; p = priv->plane[0]; y1 = priv->Y; @@ -110,20 +125,18 @@ static void YCrCB_to_YUV420P_2x1(struct jdec_private *priv) s = priv->Cb; for (i=0; i<8; i+=2) { - for (j=0; j<8; j+=1, s+=1) - *p++ = *s; - s += 8; /* Skip one line */ - p += priv->bytes_per_row[1] - 8; + memcpy(p, s, 8); + s += 16; /* Skip one line */ + p += priv->bytes_per_row[1]; } p = priv->plane[2]; s = priv->Cr; for (i=0; i<8; i+=2) { - for (j=0; j<8; j+=1, s+=1) - *p++ = *s; - s += 8; /* Skip one line */ - p += priv->bytes_per_row[2] - 8; + memcpy(p, s, 8); + s += 16; /* Skip one line */ + p += priv->bytes_per_row[2]; } } @@ -182,7 +195,7 @@ static void YCrCB_to_YUV420P_2x2(struct jdec_private *priv) { unsigned char *p; const unsigned char *s, *y1; - int i; + unsigned int i; p = priv->plane[0]; y1 = priv->Y; -- 2.7.4