aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gall <tom.gall@linaro.org>2011-09-01 16:02:38 -0500
committerTom Gall <tom.gall@linaro.org>2011-12-23 11:38:02 -0600
commit2cbd712ef84e6729357e98761fa17f4be054b944 (patch)
treead66281d7b7f6ab8998a76ff237dba55f535f8dd
parentd519a0ef385e8d74fce083497630ffb4e9ba0adc (diff)
first cut at port of Android extentions
-rw-r--r--Android.mk254
-rw-r--r--config.h131
-rw-r--r--jccolor.c69
-rw-r--r--jconfig.h66
-rw-r--r--jdapimin.c9
-rw-r--r--jdapistd.c129
-rw-r--r--jdcoefct.c366
-rw-r--r--jdcolor.c532
-rw-r--r--jdhuff.c265
-rw-r--r--jdhuff.h1
-rw-r--r--jdinput.c55
-rw-r--r--jdmarker.c52
-rw-r--r--jdmaster.c25
-rw-r--r--jdmerge.c357
-rw-r--r--jdphuff.c127
-rw-r--r--jdtrans.c131
-rw-r--r--jmorecfg.h32
-rw-r--r--jpegint.h59
-rw-r--r--jpeglib.h110
-rw-r--r--jutils.c5
20 files changed, 2747 insertions, 28 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..4075dc9
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,254 @@
+# Makefile for libjpeg-turbo
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+##################################################
+### simd ###
+##################################################
+LOCAL_PATH := $(my-dir)
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+EXTRA_DIST = simd/nasm_lt.sh simd/jcclrmmx.asm simd/jcclrss2.asm simd/jdclrmmx.asm simd/jdclrss2.asm \
+ simd/jdmrgmmx.asm simd/jdmrgss2.asm simd/jcclrss2-64.asm simd/jdclrss2-64.asm \
+ simd/jdmrgss2-64.asm simd/CMakeLists.txt
+
+libsimd_SOURCES_DIST = simd/jsimd_arm_neon.S \
+ simd/jsimd_arm.c
+
+# or jsimd_none.c
+
+
+LOCAL_SRC_FILES := $(libsimd_SOURCES_DIST)
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/simd
+
+LOCAL_CFLAGS :=
+AM_CFLAGS := -march=armv7-a -mfpu=neon
+AM_CCASFLAGS := -march=armv7-a -mfpu=neon
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := libsimd
+
+include $(BUILD_STATIC_LIBRARY)
+
+######################################################
+### libjpeg.so ##
+######################################################
+
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+libjpeg_SOURCES_DIST = jcapimin.c jcapistd.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcphuff.c jcprepct.c jcsample.c jctrans.c \
+ jdapimin.c jdapistd.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdphuff.c jdpostct.c jdsample.c jdtrans.c jerror.c \
+ jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c \
+ jidctred.c jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c \
+ jaricom.c jcarith.c jdarith.c \
+ turbojpeg.c transupp.c jdatadst-tj.c jdatasrc-tj.c \
+ turbojpeg-mapfile
+
+#possible adds jmem-android.c jmemnobs.c jmemmgr.c jmem-ashmem.c
+
+LOCAL_SRC_FILES:= $(libjpeg_SOURCES_DIST)
+
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_STATIC_LIBRARIES := libsimd
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS := -DAVOID_TABLES -O3 -fstrict-aliasing -fprefetch-loop-arrays -DANDROID
+
+#-DANDROID_TILE_BASED_DECODE -DUSE_ANDROID_ASHMEM
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_STATIC_LIBRARY)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := libjpeg
+
+include $(BUILD_SHARED_LIBRARY)
+
+######################################################
+### cjpeg ###
+######################################################
+
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+cjpeg_SOURCES = cdjpeg.c cjpeg.c rdbmp.c rdgif.c \
+ rdppm.c rdswitch.c rdtarga.c
+
+LOCAL_SRC_FILES:= $(cjpeg_SOURCES)
+
+LOCAL_SHARED_LIBRARIES := libjpeg
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS := -DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLE)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := cjpeg
+
+include $(BUILD_EXECUTABLE)
+
+######################################################
+### djpeg ###
+######################################################
+
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+djpeg_SOURCES = cdjpeg.c djpeg.c rdcolmap.c rdswitch.c \
+ wrbmp.c wrgif.c wrppm.c wrtarga.c
+
+LOCAL_SRC_FILES:= $(djpeg_SOURCES)
+
+LOCAL_SHARED_LIBRARIES := libjpeg
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS := -DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLE)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := djpeg
+
+include $(BUILD_EXECUTABLE)
+
+######################################################
+### jpegtran ###
+######################################################
+
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+jpegtran_SOURCES = jpegtran.c rdswitch.c cdjpeg.c transupp.c
+
+LOCAL_SRC_FILES:= $(jpegtran_SOURCES)
+
+LOCAL_SHARED_LIBRARIES := libjpeg
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS :=
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLE)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := jpegtran
+
+include $(BUILD_EXECUTABLE)
+
+######################################################
+### tjunittest ###
+######################################################
+
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+tjunittest_SOURCES = tjunittest.c tjutil.c
+
+LOCAL_SRC_FILES:= $(tjunittest_SOURCES)
+
+LOCAL_SHARED_LIBRARIES := libjpeg
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS :=
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLE)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := tjunittest
+
+include $(BUILD_EXECUTABLE)
+
+######################################################
+### tjbench ###
+######################################################
+
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+tjbench_SOURCES = tjbench.c bmp.c tjutil.c rdbmp.c rdppm.c \
+ wrbmp.c wrppm.c
+
+LOCAL_SRC_FILES:= $(tjbench_SOURCES)
+
+LOCAL_SHARED_LIBRARIES := libjpeg
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS := -DBMP_SUPPORTED -DPPM_SUPPORTED
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLE)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := tjbench
+
+include $(BUILD_EXECUTABLE)
+
+######################################################
+### rdjpgcom ###
+######################################################
+
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+rdjpgcom_SOURCES = rdjpgcom.c
+
+LOCAL_SRC_FILES:= $(rdjpgcom_SOURCES)
+
+LOCAL_SHARED_LIBRARIES := libjpeg
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS :=
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLE)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := rdjpgcom
+
+include $(BUILD_EXECUTABLE)
+
+######################################################
+### wrjpgcom ###
+######################################################
+
+include $(CLEAR_VARS)
+
+# From autoconf-generated Makefile
+wrjpgcom_SOURCES = wrjpgcom.c
+
+LOCAL_SRC_FILES:= $(wrjpgcom_SOURCES)
+
+LOCAL_SHARED_LIBRARIES := libjpeg
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS :=
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLE)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := wrjpgcom
+
+include $(BUILD_EXECUTABLE)
+
+endif # TARGET_SIMULATOR != true
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..6e38c88
--- /dev/null
+++ b/config.h
@@ -0,0 +1,131 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Build number */
+#define BUILD "20110829"
+
+/* Support arithmetic encoding */
+#define C_ARITH_CODING_SUPPORTED 1
+
+/* Support arithmetic decoding */
+#define D_ARITH_CODING_SUPPORTED 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <jni.h> header file. */
+/* #undef HAVE_JNI_H */
+
+/* Define to 1 if you have the `memcpy' function. */
+#define HAVE_MEMCPY 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define if your compiler supports prototypes */
+#define HAVE_PROTOTYPES 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the system has the type `unsigned char'. */
+#define HAVE_UNSIGNED_CHAR 1
+
+/* Define to 1 if the system has the type `unsigned short'. */
+#define HAVE_UNSIGNED_SHORT 1
+
+/* Compiler does not support pointers to undefined structures. */
+/* #undef INCOMPLETE_TYPES_BROKEN */
+
+/* libjpeg API version */
+#define JPEG_LIB_VERSION 62
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define if you have BSD-like bzero and bcopy */
+/* #undef NEED_BSD_STRINGS */
+
+/* Define if you need short function names */
+/* #undef NEED_SHORT_EXTERNAL_NAMES */
+
+/* Define if you have sys/types.h */
+#define NEED_SYS_TYPES_H 1
+
+/* Name of package */
+#define PACKAGE "libjpeg-turbo"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libjpeg-turbo"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libjpeg-turbo 1.1.90"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libjpeg-turbo"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.1.90"
+
+/* Define if shift is unsigned */
+/* #undef RIGHT_SHIFT_IS_UNSIGNED */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.1.90"
+
+/* Use accelerated SIMD routines. */
+#define WITH_SIMD 1
+
+/* Define to 1 if type `char' is unsigned and you are not using gcc. */
+#ifndef __CHAR_UNSIGNED__
+/* # undef __CHAR_UNSIGNED__ */
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/jccolor.c b/jccolor.c
index 0d8910a..d46b6c7 100644
--- a/jccolor.c
+++ b/jccolor.c
@@ -14,6 +14,7 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
+#include "jconfig.h"
/* Private subobject */
@@ -27,6 +28,37 @@ typedef struct {
typedef my_color_converter * my_cconvert_ptr;
+#ifdef ENABLE_ANDROID_NULL_CONVERT
+
+typedef unsigned long UINT32;
+
+#define B0(n) ((n) & 0xFF)
+#define B1(n) (((n) >> 8) & 0xFF)
+#define B2(n) (((n) >> 16) & 0xFF)
+#define B3(n) ((n) >> 24)
+
+#define PACK(a, b, c, d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
+
+static int ptr_is_quad(const void* p)
+{
+ return (((const char*)p - (const char*)0) & 3) == 0;
+}
+
+static void copyquads(const UINT32 in[], UINT32 out0[], UINT32 out1[], UINT32 out2[], int col4)
+{
+ do {
+ UINT32 src0 = *in++;
+ UINT32 src1 = *in++;
+ UINT32 src2 = *in++;
+ // LEndian
+ *out0++ = PACK(B0(src0), B3(src0), B2(src1), B1(src2));
+ *out1++ = PACK(B1(src0), B0(src1), B3(src1), B2(src2));
+ *out2++ = PACK(B2(src0), B1(src1), B0(src2), B3(src2));
+ } while (--col4 != 0);
+}
+
+#endif
+
/**************** RGB -> YCbCr conversion: most common case **************/
@@ -409,6 +441,43 @@ null_convert (j_compress_ptr cinfo,
int nc = cinfo->num_components;
JDIMENSION num_cols = cinfo->image_width;
+#ifdef ENABLE_ANDROID_NULL_CONVERT
+ if (1 == num_rows && 3 == nc && num_cols > 0) {
+ JSAMPROW inptr = *input_buf;
+ JSAMPROW outptr0 = output_buf[0][output_row];
+ JSAMPROW outptr1 = output_buf[1][output_row];
+ JSAMPROW outptr2 = output_buf[2][output_row];
+
+ int col = num_cols;
+ int col4 = col >> 2;
+ if (col4 > 0 && ptr_is_quad(inptr) && ptr_is_quad(outptr0) &&
+ ptr_is_quad(outptr1) && ptr_is_quad(outptr2)) {
+
+ const UINT32* in = (const UINT32*)inptr;
+ UINT32* out0 = (UINT32*)outptr0;
+ UINT32* out1 = (UINT32*)outptr1;
+ UINT32* out2 = (UINT32*)outptr2;
+ copyquads(in, out0, out1, out2, col4);
+ col &= 3;
+ if (0 == col)
+ return;
+ col4 <<= 2;
+ inptr += col4 * 3; /* we read this 3 times per in copyquads */
+ outptr0 += col4;
+ outptr1 += col4;
+ outptr2 += col4;
+ /* fall through to while-loop */
+ }
+ do {
+ *outptr0++ = *inptr++;
+ *outptr1++ = *inptr++;
+ *outptr2++ = *inptr++;
+ } while (--col != 0);
+ return;
+ }
+SLOW:
+#endif
+
while (--num_rows >= 0) {
/* It seems fastest to make a separate pass for each component. */
for (ci = 0; ci < nc; ci++) {
diff --git a/jconfig.h b/jconfig.h
new file mode 100644
index 0000000..e89b18b
--- /dev/null
+++ b/jconfig.h
@@ -0,0 +1,66 @@
+/* jconfig.h. Generated from jconfig.h.in by configure. */
+/* Version ID for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
+ */
+#define JPEG_LIB_VERSION 62
+
+/* Support arithmetic encoding */
+#define C_ARITH_CODING_SUPPORTED 1
+
+/* Support arithmetic decoding */
+#define D_ARITH_CODING_SUPPORTED 1
+
+/* Define if your compiler supports prototypes */
+#define HAVE_PROTOTYPES 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if the system has the type `unsigned char'. */
+#define HAVE_UNSIGNED_CHAR 1
+
+/* Define to 1 if the system has the type `unsigned short'. */
+#define HAVE_UNSIGNED_SHORT 1
+
+/* Define if you want use complete types */
+/* #undef INCOMPLETE_TYPES_BROKEN */
+
+/* Define if you have BSD-like bzero and bcopy */
+/* #undef NEED_BSD_STRINGS */
+
+/* Define if you need short function names */
+/* #undef NEED_SHORT_EXTERNAL_NAMES */
+
+/* Define if you have sys/types.h */
+#define NEED_SYS_TYPES_H 1
+
+/* Define if shift is unsigned */
+/* #undef RIGHT_SHIFT_IS_UNSIGNED */
+
+/* Use accelerated SIMD routines. */
+#define WITH_SIMD 1
+
+/* Define to 1 if type `char' is unsigned and you are not using gcc. */
+#ifndef __CHAR_UNSIGNED__
+/* # undef __CHAR_UNSIGNED__ */
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Android specific */
+#define ANDROID_RGB
+
+#define ENABLE_ANDROID_NULL_CONVERT
diff --git a/jdapimin.c b/jdapimin.c
index cadb59f..091b432 100644
--- a/jdapimin.c
+++ b/jdapimin.c
@@ -54,6 +54,10 @@ jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
}
cinfo->is_decompressor = TRUE;
+#ifdef ANDROID
+ cinfo->tile_decode = FALSE;
+#endif
+
/* Initialize a memory manager instance for this object */
jinit_memory_mgr((j_common_ptr) cinfo);
@@ -370,6 +374,9 @@ jpeg_finish_decompress (j_decompress_ptr cinfo)
{
if ((cinfo->global_state == DSTATE_SCANNING ||
cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) {
+#ifdef ANDROID_TILE_BASED_DECODE
+ cinfo->output_scanline = cinfo->output_height;
+#endif
/* Terminate final pass of non-buffered mode */
if (cinfo->output_scanline < cinfo->output_height)
ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
@@ -383,10 +390,12 @@ jpeg_finish_decompress (j_decompress_ptr cinfo)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
}
/* Read until EOI */
+#ifndef ANDROID_TILE_BASED_DECODE
while (! cinfo->inputctl->eoi_reached) {
if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
return FALSE; /* Suspend, come back later */
}
+#endif
/* Do final cleanup */
(*cinfo->src->term_source) (cinfo);
/* We can use jpeg_abort to release memory and reset global_state */
diff --git a/jdapistd.c b/jdapistd.c
index 2343da5..981b0ff 100644
--- a/jdapistd.c
+++ b/jdapistd.c
@@ -84,7 +84,6 @@ jpeg_start_decompress (j_decompress_ptr cinfo)
return output_pass_setup(cinfo);
}
-
/*
* Set up for an output pass, and perform any dummy pass(es) needed.
* Common subroutine for jpeg_start_decompress and jpeg_start_output.
@@ -275,3 +274,131 @@ jpeg_finish_output (j_decompress_ptr cinfo)
}
#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+#ifdef ANDROID
+
+/*
+ * Tile decompression initialization.
+ * jpeg_read_header must be completed before calling this.
+ */
+
+GLOBAL(boolean)
+jpeg_start_tile_decompress (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ /* First call: initialize master control, select active modules */
+ cinfo->tile_decode = TRUE;
+ jinit_master_decompress(cinfo);
+ if (cinfo->buffered_image) {
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+ }
+ cinfo->global_state = DSTATE_PRELOAD;
+ }
+ if (cinfo->global_state == DSTATE_PRELOAD) {
+ cinfo->output_scan_number = cinfo->input_scan_number;
+ } else if (cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Perform any dummy output passes, and set up for the final pass */
+ return output_pass_setup(cinfo);
+}
+
+/*
+ * Initialize the jpeg decoder to decompressing a rectangle with size of (width, height)
+ * and its upper-left corner located at (start_x, start_y).
+ * Align start_x and start_y to multiplies of iMCU width and height, respectively.
+ * Also, the new reader position and sampled image size will be returned in
+ * (start_x, start_y) and (width, height), respectively.
++ */
+
+GLOBAL(void)
+jpeg_init_read_tile_scanline(j_decompress_ptr cinfo, huffman_index *index,
+ int *start_x, int *start_y, int *width, int *height)
+{
+ // Calculates the boundary of iMCU
+ int lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE;
+ int lines_per_iMCU_col = cinfo->max_h_samp_factor * DCTSIZE;
+ int row_offset = *start_y / lines_per_iMCU_row;
+ int col_left_boundary = ((*start_x / lines_per_iMCU_col)
+ / index->MCU_sample_size) * index->MCU_sample_size;
+ int col_right_boundary =
+ jdiv_round_up(*start_x + *width, lines_per_iMCU_col);
+
+ cinfo->coef->MCU_columns_to_skip =
+ *start_x / lines_per_iMCU_col - col_left_boundary;
+
+ *height = (*start_y - row_offset * lines_per_iMCU_row) + *height;
+ *start_x = col_left_boundary * lines_per_iMCU_col;
+ *start_y = row_offset * lines_per_iMCU_row;
+ cinfo->image_width = jmin(cinfo->original_image_width,
+ col_right_boundary * lines_per_iMCU_col) -
+ col_left_boundary * lines_per_iMCU_col;
+ cinfo->input_iMCU_row = row_offset;
+ cinfo->output_iMCU_row = row_offset;
+
+ // Updates JPEG decoder parameter
+ jinit_color_deconverter(cinfo);
+ jpeg_calc_output_dimensions(cinfo);
+ jinit_upsampler(cinfo);
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ if (cinfo->progressive_mode)
+ (*cinfo->entropy->start_pass) (cinfo);
+ else
+ jpeg_decompress_per_scan_setup(cinfo);
+
+ int sample_size = DCTSIZE / cinfo->min_DCT_scaled_size;
+
+ *height = jdiv_round_up(*height, sample_size);
+ *width = cinfo->output_width;
+ cinfo->output_scanline = lines_per_iMCU_row * row_offset / sample_size;
+ cinfo->inputctl->consume_input = cinfo->coef->consume_data;
+ cinfo->inputctl->consume_input_build_huffman_index =
+ cinfo->coef->consume_data_build_huffman_index;
+ cinfo->entropy->index = index;
+ cinfo->input_iMCU_row = row_offset;
+ cinfo->output_iMCU_row = row_offset;
+ cinfo->coef->MCU_column_left_boundary = col_left_boundary;
+ cinfo->coef->MCU_column_right_boundary = col_right_boundary;
+ cinfo->coef->column_left_boundary =
+ col_left_boundary / index->MCU_sample_size;
+ cinfo->coef->column_right_boundary =
+ jdiv_round_up(col_right_boundary, index->MCU_sample_size);
+}
+
+/*
+ * Read a scanline from the current position.
+ *
+ * Return the number of lines actually read.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_tile_scanline (j_decompress_ptr cinfo, huffman_index *index,
+ JSAMPARRAY scanlines)
+{
+ // Calculates the boundary of iMCU
+ int lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE;
+ int lines_per_iMCU_col = cinfo->max_h_samp_factor * DCTSIZE;
+ int sample_size = DCTSIZE / cinfo->min_DCT_scaled_size;
+ JDIMENSION row_ctr = 0;
+
+ if (cinfo->progressive_mode) {
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, 1);
+ } else {
+ if (cinfo->output_scanline % (lines_per_iMCU_row / sample_size) == 0) {
+ // Set the read head to the next iMCU row
+ int iMCU_row_offset = cinfo->output_scanline /
+ (lines_per_iMCU_row / sample_size);
+ int offset_data_col_position = cinfo->coef->MCU_column_left_boundary /
+ index->MCU_sample_size;
+ huffman_offset_data offset_data =
+ index->scan[0].offset[iMCU_row_offset][offset_data_col_position];
+ (*cinfo->entropy->configure_huffman_decoder) (cinfo, offset_data);
+ }
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, 1);
+ }
+
+ cinfo->output_scanline += row_ctr;
+ return row_ctr;
+}
+
+#endif /* ANDROID */
diff --git a/jdcoefct.c b/jdcoefct.c
index 48a9fc6..7f80669 100644
--- a/jdcoefct.c
+++ b/jdcoefct.c
@@ -161,20 +161,39 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
jpeg_component_info *compptr;
inverse_DCT_method_ptr inverse_DCT;
+#ifdef ANDROID_TILE_BASED_DECODE
+ if (cinfo->tile_decode) {
+ last_MCU_col =
+ (cinfo->coef->MCU_column_right_boundary -
+ cinfo->coef->MCU_column_left_boundary) - 1;
+ }
+#endif
+
/* Loop to process as much as one whole iMCU row */
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
yoffset++) {
for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;
MCU_col_num++) {
/* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
- jzero_far((void FAR *) coef->MCU_buffer[0],
+#ifdef ANDROID
+
+ if (MCU_col_num < coef->pub.MCU_columns_to_skip) {
+ (*cinfo->entropy->decode_mcu_discard_coef) (cinfo);
+ continue;
+ } else {
+#endif /* ANDROID */
+ jzero_far((void FAR *) coef->MCU_buffer[0],
(size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK)));
- if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
- /* Suspension forced; update state counters and exit */
- coef->MCU_vert_offset = yoffset;
- coef->MCU_ctr = MCU_col_num;
- return JPEG_SUSPENDED;
+ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+
+#ifdef ANDROID
}
+#endif /* ANDROID */
/* Determine where data should go in output_buf and do the IDCT thing.
* We skip dummy blocks at the right and bottom edges (but blkn gets
* incremented past them!). Note the inner loop relies on having
@@ -261,7 +280,11 @@ consume_data (j_decompress_ptr cinfo)
compptr = cinfo->cur_comp_info[ci];
buffer[ci] = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+#ifdef ANDROID
+ cinfo->tile_decode ? 0 : cinfo->input_iMCU_row * compptr->v_samp_factor,
+#else
cinfo->input_iMCU_row * compptr->v_samp_factor,
+#endif /* ANDROID */
(JDIMENSION) compptr->v_samp_factor, TRUE);
/* Note: entropy decoder expects buffer to be zeroed,
* but this is handled automatically by the memory manager
@@ -269,29 +292,67 @@ consume_data (j_decompress_ptr cinfo)
*/
}
+ unsigned int MCUs_per_row = cinfo->MCUs_per_row;
+#ifdef ANDROID_TILE_BASED_DECODE
+ if (cinfo->tile_decode) {
+ int iMCU_width_To_MCU_width;
+ if (cinfo->comps_in_scan > 1) {
+ // Interleaved
+ iMCU_width_To_MCU_width = 1;
+ } else {
+ // Non-intervleaved
+ iMCU_width_To_MCU_width = cinfo->cur_comp_info[0]->h_samp_factor;
+ }
+ MCUs_per_row = jmin(MCUs_per_row,
+ (cinfo->coef->column_right_boundary - cinfo->coef->column_left_boundary)
+ * cinfo->entropy->index->MCU_sample_size * iMCU_width_To_MCU_width);
+ }
+#endif
+
/* Loop to process one whole iMCU row */
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
yoffset++) {
- for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
- MCU_col_num++) {
+ // configure huffman decoder
+#ifdef ANDROID_TILE_BASED_DECODE
+ if (cinfo->tile_decode) {
+ huffman_scan_header scan_header =
+ cinfo->entropy->index->scan[cinfo->input_scan_number];
+ int col_offset = cinfo->coef->column_left_boundary;
+ (*cinfo->entropy->configure_huffman_decoder) (cinfo,
+ scan_header.offset[cinfo->input_iMCU_row]
+ [col_offset + yoffset * scan_header.MCUs_per_row]);
+ }
+#endif
+
+ // zero all blocks
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num < MCUs_per_row;
+ MCU_col_num++) {
/* Construct list of pointers to DCT blocks belonging to this MCU */
blkn = 0; /* index of current DCT block within MCU */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- start_col = MCU_col_num * compptr->MCU_width;
- for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
- buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
- for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
- coef->MCU_buffer[blkn++] = buffer_ptr++;
- }
- }
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+ coef->MCU_buffer[blkn++] = buffer_ptr++;
+#ifdef ANDROID_TILE_BASED_DECODE
+ if (cinfo->tile_decode && cinfo->input_scan_number == 0) {
+ // need to do pre-zero ourselves.
+ jzero_far((void FAR *) coef->MCU_buffer[blkn-1],
+ (size_t) (SIZEOF(JBLOCK)));
+ }
+#endif /* ANDROID_TILE_BASED_DECODE */
+
+ }
+ }
}
/* Try to fetch the MCU. */
if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
- /* Suspension forced; update state counters and exit */
- coef->MCU_vert_offset = yoffset;
- coef->MCU_ctr = MCU_col_num;
- return JPEG_SUSPENDED;
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
}
}
/* Completed an MCU row, but perhaps not an iMCU row */
@@ -347,7 +408,11 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
/* Align the virtual buffer for this component. */
buffer = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image[ci],
+#ifndef ANDROID
cinfo->output_iMCU_row * compptr->v_samp_factor,
+#else
+ cinfo->tile_decode ? 0 : cinfo->output_iMCU_row * compptr->v_samp_factor,
+#endif
(JDIMENSION) compptr->v_samp_factor, FALSE);
/* Count non-dummy DCT block rows in this iMCU row. */
if (cinfo->output_iMCU_row < last_iMCU_row)
@@ -359,11 +424,25 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
}
inverse_DCT = cinfo->idct->inverse_DCT[ci];
output_ptr = output_buf[ci];
+ int width_in_blocks = compptr->width_in_blocks;
+ int start_block = 0;
+#if ANDROID_TILE_BASED_DECODE
+ if (cinfo->tile_decode) {
+ // width_in_blocks for a component depends on its h_samp_factor.
+ width_in_blocks = jmin(width_in_blocks,
+ (cinfo->coef->MCU_column_right_boundary -
+ cinfo->coef->MCU_column_left_boundary) *
+ compptr->h_samp_factor);
+ start_block = coef->pub.MCU_columns_to_skip *
+ compptr->h_samp_factor;
+ }
+#endif /* ANDROID_TILE_BASED_DECODE */
/* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) {
buffer_ptr = buffer[block_row];
- output_col = 0;
- for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
+ output_col = start_block * compptr->DCT_scaled_size;
+ buffer_ptr += start_block;
+ for (block_num = start_block; block_num < width_in_blocks; block_num++) {
(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
output_ptr, output_col);
buffer_ptr++;
@@ -691,10 +770,60 @@ jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
cinfo->coef = (struct jpeg_d_coef_controller *) coef;
coef->pub.start_input_pass = start_input_pass;
coef->pub.start_output_pass = start_output_pass;
+
#ifdef BLOCK_SMOOTHING_SUPPORTED
coef->coef_bits_latch = NULL;
#endif
+#ifdef ANDROID_TILE_BASED_DECODE
+ coef->pub.column_left_boundary = 0;
+ coef->pub.column_right_boundary = 0;
+ coef->pub.MCU_columns_to_skip = 0;
+ if (cinfo->tile_decode) {
+ if (cinfo->progressive_mode) {
+ /* Allocate one iMCU row virtual array, coef->whole_image[ci],
+ * for each color component, padded to a multiple of h_samp_factor
+ * DCT blocks in the horizontal direction.
+ */
+ int ci, access_rows;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ access_rows = compptr->v_samp_factor;
+ coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,
+ (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+ (long) compptr->h_samp_factor),
+ (JDIMENSION) compptr->v_samp_factor, // one iMCU row
+ (JDIMENSION) access_rows);
+ }
+ coef->pub.consume_data_build_huffman_index =
+ consume_data_build_huffman_index_progressive;
+ coef->pub.consume_data = consume_data_multi_scan;
+ coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
+ coef->pub.decompress_data = decompress_onepass;
+ } else {
+ /* We only need a single-MCU buffer. */
+ JBLOCKROW buffer;
+ int i;
+
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) {
+ coef->MCU_buffer[i] = buffer + i;
+ }
+ coef->pub.consume_data_build_huffman_index =
+ consume_data_build_huffman_index_baseline;
+ coef->pub.consume_data = dummy_consume_data;
+ coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
+ coef->pub.decompress_data = decompress_onepass;
+ }
+ return;
+ }
+#endif
+
/* Create the coefficient buffer. */
if (need_full_buffer) {
#ifdef D_MULTISCAN_FILES_SUPPORTED
@@ -747,3 +876,196 @@ jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(JCOEF) * DCTSIZE2);
}
+
+#ifdef ANDROID
+/*
+ * Consume input data and store it in the coefficient buffer.
+ * Read one fully interleaved MCU row ("iMCU" row) per call.
+ */
+
+METHODDEF(int)
+consume_data_multi_scan (j_decompress_ptr cinfo)
+{
+ huffman_index *index = cinfo->entropy->index;
+ int i, retcode, ci;
+ int mcu = cinfo->input_iMCU_row;
+ jinit_phuff_decoder(cinfo);
+ for (i = 0; i < index->scan_count; i++) {
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ jset_input_stream_position(cinfo, index->scan[i].bitstream_offset);
+ cinfo->output_iMCU_row = mcu;
+ cinfo->unread_marker = 0;
+ // Consume SOS and DHT headers
+ retcode = (*cinfo->inputctl->consume_markers) (cinfo, index, i);
+ cinfo->input_iMCU_row = mcu;
+ cinfo->input_scan_number = i;
+ cinfo->entropy->index = index;
+ // Consume scan block data
+ consume_data(cinfo);
+ }
+ cinfo->input_iMCU_row = mcu + 1;
+ cinfo->input_scan_number = 0;
+ cinfo->output_scan_number = 0;
+ return JPEG_ROW_COMPLETED;
+}
+
+/*
+ * Same as consume_data, expect for saving the Huffman decode information
+ * - bitstream offset and DC coefficient to index.
+ */
+
+METHODDEF(int)
+consume_data_build_huffman_index_baseline (j_decompress_ptr cinfo,
+ huffman_index *index, int current_scan)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ int ci, xindex, yindex, yoffset;
+ JDIMENSION start_col;
+ JBLOCKROW buffer_ptr;
+
+ huffman_scan_header *scan_header = index->scan + current_scan;
+ scan_header->MCU_rows_per_iMCU_row = coef->MCU_rows_per_iMCU_row;
+
+ size_t allocate_size = coef->MCU_rows_per_iMCU_row
+ * jdiv_round_up(cinfo->MCUs_per_row, index->MCU_sample_size)
+ * sizeof(huffman_offset_data);
+ scan_header->offset[cinfo->input_iMCU_row] =
+ (huffman_offset_data*)malloc(allocate_size);
+ index->mem_used += allocate_size;
+
+ huffman_offset_data *offset_data = scan_header->offset[cinfo->input_iMCU_row];
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ // Record huffman bit offset
+ if (MCU_col_num % index->MCU_sample_size == 0) {
+ (*cinfo->entropy->get_huffman_decoder_configuration)
+ (cinfo, offset_data);
+ ++offset_data;
+ }
+
+ /* Try to fetch the MCU. */
+ if (! (*cinfo->entropy->decode_mcu_discard_coef) (cinfo)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+/*
+ * Same as consume_data, expect for saving the Huffman decode information
+ * - bitstream offset and DC coefficient to index.
+ */
+
+METHODDEF(int)
+consume_data_build_huffman_index_progressive (j_decompress_ptr cinfo,
+ huffman_index *index, int current_scan)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ int blkn, ci, xindex, yindex, yoffset;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ int factor = 4; // maximum factor is 4.
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ factor = jmin(factor, cinfo->cur_comp_info[ci]->h_samp_factor);
+
+ int sample_size = index->MCU_sample_size * factor;
+ huffman_scan_header *scan_header = index->scan + current_scan;
+ scan_header->MCU_rows_per_iMCU_row = coef->MCU_rows_per_iMCU_row;
+ scan_header->MCUs_per_row = jdiv_round_up(cinfo->MCUs_per_row, sample_size);
+ scan_header->comps_in_scan = cinfo->comps_in_scan;
+
+ size_t allocate_size = coef->MCU_rows_per_iMCU_row
+ * scan_header->MCUs_per_row * sizeof(huffman_offset_data);
+ scan_header->offset[cinfo->input_iMCU_row] =
+ (huffman_offset_data*)malloc(allocate_size);
+ index->mem_used += allocate_size;
+
+ huffman_offset_data *offset_data = scan_header->offset[cinfo->input_iMCU_row];
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ 0, // Only need one row buffer
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ }
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* For each MCU, we loop through different color components.
+ * Then, for each color component we will get a list of pointers to DCT
+ * blocks in the virtual buffer.
+ */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ /* Get the list of pointers to DCT blocks in
+ * the virtual buffer in a color component of the MCU.
+ */
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+ coef->MCU_buffer[blkn++] = buffer_ptr++;
+ if (cinfo->input_scan_number == 0) {
+ // need to do pre-zero by ourself.
+ jzero_far((void FAR *) coef->MCU_buffer[blkn-1],
+ (size_t) (SIZEOF(JBLOCK)));
+ }
+ }
+ }
+ }
+ // Record huffman bit offset
+ if (MCU_col_num % sample_size == 0) {
+ (*cinfo->entropy->get_huffman_decoder_configuration)
+ (cinfo, offset_data);
+ ++offset_data;
+ }
+ /* Try to fetch the MCU. */
+ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+#endif /* ANDROID */
diff --git a/jdcolor.c b/jdcolor.c
index a9a9220..e6bfa43 100644
--- a/jdcolor.c
+++ b/jdcolor.c
@@ -30,6 +30,69 @@ typedef struct {
typedef my_color_deconverter * my_cconvert_ptr;
+#ifdef ANDROID_RGB
+
+/* Declarations for ordered dithering.
+ *
+ * We use 4x4 ordered dither array packed into 32 bits. This array is
+ * sufficent for dithering RGB_888 to RGB_565.
+ */
+
+#define DITHER_MASK 0x3
+#define DITHER_ROTATE(x) (((x)<<24) | (((x)>>8)&0x00FFFFFF))
+static const INT32 dither_matrix[4] = {
+ 0x0008020A,
+ 0x0C040E06,
+ 0x030B0109,
+ 0x0F070D05
+};
+
+METHODDEF(void)
+ycc_rgba_8888_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+
+METHODDEF(void)
+gray_rgba_8888_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+
+METHODDEF(void)
+gray_rgb_565_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+
+METHODDEF(void)
+gray_rgb_565D_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+
+METHODDEF(void)
+rgb_rgba_8888_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+
+METHODDEF(void)
+ycc_rgb_565_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+
+METHODDEF(void)
+rgb_rgb_565_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+
+METHODDEF(void)
+ycc_rgb_565D_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+
+METHODDEF(void)
+rgb_rgb_565D_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows);
+#endif
+
/**************** YCbCr -> RGB conversion: most common case **************/
@@ -511,6 +574,48 @@ jinit_color_deconverter (j_decompress_ptr cinfo)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
+#ifdef ANDROID_RGB
+ case JCS_RGBA_8888:
+ cinfo->out_color_components = 4;
+ if (cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = ycc_rgba_8888_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
+ cconvert->pub.color_convert = gray_rgba_8888_convert;
+ } else if (cinfo->jpeg_color_space == JCS_RGB) {
+ cconvert->pub.color_convert = rgb_rgba_8888_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_RGB_565:
+ cinfo->out_color_components = RGB_PIXELSIZE;
+ if (cinfo->dither_mode == JDITHER_NONE) {
+ if (cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = ycc_rgb_565_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
+ cconvert->pub.color_convert = gray_rgb_565_convert;
+ } else if (cinfo->jpeg_color_space == JCS_RGB) {
+ cconvert->pub.color_convert = rgb_rgb_565_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ } else {
+ /* only ordered dither is supported */
+ if (cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = ycc_rgb_565D_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
+ cconvert->pub.color_convert = gray_rgb_565D_convert;
+ } else if (cinfo->jpeg_color_space == JCS_RGB) {
+ cconvert->pub.color_convert = rgb_rgb_565D_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ }
+ break;
+#endif /* ANDROID_RGB */
+
+
default:
/* Permit null conversion to same output space */
if (cinfo->out_color_space == cinfo->jpeg_color_space) {
@@ -526,3 +631,430 @@ jinit_color_deconverter (j_decompress_ptr cinfo)
else
cinfo->output_components = cinfo->out_color_components;
}
+
+#ifdef ANDROID
+
+#ifdef ANDROID_RGB
+METHODDEF(void)
+ycc_rgba_8888_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ y = GETJSAMPLE(inptr0[col]);
+ cb = GETJSAMPLE(inptr1[col]);
+ cr = GETJSAMPLE(inptr2[col]);
+ /* Range-limiting is essential due to noise introduced by DCT losses. */
+ outptr[RGB_RED] = range_limit[y + Crrtab[cr]];
+ outptr[RGB_GREEN] = range_limit[y +
+ ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+ SCALEBITS))];
+ outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
+ outptr[RGB_ALPHA] = 0xFF;
+ outptr += 4;
+ }
+ }
+}
+
+
+METHODDEF(void)
+ycc_rgb_565_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ INT32 rgb;
+ unsigned int r, g, b;
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+
+ if (PACK_NEED_ALIGNMENT(outptr)) {
+ y = GETJSAMPLE(*inptr0++);
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ r = range_limit[y + Crrtab[cr]];
+ g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb]+Crgtab[cr], SCALEBITS))];
+ b = range_limit[y + Cbbtab[cb]];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ outptr += 2;
+ num_cols--;
+ }
+ for (col = 0; col < (num_cols>>1); col++) {
+ y = GETJSAMPLE(*inptr0++);
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ r = range_limit[y + Crrtab[cr]];
+ g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb]+Crgtab[cr], SCALEBITS))];
+ b = range_limit[y + Cbbtab[cb]];
+ rgb = PACK_SHORT_565(r,g,b);
+
+ y = GETJSAMPLE(*inptr0++);
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ r = range_limit[y + Crrtab[cr]];
+ g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb]+Crgtab[cr], SCALEBITS))];
+ b = range_limit[y + Cbbtab[cb]];
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_ALIGNED_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ if (num_cols&1) {
+ y = GETJSAMPLE(*inptr0);
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ r = range_limit[y + Crrtab[cr]];
+ g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb]+Crgtab[cr], SCALEBITS))];
+ b = range_limit[y + Cbbtab[cb]];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ }
+ }
+}
+
+METHODDEF(void)
+ycc_rgb_565D_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ INT32 rgb;
+ unsigned int r, g, b;
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ if (PACK_NEED_ALIGNMENT(outptr)) {
+ y = GETJSAMPLE(*inptr0++);
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)];
+ g = range_limit[DITHER_565_G(y + ((int)RIGHT_SHIFT(Cbgtab[cb]+Crgtab[cr], SCALEBITS)), d0)];
+ b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ outptr += 2;
+ num_cols--;
+ }
+ for (col = 0; col < (num_cols>>1); col++) {
+ y = GETJSAMPLE(*inptr0++);
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)];
+ g = range_limit[DITHER_565_G(y + ((int)RIGHT_SHIFT(Cbgtab[cb]+Crgtab[cr], SCALEBITS)), d0)];
+ b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr0++);
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)];
+ g = range_limit[DITHER_565_G(y + ((int)RIGHT_SHIFT(Cbgtab[cb]+Crgtab[cr], SCALEBITS)), d0)];
+ b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_ALIGNED_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ if (num_cols&1) {
+ y = GETJSAMPLE(*inptr0);
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)];
+ g = range_limit[DITHER_565_G(y + ((int)RIGHT_SHIFT(Cbgtab[cb]+Crgtab[cr], SCALEBITS)), d0)];
+ b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ }
+ }
+}
+
+METHODDEF(void)
+rgb_rgba_8888_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ *outptr++ = *inptr0++;
+ *outptr++ = *inptr1++;
+ *outptr++ = *inptr2++;
+ *outptr++ = 0xFF;
+ }
+ }
+}
+
+METHODDEF(void)
+rgb_rgb_565_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ INT32 rgb;
+ unsigned int r, g, b;
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ if (PACK_NEED_ALIGNMENT(outptr)) {
+ r = GETJSAMPLE(*inptr0++);
+ g = GETJSAMPLE(*inptr1++);
+ b = GETJSAMPLE(*inptr2++);
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ outptr += 2;
+ num_cols--;
+ }
+ for (col = 0; col < (num_cols>>1); col++) {
+ r = GETJSAMPLE(*inptr0++);
+ g = GETJSAMPLE(*inptr1++);
+ b = GETJSAMPLE(*inptr2++);
+ rgb = PACK_SHORT_565(r,g,b);
+ r = GETJSAMPLE(*inptr0++);
+ g = GETJSAMPLE(*inptr1++);
+ b = GETJSAMPLE(*inptr2++);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_ALIGNED_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ if (num_cols&1) {
+ r = GETJSAMPLE(*inptr0);
+ g = GETJSAMPLE(*inptr1);
+ b = GETJSAMPLE(*inptr2);
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ }
+ }
+}
+
+METHODDEF(void)
+rgb_rgb_565D_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ JDIMENSION num_cols = cinfo->output_width;
+ INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ INT32 rgb;
+ unsigned int r, g, b;
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ if (PACK_NEED_ALIGNMENT(outptr)) {
+ r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)];
+ g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
+ b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ outptr += 2;
+ num_cols--;
+ }
+ for (col = 0; col < (num_cols>>1); col++) {
+ r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)];
+ g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
+ b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_SHORT_565(r,g,b);
+ r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)];
+ g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
+ b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_ALIGNED_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ if (num_cols&1) {
+ r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0), d0)];
+ g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1), d0)];
+ b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2), d0)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ }
+ }
+}
+
+METHODDEF(void)
+gray_rgba_8888_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+
+ while (--num_rows >= 0) {
+ inptr = input_buf[0][input_row++];
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ /* We can dispense with GETJSAMPLE() here */
+ outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
+ outptr[RGB_ALPHA] = 0xff;
+ outptr += 4;
+ }
+ }
+}
+
+METHODDEF(void)
+gray_rgb_565_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+
+ while (--num_rows >= 0) {
+ INT32 rgb;
+ unsigned int g;
+ inptr = input_buf[0][input_row++];
+ outptr = *output_buf++;
+ if (PACK_NEED_ALIGNMENT(outptr)) {
+ g = *inptr++;
+ rgb = PACK_SHORT_565(g, g, g);
+ *(INT16*)outptr = rgb;
+ outptr += 2;
+ num_cols--;
+ }
+ for (col = 0; col < (num_cols>>1); col++) {
+ g = *inptr++;
+ rgb = PACK_SHORT_565(g, g, g);
+ g = *inptr++;
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(g, g, g));
+ WRITE_TWO_ALIGNED_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ if (num_cols&1) {
+ g = *inptr;
+ rgb = PACK_SHORT_565(g, g, g);
+ *(INT16*)outptr = rgb;
+ }
+ }
+}
+
+METHODDEF(void)
+gray_rgb_565D_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ JDIMENSION num_cols = cinfo->output_width;
+ INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
+
+ while (--num_rows >= 0) {
+ INT32 rgb;
+ unsigned int g;
+ inptr = input_buf[0][input_row++];
+ outptr = *output_buf++;
+ if (PACK_NEED_ALIGNMENT(outptr)) {
+ g = *inptr++;
+ g = range_limit[DITHER_565_R(g, d0)];
+ rgb = PACK_SHORT_565(g, g, g);
+ *(INT16*)outptr = rgb;
+ outptr += 2;
+ num_cols--;
+ }
+ for (col = 0; col < (num_cols>>1); col++) {
+ g = *inptr++;
+ g = range_limit[DITHER_565_R(g, d0)];
+ rgb = PACK_SHORT_565(g, g, g);
+ d0 = DITHER_ROTATE(d0);
+ g = *inptr++;
+ g = range_limit[DITHER_565_R(g, d0)];
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(g, g, g));
+ d0 = DITHER_ROTATE(d0);
+ WRITE_TWO_ALIGNED_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ if (num_cols&1) {
+ g = *inptr;
+ g = range_limit[DITHER_565_R(g, d0)];
+ rgb = PACK_SHORT_565(g, g, g);
+ *(INT16*)outptr = rgb;
+ }
+ }
+}
+
+#endif /* ANDROID_RGB */
+
+#endif /* ANDROID */
diff --git a/jdhuff.c b/jdhuff.c
index c2b38a9..235782d 100644
--- a/jdhuff.c
+++ b/jdhuff.c
@@ -79,6 +79,18 @@ typedef struct {
typedef huff_entropy_decoder * huff_entropy_ptr;
+#ifdef ANDROID
+
+METHODDEF(boolean)
+decode_mcu_discard_coef (j_decompress_ptr cinfo);
+
+METHODDEF(void)
+configure_huffman_decoder(j_decompress_ptr cinfo, huffman_offset_data offset);
+
+METHODDEF(void)
+get_huffman_decoder_configuration(j_decompress_ptr cinfo,
+ huffman_offset_data *offset);
+#endif
/*
* Initialize for a Huffman-compressed scan.
@@ -800,9 +812,262 @@ jinit_huff_decoder (j_decompress_ptr cinfo)
cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
entropy->pub.start_pass = start_pass_huff_decoder;
entropy->pub.decode_mcu = decode_mcu;
+#ifdef ANDROID
+ entropy->pub.decode_mcu_discard_coef = decode_mcu_discard_coef;
+ entropy->pub.configure_huffman_decoder = configure_huffman_decoder;
+ entropy->pub.get_huffman_decoder_configuration =
+ get_huffman_decoder_configuration;
+ entropy->pub.index = NULL;
+#endif /* ANDROID */
+
/* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) {
entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
}
}
+
+#ifdef ANDROID
+
+LOCAL(boolean) process_restart (j_decompress_ptr cinfo);
+
+/*
+ * Save the current Huffman deocde position and the DC coefficients
+ * for each component into bitstream_offset and dc_info[], respectively.
+ */
+METHODDEF(void)
+get_huffman_decoder_configuration(j_decompress_ptr cinfo,
+ huffman_offset_data *offset)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ short int *dc_info = offset->prev_dc;
+ int i;
+ jpeg_get_huffman_decoder_configuration(cinfo, offset);
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ dc_info[i] = entropy->saved.last_dc_val[i];
+ }
+}
+
+/*
+ * Save the current Huffman decoder position and the bit buffer
+ * into bitstream_offset and get_buffer, respectively.
+ */
+GLOBAL(void)
+jpeg_get_huffman_decoder_configuration(j_decompress_ptr cinfo,
+ huffman_offset_data *offset)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+
+ if (cinfo->restart_interval) {
+ // We are at the end of a data segment
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return;
+ }
+
+ // Save restarts_to_go and next_restart_num
+ offset->restarts_to_go = (unsigned short) entropy->restarts_to_go;
+ offset->next_restart_num = cinfo->marker->next_restart_num;
+
+ offset->bitstream_offset =
+ (jget_input_stream_position(cinfo) << LOG_TWO_BIT_BUF_SIZE)
+ + entropy->bitstate.bits_left;
+
+ offset->get_buffer = entropy->bitstate.get_buffer;
+}
+
+/*
+ * Configure the Huffman decoder to decode the image
+ * starting from the bitstream position recorded in offset.
+ */
+METHODDEF(void)
+configure_huffman_decoder(j_decompress_ptr cinfo, huffman_offset_data offset)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ short int *dc_info = offset.prev_dc;
+ int i;
+ jpeg_configure_huffman_decoder(cinfo, offset);
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ entropy->saved.last_dc_val[i] = dc_info[i];
+ }
+}
+
+/*
+ * Configure the Huffman decoder reader position and bit buffer.
+ */
+GLOBAL(void)
+jpeg_configure_huffman_decoder(j_decompress_ptr cinfo,
+ huffman_offset_data offset)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+
+ // Restore restarts_to_go and next_restart_num
+ cinfo->unread_marker = 0;
+ entropy->restarts_to_go = offset.restarts_to_go;
+ cinfo->marker->next_restart_num = offset.next_restart_num;
+
+ unsigned int bitstream_offset = offset.bitstream_offset;
+ int blkn, i;
+
+ unsigned int byte_offset = bitstream_offset >> LOG_TWO_BIT_BUF_SIZE;
+ unsigned int bit_in_bit_buffer =
+ bitstream_offset & ((1 << LOG_TWO_BIT_BUF_SIZE) - 1);
+
+ jset_input_stream_position_bit(cinfo, byte_offset,
+ bit_in_bit_buffer, offset.get_buffer);
+}
+
+/*
+ * Decode one MCU's worth of Huffman-compressed coefficients.
+ * The propose of this method is to calculate the
+ * data length of one MCU in Huffman-coded format.
+ * Therefore, all coefficients are discarded.
+ */
+
+METHODDEF(boolean)
+decode_mcu_discard_coef (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int blkn;
+ BITREAD_STATE_VARS;
+ savable_state state;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ if (! entropy->pub.insufficient_data) {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
+ d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
+ register int s, k, r;
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+
+ /* discard all coefficients */
+ if (entropy->dc_needed[blkn]) {
+ /* Convert DC difference to actual value, update last_dc_val */
+ int ci = cinfo->MCU_membership[blkn];
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ }
+ for (k = 1; k < DCTSIZE2; k++) {
+ HUFF_DECODE(s, br_state, actbl, return FALSE, label3);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+/*
+ * Call after jpeg_read_header
+ */
+GLOBAL(void)
+jpeg_create_huffman_index(j_decompress_ptr cinfo, huffman_index *index)
+{
+ int i, s;
+ index->scan_count = 1;
+ index->total_iMCU_rows = cinfo->total_iMCU_rows;
+ index->scan = (huffman_scan_header*)malloc(index->scan_count
+ * sizeof(huffman_scan_header));
+ index->scan[0].offset = (huffman_offset_data**)malloc(cinfo->total_iMCU_rows
+ * sizeof(huffman_offset_data*));
+ index->scan[0].prev_MCU_offset.bitstream_offset = 0;
+ index->MCU_sample_size = DEFAULT_MCU_SAMPLE_SIZE;
+
+ index->mem_used = sizeof(huffman_scan_header)
+ + cinfo->total_iMCU_rows * sizeof(huffman_offset_data*);
+}
+
+GLOBAL(void)
+jpeg_destroy_huffman_index(huffman_index *index)
+{
+ int i, j;
+ for (i = 0; i < index->scan_count; i++) {
+ for(j = 0; j < index->total_iMCU_rows; j++) {
+ free(index->scan[i].offset[j]);
+ }
+ free(index->scan[i].offset);
+ }
+ free(index->scan);
+}
+
+/*
+ * Set the reader byte position to offset
+ */
+GLOBAL(void)
+jset_input_stream_position(j_decompress_ptr cinfo, int offset)
+{
+ if (cinfo->src->seek_input_data) {
+ cinfo->src->seek_input_data(cinfo, offset);
+ } else {
+ cinfo->src->bytes_in_buffer = cinfo->src->current_offset - offset;
+ cinfo->src->next_input_byte = cinfo->src->start_input_byte + offset;
+ }
+}
+
+/*
+ * Set the reader byte position to offset and bit position to bit_left
+ * with bit buffer set to buf.
+ */
+GLOBAL(void)
+jset_input_stream_position_bit(j_decompress_ptr cinfo,
+ int byte_offset, int bit_left, INT32 buf)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+
+ entropy->bitstate.bits_left = bit_left;
+ entropy->bitstate.get_buffer = buf;
+
+ jset_input_stream_position(cinfo, byte_offset);
+}
+
+/*
+ * Get the current reader byte position.
+ */
+GLOBAL(int)
+jget_input_stream_position(j_decompress_ptr cinfo)
+{
+ return cinfo->src->current_offset - cinfo->src->bytes_in_buffer;
+}
+
+#endif /* ANDROID */
diff --git a/jdhuff.h b/jdhuff.h
index 96f2dab..5d2da88 100644
--- a/jdhuff.h
+++ b/jdhuff.h
@@ -85,6 +85,7 @@ typedef INT32 bit_buf_type; /* type of bit-extraction buffer */
#define BIT_BUF_SIZE 32 /* size of buffer in bits */
#endif
+#define LOG_TWO_BIT_BUF_SIZE 5 /* log_2(BIT_BUF_SIZE) */
/* If long is > 32 bits on your machine, and shifting/masking longs is
* reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE
diff --git a/jdinput.c b/jdinput.c
index 9fcd089..6241e25 100644
--- a/jdinput.c
+++ b/jdinput.c
@@ -32,7 +32,10 @@ typedef my_input_controller * my_inputctl_ptr;
/* Forward declarations */
METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo));
-
+#ifdef ANDROID
+METHODDEF(int) consume_markers_with_huffman_index JPP((j_decompress_ptr cinfo,
+ huffman_index *index, int current_scan));
+#endif /* ANDROID */
/*
* Routines to calculate various quantities related to the size of the image.
@@ -204,6 +207,10 @@ initial_setup (j_decompress_ptr cinfo)
cinfo->inputctl->has_multiple_scans = TRUE;
else
cinfo->inputctl->has_multiple_scans = FALSE;
+
+#ifdef ANDROID
+ cinfo->original_image_width = cinfo->image_width;
+#endif /* ANDROID */
}
@@ -269,6 +276,16 @@ per_scan_setup (j_decompress_ptr cinfo)
tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width;
compptr->last_col_width = tmp;
+
+#ifdef ANDROID_TILE_BASED_DECODE
+ if (cinfo->tile_decode) {
+ tmp = (int) (jdiv_round_up(cinfo->image_width, 8)
+ % compptr->MCU_width);
+ if (tmp == 0) tmp = compptr->MCU_width;
+ compptr->last_col_width = tmp;
+ }
+#endif
+
tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
if (tmp == 0) tmp = compptr->MCU_height;
compptr->last_row_height = tmp;
@@ -348,6 +365,10 @@ start_input_pass (j_decompress_ptr cinfo)
(*cinfo->entropy->start_pass) (cinfo);
(*cinfo->coef->start_input_pass) (cinfo);
cinfo->inputctl->consume_input = cinfo->coef->consume_data;
+#ifdef ANDROID
+ cinfo->inputctl->consume_input_build_huffman_index =
+ cinfo->coef->consume_data_build_huffman_index;
+#endif /* ANDROID */
}
@@ -361,6 +382,10 @@ METHODDEF(void)
finish_input_pass (j_decompress_ptr cinfo)
{
cinfo->inputctl->consume_input = consume_markers;
+#ifdef ANDROID
+ cinfo->inputctl->consume_input_build_huffman_index =
+ consume_markers_with_huffman_index;
+#endif /* ANDROID */
}
@@ -434,6 +459,11 @@ reset_input_controller (j_decompress_ptr cinfo)
inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
inputctl->pub.eoi_reached = FALSE;
inputctl->inheaders = TRUE;
+#ifdef ANDROID
+ inputctl->pub.consume_input_build_huffman_index =
+ consume_markers_with_huffman_index;
+#endif /* ANDROID */
+
/* Reset other modules */
(*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
(*cinfo->marker->reset_marker_reader) (cinfo);
@@ -468,4 +498,27 @@ jinit_input_controller (j_decompress_ptr cinfo)
inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
inputctl->pub.eoi_reached = FALSE;
inputctl->inheaders = TRUE;
+
+#ifdef ANDROID
+ inputctl->pub.consume_markers = consume_markers_with_huffman_index;
+ inputctl->pub.consume_input_build_huffman_index =
+ consume_markers_with_huffman_index;
+#endif /* ANDROID */
+}
+
+#ifdef ANDROID
+
+GLOBAL(void)
+jpeg_decompress_per_scan_setup(j_decompress_ptr cinfo)
+{
+ per_scan_setup(cinfo);
}
+
+METHODDEF(int)
+consume_markers_with_huffman_index (j_decompress_ptr cinfo,
+ huffman_index *index, int current_scan)
+{
+ return consume_markers(cinfo);
+}
+
+#endif /* ANDROID */
diff --git a/jdmarker.c b/jdmarker.c
index f4cca8c..4b10596 100644
--- a/jdmarker.c
+++ b/jdmarker.c
@@ -964,6 +964,18 @@ read_markers (j_decompress_ptr cinfo)
return JPEG_SUSPENDED;
}
}
+
+#ifdef ANDROID
+
+ /*
+ * Save the position of the fist marker after SOF.
+ */
+ if (cinfo->marker->current_sos_marker_position == -1)
+ cinfo->marker->current_sos_marker_position =
+ jget_input_stream_position(cinfo) - 2;
+
+#endif /* ANDROID */
+
/* At this point cinfo->unread_marker contains the marker code and the
* input point is just past the marker proper, but before any parameters.
* A suspension will cause us to return with this state still true.
@@ -981,6 +993,9 @@ read_markers (j_decompress_ptr cinfo)
break;
case M_SOF2: /* Progressive, Huffman */
+#ifdef ANDROID
+ cinfo->marker->current_sos_marker_position = -1;
+#endif /* ANDROID */
if (! get_sof(cinfo, TRUE, FALSE))
return JPEG_SUSPENDED;
break;
@@ -1252,6 +1267,38 @@ reset_marker_reader (j_decompress_ptr cinfo)
marker->cur_marker = NULL;
}
+#ifdef ANDROID
+
+/*
+ * Get the position for all SOS markers in the image.
+ */
+
+METHODDEF(void)
+get_sos_marker_position(j_decompress_ptr cinfo, huffman_index *index)
+{
+ unsigned char *head;
+ int count = 0;
+ int retcode = JPEG_REACHED_SOS;
+
+ while (cinfo->src->bytes_in_buffer > 0) {
+ if (retcode == JPEG_REACHED_SOS) {
+ jpeg_configure_huffman_index_scan(cinfo, index, count++,
+ cinfo->marker->current_sos_marker_position);
+ // Skips scan content to the next non-RST JPEG marker.
+ while(next_marker(cinfo) &&
+ cinfo->unread_marker >= M_RST0 && cinfo->unread_marker <= M_RST7)
+ ;
+ cinfo->marker->current_sos_marker_position =
+ jget_input_stream_position(cinfo) - 2;
+ retcode = read_markers(cinfo);
+ } else {
+ break;
+ }
+ }
+}
+
+#endif /* ANDROID */
+
/*
* Initialize the marker reader module.
@@ -1273,6 +1320,11 @@ jinit_marker_reader (j_decompress_ptr cinfo)
marker->pub.reset_marker_reader = reset_marker_reader;
marker->pub.read_markers = read_markers;
marker->pub.read_restart_marker = read_restart_marker;
+#ifdef ANDROID
+ marker->pub.get_sos_marker_position = get_sos_marker_position;
+#endif /* ANDROID */
+
+
/* Initialize COM/APPn processing.
* By default, we examine and then discard APP0 and APP14,
* but simply discard COM and all other APPn.
diff --git a/jdmaster.c b/jdmaster.c
index c73ec02..e9d427c 100644
--- a/jdmaster.c
+++ b/jdmaster.c
@@ -49,6 +49,16 @@ use_merged_upsample (j_decompress_ptr cinfo)
/* Merging is the equivalent of plain box-filter upsampling */
if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
return FALSE;
+#ifdef ANDROID_RGB
+ /* jdmerge.c only supports YCC=>RGB565 and YCC=>RGB color conversion */
+ if (cinfo->jpeg_color_space != JCS_YCbCr ||
+ cinfo->num_components != 3 ||
+ cinfo->out_color_components != 3 ||
+ (cinfo->out_color_space != JCS_RGB_565 &&
+ cinfo->out_color_space != JCS_RGB)) {
+ return FALSE;
+ }
+#else
/* jdmerge.c only supports YCC=>RGB color conversion */
if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
(cinfo->out_color_space != JCS_RGB &&
@@ -64,6 +74,7 @@ use_merged_upsample (j_decompress_ptr cinfo)
cinfo->out_color_space != JCS_EXT_ARGB) ||
cinfo->out_color_components != rgb_pixelsize[cinfo->out_color_space])
return FALSE;
+#endif /* ANDROID_RGB */
/* and it only handles 2h1v or 2h2v sampling ratios */
if (cinfo->comp_info[0].h_samp_factor != 2 ||
cinfo->comp_info[1].h_samp_factor != 1 ||
@@ -102,8 +113,12 @@ jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
#endif
/* Prevent application from calling me at wrong times */
- if (cinfo->global_state != DSTATE_READY)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+#if ANDROID_TILE_BASED_DECODE
+ // Tile based decoding may call this function several times.
+ if (!cinfo->tile_decode)
+#endif /* ANDROID_TILE_BASED_DECODE */
+ if (cinfo->global_state != DSTATE_READY)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
#ifdef IDCT_SCALING_SUPPORTED
@@ -219,9 +234,15 @@ jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
case JCS_EXT_ARGB:
cinfo->out_color_components = rgb_pixelsize[cinfo->out_color_space];
break;
+#ifdef ANDROID_RGB
+ case JCS_RGB_565:
+#endif /* ANDROID_RGB */
case JCS_YCbCr:
cinfo->out_color_components = 3;
break;
+#ifdef ANDROID_RGB
+ case JCS_RGBA_8888:
+#endif
case JCS_CMYK:
case JCS_YCCK:
cinfo->out_color_components = 4;
diff --git a/jdmerge.c b/jdmerge.c
index c813080..0ea6b2d 100644
--- a/jdmerge.c
+++ b/jdmerge.c
@@ -41,6 +41,24 @@
#ifdef UPSAMPLE_MERGING_SUPPORTED
+#ifdef ANDROID_RGB
+
+/* Declarations for ordered dithering.
+ *
+ * We use 4x4 ordered dither array packed into 32 bits. This array is
+ * sufficent for dithering RGB_888 to RGB_565.
+ */
+
+#define DITHER_MASK 0x3
+#define DITHER_ROTATE(x) (((x)<<24) | (((x)>>8)&0x00FFFFFF))
+static const INT32 dither_matrix[4] = {
+ 0x0008020A,
+ 0x0C040E06,
+ 0x030B0109,
+ 0x0F070D05
+};
+
+#endif /* ANDROID_RGB */
/* Private subobject */
@@ -250,8 +268,14 @@ merged_2v_upsample (j_decompress_ptr cinfo,
if (upsample->spare_full) {
/* If we have a spare row saved from a previous cycle, just return it. */
+ JDIMENSION size = upsample->out_row_width;
+#ifdef ANDROID_RGB
+ if (cinfo->out_color_space == JCS_RGB_565)
+ size = cinfo->output_width*2;
+#endif
+
jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
- 1, upsample->out_row_width);
+ 1, size);
num_rows = 1;
upsample->spare_full = FALSE;
} else {
@@ -405,6 +429,317 @@ h2v2_merged_upsample (j_decompress_ptr cinfo,
}
}
+#ifdef ANDROID
+
+#ifdef ANDROID_RGB
+METHODDEF(void)
+h2v1_merged_upsample_565 (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr;
+ JSAMPROW inptr0, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ unsigned int r, g, b;
+ INT32 rgb;
+ SHIFT_TEMPS
+
+ inptr0 = input_buf[0][in_row_group_ctr];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr = output_buf[0];
+ /* Loop for each pair of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 2 Y values and emit 2 pixels */
+ y = GETJSAMPLE(*inptr0++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr0++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr0);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ }
+ }
+
+METHODDEF(void)
+h2v1_merged_upsample_565D (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr;
+ JSAMPROW inptr0, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ JDIMENSION col_index = 0;
+ INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
+ unsigned int r, g, b;
+ INT32 rgb;
+ SHIFT_TEMPS
+
+ inptr0 = input_buf[0][in_row_group_ctr];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr = output_buf[0];
+ /* Loop for each pair of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 2 Y values and emit 2 pixels */
+ y = GETJSAMPLE(*inptr0++);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr0++);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr0);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ }
+}
+
+METHODDEF(void)
+h2v2_merged_upsample_565 (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr0, outptr1;
+ JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ unsigned int r, g, b;
+ INT32 rgb;
+ SHIFT_TEMPS
+
+ inptr00 = input_buf[0][in_row_group_ctr*2];
+ inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr0 = output_buf[0];
+ outptr1 = output_buf[1];
+ /* Loop for each group of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 4 Y values and emit 4 pixels */
+ y = GETJSAMPLE(*inptr00++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr00++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr0, rgb);
+ outptr0 += 4;
+ y = GETJSAMPLE(*inptr01++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr01++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr1, rgb);
+ outptr1 += 4;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr00);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr0 = rgb;
+ y = GETJSAMPLE(*inptr01);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr1 = rgb;
+ }
+ }
+
+METHODDEF(void)
+h2v2_merged_upsample_565D (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr0, outptr1;
+ JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ JDIMENSION col_index = 0;
+ INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
+ INT32 d1 = dither_matrix[(cinfo->output_scanline+1) & DITHER_MASK];
+ unsigned int r, g, b;
+ INT32 rgb;
+ SHIFT_TEMPS
+
+ inptr00 = input_buf[0][in_row_group_ctr*2];
+ inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr0 = output_buf[0];
+ outptr1 = output_buf[1];
+ /* Loop for each group of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 4 Y values and emit 4 pixels */
+ y = GETJSAMPLE(*inptr00++);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr00++);
+ r = range_limit[DITHER_565_R(y + cred, d1)];
+ g = range_limit[DITHER_565_G(y + cgreen, d1)];
+ b = range_limit[DITHER_565_B(y + cblue, d1)];
+ d1 = DITHER_ROTATE(d1);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr0, rgb);
+ outptr0 += 4;
+ y = GETJSAMPLE(*inptr01++);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr01++);
+ r = range_limit[DITHER_565_R(y + cred, d1)];
+ g = range_limit[DITHER_565_G(y + cgreen, d1)];
+ b = range_limit[DITHER_565_B(y + cblue, d1)];
+ d1 = DITHER_ROTATE(d1);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr1, rgb);
+ outptr1 += 4;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr00);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr0 = rgb;
+ y = GETJSAMPLE(*inptr01);
+ r = range_limit[DITHER_565_R(y + cred, d1)];
+ g = range_limit[DITHER_565_G(y + cgreen, d1)];
+ b = range_limit[DITHER_565_B(y + cblue, d1)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr1 = rgb;
+ }
+}
+
+#endif /* ANDROID_RGB */
+
+
+#endif /* ANDROID */
/*
* Module initialization routine for merged upsampling/color conversion.
@@ -434,6 +769,17 @@ jinit_merged_upsampler (j_decompress_ptr cinfo)
upsample->upmethod = jsimd_h2v2_merged_upsample;
else
upsample->upmethod = h2v2_merged_upsample;
+
+#ifdef ANDROID_RGB
+ if (cinfo->out_color_space == JCS_RGB_565) {
+ if (cinfo->dither_mode == JDITHER_NONE) {
+ upsample->upmethod = h2v2_merged_upsample_565;
+ } else {
+ upsample->upmethod = h2v2_merged_upsample_565D;
+ }
+ }
+#endif /* ANDROID_RGB */
+
/* Allocate a spare row buffer */
upsample->spare_row = (JSAMPROW)
(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
@@ -444,6 +790,15 @@ jinit_merged_upsampler (j_decompress_ptr cinfo)
upsample->upmethod = jsimd_h2v1_merged_upsample;
else
upsample->upmethod = h2v1_merged_upsample;
+#ifdef ANDROID_RGB
+ if (cinfo->out_color_space == JCS_RGB_565) {
+ if (cinfo->dither_mode == JDITHER_NONE) {
+ upsample->upmethod = h2v1_merged_upsample_565;
+ } else {
+ upsample->upmethod = h2v1_merged_upsample_565D;
+ }
+ }
+#endif /* ANDROID_RGB */
/* No spare row needed */
upsample->spare_row = NULL;
}
diff --git a/jdphuff.c b/jdphuff.c
index 2267809..2654783 100644
--- a/jdphuff.c
+++ b/jdphuff.c
@@ -83,6 +83,21 @@ METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo,
METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo,
JBLOCKROW *MCU_data));
+#ifdef ANDROID
+METHODDEF(void)
+configure_huffman_decoder(j_decompress_ptr cinfo, huffman_offset_data offset);
+
+METHODDEF(void)
+get_huffman_decoder_configuration(j_decompress_ptr cinfo,
+ huffman_offset_data *offset);
+
+GLOBAL(void)
+jpeg_configure_huffman_decoder_progressive(j_decompress_ptr cinfo,
+ huffman_offset_data offset);
+GLOBAL(void)
+jpeg_get_huffman_decoder_configuration_progressive(j_decompress_ptr cinfo,
+ huffman_offset_data *offset);
+#endif
/*
* Initialize for a Huffman-compressed scan.
@@ -649,6 +664,11 @@ jinit_phuff_decoder (j_decompress_ptr cinfo)
SIZEOF(phuff_entropy_decoder));
cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
entropy->pub.start_pass = start_pass_phuff_decoder;
+#ifdef ANDROID
+ entropy->pub.configure_huffman_decoder = configure_huffman_decoder;
+ entropy->pub.get_huffman_decoder_configuration =
+ get_huffman_decoder_configuration;
+#endif /* ANDROID */
/* Mark derived tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) {
@@ -665,4 +685,111 @@ jinit_phuff_decoder (j_decompress_ptr cinfo)
*coef_bit_ptr++ = -1;
}
+#ifdef ANDROID
+
+/*
+ * Save the current Huffman deocde position and the DC coefficients
+ * for each component into bitstream_offset and dc_info[], respectively.
+ */
+METHODDEF(void)
+get_huffman_decoder_configuration(j_decompress_ptr cinfo,
+ huffman_offset_data *offset)
+{
+ int i;
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ jpeg_get_huffman_decoder_configuration_progressive(cinfo, offset);
+ offset->EOBRUN = entropy->saved.EOBRUN;
+ for (i = 0; i < cinfo->comps_in_scan; i++)
+ offset->prev_dc[i] = entropy->saved.last_dc_val[i];
+}
+
+/*
+ * Save the current Huffman decoder position and the bit buffer
+ * into bitstream_offset and get_buffer, respectively.
+ */
+GLOBAL(void)
+jpeg_get_huffman_decoder_configuration_progressive(j_decompress_ptr cinfo,
+ huffman_offset_data *offset)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+
+ if (cinfo->restart_interval) {
+ // We are at the end of a data segment
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return;
+ }
+
+ // Save restarts_to_go and next_restart_num.
+ offset->restarts_to_go = (unsigned short) entropy->restarts_to_go;
+ offset->next_restart_num = cinfo->marker->next_restart_num;
+
+ offset->bitstream_offset =
+ (jget_input_stream_position(cinfo) << LOG_TWO_BIT_BUF_SIZE)
+ + entropy->bitstate.bits_left;
+
+ offset->get_buffer = entropy->bitstate.get_buffer;
+}
+
+
+/*
+ * Configure the Huffman decoder to decode the image
+ * starting from (iMCU_row_offset, iMCU_col_offset).
+ */
+METHODDEF(void)
+configure_huffman_decoder(j_decompress_ptr cinfo, huffman_offset_data offset)
+{
+ int i;
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ jpeg_configure_huffman_decoder_progressive(cinfo, offset);
+ entropy->saved.EOBRUN = offset.EOBRUN;
+ for (i = 0; i < cinfo->comps_in_scan; i++)
+ entropy->saved.last_dc_val[i] = offset.prev_dc[i];
+}
+
+/*
+ * Configure the Huffman decoder reader position and bit buffer.
+ */
+GLOBAL(void)
+jpeg_configure_huffman_decoder_progressive(j_decompress_ptr cinfo,
+ huffman_offset_data offset)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+
+ // Restore restarts_to_go and next_restart_num
+ cinfo->unread_marker = 0;
+ entropy->restarts_to_go = offset.restarts_to_go;
+ cinfo->marker->next_restart_num = offset.next_restart_num;
+
+ unsigned int bitstream_offset = offset.bitstream_offset;
+ int blkn, i;
+
+ unsigned int byte_offset = bitstream_offset >> LOG_TWO_BIT_BUF_SIZE;
+ unsigned int bit_in_bit_buffer =
+ bitstream_offset & ((1 << LOG_TWO_BIT_BUF_SIZE) - 1);
+
+ jset_input_stream_position_bit(cinfo, byte_offset,
+ bit_in_bit_buffer, offset.get_buffer);
+}
+
+GLOBAL(void)
+jpeg_configure_huffman_index_scan(j_decompress_ptr cinfo,
+ huffman_index *index, int scan_no, int offset)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ if (scan_no >= index->scan_count) {
+ index->scan = realloc(index->scan,
+ (scan_no + 1) * sizeof(huffman_scan_header));
+ index->mem_used += (scan_no - index->scan_count + 1)
+ * (sizeof(huffman_scan_header) + cinfo->total_iMCU_rows
+ * sizeof(huffman_offset_data*));
+ index->scan_count = scan_no + 1;
+ }
+ index->scan[scan_no].offset = (huffman_offset_data**)malloc(
+ cinfo->total_iMCU_rows * sizeof(huffman_offset_data*));
+ index->scan[scan_no].bitstream_offset = offset;
+}
+
+#endif /* ANDROID */
+
#endif /* D_PROGRESSIVE_SUPPORTED */
diff --git a/jdtrans.c b/jdtrans.c
index f0cd0ae..3c28602 100644
--- a/jdtrans.c
+++ b/jdtrans.c
@@ -150,3 +150,134 @@ transdecode_master_selection (j_decompress_ptr cinfo)
cinfo->progress->total_passes = 1;
}
}
+
+#ifdef ANDROID
+
+LOCAL(boolean)
+jpeg_build_huffman_index_progressive(j_decompress_ptr cinfo,
+ huffman_index *index)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ printf("Progressive Mode\n");
+ /* First call: initialize active modules */
+ transdecode_master_selection(cinfo);
+ cinfo->global_state = DSTATE_RDCOEFS;
+ }
+ if (cinfo->global_state == DSTATE_RDCOEFS) {
+ int mcu, i;
+ cinfo->marker->get_sos_marker_position(cinfo, index);
+
+ /* Absorb whole file into the coef buffer */
+ for (mcu = 0; mcu < cinfo->total_iMCU_rows; mcu++) {
+ int retcode = 0;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ jinit_phuff_decoder(cinfo);
+ for (i = 0; i < index->scan_count; i++) {
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ jset_input_stream_position(cinfo, index->scan[i].bitstream_offset);
+ cinfo->unread_marker = 0;
+ retcode = (*cinfo->inputctl->consume_input_build_huffman_index)
+ (cinfo, index, i);
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ cinfo->input_iMCU_row = mcu;
+ if (mcu != 0)
+ (*cinfo->entropy->configure_huffman_decoder)
+ (cinfo, index->scan[i].prev_MCU_offset);
+ cinfo->input_scan_number = i;
+ retcode = (*cinfo->inputctl->consume_input_build_huffman_index)
+ (cinfo, index, i);
+ }
+ if (retcode == JPEG_SUSPENDED)
+ return FALSE;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* startup underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+ cinfo->global_state = DSTATE_STOPPING;
+ }
+ /* At this point we should be in state DSTATE_STOPPING if being used
+ * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access
+ * to the coefficients during a full buffered-image-mode decompression.
+ */
+ if ((cinfo->global_state == DSTATE_STOPPING ||
+ cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) {
+ return TRUE;
+ }
+ /* Oops, improper usage */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return FALSE; /* keep compiler happy */
+}
+
+LOCAL(boolean)
+jpeg_build_huffman_index_baseline(j_decompress_ptr cinfo, huffman_index *index)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ printf("Baseline Mode\n");
+ /* First call: initialize active modules */
+ transdecode_master_selection(cinfo);
+ cinfo->global_state = DSTATE_RDCOEFS;
+ }
+ if (cinfo->global_state == DSTATE_RDCOEFS) {
+ /* Absorb whole file into the coef buffer */
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = (*cinfo->inputctl->consume_input_build_huffman_index)
+ (cinfo, index, 0);
+ if (retcode == JPEG_SUSPENDED)
+ return FALSE;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ if (retcode == JPEG_SCAN_COMPLETED)
+ break;
+
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* startup underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+ /* Set state so that jpeg_finish_decompress does the right thing */
+ cinfo->global_state = DSTATE_STOPPING;
+ }
+ /* At this point we should be in state DSTATE_STOPPING if being used
+ * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access
+ * to the coefficients during a full buffered-image-mode decompression.
+ */
+ if ((cinfo->global_state == DSTATE_STOPPING ||
+ cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) {
+ return TRUE;
+ }
+ /* Oops, improper usage */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return FALSE; /* keep compiler happy */
+}
+
+GLOBAL(boolean)
+jpeg_build_huffman_index(j_decompress_ptr cinfo, huffman_index *index)
+{
+ cinfo->tile_decode = TRUE;
+ if (cinfo->progressive_mode)
+ return jpeg_build_huffman_index_progressive(cinfo, index);
+ else
+ return jpeg_build_huffman_index_baseline(cinfo, index);
+}
+
+#endif /* ANDROID */
diff --git a/jmorecfg.h b/jmorecfg.h
index f22c4f3..c3d27d9 100644
--- a/jmorecfg.h
+++ b/jmorecfg.h
@@ -313,6 +313,7 @@ typedef int boolean;
#define RGB_BLUE 2 /* Offset of Blue */
#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */
+<<<<<<< HEAD
#define JPEG_NUMCS 16
#define EXT_RGB_RED 0
@@ -344,6 +345,14 @@ typedef int boolean;
#define EXT_XRGB_GREEN 2
#define EXT_XRGB_BLUE 3
#define EXT_XRGB_PIXELSIZE 4
+=======
+#ifdef ANDROID_RGB
+#define RGB_ALPHA 3 /* Offset of Alpha */
+#endif
+
+
+#define JPEG_NUMCS 12
+>>>>>>> first cut at port of Android extentions
static const int rgb_red[JPEG_NUMCS] = {
-1, -1, RGB_RED, -1, -1, -1, EXT_RGB_RED, EXT_RGBX_RED,
@@ -369,6 +378,29 @@ static const int rgb_pixelsize[JPEG_NUMCS] = {
EXT_RGBX_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE
};
+
+/*
+ * Define ANDROID_RGB to enable specific optimizations for Android
+ * JCS_RGBA_8888 support
+ * JCS_RGB_565 support
+ *
+ */
+
+#ifdef ANDROID_RGB
+#define PACK_SHORT_565(r,g,b) ((((r)<<8)&0xf800)|(((g)<<3)&0x7E0)|((b)>>3))
+#define PACK_TWO_PIXELS(l,r) ((r<<16) | l)
+#define PACK_NEED_ALIGNMENT(ptr) (((int)(ptr))&3)
+#define WRITE_TWO_PIXELS(addr, pixels) do { \
+ ((INT16*)(addr))[0] = (pixels); \
+ ((INT16*)(addr))[1] = (pixels)>>16; \
+ } while(0)
+#define WRITE_TWO_ALIGNED_PIXELS(addr, pixels) ((*(INT32*)(addr)) = pixels)
+#define DITHER_565_R(r, dither) ((r) + ((dither)&0xFF))
+#define DITHER_565_G(g, dither) ((g) + (((dither)&0xFF)>>1))
+#define DITHER_565_B(b, dither) ((b) + ((dither)&0xFF))
+#endif
+
+
/* Definitions for speed-related optimizations. */
/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying
diff --git a/jpegint.h b/jpegint.h
index 7871748..a6fa9aa 100644
--- a/jpegint.h
+++ b/jpegint.h
@@ -153,6 +153,13 @@ struct jpeg_input_controller {
/* State variables made visible to other modules */
boolean has_multiple_scans; /* True if file has multiple scans */
boolean eoi_reached; /* True when EOI has been consumed */
+
+#ifdef ANDROID
+ JMETHOD(int, consume_input_build_huffman_index, (j_decompress_ptr cinfo,
+ huffman_index *index, int scan_count));
+ JMETHOD(int, consume_markers, (j_decompress_ptr cinfo,
+ huffman_index *index, int scan_count));
+#endif
};
/* Main buffer control (downsampled-data buffer) */
@@ -170,8 +177,29 @@ struct jpeg_d_coef_controller {
JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));
JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,
JSAMPIMAGE output_buf));
+
/* Pointer to array of coefficient virtual arrays, or NULL if none */
jvirt_barray_ptr *coef_arrays;
+
+#ifdef ANDROID
+ JMETHOD(int, consume_data_build_huffman_index, (j_decompress_ptr cinfo,
+ huffman_index* index, int scan_count));
+
+ /* column number of the first and last tile, respectively */
+ int column_left_boundary;
+ int column_right_boundary;
+
+ /* column number of the first and last MCU, respectively */
+ int MCU_column_left_boundary;
+ int MCU_column_right_boundary;
+
+ /* the number of MCU columns to skip from the indexed MCU, iM,
+ * to the requested MCU boundary, rM, where iM is the MCU that we sample
+ * into our index and is the nearest one to the left of rM.
+ */
+ int MCU_columns_to_skip;
+
+#endif
};
/* Decompression postprocessing (color quantization buffer control) */
@@ -204,6 +232,13 @@ struct jpeg_marker_reader {
boolean saw_SOF; /* found SOF? */
int next_restart_num; /* next restart number expected (0-7) */
unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
+
+#ifdef ANDROID
+ JMETHOD(void, get_sos_marker_position, (j_decompress_ptr cinfo,
+ huffman_index *index));
+
+ int current_sos_marker_position;
+#endif
};
/* Entropy decoding */
@@ -215,6 +250,16 @@ struct jpeg_entropy_decoder {
/* This is here to share code between baseline and progressive decoders; */
/* other modules probably should not use it */
boolean insufficient_data; /* set TRUE after emitting warning */
+
+#ifdef ANDROID
+ JMETHOD(boolean, decode_mcu_discard_coef, (j_decompress_ptr cinfo));
+ JMETHOD(void, configure_huffman_decoder, (j_decompress_ptr cinfo,
+ huffman_offset_data offset));
+ JMETHOD(void, get_huffman_decoder_configuration, (j_decompress_ptr cinfo,
+ huffman_offset_data *offset));
+
+ huffman_index *index;
+#endif
};
/* Inverse DCT (also performs dequantization) */
@@ -370,18 +415,32 @@ EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo));
+
+#ifdef ANDROID
+EXTERN(void) jinit_huff_decoder_no_data JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_decompress_per_scan_setup (j_decompress_ptr cinfo);
+#endif
+
/* Memory manager initialization */
EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo));
/* Utility routines in jutils.c */
EXTERN(long) jdiv_round_up JPP((long a, long b));
EXTERN(long) jround_up JPP((long a, long b));
+EXTERN(long) jmin JPP((long a, long b));
EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
JSAMPARRAY output_array, int dest_row,
int num_rows, JDIMENSION num_cols));
EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row,
JDIMENSION num_blocks));
EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero));
+EXTERN(void) jset_input_stream_position JPP((j_decompress_ptr cinfo,
+ int offset));
+EXTERN(void) jset_input_stream_position_bit JPP((j_decompress_ptr cinfo,
+ int byte_offset, int bit_left, INT32 buf));
+
+EXTERN(int) jget_input_stream_position JPP((j_decompress_ptr cinfo));
+
/* Constant tables in jutils.c */
#if 0 /* This table is not actually needed in v6a */
extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
diff --git a/jpeglib.h b/jpeglib.h
index d19a3ef..1d0b3e1 100644
--- a/jpeglib.h
+++ b/jpeglib.h
@@ -27,12 +27,13 @@
#endif
#include "jmorecfg.h" /* seldom changed options */
-
+#ifndef ANDROID
#ifdef __cplusplus
#ifndef DONT_USE_EXTERN_C
extern "C" {
#endif
#endif
+#endif
/* Various constants determining the sizes of things.
@@ -227,6 +228,7 @@ typedef enum {
JCS_EXT_BGRX, /* blue/green/red/x */
JCS_EXT_XBGR, /* x/blue/green/red */
JCS_EXT_XRGB, /* x/red/green/blue */
+<<<<<<< HEAD
/* When out_color_space it set to JCS_EXT_RGBX, JCS_EXT_BGRX,
JCS_EXT_XBGR, or JCS_EXT_XRGB during decompression, the X byte is
undefined, and in order to ensure the best performance,
@@ -238,6 +240,12 @@ typedef enum {
JCS_EXT_BGRA, /* blue/green/red/alpha */
JCS_EXT_ABGR, /* alpha/blue/green/red */
JCS_EXT_ARGB /* alpha/red/green/blue */
+=======
+#ifdef ANDROID_RGB
+ JCS_RGBA_8888, /* red/green/blue/alpha */
+ JCS_RGB_565 /* red/green/blue in 565 format */
+#endif
+>>>>>>> first cut at port of Android extentions
} J_COLOR_SPACE;
/* DCT/IDCT algorithm options. */
@@ -477,6 +485,7 @@ struct jpeg_decompress_struct {
/* Basic description of image --- filled in by jpeg_read_header(). */
/* Application may inspect these values to decide how to process image. */
+ JDIMENSION original_image_width; /* nominal image width (from SOF marker) */
JDIMENSION image_width; /* nominal image width (from SOF marker) */
JDIMENSION image_height; /* nominal image height */
int num_components; /* # of color components in JPEG image */
@@ -598,6 +607,9 @@ struct jpeg_decompress_struct {
#if JPEG_LIB_VERSION >= 80
boolean is_baseline; /* TRUE if Baseline SOF0 encountered */
#endif
+#ifdef ANDROID
+ boolean tile_decode; /* TRUE if using tile based decoding */
+#endif
boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */
boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
@@ -706,6 +718,61 @@ struct jpeg_decompress_struct {
};
+typedef struct {
+
+ // |--- byte_offset ---|- bit_left -|
+ // \------ 27 -------/ \---- 5 ----/
+ unsigned int bitstream_offset;
+ short prev_dc[3];
+
+ // remaining EOBs in EOBRUN
+ unsigned short EOBRUN;
+
+ // save the decoder current bit buffer, entropy->bitstate.get_buffer.
+ INT32 get_buffer;
+
+ // save the restart info.
+ unsigned short restarts_to_go;
+ unsigned char next_restart_num;
+} huffman_offset_data;
+
+typedef struct {
+
+ // The header starting position of this scan
+ unsigned int bitstream_offset;
+
+ // Number of components in this scan
+ int comps_in_scan;
+
+ // Number of MCUs in each row
+ int MCUs_per_row;
+ int MCU_rows_per_iMCU_row;
+
+ // The last MCU position and its dc value in this scan
+ huffman_offset_data prev_MCU_offset;
+
+ huffman_offset_data **offset;
+} huffman_scan_header;
+
+#define DEFAULT_MCU_SAMPLE_SIZE 16
+
+typedef struct {
+
+ // The number of MCUs that we sample each time as an index point
+ int MCU_sample_size;
+
+ // Number of scan in this image
+ int scan_count;
+
+ // Number of iMCUs rows in this image
+ int total_iMCU_rows;
+
+ // Memory used by scan struct
+ size_t mem_used;
+ huffman_scan_header *scan;
+} huffman_index;
+
+
/* "Object" declarations for JPEG modules that may be supplied or called
* directly by the surrounding application.
* As with all objects in the JPEG library, these structs only define the
@@ -801,12 +868,19 @@ struct jpeg_destination_mgr {
struct jpeg_source_mgr {
const JOCTET * next_input_byte; /* => next byte to read from buffer */
size_t bytes_in_buffer; /* # of bytes remaining in buffer */
+#ifdef ANDROID
+ const JOCTET * start_input_byte; /* => first byte to read from input */
+ size_t current_offset; /* current readed input offset */
+#endif
JMETHOD(void, init_source, (j_decompress_ptr cinfo));
JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));
JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));
JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired));
JMETHOD(void, term_source, (j_decompress_ptr cinfo));
+#ifdef ANDROID
+ JMETHOD(boolean, seek_input_data, (j_decompress_ptr cinfo, long byte_offset));
+#endif
};
@@ -1081,6 +1155,11 @@ EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo,
/* Main entry points for decompression */
EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo));
+
+#ifdef ANDROID
+EXTERN(boolean) jpeg_start_tile_decompress JPP((j_decompress_ptr cinfo));
+#endif
+
EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo,
JSAMPARRAY scanlines,
JDIMENSION max_lines));
@@ -1091,6 +1170,20 @@ EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo,
JSAMPIMAGE data,
JDIMENSION max_lines));
+#ifdef ANDROID
+EXTERN(JDIMENSION) jpeg_read_scanlines_from JPP((j_decompress_ptr cinfo,
+ JSAMPARRAY scanlines,
+ int line_offset,
+ JDIMENSION max_lines));
+EXTERN(JDIMENSION) jpeg_read_tile_scanline JPP((j_decompress_ptr cinfo,
+ huffman_index *index,
+ JSAMPARRAY scanlines));
+EXTERN(void) jpeg_init_read_tile_scanline JPP((j_decompress_ptr cinfo,
+ huffman_index *index,
+ int *start_x, int *start_y,
+ int *width, int *height));
+#endif
+
/* Additional entry points for buffered-image mode. */
EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo));
EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo,
@@ -1148,6 +1241,19 @@ EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo));
EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo,
int desired));
+#ifdef ANDROID
+EXTERN(boolean) jpeg_build_huffman_index
+ JPP((j_decompress_ptr cinfo, huffman_index *index));
+EXTERN(void) jpeg_configure_huffman_decoder(j_decompress_ptr cinfo,
+ huffman_offset_data offset);
+EXTERN(void) jpeg_get_huffman_decoder_configuration(j_decompress_ptr cinfo,
+ huffman_offset_data *offset);
+EXTERN(void) jpeg_create_huffman_index(j_decompress_ptr cinfo,
+ huffman_index *index);
+EXTERN(void) jpeg_configure_huffman_index_scan(j_decompress_ptr cinfo,
+ huffman_index *index, int scan_no, int offset);
+EXTERN(void) jpeg_destroy_huffman_index(huffman_index *index);
+#endif
/* These marker codes are exported since applications and data source modules
* are likely to want to use them.
@@ -1204,10 +1310,12 @@ struct jpeg_color_quantizer { long dummy; };
#include "jerror.h" /* fetch error codes too */
#endif
+#ifndef ANDROID
#ifdef __cplusplus
#ifndef DONT_USE_EXTERN_C
}
#endif
#endif
+#endif
#endif /* JPEGLIB_H */
diff --git a/jutils.c b/jutils.c
index d18a955..6c5cde9 100644
--- a/jutils.c
+++ b/jutils.c
@@ -86,6 +86,11 @@ jround_up (long a, long b)
return a - (a % b);
}
+GLOBAL(long)
+jmin (long a, long b)
+{
+ return a < b ? a : b;
+}
/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
* and coefficient-block arrays. This won't work on 80x86 because the arrays