diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | d9bb1510bee7d9bf2a0f2699c647a65e67ab9cf8 (patch) | |
tree | a23a17e9a6b51b90db0a8fa1f15423f488814866 | |
parent | c6a7fc661d57f86ac08cd637abc881cbe687b11a (diff) | |
download | jpeg-d9bb1510bee7d9bf2a0f2699c647a65e67ab9cf8.tar.gz |
Initial Contributionandroid-1.0release-1.0cdma-import
-rw-r--r-- | Android.mk | 37 | ||||
-rw-r--r-- | MODULE_LICENSE_BSD_LIKE | 0 | ||||
-rw-r--r-- | NOTICE | 38 | ||||
-rw-r--r-- | jccolor.c | 68 | ||||
-rw-r--r-- | jconfig.h | 156 | ||||
-rw-r--r-- | jdcolor.c | 515 | ||||
-rw-r--r-- | jdmaster.c | 21 | ||||
-rw-r--r-- | jdmerge.c | 397 | ||||
-rw-r--r-- | jidctfst.S | 452 | ||||
-rw-r--r-- | jmorecfg.h | 28 | ||||
-rw-r--r-- | jpeglib.h | 34 |
11 files changed, 1693 insertions, 53 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..9cfe4f6 --- /dev/null +++ b/Android.mk @@ -0,0 +1,37 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_ARM_MODE := arm + +LOCAL_SRC_FILES := \ + 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 jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c \ + jmemnobs.c + +# the assembler is only for the ARM version, don't break the Linux sim +ifneq ($(TARGET_ARCH),arm) +ANDROID_JPEG_NO_ASSEMBLER := true +endif + +# temp fix until we understand why this broke cnn.com +#ANDROID_JPEG_NO_ASSEMBLER := true + +ifeq ($(strip $(ANDROID_JPEG_NO_ASSEMBLER)),true) +LOCAL_SRC_FILES += jidctint.c jidctfst.c +else +LOCAL_SRC_FILES += jidctint.c jidctfst.S +endif + +LOCAL_CFLAGS += -DAVOID_TABLES +LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays +#LOCAL_CFLAGS += -march=armv6j + +LOCAL_MODULE:= libjpeg + +include $(BUILD_STATIC_LIBRARY) diff --git a/MODULE_LICENSE_BSD_LIKE b/MODULE_LICENSE_BSD_LIKE new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_BSD_LIKE @@ -0,0 +1,38 @@ +This software is based in part on the work of the Independent JPEG Group. + +---------------------- + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-1998, Thomas G. Lane. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. @@ -12,6 +12,8 @@ #include "jinclude.h" #include "jpeglib.h" +// this enables unrolling null_convert's loop, and reading/write ints for speed +#define ENABLE_ANDROID_NULL_CONVERT /* Private subobject */ @@ -298,6 +300,36 @@ grayscale_convert (j_compress_ptr cinfo, } } +#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 /* * Convert some rows of samples to the JPEG colorspace. @@ -317,6 +349,42 @@ 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..15a9817 --- /dev/null +++ b/jconfig.h @@ -0,0 +1,156 @@ +/* android jconfig.h */ +/* + * jconfig.doc + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file documents the configuration options that are required to + * customize the JPEG software for a particular system. + * + * The actual configuration options for a particular installation are stored + * in jconfig.h. On many machines, jconfig.h can be generated automatically + * or copied from one of the "canned" jconfig files that we supply. But if + * you need to generate a jconfig.h file by hand, this file tells you how. + * + * DO NOT EDIT THIS FILE --- IT WON'T ACCOMPLISH ANYTHING. + * EDIT A COPY NAMED JCONFIG.H. + */ + + +/* + * These symbols indicate the properties of your machine or compiler. + * #define the symbol if yes, #undef it if no. + */ + +/* Does your compiler support function prototypes? + * (If not, you also need to use ansi2knr, see install.doc) + */ +#define HAVE_PROTOTYPES + +/* Does your compiler support the declaration "unsigned char" ? + * How about "unsigned short" ? + */ +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT + +/* Define "void" as "char" if your compiler doesn't know about type void. + * NOTE: be sure to define void such that "void *" represents the most general + * pointer type, e.g., that returned by malloc(). + */ +/* #define void char */ + +/* Define "const" as empty if your compiler doesn't know the "const" keyword. + */ +/* #define const */ + +/* Define this if an ordinary "char" type is unsigned. + * If you're not sure, leaving it undefined will work at some cost in speed. + * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal. + */ +#undef CHAR_IS_UNSIGNED + +/* Define this if your system has an ANSI-conforming <stddef.h> file. + */ +#define HAVE_STDDEF_H + +/* Define this if your system has an ANSI-conforming <stdlib.h> file. + */ +#define HAVE_STDLIB_H + +/* Define this if your system does not have an ANSI/SysV <string.h>, + * but does have a BSD-style <strings.h>. + */ +#undef NEED_BSD_STRINGS + +/* Define this if your system does not provide typedef size_t in any of the + * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in + * <sys/types.h> instead. + */ +#undef NEED_SYS_TYPES_H + +/* For 80x86 machines, you need to define NEED_FAR_POINTERS, + * unless you are using a large-data memory model or 80386 flat-memory mode. + * On less brain-damaged CPUs this symbol must not be defined. + * (Defining this symbol causes large data structures to be referenced through + * "far" pointers and to be allocated with a special version of malloc.) + */ +#undef NEED_FAR_POINTERS + +/* Define this if your linker needs global names to be unique in less + * than the first 15 characters. + */ +#undef NEED_SHORT_EXTERNAL_NAMES + +/* Although a real ANSI C compiler can deal perfectly well with pointers to + * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI + * and pseudo-ANSI compilers get confused. To keep one of these bozos happy, + * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you + * actually get "missing structure definition" warnings or errors while + * compiling the JPEG code. + */ +#undef INCOMPLETE_TYPES_BROKEN + + +/* + * The following options affect code selection within the JPEG library, + * but they don't need to be visible to applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS has been defined. + */ + +#ifdef JPEG_INTERNALS + +/* Define this if your compiler implements ">>" on signed values as a logical + * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift, + * which is the normal and rational definition. + */ +#undef RIGHT_SHIFT_IS_UNSIGNED + + +#endif /* JPEG_INTERNALS */ + + +/* + * The remaining options do not affect the JPEG library proper, + * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c). + * Other applications can ignore these. + */ + +#ifdef JPEG_CJPEG_DJPEG + +/* These defines indicate which image (non-JPEG) file formats are allowed. */ + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +/* Define this if you want to name both input and output files on the command + * line, rather than using stdout and optionally stdin. You MUST do this if + * your system can't cope with binary I/O to stdin/stdout. See comments at + * head of cjpeg.c or djpeg.c. + */ +#undef TWO_FILE_COMMANDLINE + +/* Define this if your system needs explicit cleanup of temporary files. + * This is crucial under MS-DOS, where the temporary "files" may be areas + * of extended memory; on most other systems it's not as important. + */ +#undef NEED_SIGNAL_CATCHER + +/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb"). + * This is necessary on systems that distinguish text files from binary files, + * and is harmless on most systems that don't. If you have one of the rare + * systems that complains about the "b" spec, define this symbol. + */ +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. + */ +#undef PROGRESS_REPORT + + +#endif /* JPEG_CJPEG_DJPEG */ @@ -28,6 +28,26 @@ 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 +}; + +#endif + + /**************** YCbCr -> RGB conversion: most common case **************/ /* @@ -76,26 +96,26 @@ build_ycc_rgb_table (j_decompress_ptr cinfo) cconvert->Cr_r_tab = (int *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); + (MAXJSAMPLE+1) * SIZEOF(int)); cconvert->Cb_b_tab = (int *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); + (MAXJSAMPLE+1) * SIZEOF(int)); cconvert->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); + (MAXJSAMPLE+1) * SIZEOF(INT32)); cconvert->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); + (MAXJSAMPLE+1) * SIZEOF(INT32)); for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ /* Cr=>R value is nearest int to 1.40200 * x */ cconvert->Cr_r_tab[i] = (int) - RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); /* Cb=>B value is nearest int to 1.77200 * x */ cconvert->Cb_b_tab[i] = (int) - RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); /* Cr=>G value is scaled-up -0.71414 * x */ cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; /* Cb=>G value is scaled-up -0.34414 * x */ @@ -104,7 +124,6 @@ build_ycc_rgb_table (j_decompress_ptr cinfo) } } - /* * Convert some rows of samples to the output colorspace. * @@ -148,17 +167,338 @@ ycc_rgb_convert (j_decompress_ptr cinfo, /* 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))]; + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; outptr += RGB_PIXELSIZE; } } } +#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; + } + } +} + +#endif -/**************** Cases other than YCbCr -> RGB **************/ +/**************** Cases other than YCbCr -> RGB(A) **************/ +#ifdef ANDROID_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; + } + } +} + +#endif /* * Color conversion for no colorspace change: just copy the data, @@ -233,6 +573,110 @@ gray_rgb_convert (j_decompress_ptr cinfo, } } +#ifdef ANDROID_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 /* * Adobe-style YCCK->CMYK conversion. @@ -272,11 +716,11 @@ ycck_cmyk_convert (j_decompress_ptr cinfo, cb = GETJSAMPLE(inptr1[col]); cr = GETJSAMPLE(inptr2[col]); /* Range-limiting is essential due to noise introduced by DCT losses. */ - outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ - outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ - ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], - SCALEBITS)))]; - outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)))]; + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ /* K passes through unchanged */ outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ outptr += 4; @@ -368,6 +812,47 @@ 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 + case JCS_CMYK: cinfo->out_color_components = 4; if (cinfo->jpeg_color_space == JCS_YCCK) { @@ -47,11 +47,24 @@ 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 || cinfo->out_color_components != RGB_PIXELSIZE) return FALSE; +#endif + /* 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 || @@ -179,11 +192,17 @@ jpeg_calc_output_dimensions (j_decompress_ptr cinfo) cinfo->out_color_components = RGB_PIXELSIZE; break; #endif /* else share code with YCbCr */ +#ifdef ANDROID_RGB + case JCS_RGB_565: +#endif case JCS_YCbCr: cinfo->out_color_components = 3; break; case JCS_CMYK: case JCS_YCCK: +#ifdef ANDROID_RGB + case JCS_RGBA_8888: +#endif cinfo->out_color_components = 4; break; default: /* else must be same colorspace as in file */ @@ -217,7 +236,7 @@ jpeg_calc_output_dimensions (j_decompress_ptr cinfo) * For most steps we can mathematically guarantee that the initial value * of x is within MAXJSAMPLE+1 of the legal range, so a table running from * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial - * limiting step (just after the IDCT), a wildly out-of-range value is + * limiting step (just after the IDCT), a wildly out-of-range value is * possible if the input data is corrupt. To avoid any chance of indexing * off the end of memory and getting a bad-pointer trap, we perform the * post-IDCT limiting thus: @@ -38,6 +38,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 /* Private subobject */ @@ -154,8 +172,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 { @@ -255,14 +279,14 @@ h2v1_merged_upsample (j_decompress_ptr cinfo, cblue = Cbbtab[cb]; /* Fetch 2 Y values and emit 2 pixels */ y = GETJSAMPLE(*inptr0++); - outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_RED] = range_limit[y + cred]; outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr[RGB_BLUE] = range_limit[y + cblue]; outptr += RGB_PIXELSIZE; y = GETJSAMPLE(*inptr0++); - outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_RED] = range_limit[y + cred]; outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr[RGB_BLUE] = range_limit[y + cblue]; outptr += RGB_PIXELSIZE; } /* If image width is odd, do the last output column separately */ @@ -273,13 +297,148 @@ h2v1_merged_upsample (j_decompress_ptr cinfo, cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); cblue = Cbbtab[cb]; y = GETJSAMPLE(*inptr0); - outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_RED] = range_limit[y + cred]; outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +#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; + } +} + + +#endif + /* * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. */ @@ -319,24 +478,24 @@ h2v2_merged_upsample (j_decompress_ptr cinfo, cblue = Cbbtab[cb]; /* Fetch 4 Y values and emit 4 pixels */ y = GETJSAMPLE(*inptr00++); - outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_RED] = range_limit[y + cred]; outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; outptr0 += RGB_PIXELSIZE; y = GETJSAMPLE(*inptr00++); - outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_RED] = range_limit[y + cred]; outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; outptr0 += RGB_PIXELSIZE; y = GETJSAMPLE(*inptr01++); - outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_RED] = range_limit[y + cred]; outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; outptr1 += RGB_PIXELSIZE; y = GETJSAMPLE(*inptr01++); - outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_RED] = range_limit[y + cred]; outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; outptr1 += RGB_PIXELSIZE; } /* If image width is odd, do the last output column separately */ @@ -347,17 +506,197 @@ h2v2_merged_upsample (j_decompress_ptr cinfo, cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); cblue = Cbbtab[cb]; y = GETJSAMPLE(*inptr00); - outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_RED] = range_limit[y + cred]; outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; y = GETJSAMPLE(*inptr01); - outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_RED] = range_limit[y + cred]; outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +#ifdef ANDROID_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 + /* * Module initialization routine for merged upsampling/color conversion. * @@ -379,10 +718,19 @@ jinit_merged_upsampler (j_decompress_ptr cinfo) upsample->pub.need_context_rows = FALSE; upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; - + if (cinfo->max_v_samp_factor == 2) { upsample->pub.upsample = merged_2v_upsample; 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 /* Allocate a spare row buffer */ upsample->spare_row = (JSAMPROW) (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, @@ -390,6 +738,15 @@ jinit_merged_upsampler (j_decompress_ptr cinfo) } else { upsample->pub.upsample = merged_1v_upsample; 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 /* No spare row needed */ upsample->spare_row = NULL; } diff --git a/jidctfst.S b/jidctfst.S new file mode 100644 index 0000000..88fb661 --- /dev/null +++ b/jidctfst.S @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + .text + .align + + .global jpeg_idct_ifast + .func jpeg_idct_ifast + +// NOTE: sb=r9, fp=r11 ip=r12, sp=r13, lr=r14, pc=r15 + +// jpeg_idct_ifast (j_decompress_ptr cinfo, +// jpeg_component_info * compptr, +// short* coef_block, +// unsigned char* output_buf, +// int output_col) + +#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) +#define ARMv6 1 +#endif + +#define local_TMP0123 sp +#define local_TMP0 [sp, #0] +#define local_TMP1 [sp, #4] +#define local_TMP2 [sp, #8] +#define local_TMP3 [sp, #12] +#define local_RANGE_TABLE [sp, #16] +#define local_OUTPUT_COL [sp, #20] +#define local_OUTPUT_BUF [sp, #24] +#define local_UNUSED [sp, #28] +#define off_WORKSPACE 32 +#define local_WORKSPACE [sp, #offWORKSPACE] +#define local_SIZE (off_WORKSPACE + 8*8*4) + +#define off_DECOMPRESS_range_limit_base 324 +#define off_COMPINFO_quanttable 80 + +#define DCTSIZE 8 +#define VY(x) ((x)*DCTSIZE*2) +#define QY(x) ((x)*DCTSIZE*4) + +#define VX(x) ((x)*2) +#define QX(x) ((x)*4) + +#define FIX_1_414213562 #362 +#define FIX_1_082392200 #277 +#define FIX_1_847759065 #473 +#define FIX_2_613125930 #669 + +#define RANGE_MASK 1023 + + + +jpeg_idct_ifast: + pld [r2, #0] + stmdb sp!, {r4,r5, r6,r7, r8,r9, r10,r11, r12,lr} + ldr r4, [sp, #4*10] + sub sp, #local_SIZE + + ldr r10,[r1, #off_COMPINFO_quanttable] // r10 = quanttable + str r4, local_OUTPUT_COL + str r3, local_OUTPUT_BUF + ldr r5, [r0, #off_DECOMPRESS_range_limit_base] + add r5, r5, #128 + str r5, local_RANGE_TABLE + mov fp, r2 // fp = coef_block + add ip, sp, #off_WORKSPACE + +VLoopTail: + ldrsh r0, [fp, #VY(0)] + ldrsh r1, [fp, #VY(1)] + ldrsh r2, [fp, #VY(2)] + ldrsh r3, [fp, #VY(3)] + ldrsh r4, [fp, #VY(4)] + ldrsh r5, [fp, #VY(5)] + ldrsh r6, [fp, #VY(6)] + ldrsh r7, [fp, #VY(7)] + + cmp r1, #0 + orreqs r8, r2, r3 + orreqs r8, r4, r5 + orreqs r8, r6, r7 + beq VLoopHeadZero + +VLoopHead: + // tmp0 = DEQUANTIZE(in[DCTSIZE*0], quant[DCTSIZE*0] (r0) + // tmp2 = DEQUANTIZE(in[DCTSIZE*4], quant[DCTSIZE*4] (r4) + // tmp1 = DEQUANTIZE(in[DCTSIZE*2], quant[DCTSIZE*2] (r2) + // tmp3 = DEQUANTIZE(in[DCTSIZE*6], quant[DCTSIZE*6] (r6) + // tmp10 = tmp0 + tmp2 (r0) + // tmp11 = tmp0 - tmp2 (r4) + + ldr r9, [r10, #QY(4)] + ldr r8, [r10, #QY(0)] + smulbb r4, r9, r4 + smlabb r0, r8, r0, r4 + ldr r9, [r10, #QY(6)] + ldr r8, [r10, #QY(2)] + sub r4, r0, r4, lsl #1 + smulbb r6, r9, r6 + smlabb r2, r8, r2, r6 + + // tmp13 = tmp1 + tmp3 (r2) + // tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13 (r6) + // FIX_1_4142... = 362 = 45*8 + 2 + sub r6, r2, r6, lsl #1 + mov r8, #360 + add r8, r8, #2 + mul r9, r6, r8 + + // tmp0 = tmp10 + tmp13; (r0) + // tmp3 = tmp10 - tmp13; (r8) + // tmp1 = tmp11 + tmp12; (r4) + // tmp2 = tmp11 - tmp12; (r6) + add r0, r0, r2 + rsb r6, r2, r9, asr #8 + sub r8, r0, r2, lsl #1 + add r4, r4, r6 + sub r6, r4, r6, lsl #1 + + stmia local_TMP0123, {r0, r4, r6, r8} + + // NOTE: be sure to not user r0,r4,r6,r8 soon after stm above + + // odd part + // tmp4 = DEQUANTIZE( in[DCTSIZE*1], quant[DCTSIZE*1] ) (r1) + // tmp6 = DEQUANTIZE( in[DCTSIZE*5], quant[DCTSIZE*5] ) (r5) + // tmp5 = DEQUANTIZE( in[DCTSIZE*3], quant[DCTSIZE*3] ) (r3) + // tmp7 = DEQUANTIZE( in[DCTSIZE*7], quant[DCTSIZE*7] ) (r7) + // z13 = tmp6 + tmp5; (r0) + // z10 = tmp6 - tmp5; (r2) + // z11 = tmp4 + tmp7; (r4) + // z12 = tmp4 - tmp7; (r6) + + ldr r2, [r10, #QY(1)] + ldr r9, [r10, #QY(5)] + smulbb r1, r2, r1 + ldr r2, [r10, #QY(3)] + smulbb r5, r9, r5 + ldr r9, [r10, #QY(7)] + smlabb r0, r2, r3, r5 + smlabb r4, r9, r7, r1 + rsb r2, r0, r5, lsl #1 + rsb r6, r4, r1, lsl #1 + + // tmp7 = z11 + z13; (r7) + // tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); (r1) + // FIX_... = 360 + 2 + add r7, r4, r0 + sub r1, r4, r0 + mov r8, #360 + add r8, r8, #2 + mul r1, r8, r1 + + // z5 = MULTIPLY(z10 + z12, FIX_1_847759065); (r8) + // tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; (r0) + // tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; (r2) + // FIX_1_8477... = 473 = 472 + 1 + // FIX_1_082... = 277 = 276 + 1 + // FIX_2_... = 669 = 668 + 1 + add r8, r2, r6 + mov r9, #472 + mla r8, r9, r8, r8 + mov r9, #276 + mla r0, r6, r9, r6 + mov r9, #668 + mla r2, r9, r2, r2 + sub r0, r0, r8 + rsb r2, r2, r8 + + // tmp6 = tmp12 - tmp7; (r6) + // tmp5 = tmp11 - tmp6; (r5) + // tmp4 = tmp10 + tmp5; (r4) + rsb r6, r7, r2, asr #8 + rsb r5, r6, r1, asr #8 + add r4, r5, r0, asr #8 + + ldmia local_TMP0123, {r0, r1, r2, r3} + + // wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); + // wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); + // wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); + // wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); + // wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); + // wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); + // wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); + // wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); + + add r0, r0, r7 + sub r7, r0, r7, lsl #1 + add r1, r1, r6 + sub r6, r1, r6, lsl #1 + add r2, r2, r5 + sub r5, r2, r5, lsl #1 + sub r3, r3, r4 + add r4, r3, r4, lsl #1 + + str r0, [ip, #QY(0)] + str r1, [ip, #QY(1)] + str r2, [ip, #QY(2)] + str r3, [ip, #QY(3)] + str r4, [ip, #QY(4)] + str r5, [ip, #QY(5)] + str r6, [ip, #QY(6)] + str r7, [ip, #QY(7)] + + // inptr++; /* advance pointers to next column */ + // quantptr++; + // wsptr++; + add fp, fp, #2 + add r10, r10, #4 + add ip, ip, #4 + add r0, sp, #(off_WORKSPACE + 4*8) + cmp ip, r0 + bne VLoopTail + + + +HLoopStart: + // reset pointers + pld [sp, #off_WORKSPACE] + add ip, sp, #off_WORKSPACE + ldr r10, local_RANGE_TABLE + +HLoopTail: + // output = *output_buf++ + output_col + ldr r0, local_OUTPUT_BUF + ldr r1, local_OUTPUT_COL + ldr r2, [r0], #4 + str r0, local_OUTPUT_BUF + add fp, r2, r1 + + pld [ip, #32] + ldmia ip!, {r0-r7} + + cmp r1, #0 + orreqs r8, r2, r3 + orreqs r8, r4, r5 + orreqs r8, r6, r7 + beq HLoopTailZero + +HLoopHead: + // tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); (r0) + // tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); (r4) + add r0, r0, r4 + sub r4, r0, r4, lsl #1 + + // tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); (r2) + // tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) - tmp13; (r6) + // FIX_... = 360 + 2 + add r2, r2, r6 + sub r6, r2, r6, lsl #1 + mov r8, #360 + add r8, r8, #2 + mul r6, r8, r6 + + // tmp0 = tmp10 + tmp13; (r0) + // tmp3 = tmp10 - tmp13; (r8) + // tmp1 = tmp11 + tmp12; (r4) + // tmp2 = tmp11 - tmp12; (r6) + add r0, r0, r2 + rsb r6, r2, r6, asr #8 + sub r8, r0, r2, lsl #1 + add r4, r4, r6 + sub r6, r4, r6, lsl #1 + + stmia local_TMP0123, {r0, r4, r6, r8} + + // Odd part + + // z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; (r0) + // z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; (r2) + // z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; (r4) + // z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; (r6) + add r0, r5, r3 + sub r2, r5, r3 + add r4, r1, r7 + sub r6, r1, r7 + + // tmp7 = z11 + z13; (r7) + // tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); (r1) + // FIX_... = 360 + 2 + add r7, r4, r0 + sub r1, r4, r0 + mov r8, #360 + add r8, r8, #2 + mul r1, r8, r1 + + // z5 = MULTIPLY(z10 + z12, FIX_1_847759065); (r8) + // tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; (r0) + // tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; (r2) + // FIX_1_8477... = 473 = 472 + 1 + // FIX_1_082... = 277 = 276 + 1 + // FIX_2_... = 669 = 668 + 1 + add r8, r2, r6 + mov r9, #472 + mla r8, r9, r8, r8 + mov r9, #276 + mla r0, r6, r9, r6 + mov r9, #668 + mla r2, r9, r2, r2 + sub r0, r0, r8 + sub r2, r8, r2 + + // tmp6 = tmp12 - tmp7; (r6) + // tmp5 = tmp11 - tmp6; (r5) + // tmp4 = tmp10 + tmp5; (r4) + rsb r6, r7, r2, asr #8 + rsb r5, r6, r1, asr #8 + add r4, r5, r0, asr #8 + + ldmia local_TMP0123, {r0, r1, r2, r3} + + // outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) & RANGE_MASK]; + // outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) & RANGE_MASK]; + // outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) & RANGE_MASK]; + // outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) & RANGE_MASK]; + // outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) & RANGE_MASK]; + // outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) & RANGE_MASK]; + // outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) & RANGE_MASK]; + // outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) & RANGE_MASK]; + + mov r8, #128 + add r0, r0, r7 + sub r7, r0, r7, lsl #1 + add r0, r8, r0, asr #5 + add r7, r8, r7, asr #5 + add r1, r1, r6 + sub r6, r1, r6, lsl #1 + add r1, r8, r1, asr #5 + add r6, r8, r6, asr #5 + add r2, r2, r5 + sub r5, r2, r5, lsl #1 + add r2, r8, r2, asr #5 + add r5, r8, r5, asr #5 + sub r3, r3, r4 + add r4, r3, r4, lsl #1 + add r3, r8, r3, asr #5 + add r4, r8, r4, asr #5 + +#ifdef ARMv6 + usat r0, #8, r0 + usat r1, #8, r1 + usat r2, #8, r2 + usat r3, #8, r3 + usat r4, #8, r4 + usat r5, #8, r5 + usat r6, #8, r6 + usat r7, #8, r7 +#else + cmp r0, #255 + mvnhi r0, r0, asr #31 + andhi r0, #255 + cmp r7, #255 + mvnhi r7, r7, asr #31 + cmp r1, #255 + mvnhi r1, r1, asr #31 + andhi r1, #255 + cmp r6, #255 + mvnhi r6, r6, asr #31 + andhi r6, #255 + cmp r2, #255 + mvnhi r2, r2, asr #31 + andhi r2, #255 + cmp r5, #255 + mvnhi r5, r5, asr #31 + andhi r5, #255 + cmp r3, #255 + mvnhi r3, r3, asr #31 + cmp r4, #255 + mvnhi r4, r4, asr #31 + andhi r4, #255 +#endif + + // r3 r2 r1 r0 + orr r0, r0, r1, lsl #8 + orr r0, r0, r2, lsl #16 + orr r0, r0, r3, lsl #24 + + // r7 r6 r5 r4 + orr r1, r4, r5, lsl #8 + orr r1, r1, r6, lsl #16 + orr r1, r1, r7, lsl #24 + stmia fp, {r0, r1} + + add r0, sp, #(off_WORKSPACE + 8*8*4) + cmp ip, r0 + bne HLoopTail + +Exit: + add sp, sp, #local_SIZE + ldmia sp!, {r4,r5, r6,r7, r8,r9, r10,r11, r12,lr} + bx lr + + +VLoopHeadZero: +// ok, all AC coefficients are 0 + ldr r1, [r10, #QY(0)] + add fp, fp, #2 + add r10, r10, #4 + mul r0, r1, r0 + str r0, [ip, #QY(0)] + str r0, [ip, #QY(1)] + str r0, [ip, #QY(2)] + str r0, [ip, #QY(3)] + str r0, [ip, #QY(4)] + str r0, [ip, #QY(5)] + str r0, [ip, #QY(6)] + str r0, [ip, #QY(7)] + add ip, ip, #4 + add r0, sp, #(off_WORKSPACE + 4*8) + cmp ip, r0 + beq HLoopStart + b VLoopTail + +HLoopTailZero: + mov r0, r0, asr #5 + add r0, #128 + +#ifdef ARMv6 + usat r0, #8, r0 +#else + cmp r0, #255 + mvnhi r0, r0, asr #31 + andhi r0, r0, #255 +#endif + + orr r0, r0, lsl #8 + orr r0, r0, lsl #16 + mov r1, r0 + stmia fp, {r0, r1} + + add r0, sp, #(off_WORKSPACE + 64*4) + cmp ip, r0 + beq Exit + b HLoopTail + + .endfunc @@ -10,6 +10,28 @@ * optimizations. Most users will not need to touch this file. */ +/* + * Define ANDROID_RGB to enable specific optimizations for Android + * JCS_RGBA_8888 support + * JCS_RGB_565 support + * + */ + +#define ANDROID_RGB + +#ifdef ANDROID_RGB +#define PACK_SHORT_565(r,g,b) ((((r)<<8)&0xf800)|(((g)<<3)&0x7C0)|((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 /* * Define BITS_IN_JSAMPLE as either @@ -314,8 +336,10 @@ typedef int boolean; #define RGB_RED 0 /* Offset of Red in an RGB scanline element */ #define RGB_GREEN 1 /* Offset of Green */ #define RGB_BLUE 2 /* Offset of Blue */ -#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ - +#ifdef ANDROID_RGB +#define RGB_ALPHA 3 /* Offset of Alpha */ +#endif +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ /* Definitions for speed-related optimizations. */ @@ -128,9 +128,9 @@ typedef struct { /* The decompressor output side may not use these variables. */ int dc_tbl_no; /* DC entropy table selector (0..3) */ int ac_tbl_no; /* AC entropy table selector (0..3) */ - + /* Remaining fields should be treated as private by applications. */ - + /* These values are computed during compression or decompression startup: */ /* Component's size in DCT blocks. * Any dummy blocks added to complete an MCU are not counted; therefore @@ -209,7 +209,11 @@ typedef enum { JCS_RGB, /* red/green/blue */ JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ JCS_CMYK, /* C/M/Y/K */ - JCS_YCCK /* Y/Cb/Cr/K */ + JCS_YCCK, /* Y/Cb/Cr/K */ +#ifdef ANDROID_RGB + JCS_RGBA_8888, /* red/green/blue/alpha */ + JCS_RGB_565 /* red/green/blue in 565 format */ +#endif } J_COLOR_SPACE; /* DCT/IDCT algorithm options. */ @@ -298,14 +302,14 @@ struct jpeg_compress_struct { jpeg_component_info * comp_info; /* comp_info[i] describes component that appears i'th in SOF */ - + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; /* ptrs to coefficient quantization tables, or NULL if not defined */ - + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; /* ptrs to Huffman coding tables, or NULL if not defined */ - + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ @@ -345,7 +349,7 @@ struct jpeg_compress_struct { UINT16 X_density; /* Horizontal pixel density */ UINT16 Y_density; /* Vertical pixel density */ boolean write_Adobe_marker; /* should an Adobe marker be written? */ - + /* State variable: index of next scanline to be written to * jpeg_write_scanlines(). Application may use this to control its * processing loop, e.g., "while (next_scanline < image_height)". @@ -370,7 +374,7 @@ struct jpeg_compress_struct { * There are v_samp_factor * DCTSIZE sample rows of each component in an * "iMCU" (interleaved MCU) row. */ - + /* * These fields are valid during any one scan. * They describe the components and MCUs actually appearing in the scan. @@ -378,10 +382,10 @@ struct jpeg_compress_struct { int comps_in_scan; /* # of JPEG components in this scan */ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; /* *cur_comp_info[i] describes component that appears i'th in SOS */ - + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ - + int blocks_in_MCU; /* # of DCT blocks per MCU */ int MCU_membership[C_MAX_BLOCKS_IN_MCU]; /* MCU_membership[i] is index in cur_comp_info of component owning */ @@ -652,7 +656,7 @@ struct jpeg_error_mgr { #define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ /* Reset error state variables at start of a new image */ JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); - + /* The message ID code and any parameters are saved here. * A message can have one string parameter or up to 8 int parameters. */ @@ -662,11 +666,11 @@ struct jpeg_error_mgr { int i[8]; char s[JMSG_STR_PARM_MAX]; } msg_parm; - + /* Standard state variables for error facility */ - + int trace_level; /* max msg_level that will be displayed */ - + /* For recoverable corrupt-data errors, we emit a warning message, * but keep going unless emit_message chooses to abort. emit_message * should count warnings in num_warnings. The surrounding application @@ -824,7 +828,7 @@ typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); /* Short forms of external names for systems with brain-damaged linkers. * We shorten external names to be unique in the first six letters, which * is good enough for all known systems. - * (If your compiler itself needs names to be unique in less than 15 + * (If your compiler itself needs names to be unique in less than 15 * characters, you are out of luck. Get a better compiler.) */ |