diff -r e4d67989cc36 -r 47c74d1534e1 genericopenlibs/liboil/tsrc/examples/jpeg/src/jpeg.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/genericopenlibs/liboil/tsrc/examples/jpeg/src/jpeg.c Fri Apr 16 16:46:38 2010 +0300 @@ -0,0 +1,1130 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jpeg_internal.h" +#include + +#define MAX(a,b) ((a)>(b) ? (a) : (b)) + + +extern uint8_t jpeg_standard_tables[]; +extern int jpeg_standard_tables_size; + +void jpeg_decoder_error(JpegDecoder *dec, char *fmt, ...); + +void jpeg_decoder_define_huffman_tables (JpegDecoder * dec); +void jpeg_decoder_define_arithmetic_conditioning (JpegDecoder *dec); +void jpeg_decoder_define_quantization_tables (JpegDecoder *dec); +void jpeg_decoder_define_restart_interval (JpegDecoder *dec); +void jpeg_decoder_start_of_frame (JpegDecoder * dec, int marker); +void jpeg_decoder_start_of_scan (JpegDecoder * dec); + + +/* misc helper function declarations */ + +static void dumpbits (JpegBits * bits); +static char *sprintbits (char *str, unsigned int bits, int n); + +static void huffman_table_load_std_jpeg (JpegDecoder * dec); + +static void jpeg_decoder_verify_header (JpegDecoder *dec); +static void jpeg_decoder_init_decoder (JpegDecoder *dec); + + + +static void +jpeg_decoder_verify_header (JpegDecoder *dec) +{ + int max_quant_table = 0; + int i; + + if (dec->sof_type != JPEG_MARKER_SOF_0) { + OIL_ERROR("only handle baseline DCT"); + dec->error = TRUE; + } + + if (dec->width < 1) { + OIL_ERROR("height can't be 0"); + dec->error = TRUE; + } + + switch (dec->sof_type) { + case JPEG_MARKER_SOF_0: + /* baseline DCT */ + max_quant_table = 3; + if (dec->depth != 8) { + OIL_ERROR("depth must be 8 (%d)", dec->depth); + dec->error = TRUE; + } + break; + case JPEG_MARKER_SOF_1: + /* extended DCT */ + max_quant_table = 3; + if (dec->depth != 8 && dec->depth != 12) { + OIL_ERROR("depth must be 8 or 12 (%d)", dec->depth); + dec->error = TRUE; + } + break; + case JPEG_MARKER_SOF_2: + /* progressive DCT */ + max_quant_table = 3; + if (dec->depth != 8 && dec->depth != 12) { + OIL_ERROR("depth must be 8 or 12 (%d)", dec->depth); + dec->error = TRUE; + } + break; + case JPEG_MARKER_SOF_3: + /* lossless DCT */ + max_quant_table = 0; + if (dec->depth < 2 || dec->depth > 16) { + OIL_ERROR("depth must be between 2 and 16 (%d)", dec->depth); + dec->error = TRUE; + } + break; + default: + break; + } + + if (dec->n_components < 0 || dec->n_components > 255) { + OIL_ERROR("n_components must be in the range 0-255 (%d)", + dec->n_components); + dec->error = TRUE; + } + if (dec->sof_type == JPEG_MARKER_SOF_2 && dec->n_components > 4) { + OIL_ERROR("n_components must be <= 4 for progressive DCT (%d)", + dec->n_components); + dec->error = TRUE; + } + + for (i = 0; i < dec->n_components; i++) { + if (dec->components[i].id < 0 || dec->components[i].id > 255) { + OIL_ERROR("component ID out of range"); + dec->error = TRUE; + break; + } + if (dec->components[i].h_sample < 1 || dec->components[i].h_sample > 4 || + dec->components[i].v_sample < 1 || dec->components[i].v_sample > 4) { + OIL_ERROR("sample factor(s) for component %d out of range %d %d", + i, dec->components[i].h_sample, dec->components[i].v_sample); + dec->error = TRUE; + break; + } + if (dec->components[i].quant_table < 0 || + dec->components[i].quant_table > max_quant_table) { + OIL_ERROR("quant table for component %d out of range (%d)", + i, dec->components[i].quant_table); + dec->error = TRUE; + break; + } + } +} + +static void +jpeg_decoder_init_decoder (JpegDecoder *dec) +{ + int max_h_sample = 0; + int max_v_sample = 0; + int i; + + /* decoder limitations */ + if (dec->n_components != 3) { + jpeg_decoder_error(dec, "wrong number of components %d", dec->n_components); + return; + } + if (dec->sof_type != JPEG_MARKER_SOF_0) { + jpeg_decoder_error(dec, "only handle baseline DCT"); + return; + } + + + + + for (i=0; i < dec->n_components; i++) { + max_h_sample = MAX (max_h_sample, dec->components[i].h_sample); + max_v_sample = MAX (max_v_sample, dec->components[i].v_sample); + } + + dec->width_blocks = + (dec->width + 8 * max_h_sample - 1) / (8 * max_h_sample); + dec->height_blocks = + (dec->height + 8 * max_v_sample - 1) / (8 * max_v_sample); + for (i = 0; i < dec->n_components; i++) { + int rowstride; + int image_size; + + dec->components[i].h_subsample = max_h_sample / + dec->components[i].h_sample; + dec->components[i].v_subsample = max_v_sample / + dec->components[i].v_sample; + + rowstride = dec->width_blocks * 8 * max_h_sample / + dec->components[i].h_subsample; + image_size = rowstride * + (dec->height_blocks * 8 * max_v_sample / + dec->components[i].v_subsample); + dec->components[i].rowstride = rowstride; + dec->components[i].image = malloc (image_size); + } +} + + +void +generate_code_table (int *huffsize) +{ + int code; + int i; + int j; + int k; + char str[33]; + + //int l; + + code = 0; + k = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < huffsize[i]; j++) { + OIL_DEBUG ("huffcode[%d] = %s", k, + sprintbits (str, code >> (15 - i), i + 1)); + code++; + k++; + } + code <<= 1; + } + +} + +int +huffman_table_init_jpeg (HuffmanTable *table, JpegBits * bits) +{ + int n_symbols; + int huffsize[16]; + int i, j, k; + unsigned int symbol; + int n = 0; + + huffman_table_init (table); + + /* huffsize[i] is the number of symbols that have length + * (i+1) bits. Maximum bit length is 16 bits, so there are + * 16 entries. */ + n_symbols = 0; + for (i = 0; i < 16; i++) { + huffsize[i] = jpeg_bits_get_u8 (bits); + n++; + n_symbols += huffsize[i]; + } + + /* Build up the symbol table. The first symbol is all 0's, with + * the number of bits determined by the first non-zero entry in + * huffsize[]. Subsequent symbols with the same bit length are + * incremented by 1. Increasing the bit length shifts the + * symbol 1 bit to the left. */ + symbol = 0; + k = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < huffsize[i]; j++) { + huffman_table_add (table, symbol, i + 1, jpeg_bits_get_u8 (bits)); + n++; + symbol++; + k++; + } + /* This checks that our symbol is actually less than the + * number of bits we think it is. This is only triggered + * for bad huffsize[] arrays. */ + if (symbol >= (1 << (i + 1))) { + /* FIXME jpeg_decoder_error() */ + OIL_DEBUG ("bad huffsize[] array"); + return -1; + } + + symbol <<= 1; + } + + huffman_table_dump (table); + + return n; +} + +static void +dumpbits (JpegBits * bits) +{ + int i; + int j; + unsigned char *p; + char s[40]; + + p = bits->ptr; + for (i = 0; i < 8; i++) { + sprintf (s, "%02x %02x %02x %02x %02x %02x %02x %02x ........", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + for (j = 0; j < 8; j++) { + s[j + 24] = (isprint (p[j])) ? p[j] : '.'; + } + OIL_DEBUG ("%s", s); + p += 8; + } + +} + +int +jpeg_decoder_find_component_by_id (JpegDecoder * dec, int id) +{ + int i; + + for (i = 0; i < dec->n_components; i++) { + if (dec->components[i].id == id) + return i; + } + OIL_DEBUG ("undefined component id %d", id); + return 0; +} + +int +jpeg_decoder_application0 (JpegDecoder * dec, JpegBits * bits) +{ + int length; + + OIL_DEBUG ("app0"); + + length = get_be_u16 (bits); + OIL_DEBUG ("length=%d", length); + + if (memcmp (bits->ptr, "JFIF", 4) == 0 && bits->ptr[4] == 0) { + int version; + int units; + int x_density; + int y_density; + int x_thumbnail; + int y_thumbnail; + + OIL_DEBUG ("JFIF"); + bits->ptr += 5; + + version = get_be_u16 (bits); + units = get_u8 (bits); + x_density = get_be_u16 (bits); + y_density = get_be_u16 (bits); + x_thumbnail = get_u8 (bits); + y_thumbnail = get_u8 (bits); + + OIL_DEBUG ("version = %04x", version); + OIL_DEBUG ("units = %d", units); + OIL_DEBUG ("x_density = %d", x_density); + OIL_DEBUG ("y_density = %d", y_density); + OIL_DEBUG ("x_thumbnail = %d", x_thumbnail); + OIL_DEBUG ("y_thumbnail = %d", y_thumbnail); + + } + + if (memcmp (bits->ptr, "JFXX", 4) == 0 && bits->ptr[4] == 0) { + OIL_DEBUG ("JFIF extension (not handled)"); + bits->ptr += length - 2; + } + + return length; +} + +int +jpeg_decoder_application_misc (JpegDecoder * dec, JpegBits * bits) +{ + int length; + + OIL_DEBUG ("appX"); + + length = get_be_u16 (bits); + OIL_DEBUG ("length=%d", length); + + OIL_DEBUG ("JPEG application tag X ignored"); + dumpbits (bits); + + bits->ptr += length - 2; + + return length; +} + +int +jpeg_decoder_comment (JpegDecoder * dec, JpegBits * bits) +{ + int length; + + OIL_DEBUG ("comment"); + + length = get_be_u16 (bits); + OIL_DEBUG ("length=%d", length); + + dumpbits (bits); + + bits->ptr += length - 2; + + return length; +} + +int +jpeg_decoder_restart_interval (JpegDecoder * dec, JpegBits * bits) +{ + int length; + + OIL_DEBUG ("comment"); + + length = get_be_u16 (bits); + OIL_DEBUG ("length=%d", length); + + dec->restart_interval = get_be_u16 (bits); + OIL_DEBUG ("restart_interval=%d", dec->restart_interval); + + return length; +} + +int +jpeg_decoder_restart (JpegDecoder * dec, JpegBits * bits) +{ + OIL_DEBUG ("restart"); + + return 0; +} + +void +jpeg_decoder_decode_entropy_segment (JpegDecoder * dec) +{ + JpegBits * bits = &dec->bits; + JpegBits b2, *bits2 = &b2; + short block[64]; + short block2[64]; + unsigned char *newptr; + int len; + int j; + int i; + int go; + int x, y; + int n; + int ret; + + len = 0; + j = 0; + while (1) { + if (bits->ptr[len] == 0xff && bits->ptr[len + 1] != 0x00) { + break; + } + len++; + } + OIL_DEBUG ("entropy length = %d", len); + + /* we allocate extra space, since the getbits() code can + * potentially read past the end of the buffer */ + newptr = malloc (len + 2); + for (i = 0; i < len; i++) { + newptr[j] = bits->ptr[i]; + j++; + if (bits->ptr[i] == 0xff) + i++; + } + bits->ptr += len; + + bits2->ptr = newptr; + bits2->idx = 0; + bits2->end = newptr + j; + newptr[j] = 0; + newptr[j + 1] = 0; + + dec->dc[0] = dec->dc[1] = dec->dc[2] = dec->dc[3] = 128 * 8; + go = 1; + x = dec->x; + y = dec->y; + n = dec->restart_interval; + if (n == 0) n = INT_MAX; + while (n-- > 0) { + for (i = 0; i < dec->scan_list_length; i++) { + int dc_table_index; + int ac_table_index; + int quant_index; + unsigned char *ptr; + int component_index; + + OIL_DEBUG ("%d,%d: component=%d dc_table=%d ac_table=%d", + x, y, + dec->scan_list[i].component_index, + dec->scan_list[i].dc_table, dec->scan_list[i].ac_table); + + component_index = dec->scan_list[i].component_index; + dc_table_index = dec->scan_list[i].dc_table; + ac_table_index = dec->scan_list[i].ac_table; + quant_index = dec->scan_list[i].quant_table; + + ret = huffman_table_decode_macroblock (block, + &dec->dc_huff_table[dc_table_index], + &dec->ac_huff_table[ac_table_index], bits2); + if (ret < 0) { + OIL_DEBUG ("%d,%d: component=%d dc_table=%d ac_table=%d", + x, y, + dec->scan_list[i].component_index, + dec->scan_list[i].dc_table, dec->scan_list[i].ac_table); + n = 0; + break; + } + + OIL_DEBUG ("using quant table %d", quant_index); + oil_mult8x8_s16 (block2, block, dec->quant_tables[quant_index].quantizer, + sizeof (short) * 8, sizeof(short) * 8, sizeof (short) * 8); + dec->dc[component_index] += block2[0]; + block2[0] = dec->dc[component_index]; + oil_unzigzag8x8_s16 (block, sizeof (short) * 8, block2, + sizeof (short) * 8); + oil_idct8x8_s16 (block2, sizeof (short) * 8, block, sizeof (short) * 8); + oil_trans8x8_s16 (block, sizeof (short) * 8, block2, sizeof (short) * 8); + + ptr = dec->components[component_index].image + + x * dec->components[component_index].h_sample + + dec->scan_list[i].offset + + dec->components[component_index].rowstride * y * + dec->components[component_index].v_sample; + + oil_clipconv8x8_u8_s16 (ptr, + dec->components[component_index].rowstride, + block, sizeof (short) * 8); + } + x += 8; + if (x * dec->scan_h_subsample >= dec->width) { + x = 0; + y += 8; + } + if (y * dec->scan_v_subsample >= dec->height) { + go = 0; + } + } + dec->x = x; + dec->y = y; + free (newptr); +} + + + +JpegDecoder * +jpeg_decoder_new (void) +{ + JpegDecoder *dec; + + oil_init (); + + dec = malloc (sizeof(JpegDecoder)); + memset (dec, 0, sizeof(JpegDecoder)); + + huffman_table_load_std_jpeg (dec); + + return dec; +} + +void +jpeg_decoder_free (JpegDecoder * dec) +{ + int i; + + for (i = 0; i < JPEG_MAX_COMPONENTS; i++) { + if (dec->components[i].image) + free (dec->components[i].image); + } + + if (dec->data) + free (dec->data); + + free (dec); +} + +void +jpeg_decoder_error(JpegDecoder *dec, char *fmt, ...) +{ + va_list varargs; + + if (dec->error) return; + + va_start (varargs, fmt); +#if 0 + vasprintf(&dec->error_message, fmt, varargs); +#else + dec->error_message = malloc(100); + vsnprintf(dec->error_message, 100, fmt, varargs); +#endif + va_end (varargs); + + OIL_ERROR("decoder error: %s", dec->error_message); + abort(); + dec->error = TRUE; +} + +int +jpeg_decoder_get_marker (JpegDecoder *dec, int *marker) +{ + int a,b; + JpegBits *bits = &dec->bits; + + if (jpeg_bits_available(bits) < 2) { + return FALSE; + } + + a = jpeg_bits_get_u8(bits); + if (a != 0xff) { + jpeg_decoder_error(dec, "expected marker, not 0x%02x", a); + return FALSE; + } + + do { + b = jpeg_bits_get_u8 (bits); + } while (b == 0xff && jpeg_bits_error(bits)); + + *marker = b; + return TRUE; +} + +void +jpeg_decoder_skip (JpegDecoder *dec) +{ + int length; + + length = jpeg_bits_get_u16_be (&dec->bits); + jpeg_bits_skip (&dec->bits, length - 2); +} + +int +jpeg_decoder_decode (JpegDecoder *dec) +{ + JpegBits *bits; + int marker; + + dec->error = FALSE; + + bits = &dec->bits; + + /* Note: The spec is ambiguous as to whether fill bytes can preceed + * the first marker. We'll assume yes. */ + if (!jpeg_decoder_get_marker (dec, &marker)) { + return FALSE; + } + if (marker != JPEG_MARKER_SOI) { + jpeg_decoder_error(dec, "not a JPEG image"); + return FALSE; + } + + /* Interpret markers up to the start of frame */ + while (!dec->error) { + if (!jpeg_decoder_get_marker (dec, &marker)) { + return FALSE; + } + + if (marker == JPEG_MARKER_DEFINE_HUFFMAN_TABLES) { + jpeg_decoder_define_huffman_tables (dec); + } else if (marker == JPEG_MARKER_DEFINE_ARITHMETIC_CONDITIONING) { + jpeg_decoder_define_arithmetic_conditioning (dec); + } else if (marker == JPEG_MARKER_DEFINE_QUANTIZATION_TABLES) { + jpeg_decoder_define_quantization_tables (dec); + } else if (marker == JPEG_MARKER_DEFINE_RESTART_INTERVAL) { + jpeg_decoder_define_restart_interval (dec); + } else if (JPEG_MARKER_IS_APP(marker)) { + /* FIXME decode app segment */ + jpeg_decoder_skip (dec); + } else if (marker == JPEG_MARKER_COMMENT) { + jpeg_decoder_skip (dec); + } else if (JPEG_MARKER_IS_START_OF_FRAME(marker)) { + break; + } else { + jpeg_decoder_error(dec, "unexpected marker 0x%02x", marker); + return FALSE; + } + } + + jpeg_decoder_start_of_frame(dec, marker); + + jpeg_decoder_verify_header (dec); + if (dec->error) { + return FALSE; + } + + jpeg_decoder_init_decoder (dec); + if (dec->error) { + return FALSE; + } + + /* In this section, we loop over parse units until we reach the end + * of the image. */ + while (!dec->error) { + if (!jpeg_decoder_get_marker (dec, &marker)) { + return FALSE; + } + + if (marker == JPEG_MARKER_DEFINE_HUFFMAN_TABLES) { + jpeg_decoder_define_huffman_tables (dec); + } else if (marker == JPEG_MARKER_DEFINE_ARITHMETIC_CONDITIONING) { + jpeg_decoder_define_arithmetic_conditioning (dec); + } else if (marker == JPEG_MARKER_DEFINE_QUANTIZATION_TABLES) { + jpeg_decoder_define_quantization_tables (dec); + } else if (marker == JPEG_MARKER_DEFINE_RESTART_INTERVAL) { + jpeg_decoder_define_restart_interval (dec); + } else if (JPEG_MARKER_IS_APP(marker)) { + jpeg_decoder_skip (dec); + } else if (marker == JPEG_MARKER_COMMENT) { + jpeg_decoder_skip (dec); + } else if (marker == JPEG_MARKER_SOS) { + jpeg_decoder_start_of_scan (dec); + jpeg_decoder_decode_entropy_segment (dec); + } else if (JPEG_MARKER_IS_RESET(marker)) { + jpeg_decoder_decode_entropy_segment (dec); + } else if (marker == JPEG_MARKER_EOI) { + break; + } else { + jpeg_decoder_error(dec, "unexpected marker 0x%02x", marker); + return FALSE; + } + } + + return TRUE; +} + +/* handle markers */ + +void +jpeg_decoder_define_huffman_tables (JpegDecoder * dec) +{ + JpegBits *bits = &dec->bits; + int length; + int tc; + int th; + int x; + HuffmanTable *hufftab; + + OIL_DEBUG ("define huffman tables"); + + length = jpeg_bits_get_u16_be (bits); + if (length < 2) { + jpeg_decoder_error(dec, "length too short"); + return; + } + length -= 2; + + while (length > 0) { + x = jpeg_bits_get_u8 (bits); + length--; + + tc = x >> 4; + th = x & 0xf; + + OIL_DEBUG ("huff table type %d (%s) index %d", tc, tc ? "ac" : "dc", th); + if (tc > 1 || th > 3) { + jpeg_decoder_error(dec, "huffman table type or index out of range"); + return; + } + + if (tc) { + hufftab = &dec->ac_huff_table[th]; + length -= huffman_table_init_jpeg (hufftab, bits); + } else { + hufftab = &dec->dc_huff_table[th]; + length -= huffman_table_init_jpeg (hufftab, bits); + } + } + if (length < 0) { + jpeg_decoder_error(dec, "huffman table overran available bytes"); + return; + } +} + +void +jpeg_decoder_define_quantization_tables (JpegDecoder *dec) +{ + JpegBits *bits = &dec->bits; + JpegQuantTable *table; + int length; + int pq; + int tq; + int i; + + OIL_INFO ("define quantization table"); + + length = jpeg_bits_get_u16_be (bits); + if (length < 2) { + jpeg_decoder_error(dec, "length too short"); + return; + } + length -= 2; + + while (length > 0) { + int x; + + x = jpeg_bits_get_u8 (bits); + length--; + pq = x >> 4; + tq = x & 0xf; + + if (pq > 1) { + jpeg_decoder_error (dec, "bad pq value"); + return; + } + if (tq > 3) { + jpeg_decoder_error (dec, "bad tq value"); + return; + } + + table = &dec->quant_tables[tq]; + if (pq) { + for (i = 0; i < 64; i++) { + table->quantizer[i] = jpeg_bits_get_u16_be (bits); + length -= 2; + } + } else { + for (i = 0; i < 64; i++) { + table->quantizer[i] = jpeg_bits_get_u8 (bits); + length -= 1; + } + } + } + if (length < 0) { + jpeg_decoder_error(dec, "quantization table overran available bytes"); + return; + } +} + +void +jpeg_decoder_define_restart_interval (JpegDecoder *dec) +{ + JpegBits *bits = &dec->bits; + int length; + + length = jpeg_bits_get_u16_be (bits); + if (length != 4) { + jpeg_decoder_error(dec, "length supposed to be 4 (%d)", length); + return; + } + + /* FIXME this needs to be checked somewhere */ + dec->restart_interval = jpeg_bits_get_u16_be (bits); +} + +void +jpeg_decoder_define_arithmetic_conditioning (JpegDecoder *dec) +{ + /* we don't handle arithmetic coding, so skip it */ + jpeg_decoder_skip (dec); +} + +void +jpeg_decoder_start_of_frame (JpegDecoder * dec, int marker) +{ + JpegBits *bits = &dec->bits; + int i; + int length; + + OIL_INFO ("start of frame"); + + dec->sof_type = marker; + + length = jpeg_bits_get_u16_be (bits); + + if (jpeg_bits_available(bits) < length) { + jpeg_decoder_error(dec, "not enough data for start_of_frame (%d < %d)", + length, jpeg_bits_available(bits)); + return; + } + + dec->depth = jpeg_bits_get_u8 (bits); + dec->height = jpeg_bits_get_u16_be (bits); + dec->width = jpeg_bits_get_u16_be (bits); + dec->n_components = jpeg_bits_get_u8 (bits); + + OIL_DEBUG ( + "frame_length=%d depth=%d height=%d width=%d n_components=%d", length, + dec->depth, dec->height, dec->width, dec->n_components); + + if (dec->n_components * 3 + 8 != length) { + jpeg_decoder_error(dec, "inconsistent header"); + return; + } + + for (i = 0; i < dec->n_components; i++) { + dec->components[i].id = get_u8 (bits); + dec->components[i].h_sample = getbits (bits, 4); + dec->components[i].v_sample = getbits (bits, 4); + dec->components[i].quant_table = get_u8 (bits); + + OIL_DEBUG ( + "[%d] id=%d h_sample=%d v_sample=%d quant_table=%d", i, + dec->components[i].id, dec->components[i].h_sample, + dec->components[i].v_sample, dec->components[i].quant_table); + } +} + +void +jpeg_decoder_start_of_scan (JpegDecoder * dec) +{ + JpegBits *bits = &dec->bits; + int length; + int i; + int spectral_start; + int spectral_end; + int approx_high; + int approx_low; + int n; + int tmp; + int n_components; + + OIL_DEBUG ("start of scan"); + + length = jpeg_bits_get_u16_be (bits); + OIL_DEBUG ("length=%d", length); + + n_components = jpeg_bits_get_u8 (bits); + n = 0; + dec->scan_h_subsample = 0; + dec->scan_v_subsample = 0; + for (i = 0; i < n_components; i++) { + int component_id; + int dc_table; + int ac_table; + int x; + int y; + int index; + int h_subsample; + int v_subsample; + int quant_index; + + component_id = jpeg_bits_get_u8 (bits); + tmp = jpeg_bits_get_u8 (bits); + dc_table = tmp >> 4; + ac_table = tmp & 0xf; + index = jpeg_decoder_find_component_by_id (dec, component_id); + + h_subsample = dec->components[index].h_sample; + v_subsample = dec->components[index].v_sample; + quant_index = dec->components[index].quant_table; + + for (y = 0; y < v_subsample; y++) { + for (x = 0; x < h_subsample; x++) { + dec->scan_list[n].component_index = index; + dec->scan_list[n].dc_table = dc_table; + dec->scan_list[n].ac_table = ac_table; + dec->scan_list[n].quant_table = quant_index; + dec->scan_list[n].x = x; + dec->scan_list[n].y = y; + dec->scan_list[n].offset = + y * 8 * dec->components[index].rowstride + x * 8; + n++; + } + } + + dec->scan_h_subsample = MAX (dec->scan_h_subsample, h_subsample); + dec->scan_v_subsample = MAX (dec->scan_v_subsample, v_subsample); + + OIL_DEBUG ("component %d: index=%d dc_table=%d ac_table=%d n=%d", + component_id, index, dc_table, ac_table, n); + } + dec->scan_list_length = n; + + spectral_start = jpeg_bits_get_u8 (bits); + spectral_end = jpeg_bits_get_u8 (bits); + OIL_DEBUG ("spectral range [%d,%d]", spectral_start, spectral_end); + tmp = jpeg_bits_get_u8 (bits); + approx_high = tmp >> 4; + approx_low = tmp & 0xf; + OIL_DEBUG ("approx range [%d,%d]", approx_low, approx_high); + + dec->x = 0; + dec->y = 0; + dec->dc[0] = dec->dc[1] = dec->dc[2] = dec->dc[3] = 128 * 8; +} + + + + + + + + + + + + +int +jpeg_decoder_addbits (JpegDecoder * dec, unsigned char *data, unsigned int len) +{ + unsigned int offset; + + offset = dec->bits.ptr - dec->data; + + dec->data = realloc (dec->data, dec->data_len + len); + memcpy (dec->data + dec->data_len, data, len); + dec->data_len += len; + + dec->bits.ptr = dec->data + offset; + dec->bits.end = dec->data + dec->data_len; + + return 0; +} + +int +jpeg_decoder_get_image_size (JpegDecoder * dec, int *width, int *height) +{ + if (width) + *width = dec->width; + if (height) + *height = dec->height; + + return 0; +} + +int +jpeg_decoder_get_component_ptr (JpegDecoder * dec, int id, + unsigned char **image, int *rowstride) +{ + int i; + + i = jpeg_decoder_find_component_by_id (dec, id); + if (image) + *image = dec->components[i].image; + if (rowstride) + *rowstride = dec->components[i].rowstride; + + return 0; +} + +int +jpeg_decoder_get_component_size (JpegDecoder * dec, int id, + int *width, int *height) +{ + int i; + + /* subsampling sizes are rounded up */ + + i = jpeg_decoder_find_component_by_id (dec, id); + if (width) + *width = (dec->width - 1) / dec->components[i].h_subsample + 1; + if (height) + *height = (dec->height - 1) / dec->components[i].v_subsample + 1; + + return 0; +} + +int +jpeg_decoder_get_component_subsampling (JpegDecoder * dec, int id, + int *h_subsample, int *v_subsample) +{ + int i; + + i = jpeg_decoder_find_component_by_id (dec, id); + if (h_subsample) + *h_subsample = dec->components[i].h_subsample; + if (v_subsample) + *v_subsample = dec->components[i].v_subsample; + + return 0; +} + +#if 0 +int +jpeg_decoder_parse (JpegDecoder * dec) +{ + JpegBits *bits = &dec->bits; + JpegBits b2; + unsigned int x; + unsigned int tag; + int i; + + while (bits->ptr < bits->end) { + x = get_u8 (bits); + if (x != 0xff) { + int n = 0; + + while (x != 0xff) { + x = get_u8 (bits); + n++; + } + OIL_DEBUG ("lost sync, skipped %d bytes", n); + } + while (x == 0xff) { + x = get_u8 (bits); + } + tag = x; + OIL_DEBUG ("tag %02x", tag); + + b2 = *bits; + + for (i = 0; i < n_jpeg_markers - 1; i++) { + if (tag == jpeg_markers[i].tag) { + break; + } + } + OIL_DEBUG ("tag: %s", jpeg_markers[i].name); + if (jpeg_markers[i].func) { + jpeg_markers[i].func (dec, &b2); + } else { + OIL_DEBUG ("unhandled or illegal JPEG marker (0x%02x)", tag); + dumpbits (&b2); + } + if (jpeg_markers[i].flags & JPEG_ENTROPY_SEGMENT) { + jpeg_decoder_decode_entropy_segment (dec, &b2); + } + syncbits (&b2); + bits->ptr = b2.ptr; + } + + return 0; +} +#endif + + +/* misc helper functins */ + +static char * +sprintbits (char *str, unsigned int bits, int n) +{ + int i; + int bit = 1 << (n - 1); + + for (i = 0; i < n; i++) { + str[i] = (bits & bit) ? '1' : '0'; + bit >>= 1; + } + str[i] = 0; + + return str; +} + +static void +huffman_table_load_std_jpeg (JpegDecoder * dec) +{ + JpegBits b, *bits = &b; + + bits->ptr = jpeg_standard_tables; + bits->idx = 0; + bits->end = jpeg_standard_tables + jpeg_standard_tables_size; + + huffman_table_init_jpeg (&dec->dc_huff_table[0], bits); + huffman_table_init_jpeg (&dec->ac_huff_table[0], bits); + huffman_table_init_jpeg (&dec->dc_huff_table[1], bits); + huffman_table_init_jpeg (&dec->ac_huff_table[1], bits); +} + + +