--- /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 <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <liboil/liboil-stdint.h>
+#include <liboil/liboil.h>
+#include <liboil/liboildebug.h>
+#include <stdarg.h>
+
+#include "jpeg_internal.h"
+#include <liboil/globals.h>
+
+#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);
+}
+
+
+