| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * JPEG image viewer |
| * (This is a real mess if it has to be coded in one single C file) |
| * |
| * File scrolling addition (C) 2005 Alexander Spyridakis |
| * Copyright (C) 2004 Jörg Hohensohn aka [IDC]Dragon |
| * Heavily borrowed from the IJG implementation (C) Thomas G. Lane |
| * Small & fast downscaling IDCT (C) 2002 by Guido Vollbeding JPEGclub.org |
| * |
| * All files in this archive are subject to the GNU General Public License. |
| * See the file COPYING in the source tree root for full license agreement. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #include "plugin.h" |
| #include "playback_control.h" |
| #include "oldmenuapi.h" |
| #include "helper.h" |
| #include "lib/configfile.h" |
| |
| #ifdef HAVE_LCD_BITMAP |
| #include "grey.h" |
| #include "xlcd.h" |
| |
| PLUGIN_HEADER |
| |
| /* variable button definitions */ |
| #if CONFIG_KEYPAD == RECORDER_PAD |
| #define JPEG_ZOOM_IN BUTTON_PLAY |
| #define JPEG_ZOOM_OUT BUTTON_ON |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_NEXT BUTTON_F3 |
| #define JPEG_PREVIOUS BUTTON_F2 |
| #define JPEG_MENU BUTTON_OFF |
| |
| #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD |
| #define JPEG_ZOOM_IN BUTTON_SELECT |
| #define JPEG_ZOOM_OUT BUTTON_ON |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_NEXT BUTTON_F3 |
| #define JPEG_PREVIOUS BUTTON_F2 |
| #define JPEG_MENU BUTTON_OFF |
| |
| #elif CONFIG_KEYPAD == ONDIO_PAD |
| #define JPEG_ZOOM_PRE BUTTON_MENU |
| #define JPEG_ZOOM_IN (BUTTON_MENU | BUTTON_REL) |
| #define JPEG_ZOOM_OUT (BUTTON_MENU | BUTTON_DOWN) |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_NEXT (BUTTON_MENU | BUTTON_RIGHT) |
| #define JPEG_PREVIOUS (BUTTON_MENU | BUTTON_LEFT) |
| #define JPEG_MENU BUTTON_OFF |
| |
| #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ |
| (CONFIG_KEYPAD == IRIVER_H300_PAD) |
| #define JPEG_ZOOM_IN BUTTON_SELECT |
| #define JPEG_ZOOM_OUT BUTTON_MODE |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #if (CONFIG_KEYPAD == IRIVER_H100_PAD) |
| #define JPEG_NEXT BUTTON_ON |
| #define JPEG_PREVIOUS BUTTON_REC |
| #else |
| #define JPEG_NEXT BUTTON_REC |
| #define JPEG_PREVIOUS BUTTON_ON |
| #endif |
| #define JPEG_MENU BUTTON_OFF |
| #define JPEG_RC_MENU BUTTON_RC_STOP |
| |
| #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ |
| (CONFIG_KEYPAD == IPOD_1G2G_PAD) |
| #define JPEG_ZOOM_IN BUTTON_SCROLL_FWD |
| #define JPEG_ZOOM_OUT BUTTON_SCROLL_BACK |
| #define JPEG_UP BUTTON_MENU |
| #define JPEG_DOWN BUTTON_PLAY |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU (BUTTON_SELECT | BUTTON_MENU) |
| #define JPEG_NEXT (BUTTON_SELECT | BUTTON_RIGHT) |
| #define JPEG_PREVIOUS (BUTTON_SELECT | BUTTON_LEFT) |
| |
| #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD |
| #define JPEG_ZOOM_PRE BUTTON_SELECT |
| #define JPEG_ZOOM_IN (BUTTON_SELECT | BUTTON_REL) |
| #define JPEG_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT) |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU BUTTON_POWER |
| #define JPEG_NEXT BUTTON_PLAY |
| #define JPEG_PREVIOUS BUTTON_REC |
| |
| #elif CONFIG_KEYPAD == GIGABEAT_PAD |
| #define JPEG_ZOOM_IN BUTTON_VOL_UP |
| #define JPEG_ZOOM_OUT BUTTON_VOL_DOWN |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU BUTTON_MENU |
| #define JPEG_NEXT (BUTTON_A | BUTTON_RIGHT) |
| #define JPEG_PREVIOUS (BUTTON_A | BUTTON_LEFT) |
| |
| #elif CONFIG_KEYPAD == SANSA_E200_PAD |
| #define JPEG_ZOOM_PRE BUTTON_SELECT |
| #define JPEG_ZOOM_IN (BUTTON_SELECT | BUTTON_REL) |
| #define JPEG_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT) |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU BUTTON_POWER |
| #define JPEG_SLIDE_SHOW BUTTON_REC |
| #define JPEG_NEXT BUTTON_SCROLL_FWD |
| #define JPEG_NEXT_REPEAT (BUTTON_SCROLL_FWD|BUTTON_REPEAT) |
| #define JPEG_PREVIOUS BUTTON_SCROLL_BACK |
| #define JPEG_PREVIOUS_REPEAT (BUTTON_SCROLL_BACK|BUTTON_REPEAT) |
| |
| #elif CONFIG_KEYPAD == SANSA_C200_PAD |
| #define JPEG_ZOOM_PRE BUTTON_SELECT |
| #define JPEG_ZOOM_IN (BUTTON_SELECT | BUTTON_REL) |
| #define JPEG_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT) |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU BUTTON_POWER |
| #define JPEG_SLIDE_SHOW BUTTON_REC |
| #define JPEG_NEXT BUTTON_VOL_UP |
| #define JPEG_NEXT_REPEAT (BUTTON_VOL_UP|BUTTON_REPEAT) |
| #define JPEG_PREVIOUS BUTTON_VOL_DOWN |
| #define JPEG_PREVIOUS_REPEAT (BUTTON_VOL_DOWN|BUTTON_REPEAT) |
| |
| #elif CONFIG_KEYPAD == IRIVER_H10_PAD |
| #define JPEG_ZOOM_PRE BUTTON_PLAY |
| #define JPEG_ZOOM_IN (BUTTON_PLAY | BUTTON_REL) |
| #define JPEG_ZOOM_OUT (BUTTON_PLAY | BUTTON_REPEAT) |
| #define JPEG_UP BUTTON_SCROLL_UP |
| #define JPEG_DOWN BUTTON_SCROLL_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU BUTTON_POWER |
| #define JPEG_NEXT BUTTON_FF |
| #define JPEG_PREVIOUS BUTTON_REW |
| |
| #elif CONFIG_KEYPAD == MROBE500_PAD |
| #define JPEG_ZOOM_IN BUTTON_RC_VOL_UP |
| #define JPEG_ZOOM_OUT BUTTON_RC_VOL_DOWN |
| #define JPEG_UP BUTTON_RC_PLAY |
| #define JPEG_DOWN BUTTON_RC_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU BUTTON_POWER |
| #define JPEG_NEXT BUTTON_RC_HEART |
| #define JPEG_PREVIOUS BUTTON_RC_MODE |
| |
| #elif CONFIG_KEYPAD == GIGABEAT_S_PAD |
| #define JPEG_ZOOM_IN BUTTON_VOL_UP |
| #define JPEG_ZOOM_OUT BUTTON_VOL_DOWN |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU BUTTON_MENU |
| #define JPEG_NEXT BUTTON_NEXT |
| #define JPEG_PREVIOUS BUTTON_PREV |
| |
| #elif CONFIG_KEYPAD == MROBE100_PAD |
| #define JPEG_ZOOM_IN BUTTON_SELECT |
| #define JPEG_ZOOM_OUT BUTTON_PLAY |
| #define JPEG_UP BUTTON_UP |
| #define JPEG_DOWN BUTTON_DOWN |
| #define JPEG_LEFT BUTTON_LEFT |
| #define JPEG_RIGHT BUTTON_RIGHT |
| #define JPEG_MENU BUTTON_MENU |
| #define JPEG_NEXT (BUTTON_DISPLAY | BUTTON_RIGHT) |
| #define JPEG_PREVIOUS (BUTTON_DISPLAY | BUTTON_LEFT) |
| |
| #elif CONFIG_KEYPAD == IAUDIO_M3_PAD |
| #define JPEG_ZOOM_PRE BUTTON_RC_PLAY |
| #define JPEG_ZOOM_IN (BUTTON_RC_PLAY|BUTTON_REL) |
| #define JPEG_ZOOM_OUT (BUTTON_RC_PLAY|BUTTON_REPEAT) |
| #define JPEG_UP BUTTON_RC_VOL_UP |
| #define JPEG_DOWN BUTTON_RC_VOL_DOWN |
| #define JPEG_LEFT BUTTON_RC_REW |
| #define JPEG_RIGHT BUTTON_RC_FF |
| #define JPEG_MENU BUTTON_RC_REC |
| #define JPEG_NEXT BUTTON_RC_MODE |
| #define JPEG_PREVIOUS BUTTON_RC_MENU |
| |
| #elif CONFIG_KEYPAD == COWOND2_PAD |
| |
| #else |
| #error No keymap defined! |
| #endif |
| |
| #ifdef HAVE_TOUCHPAD |
| #ifndef JPEG_UP |
| #define JPEG_UP BUTTON_TOPMIDDLE |
| #endif |
| #ifndef JPEG_DOWN |
| #define JPEG_DOWN BUTTON_BOTTOMMIDDLE |
| #endif |
| #ifndef JPEG_LEFT |
| #define JPEG_LEFT BUTTON_MIDLEFT |
| #endif |
| #ifndef JPEG_RIGHT |
| #define JPEG_RIGHT BUTTON_MIDRIGHT |
| #endif |
| #ifndef JPEG_ZOOM_IN |
| #define JPEG_ZOOM_IN BUTTON_TOPRIGHT |
| #endif |
| #ifndef JPEG_ZOOM_OUT |
| #define JPEG_ZOOM_OUT BUTTON_TOPLEFT |
| #endif |
| #ifndef JPEG_MENU |
| #define JPEG_MENU (BUTTON_CENTER|BUTTON_REL) |
| #endif |
| #ifndef JPEG_NEXT |
| #define JPEG_NEXT BUTTON_BOTTOMRIGHT |
| #endif |
| #ifndef JPEG_PREVIOUS |
| #define JPEG_PREVIOUS BUTTON_BOTTOMLEFT |
| #endif |
| #endif |
| |
| /* different graphics libraries */ |
| #if LCD_DEPTH < 8 |
| #define USEGSLIB |
| GREY_INFO_STRUCT |
| #define MYLCD(fn) grey_ub_ ## fn |
| #define MYLCD_UPDATE() |
| #define MYXLCD(fn) grey_ub_ ## fn |
| #else |
| #define MYLCD(fn) rb->lcd_ ## fn |
| #define MYLCD_UPDATE() rb->lcd_update(); |
| #define MYXLCD(fn) xlcd_ ## fn |
| #endif |
| |
| #define MAX_X_SIZE LCD_WIDTH*8 |
| |
| /* Min memory allowing us to use the plugin buffer |
| * and thus not stopping the music |
| * *Very* rough estimation: |
| * Max 10 000 dir entries * 4bytes/entry (char **) = 40000 bytes |
| * + 20k code size = 60 000 |
| * + 50k min for jpeg = 120 000 |
| */ |
| #define MIN_MEM 120000 |
| |
| /* Headings */ |
| #define DIR_PREV 1 |
| #define DIR_NEXT -1 |
| #define DIR_NONE 0 |
| |
| #define PLUGIN_OTHER 10 /* State code for output with return. */ |
| |
| /******************************* Globals ***********************************/ |
| |
| static struct plugin_api* rb; |
| MEM_FUNCTION_WRAPPERS(rb); |
| |
| /* for portability of below JPEG code */ |
| #define MEMSET(p,v,c) rb->memset(p,v,c) |
| #define MEMCPY(d,s,c) rb->memcpy(d,s,c) |
| #define INLINE static inline |
| #define ENDIAN_SWAP16(n) n /* only for poor little endian machines */ |
| |
| static int slideshow_enabled = false; /* run slideshow */ |
| static int running_slideshow = false; /* loading image because of slideshw */ |
| #ifndef SIMULATOR |
| static int immediate_ata_off = false; /* power down disk after loading */ |
| #endif |
| |
| /* Persistent configuration */ |
| #define JPEG_CONFIGFILE "jpeg.cfg" |
| #define JPEG_SETTINGS_MINVERSION 1 |
| #define JPEG_SETTINGS_VERSION 2 |
| |
| /* Slideshow times */ |
| #define SS_MIN_TIMEOUT 1 |
| #define SS_MAX_TIMEOUT 20 |
| #define SS_DEFAULT_TIMEOUT 5 |
| |
| enum color_modes |
| { |
| COLOURMODE_COLOUR = 0, |
| COLOURMODE_GRAY, |
| COLOUR_NUM_MODES |
| }; |
| |
| enum dither_modes |
| { |
| DITHER_NONE = 0, /* No dithering */ |
| DITHER_ORDERED, /* Bayer ordered */ |
| DITHER_DIFFUSION, /* Floyd/Steinberg error diffusion */ |
| DITHER_NUM_MODES |
| }; |
| |
| struct jpeg_settings |
| { |
| int colour_mode; |
| int dither_mode; |
| int ss_timeout; |
| }; |
| |
| static struct jpeg_settings jpeg_settings = |
| { COLOURMODE_COLOUR, DITHER_NONE, SS_DEFAULT_TIMEOUT }; |
| static struct jpeg_settings old_settings; |
| |
| static struct configdata jpeg_config[] = |
| { |
| #ifdef HAVE_LCD_COLOR |
| { TYPE_ENUM, 0, COLOUR_NUM_MODES, &jpeg_settings.colour_mode, |
| "Colour Mode", (char *[]){ "Colour", "Grayscale" }, NULL }, |
| { TYPE_ENUM, 0, DITHER_NUM_MODES, &jpeg_settings.dither_mode, |
| "Dither Mode", (char *[]){ "None", "Ordered", "Diffusion" }, NULL }, |
| #endif |
| { TYPE_INT, SS_MIN_TIMEOUT, SS_MAX_TIMEOUT, &jpeg_settings.ss_timeout, |
| "Slideshow Time", NULL, NULL}, |
| }; |
| |
| #if LCD_DEPTH > 1 |
| fb_data* old_backdrop; |
| #endif |
| |
| /**************** begin JPEG code ********************/ |
| |
| INLINE unsigned range_limit(int value) |
| { |
| #if CONFIG_CPU == SH7034 |
| unsigned tmp; |
| asm ( /* Note: Uses knowledge that only low byte of result is used */ |
| "mov #-128,%[t] \n" |
| "sub %[t],%[v] \n" /* value -= -128; equals value += 128; */ |
| "extu.b %[v],%[t] \n" |
| "cmp/eq %[v],%[t] \n" /* low byte == whole number ? */ |
| "bt 1f \n" /* yes: no overflow */ |
| "cmp/pz %[v] \n" /* overflow: positive? */ |
| "subc %[v],%[v] \n" /* %[r] now either 0 or 0xffffffff */ |
| "1: \n" |
| : /* outputs */ |
| [v]"+r"(value), |
| [t]"=&r"(tmp) |
| ); |
| return value; |
| #elif defined(CPU_COLDFIRE) |
| asm ( /* Note: Uses knowledge that only the low byte of the result is used */ |
| "add.l #128,%[v] \n" /* value += 128; */ |
| "cmp.l #255,%[v] \n" /* overflow? */ |
| "bls.b 1f \n" /* no: return value */ |
| "spl.b %[v] \n" /* yes: set low byte to appropriate boundary */ |
| "1: \n" |
| : /* outputs */ |
| [v]"+d"(value) |
| ); |
| return value; |
| #elif defined(CPU_ARM) |
| asm ( /* Note: Uses knowledge that only the low byte of the result is used */ |
| "add %[v], %[v], #128 \n" /* value += 128 */ |
| "cmp %[v], #255 \n" /* out of range 0..255? */ |
| "mvnhi %[v], %[v], asr #31 \n" /* yes: set all bits to ~(sign_bit) */ |
| : /* outputs */ |
| [v]"+r"(value) |
| ); |
| return value; |
| #else |
| value += 128; |
| |
| if ((unsigned)value <= 255) |
| return value; |
| |
| if (value < 0) |
| return 0; |
| |
| return 255; |
| #endif |
| } |
| |
| /* IDCT implementation */ |
| |
| |
| #define CONST_BITS 13 |
| #define PASS1_BITS 2 |
| |
| |
| /* Some C compilers fail to reduce "FIX(constant)" at compile time, thus |
| * causing a lot of useless floating-point operations at run time. |
| * To get around this we use the following pre-calculated constants. |
| * If you change CONST_BITS you may want to add appropriate values. |
| * (With a reasonable C compiler, you can just rely on the FIX() macro...) |
| */ |
| #define FIX_0_298631336 2446 /* FIX(0.298631336) */ |
| #define FIX_0_390180644 3196 /* FIX(0.390180644) */ |
| #define FIX_0_541196100 4433 /* FIX(0.541196100) */ |
| #define FIX_0_765366865 6270 /* FIX(0.765366865) */ |
| #define FIX_0_899976223 7373 /* FIX(0.899976223) */ |
| #define FIX_1_175875602 9633 /* FIX(1.175875602) */ |
| #define FIX_1_501321110 12299 /* FIX(1.501321110) */ |
| #define FIX_1_847759065 15137 /* FIX(1.847759065) */ |
| #define FIX_1_961570560 16069 /* FIX(1.961570560) */ |
| #define FIX_2_053119869 16819 /* FIX(2.053119869) */ |
| #define FIX_2_562915447 20995 /* FIX(2.562915447) */ |
| #define FIX_3_072711026 25172 /* FIX(3.072711026) */ |
| |
| |
| |
| /* Multiply an long variable by an long constant to yield an long result. |
| * For 8-bit samples with the recommended scaling, all the variable |
| * and constant values involved are no more than 16 bits wide, so a |
| * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. |
| * For 12-bit samples, a full 32-bit multiplication will be needed. |
| */ |
| #define MULTIPLY16(var,const) (((short) (var)) * ((short) (const))) |
| |
| |
| /* Dequantize a coefficient by multiplying it by the multiplier-table |
| * entry; produce an int result. In this module, both inputs and result |
| * are 16 bits or less, so either int or short multiply will work. |
| */ |
| /* #define DEQUANTIZE(coef,quantval) (((int) (coef)) * (quantval)) */ |
| #define DEQUANTIZE MULTIPLY16 |
| |
| /* Descale and correctly round an int value that's scaled by N bits. |
| * We assume RIGHT_SHIFT rounds towards minus infinity, so adding |
| * the fudge factor is correct for either sign of X. |
| */ |
| #define DESCALE(x,n) (((x) + (1l << ((n)-1))) >> (n)) |
| |
| |
| |
| /* |
| * Perform dequantization and inverse DCT on one block of coefficients, |
| * producing a reduced-size 1x1 output block. |
| */ |
| void idct1x1(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line) |
| { |
| (void)skip_line; /* unused */ |
| *p_byte = range_limit(inptr[0] * quantptr[0] >> 3); |
| } |
| |
| |
| |
| /* |
| * Perform dequantization and inverse DCT on one block of coefficients, |
| * producing a reduced-size 2x2 output block. |
| */ |
| void idct2x2(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line) |
| { |
| int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; |
| unsigned char* outptr; |
| |
| /* Pass 1: process columns from input, store into work array. */ |
| |
| /* Column 0 */ |
| tmp4 = DEQUANTIZE(inptr[8*0], quantptr[8*0]); |
| tmp5 = DEQUANTIZE(inptr[8*1], quantptr[8*1]); |
| |
| tmp0 = tmp4 + tmp5; |
| tmp2 = tmp4 - tmp5; |
| |
| /* Column 1 */ |
| tmp4 = DEQUANTIZE(inptr[8*0+1], quantptr[8*0+1]); |
| tmp5 = DEQUANTIZE(inptr[8*1+1], quantptr[8*1+1]); |
| |
| tmp1 = tmp4 + tmp5; |
| tmp3 = tmp4 - tmp5; |
| |
| /* Pass 2: process 2 rows, store into output array. */ |
| |
| /* Row 0 */ |
| outptr = p_byte; |
| |
| outptr[0] = range_limit((int) DESCALE(tmp0 + tmp1, 3)); |
| outptr[1] = range_limit((int) DESCALE(tmp0 - tmp1, 3)); |
| |
| /* Row 1 */ |
| outptr = p_byte + skip_line; |
| |
| outptr[0] = range_limit((int) DESCALE(tmp2 + tmp3, 3)); |
| outptr[1] = range_limit((int) DESCALE(tmp2 - tmp3, 3)); |
| } |
| |
| |
| |
| /* |
| * Perform dequantization and inverse DCT on one block of coefficients, |
| * producing a reduced-size 4x4 output block. |
| */ |
| void idct4x4(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line) |
| { |
| int tmp0, tmp2, tmp10, tmp12; |
| int z1, z2, z3; |
| int * wsptr; |
| unsigned char* outptr; |
| int ctr; |
| int workspace[4*4]; /* buffers data between passes */ |
| |
| /* Pass 1: process columns from input, store into work array. */ |
| |
| wsptr = workspace; |
| for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) |
| { |
| /* Even part */ |
| |
| tmp0 = DEQUANTIZE(inptr[8*0], quantptr[8*0]); |
| tmp2 = DEQUANTIZE(inptr[8*2], quantptr[8*2]); |
| |
| tmp10 = (tmp0 + tmp2) << PASS1_BITS; |
| tmp12 = (tmp0 - tmp2) << PASS1_BITS; |
| |
| /* Odd part */ |
| /* Same rotation as in the even part of the 8x8 LL&M IDCT */ |
| |
| z2 = DEQUANTIZE(inptr[8*1], quantptr[8*1]); |
| z3 = DEQUANTIZE(inptr[8*3], quantptr[8*3]); |
| |
| z1 = MULTIPLY16(z2 + z3, FIX_0_541196100); |
| tmp0 = DESCALE(z1 + MULTIPLY16(z3, - FIX_1_847759065), CONST_BITS-PASS1_BITS); |
| tmp2 = DESCALE(z1 + MULTIPLY16(z2, FIX_0_765366865), CONST_BITS-PASS1_BITS); |
| |
| /* Final output stage */ |
| |
| wsptr[4*0] = (int) (tmp10 + tmp2); |
| wsptr[4*3] = (int) (tmp10 - tmp2); |
| wsptr[4*1] = (int) (tmp12 + tmp0); |
| wsptr[4*2] = (int) (tmp12 - tmp0); |
| } |
| |
| /* Pass 2: process 4 rows from work array, store into output array. */ |
| |
| wsptr = workspace; |
| for (ctr = 0; ctr < 4; ctr++) |
| { |
| outptr = p_byte + (ctr*skip_line); |
| /* Even part */ |
| |
| tmp0 = (int) wsptr[0]; |
| tmp2 = (int) wsptr[2]; |
| |
| tmp10 = (tmp0 + tmp2) << CONST_BITS; |
| tmp12 = (tmp0 - tmp2) << CONST_BITS; |
| |
| /* Odd part */ |
| /* Same rotation as in the even part of the 8x8 LL&M IDCT */ |
| |
| z2 = (int) wsptr[1]; |
| z3 = (int) wsptr[3]; |
| |
| z1 = MULTIPLY16(z2 + z3, FIX_0_541196100); |
| tmp0 = z1 + MULTIPLY16(z3, - FIX_1_847759065); |
| tmp2 = z1 + MULTIPLY16(z2, FIX_0_765366865); |
| |
| /* Final output stage */ |
| |
| outptr[0] = range_limit((int) DESCALE(tmp10 + tmp2, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[3] = range_limit((int) DESCALE(tmp10 - tmp2, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[1] = range_limit((int) DESCALE(tmp12 + tmp0, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[2] = range_limit((int) DESCALE(tmp12 - tmp0, |
| CONST_BITS+PASS1_BITS+3)); |
| |
| wsptr += 4; /* advance pointer to next row */ |
| } |
| } |
| |
| |
| |
| /* |
| * Perform dequantization and inverse DCT on one block of coefficients. |
| */ |
| void idct8x8(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line) |
| { |
| long tmp0, tmp1, tmp2, tmp3; |
| long tmp10, tmp11, tmp12, tmp13; |
| long z1, z2, z3, z4, z5; |
| int * wsptr; |
| unsigned char* outptr; |
| int ctr; |
| int workspace[64]; /* buffers data between passes */ |
| |
| /* Pass 1: process columns from input, store into work array. */ |
| /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ |
| /* furthermore, we scale the results by 2**PASS1_BITS. */ |
| |
| wsptr = workspace; |
| for (ctr = 8; ctr > 0; ctr--) |
| { |
| /* Due to quantization, we will usually find that many of the input |
| * coefficients are zero, especially the AC terms. We can exploit this |
| * by short-circuiting the IDCT calculation for any column in which all |
| * the AC terms are zero. In that case each output is equal to the |
| * DC coefficient (with scale factor as needed). |
| * With typical images and quantization tables, half or more of the |
| * column DCT calculations can be simplified this way. |
| */ |
| |
| if ((inptr[8*1] | inptr[8*2] | inptr[8*3] |
| | inptr[8*4] | inptr[8*5] | inptr[8*6] | inptr[8*7]) == 0) |
| { |
| /* AC terms all zero */ |
| int dcval = DEQUANTIZE(inptr[8*0], quantptr[8*0]) << PASS1_BITS; |
| |
| wsptr[8*0] = wsptr[8*1] = wsptr[8*2] = wsptr[8*3] = wsptr[8*4] |
| = wsptr[8*5] = wsptr[8*6] = wsptr[8*7] = dcval; |
| inptr++; /* advance pointers to next column */ |
| quantptr++; |
| wsptr++; |
| continue; |
| } |
| |
| /* Even part: reverse the even part of the forward DCT. */ |
| /* The rotator is sqrt(2)*c(-6). */ |
| |
| z2 = DEQUANTIZE(inptr[8*2], quantptr[8*2]); |
| z3 = DEQUANTIZE(inptr[8*6], quantptr[8*6]); |
| |
| z1 = MULTIPLY16(z2 + z3, FIX_0_541196100); |
| tmp2 = z1 + MULTIPLY16(z3, - FIX_1_847759065); |
| tmp3 = z1 + MULTIPLY16(z2, FIX_0_765366865); |
| |
| z2 = DEQUANTIZE(inptr[8*0], quantptr[8*0]); |
| z3 = DEQUANTIZE(inptr[8*4], quantptr[8*4]); |
| |
| tmp0 = (z2 + z3) << CONST_BITS; |
| tmp1 = (z2 - z3) << CONST_BITS; |
| |
| tmp10 = tmp0 + tmp3; |
| tmp13 = tmp0 - tmp3; |
| tmp11 = tmp1 + tmp2; |
| tmp12 = tmp1 - tmp2; |
| |
| /* Odd part per figure 8; the matrix is unitary and hence its |
| transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. */ |
| |
| tmp0 = DEQUANTIZE(inptr[8*7], quantptr[8*7]); |
| tmp1 = DEQUANTIZE(inptr[8*5], quantptr[8*5]); |
| tmp2 = DEQUANTIZE(inptr[8*3], quantptr[8*3]); |
| tmp3 = DEQUANTIZE(inptr[8*1], quantptr[8*1]); |
| |
| z1 = tmp0 + tmp3; |
| z2 = tmp1 + tmp2; |
| z3 = tmp0 + tmp2; |
| z4 = tmp1 + tmp3; |
| z5 = MULTIPLY16(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ |
| |
| tmp0 = MULTIPLY16(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ |
| tmp1 = MULTIPLY16(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ |
| tmp2 = MULTIPLY16(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ |
| tmp3 = MULTIPLY16(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ |
| z1 = MULTIPLY16(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ |
| z2 = MULTIPLY16(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ |
| z3 = MULTIPLY16(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ |
| z4 = MULTIPLY16(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ |
| |
| z3 += z5; |
| z4 += z5; |
| |
| tmp0 += z1 + z3; |
| tmp1 += z2 + z4; |
| tmp2 += z2 + z3; |
| tmp3 += z1 + z4; |
| |
| /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ |
| |
| wsptr[8*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); |
| wsptr[8*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); |
| wsptr[8*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); |
| wsptr[8*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); |
| wsptr[8*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); |
| wsptr[8*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); |
| wsptr[8*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); |
| wsptr[8*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); |
| |
| inptr++; /* advance pointers to next column */ |
| quantptr++; |
| wsptr++; |
| } |
| |
| /* Pass 2: process rows from work array, store into output array. */ |
| /* Note that we must descale the results by a factor of 8 == 2**3, */ |
| /* and also undo the PASS1_BITS scaling. */ |
| |
| wsptr = workspace; |
| for (ctr = 0; ctr < 8; ctr++) |
| { |
| outptr = p_byte + (ctr*skip_line); |
| /* Rows of zeroes can be exploited in the same way as we did with columns. |
| * However, the column calculation has created many nonzero AC terms, so |
| * the simplification applies less often (typically 5% to 10% of the time). |
| * On machines with very fast multiplication, it's possible that the |
| * test takes more time than it's worth. In that case this section |
| * may be commented out. |
| */ |
| |
| #ifndef NO_ZERO_ROW_TEST |
| if ((wsptr[1] | wsptr[2] | wsptr[3] |
| | wsptr[4] | wsptr[5] | wsptr[6] | wsptr[7]) == 0) |
| { |
| /* AC terms all zero */ |
| unsigned char dcval = range_limit((int) DESCALE((long) wsptr[0], |
| PASS1_BITS+3)); |
| |
| outptr[0] = dcval; |
| outptr[1] = dcval; |
| outptr[2] = dcval; |
| outptr[3] = dcval; |
| outptr[4] = dcval; |
| outptr[5] = dcval; |
| outptr[6] = dcval; |
| outptr[7] = dcval; |
| |
| wsptr += 8; /* advance pointer to next row */ |
| continue; |
| } |
| #endif |
| |
| /* Even part: reverse the even part of the forward DCT. */ |
| /* The rotator is sqrt(2)*c(-6). */ |
| |
| z2 = (long) wsptr[2]; |
| z3 = (long) wsptr[6]; |
| |
| z1 = MULTIPLY16(z2 + z3, FIX_0_541196100); |
| tmp2 = z1 + MULTIPLY16(z3, - FIX_1_847759065); |
| tmp3 = z1 + MULTIPLY16(z2, FIX_0_765366865); |
| |
| tmp0 = ((long) wsptr[0] + (long) wsptr[4]) << CONST_BITS; |
| tmp1 = ((long) wsptr[0] - (long) wsptr[4]) << CONST_BITS; |
| |
| tmp10 = tmp0 + tmp3; |
| tmp13 = tmp0 - tmp3; |
| tmp11 = tmp1 + tmp2; |
| tmp12 = tmp1 - tmp2; |
| |
| /* Odd part per figure 8; the matrix is unitary and hence its |
| * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. */ |
| |
| tmp0 = (long) wsptr[7]; |
| tmp1 = (long) wsptr[5]; |
| tmp2 = (long) wsptr[3]; |
| tmp3 = (long) wsptr[1]; |
| |
| z1 = tmp0 + tmp3; |
| z2 = tmp1 + tmp2; |
| z3 = tmp0 + tmp2; |
| z4 = tmp1 + tmp3; |
| z5 = MULTIPLY16(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ |
| |
| tmp0 = MULTIPLY16(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ |
| tmp1 = MULTIPLY16(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ |
| tmp2 = MULTIPLY16(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ |
| tmp3 = MULTIPLY16(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ |
| z1 = MULTIPLY16(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ |
| z2 = MULTIPLY16(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ |
| z3 = MULTIPLY16(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ |
| z4 = MULTIPLY16(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ |
| |
| z3 += z5; |
| z4 += z5; |
| |
| tmp0 += z1 + z3; |
| tmp1 += z2 + z4; |
| tmp2 += z2 + z3; |
| tmp3 += z1 + z4; |
| |
| /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ |
| |
| outptr[0] = range_limit((int) DESCALE(tmp10 + tmp3, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[7] = range_limit((int) DESCALE(tmp10 - tmp3, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[1] = range_limit((int) DESCALE(tmp11 + tmp2, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[6] = range_limit((int) DESCALE(tmp11 - tmp2, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[2] = range_limit((int) DESCALE(tmp12 + tmp1, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[5] = range_limit((int) DESCALE(tmp12 - tmp1, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[3] = range_limit((int) DESCALE(tmp13 + tmp0, |
| CONST_BITS+PASS1_BITS+3)); |
| outptr[4] = range_limit((int) DESCALE(tmp13 - tmp0, |
| CONST_BITS+PASS1_BITS+3)); |
| |
| wsptr += 8; /* advance pointer to next row */ |
| } |
| } |
| |
| |
| |
| /* JPEG decoder implementation */ |
| |
| |
| #define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ |
| |
| struct derived_tbl |
| { |
| /* Basic tables: (element [0] of each array is unused) */ |
| long mincode[17]; /* smallest code of length k */ |
| long maxcode[18]; /* largest code of length k (-1 if none) */ |
| /* (maxcode[17] is a sentinel to ensure huff_DECODE terminates) */ |
| int valptr[17]; /* huffval[] index of 1st symbol of length k */ |
| |
| /* Back link to public Huffman table (needed only in slow_DECODE) */ |
| int* pub; |
| |
| /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of |
| the input data stream. If the next Huffman code is no more |
| than HUFF_LOOKAHEAD bits long, we can obtain its length and |
| the corresponding symbol directly from these tables. */ |
| int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */ |
| unsigned char look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */ |
| }; |
| |
| #define QUANT_TABLE_LENGTH 64 |
| |
| /* for type of Huffman table */ |
| #define DC_LEN 28 |
| #define AC_LEN 178 |
| |
| struct huffman_table |
| { /* length and code according to JFIF format */ |
| int huffmancodes_dc[DC_LEN]; |
| int huffmancodes_ac[AC_LEN]; |
| }; |
| |
| struct frame_component |
| { |
| int ID; |
| int horizontal_sampling; |
| int vertical_sampling; |
| int quanttable_select; |
| }; |
| |
| struct scan_component |
| { |
| int ID; |
| int DC_select; |
| int AC_select; |
| }; |
| |
| struct bitstream |
| { |
| unsigned long get_buffer; /* current bit-extraction buffer */ |
| int bits_left; /* # of unused bits in it */ |
| unsigned char* next_input_byte; |
| unsigned char* input_end; /* upper limit +1 */ |
| }; |
| |
| struct jpeg |
| { |
| int x_size, y_size; /* size of image (can be less than block boundary) */ |
| int x_phys, y_phys; /* physical size, block aligned */ |
| int x_mbl; /* x dimension of MBL */ |
| int y_mbl; /* y dimension of MBL */ |
| int blocks; /* blocks per MB */ |
| int restart_interval; /* number of MCUs between RSTm markers */ |
| int store_pos[4]; /* for Y block ordering */ |
| |
| unsigned char* p_entropy_data; |
| unsigned char* p_entropy_end; |
| |
| int quanttable[4][QUANT_TABLE_LENGTH]; /* raw quantization tables 0-3 */ |
| int qt_idct[2][QUANT_TABLE_LENGTH]; /* quantization tables for IDCT */ |
| |
| struct huffman_table hufftable[2]; /* Huffman tables */ |
| struct derived_tbl dc_derived_tbls[2]; /* Huffman-LUTs */ |
| struct derived_tbl ac_derived_tbls[2]; |
| |
| struct frame_component frameheader[3]; /* Component descriptor */ |
| struct scan_component scanheader[3]; /* currently not used */ |
| |
| int mcu_membership[6]; /* info per block */ |
| int tab_membership[6]; |
| int subsample_x[3]; /* info per component */ |
| int subsample_y[3]; |
| }; |
| |
| |
| /* possible return flags for process_markers() */ |
| #define HUFFTAB 0x0001 /* with huffman table */ |
| #define QUANTTAB 0x0002 /* with quantization table */ |
| #define APP0_JFIF 0x0004 /* with APP0 segment following JFIF standard */ |
| #define FILL_FF 0x0008 /* with 0xFF padding bytes at begin/end */ |
| #define SOF0 0x0010 /* with SOF0-Segment */ |
| #define DHT 0x0020 /* with Definition of huffman tables */ |
| #define SOS 0x0040 /* with Start-of-Scan segment */ |
| #define DQT 0x0080 /* with definition of quantization table */ |
| |
| /* Preprocess the JPEG JFIF file */ |
| int process_markers(unsigned char* p_src, long size, struct jpeg* p_jpeg) |
| { |
| unsigned char* p_bytes = p_src; |
| int marker_size; /* variable length of marker segment */ |
| int i, j, n; |
| int ret = 0; /* returned flags */ |
| |
| p_jpeg->p_entropy_end = p_src + size; |
| |
| while (p_src < p_bytes + size) |
| { |
| if (*p_src++ != 0xFF) /* no marker? */ |
| { |
| p_src--; /* it's image data, put it back */ |
| p_jpeg->p_entropy_data = p_src; |
| break; /* exit marker processing */ |
| } |
| |
| switch (*p_src++) |
| { |
| case 0xFF: /* Fill byte */ |
| ret |= FILL_FF; |
| case 0x00: /* Zero stuffed byte - entropy data */ |
| p_src--; /* put it back */ |
| continue; |
| |
| case 0xC0: /* SOF Huff - Baseline DCT */ |
| { |
| ret |= SOF0; |
| marker_size = *p_src++ << 8; /* Highbyte */ |
| marker_size |= *p_src++; /* Lowbyte */ |
| n = *p_src++; /* sample precision (= 8 or 12) */ |
| if (n != 8) |
| { |
| return(-1); /* Unsupported sample precision */ |
| } |
| p_jpeg->y_size = *p_src++ << 8; /* Highbyte */ |
| p_jpeg->y_size |= *p_src++; /* Lowbyte */ |
| p_jpeg->x_size = *p_src++ << 8; /* Highbyte */ |
| p_jpeg->x_size |= *p_src++; /* Lowbyte */ |
| |
| n = (marker_size-2-6)/3; |
| if (*p_src++ != n || (n != 1 && n != 3)) |
| { |
| return(-2); /* Unsupported SOF0 component specification */ |
| } |
| for (i=0; i<n; i++) |
| { |
| p_jpeg->frameheader[i].ID = *p_src++; /* Component info */ |
| p_jpeg->frameheader[i].horizontal_sampling = *p_src >> 4; |
| p_jpeg->frameheader[i].vertical_sampling = *p_src++ & 0x0F; |
| p_jpeg->frameheader[i].quanttable_select = *p_src++; |
| if (p_jpeg->frameheader[i].horizontal_sampling > 2 |
| || p_jpeg->frameheader[i].vertical_sampling > 2) |
| return -3; /* Unsupported SOF0 subsampling */ |
| } |
| p_jpeg->blocks = n; |
| } |
| break; |
| |
| case 0xC1: /* SOF Huff - Extended sequential DCT*/ |
| case 0xC2: /* SOF Huff - Progressive DCT*/ |
| case 0xC3: /* SOF Huff - Spatial (sequential) lossless*/ |
| case 0xC5: /* SOF Huff - Differential sequential DCT*/ |
| case 0xC6: /* SOF Huff - Differential progressive DCT*/ |
| case 0xC7: /* SOF Huff - Differential spatial*/ |
| case 0xC8: /* SOF Arith - Reserved for JPEG extensions*/ |
| case 0xC9: /* SOF Arith - Extended sequential DCT*/ |
| case 0xCA: /* SOF Arith - Progressive DCT*/ |
| case 0xCB: /* SOF Arith - Spatial (sequential) lossless*/ |
| case 0xCD: /* SOF Arith - Differential sequential DCT*/ |
| case 0xCE: /* SOF Arith - Differential progressive DCT*/ |
| case 0xCF: /* SOF Arith - Differential spatial*/ |
| { |
| return (-4); /* other DCT model than baseline not implemented */ |
| } |
| |
| case 0xC4: /* Define Huffman Table(s) */ |
| { |
| unsigned char* p_temp; |
| |
| ret |= DHT; |
| marker_size = *p_src++ << 8; /* Highbyte */ |
| marker_size |= *p_src++; /* Lowbyte */ |
| |
| p_temp = p_src; |
| while (p_src < p_temp+marker_size-2-17) /* another table */ |
| { |
| int sum = 0; |
| i = *p_src & 0x0F; /* table index */ |
| if (i > 1) |
| { |
| return (-5); /* Huffman table index out of range */ |
| } |
| else if (*p_src++ & 0xF0) /* AC table */ |
| { |
| for (j=0; j<16; j++) |
| { |
| sum += *p_src; |
| p_jpeg->hufftable[i].huffmancodes_ac[j] = *p_src++; |
| } |
| if(16 + sum > AC_LEN) |
| return -10; /* longer than allowed */ |
| |
| for (; j < 16 + sum; j++) |
| p_jpeg->hufftable[i].huffmancodes_ac[j] = *p_src++; |
| } |
| else /* DC table */ |
| { |
| for (j=0; j<16; j++) |
| { |
| sum += *p_src; |
| p_jpeg->hufftable[i].huffmancodes_dc[j] = *p_src++; |
| } |
| if(16 + sum > DC_LEN) |
| return -11; /* longer than allowed */ |
| |
| for (; j < 16 + sum; j++) |
| p_jpeg->hufftable[i].huffmancodes_dc[j] = *p_src++; |
| } |
| } /* while */ |
| p_src = p_temp+marker_size - 2; /* skip possible residue */ |
| } |
| break; |
| |
| case 0xCC: /* Define Arithmetic coding conditioning(s) */ |
| return(-6); /* Arithmetic coding not supported */ |
| |
| case 0xD8: /* Start of Image */ |
| case 0xD9: /* End of Image */ |
| case 0x01: /* for temp private use arith code */ |
| break; /* skip parameterless marker */ |
| |
| |
| case 0xDA: /* Start of Scan */ |
| { |
| ret |= SOS; |
| marker_size = *p_src++ << 8; /* Highbyte */ |
| marker_size |= *p_src++; /* Lowbyte */ |
| |
| n = (marker_size-2-1-3)/2; |
| if (*p_src++ != n || (n != 1 && n != 3)) |
| { |
| return (-7); /* Unsupported SOS component specification */ |
| } |
| for (i=0; i<n; i++) |
| { |
| p_jpeg->scanheader[i].ID = *p_src++; |
| p_jpeg->scanheader[i].DC_select = *p_src >> 4; |
| p_jpeg->scanheader[i].AC_select = *p_src++ & 0x0F; |
| } |
| p_src += 3; /* skip spectral information */ |
| } |
| break; |
| |
| case 0xDB: /* Define quantization Table(s) */ |
| { |
| ret |= DQT; |
| marker_size = *p_src++ << 8; /* Highbyte */ |
| marker_size |= *p_src++; /* Lowbyte */ |
| n = (marker_size-2)/(QUANT_TABLE_LENGTH+1); /* # of tables */ |
| for (i=0; i<n; i++) |
| { |
| int id = *p_src++; /* ID */ |
| if (id >= 4) |
| { |
| return (-8); /* Unsupported quantization table */ |
| } |
| /* Read Quantisation table: */ |
| for (j=0; j<QUANT_TABLE_LENGTH; j++) |
| p_jpeg->quanttable[id][j] = *p_src++; |
| } |
| } |
| break; |
| |
| case 0xDD: /* Define Restart Interval */ |
| { |
| marker_size = *p_src++ << 8; /* Highbyte */ |
| marker_size |= *p_src++; /* Lowbyte */ |
| p_jpeg->restart_interval = *p_src++ << 8; /* Highbyte */ |
| p_jpeg->restart_interval |= *p_src++; /* Lowbyte */ |
| p_src += marker_size-4; /* skip segment */ |
| } |
| break; |
| |
| case 0xDC: /* Define Number of Lines */ |
| case 0xDE: /* Define Hierarchical progression */ |
| case 0xDF: /* Expand Reference Component(s) */ |
| case 0xE0: /* Application Field 0*/ |
| case 0xE1: /* Application Field 1*/ |
| case 0xE2: /* Application Field 2*/ |
| case 0xE3: /* Application Field 3*/ |
| case 0xE4: /* Application Field 4*/ |
| case 0xE5: /* Application Field 5*/ |
| case 0xE6: /* Application Field 6*/ |
| case 0xE7: /* Application Field 7*/ |
| case 0xE8: /* Application Field 8*/ |
| case 0xE9: /* Application Field 9*/ |
| case 0xEA: /* Application Field 10*/ |
| case 0xEB: /* Application Field 11*/ |
| case 0xEC: /* Application Field 12*/ |
| case 0xED: /* Application Field 13*/ |
| case 0xEE: /* Application Field 14*/ |
| case 0xEF: /* Application Field 15*/ |
| case 0xFE: /* Comment */ |
| { |
| marker_size = *p_src++ << 8; /* Highbyte */ |
| marker_size |= *p_src++; /* Lowbyte */ |
| p_src += marker_size-2; /* skip segment */ |
| } |
| break; |
| |
| case 0xF0: /* Reserved for JPEG extensions */ |
| case 0xF1: /* Reserved for JPEG extensions */ |
| case 0xF2: /* Reserved for JPEG extensions */ |
| case 0xF3: /* Reserved for JPEG extensions */ |
| case 0xF4: /* Reserved for JPEG extensions */ |
| case 0xF5: /* Reserved for JPEG extensions */ |
| case 0xF6: /* Reserved for JPEG extensions */ |
| case 0xF7: /* Reserved for JPEG extensions */ |
| case 0xF8: /* Reserved for JPEG extensions */ |
| case 0xF9: /* Reserved for JPEG extensions */ |
| case 0xFA: /* Reserved for JPEG extensions */ |
| case 0xFB: /* Reserved for JPEG extensions */ |
| case 0xFC: /* Reserved for JPEG extensions */ |
| case 0xFD: /* Reserved for JPEG extensions */ |
| case 0x02: /* Reserved */ |
| default: |
| return (-9); /* Unknown marker */ |
| } /* switch */ |
| } /* while */ |
| |
| return (ret); /* return flags with seen markers */ |
| } |
| |
| |
| void default_huff_tbl(struct jpeg* p_jpeg) |
| { |
| static const struct huffman_table luma_table = |
| { |
| { |
| 0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B |
| }, |
| { |
| 0x00,0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7D, |
| 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07, |
| 0x22,0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0, |
| 0x24,0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28, |
| 0x29,0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49, |
| 0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69, |
| 0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89, |
| 0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7, |
| 0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5, |
| 0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2, |
| 0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8, |
| 0xF9,0xFA |
| } |
| }; |
| |
| static const struct huffman_table chroma_table = |
| { |
| { |
| 0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B |
| }, |
| { |
| 0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,0x02,0x77, |
| 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71, |
| 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,0x52,0xF0, |
| 0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,0x1A,0x26, |
| 0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48, |
| 0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68, |
| 0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,0x86,0x87, |
| 0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5, |
| 0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3, |
| 0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA, |
| 0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8, |
| 0xF9,0xFA |
| } |
| }; |
| |
| MEMCPY(&p_jpeg->hufftable[0], &luma_table, sizeof(luma_table)); |
| MEMCPY(&p_jpeg->hufftable[1], &chroma_table, sizeof(chroma_table)); |
| |
| return; |
| } |
| |
| /* Compute the derived values for a Huffman table */ |
| void fix_huff_tbl(int* htbl, struct derived_tbl* dtbl) |
| { |
| int p, i, l, si; |
| int lookbits, ctr; |
| char huffsize[257]; |
| unsigned int huffcode[257]; |
| unsigned int code; |
| |
| dtbl->pub = htbl; /* fill in back link */ |
| |
| /* Figure C.1: make table of Huffman code length for each symbol */ |
| /* Note that this is in code-length order. */ |
| |
| p = 0; |
| for (l = 1; l <= 16; l++) |
| { /* all possible code length */ |
| for (i = 1; i <= (int) htbl[l-1]; i++) /* all codes per length */ |
| huffsize[p++] = (char) l; |
| } |
| huffsize[p] = 0; |
| |
| /* Figure C.2: generate the codes themselves */ |
| /* Note that this is in code-length order. */ |
| |
| code = 0; |
| si = huffsize[0]; |
| p = 0; |
| while (huffsize[p]) |
| { |
| while (((int) huffsize[p]) == si) |
| { |
| huffcode[p++] = code; |
| code++; |
| } |
| code <<= 1; |
| si++; |
| } |
| |
| /* Figure F.15: generate decoding tables for bit-sequential decoding */ |
| |
| p = 0; |
| for (l = 1; l <= 16; l++) |
| { |
| if (htbl[l-1]) |
| { |
| dtbl->valptr[l] = p; /* huffval[] index of 1st symbol of code length l */ |
| dtbl->mincode[l] = huffcode[p]; /* minimum code of length l */ |
| p += htbl[l-1]; |
| dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ |
| } |
| else |
| { |
| dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ |
| } |
| } |
| dtbl->maxcode[17] = 0xFFFFFL; /* ensures huff_DECODE terminates */ |
| |
| /* Compute lookahead tables to speed up decoding. |
| * First we set all the table entries to 0, indicating "too long"; |
| * then we iterate through the Huffman codes that are short enough and |
| * fill in all the entries that correspond to bit sequences starting |
| * with that code. |
| */ |
| |
| MEMSET(dtbl->look_nbits, 0, sizeof(dtbl->look_nbits)); |
| |
| p = 0; |
| for (l = 1; l <= HUFF_LOOKAHEAD; l++) |
| { |
| for (i = 1; i <= (int) htbl[l-1]; i++, p++) |
| { |
| /* l = current code's length, p = its index in huffcode[] & huffval[]. */ |
| /* Generate left-justified code followed by all possible bit sequences */ |
| lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); |
| for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) |
| { |
| dtbl->look_nbits[lookbits] = l; |
| dtbl->look_sym[lookbits] = htbl[16+p]; |
| lookbits++; |
| } |
| } |
| } |
| } |
| |
| |
| /* zag[i] is the natural-order position of the i'th element of zigzag order. |
| * If the incoming data is corrupted, decode_mcu could attempt to |
| * reference values beyond the end of the array. To avoid a wild store, |
| * we put some extra zeroes after the real entries. |
| */ |
| static const int zag[] = |
| { |
| 0, 1, 8, 16, 9, 2, 3, 10, |
| 17, 24, 32, 25, 18, 11, 4, 5, |
| 12, 19, 26, 33, 40, 48, 41, 34, |
| 27, 20, 13, 6, 7, 14, 21, 28, |
| 35, 42, 49, 56, 57, 50, 43, 36, |
| 29, 22, 15, 23, 30, 37, 44, 51, |
| 58, 59, 52, 45, 38, 31, 39, 46, |
| 53, 60, 61, 54, 47, 55, 62, 63, |
| 0, 0, 0, 0, 0, 0, 0, 0, /* extra entries in case k>63 below */ |
| 0, 0, 0, 0, 0, 0, 0, 0 |
| }; |
| |
| void build_lut(struct jpeg* p_jpeg) |
| { |
| int i; |
| fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_dc, |
| &p_jpeg->dc_derived_tbls[0]); |
| fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_ac, |
| &p_jpeg->ac_derived_tbls[0]); |
| fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_dc, |
| &p_jpeg->dc_derived_tbls[1]); |
| fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_ac, |
| &p_jpeg->ac_derived_tbls[1]); |
| |
| /* build the dequantization tables for the IDCT (De-ZiZagged) */ |
| for (i=0; i<64; i++) |
| { |
| p_jpeg->qt_idct[0][zag[i]] = p_jpeg->quanttable[0][i]; |
| p_jpeg->qt_idct[1][zag[i]] = p_jpeg->quanttable[1][i]; |
| } |
| |
| for (i=0; i<4; i++) |
| p_jpeg->store_pos[i] = i; /* default ordering */ |
| |
| /* assignments for the decoding of blocks */ |
| if (p_jpeg->frameheader[0].horizontal_sampling == 2 |
| && p_jpeg->frameheader[0].vertical_sampling == 1) |
| { /* 4:2:2 */ |
| p_jpeg->blocks = 4; |
| p_jpeg->x_mbl = (p_jpeg->x_size+15) / 16; |
| p_jpeg->x_phys = p_jpeg->x_mbl * 16; |
| p_jpeg->y_mbl = (p_jpeg->y_size+7) / 8; |
| p_jpeg->y_phys = p_jpeg->y_mbl * 8; |
| p_jpeg->mcu_membership[0] = 0; /* Y1=Y2=0, U=1, V=2 */ |
| p_jpeg->mcu_membership[1] = 0; |
| p_jpeg->mcu_membership[2] = 1; |
| p_jpeg->mcu_membership[3] = 2; |
| p_jpeg->tab_membership[0] = 0; /* DC, DC, AC, AC */ |
| p_jpeg->tab_membership[1] = 0; |
| p_jpeg->tab_membership[2] = 1; |
| p_jpeg->tab_membership[3] = 1; |
| p_jpeg->subsample_x[0] = 1; |
| p_jpeg->subsample_x[1] = 2; |
| p_jpeg->subsample_x[2] = 2; |
| p_jpeg->subsample_y[0] = 1; |
| p_jpeg->subsample_y[1] = 1; |
| p_jpeg->subsample_y[2] = 1; |
| } |
| if (p_jpeg->frameheader[0].horizontal_sampling == 1 |
| && p_jpeg->frameheader[0].vertical_sampling == 2) |
| { /* 4:2:2 vertically subsampled */ |
| p_jpeg->store_pos[1] = 2; /* block positions are mirrored */ |
| p_jpeg->store_pos[2] = 1; |
| p_jpeg->blocks = 4; |
| p_jpeg->x_mbl = (p_jpeg->x_size+7) / 8; |
| p_jpeg->x_phys = p_jpeg->x_mbl * 8; |
| p_jpeg->y_mbl = (p_jpeg->y_size+15) / 16; |
| p_jpeg->y_phys = p_jpeg->y_mbl * 16; |
| p_jpeg->mcu_membership[0] = 0; /* Y1=Y2=0, U=1, V=2 */ |
| p_jpeg->mcu_membership[1] = 0; |
| p_jpeg->mcu_membership[2] = 1; |
| p_jpeg->mcu_membership[3] = 2; |
| p_jpeg->tab_membership[0] = 0; /* DC, DC, AC, AC */ |
| p_jpeg->tab_membership[1] = 0; |
| p_jpeg->tab_membership[2] = 1; |
| p_jpeg->tab_membership[3] = 1; |
| p_jpeg->subsample_x[0] = 1; |
| p_jpeg->subsample_x[1] = 1; |
| p_jpeg->subsample_x[2] = 1; |
| p_jpeg->subsample_y[0] = 1; |
| p_jpeg->subsample_y[1] = 2; |
| p_jpeg->subsample_y[2] = 2; |
| } |
| else if (p_jpeg->frameheader[0].horizontal_sampling == 2 |
| && p_jpeg->frameheader[0].vertical_sampling == 2) |
| { /* 4:2:0 */ |
| p_jpeg->blocks = 6; |
| p_jpeg->x_mbl = (p_jpeg->x_size+15) / 16; |
| p_jpeg->x_phys = p_jpeg->x_mbl * 16; |
| p_jpeg->y_mbl = (p_jpeg->y_size+15) / 16; |
| p_jpeg->y_phys = p_jpeg->y_mbl * 16; |
| p_jpeg->mcu_membership[0] = 0; |
| p_jpeg->mcu_membership[1] = 0; |
| p_jpeg->mcu_membership[2] = 0; |
| p_jpeg->mcu_membership[3] = 0; |
| p_jpeg->mcu_membership[4] = 1; |
| p_jpeg->mcu_membership[5] = 2; |
| p_jpeg->tab_membership[0] = 0; |
| p_jpeg->tab_membership[1] = 0; |
| p_jpeg->tab_membership[2] = 0; |
| p_jpeg->tab_membership[3] = 0; |
| p_jpeg->tab_membership[4] = 1; |
| p_jpeg->tab_membership[5] = 1; |
| p_jpeg->subsample_x[0] = 1; |
| p_jpeg->subsample_x[1] = 2; |
| p_jpeg->subsample_x[2] = 2; |
| p_jpeg->subsample_y[0] = 1; |
| p_jpeg->subsample_y[1] = 2; |
| p_jpeg->subsample_y[2] = 2; |
| } |
| else if (p_jpeg->frameheader[0].horizontal_sampling == 1 |
| && p_jpeg->frameheader[0].vertical_sampling == 1) |
| { /* 4:4:4 */ |
| /* don't overwrite p_jpeg->blocks */ |
| p_jpeg->x_mbl = (p_jpeg->x_size+7) / 8; |
| p_jpeg->x_phys = p_jpeg->x_mbl * 8; |
| p_jpeg->y_mbl = (p_jpeg->y_size+7) / 8; |
| p_jpeg->y_phys = p_jpeg->y_mbl * 8; |
| p_jpeg->mcu_membership[0] = 0; |
| p_jpeg->mcu_membership[1] = 1; |
| p_jpeg->mcu_membership[2] = 2; |
| p_jpeg->tab_membership[0] = 0; |
| p_jpeg->tab_membership[1] = 1; |
| p_jpeg->tab_membership[2] = 1; |
| p_jpeg->subsample_x[0] = 1; |
| p_jpeg->subsample_x[1] = 1; |
| p_jpeg->subsample_x[2] = 1; |
| p_jpeg->subsample_y[0] = 1; |
| p_jpeg->subsample_y[1] = 1; |
| p_jpeg->subsample_y[2] = 1; |
| } |
| else |
| { |
| /* error */ |
| } |
| |
| } |
| |
| |
| /* |
| * These functions/macros provide the in-line portion of bit fetching. |
| * Use check_bit_buffer to ensure there are N bits in get_buffer |
| * before using get_bits, peek_bits, or drop_bits. |
| * check_bit_buffer(state,n,action); |
| * Ensure there are N bits in get_buffer; if suspend, take action. |
| * val = get_bits(n); |
| * Fetch next N bits. |
| * val = peek_bits(n); |
| * Fetch next N bits without removing them from the buffer. |
| * drop_bits(n); |
| * Discard next N bits. |
| * The value N should be a simple variable, not an expression, because it |
| * is evaluated multiple times. |
| */ |
| |
| INLINE void check_bit_buffer(struct bitstream* pb, int nbits) |
| { |
| if (pb->bits_left < nbits) |
| { /* nbits is <= 16, so I can always refill 2 bytes in this case */ |
| unsigned char byte; |
| |
| byte = *pb->next_input_byte++; |
| if (byte == 0xFF) /* legal marker can be byte stuffing or RSTm */ |
| { /* simplification: just skip the (one-byte) marker code */ |
| pb->next_input_byte++; |
| } |
| pb->get_buffer = (pb->get_buffer << 8) | byte; |
| |
| byte = *pb->next_input_byte++; |
| if (byte == 0xFF) /* legal marker can be byte stuffing or RSTm */ |
| { /* simplification: just skip the (one-byte) marker code */ |
| pb->next_input_byte++; |
| } |
| pb->get_buffer = (pb->get_buffer << 8) | byte; |
| |
| pb->bits_left += 16; |
| } |
| } |
| |
| INLINE int get_bits(struct bitstream* pb, int nbits) |
| { |
| return ((int) (pb->get_buffer >> (pb->bits_left -= nbits))) & ((1<<nbits)-1); |
| } |
| |
| INLINE int peek_bits(struct bitstream* pb, int nbits) |
| { |
| return ((int) (pb->get_buffer >> (pb->bits_left - nbits))) & ((1<<nbits)-1); |
| } |
| |
| INLINE void drop_bits(struct bitstream* pb, int nbits) |
| { |
| pb->bits_left -= nbits; |
| } |
| |
| /* re-synchronize to entropy data (skip restart marker) */ |
| void search_restart(struct bitstream* pb) |
| { |
| pb->next_input_byte--; /* we may have overread it, taking 2 bytes */ |
| /* search for a non-byte-padding marker, has to be RSTm or EOS */ |
| while (pb->next_input_byte < pb->input_end && |
| (pb->next_input_byte[-2] != 0xFF || pb->next_input_byte[-1] == 0x00)) |
| { |
| pb->next_input_byte++; |
| } |
| pb->bits_left = 0; |
| } |
| |
| /* Figure F.12: extend sign bit. */ |
| #define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) |
| |
| static const int extend_test[16] = /* entry n is 2**(n-1) */ |
| { |
| 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, |
| 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 |
| }; |
| |
| static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ |
| { |
| 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, |
| ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, |
| ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, |
| ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 |
| }; |
| |
| /* Decode a single value */ |
| INLINE int huff_decode_dc(struct bitstream* bs, struct derived_tbl* tbl) |
| { |
| int nb, look, s, r; |
| |
| check_bit_buffer(bs, HUFF_LOOKAHEAD); |
| look = peek_bits(bs, HUFF_LOOKAHEAD); |
| if ((nb = tbl->look_nbits[look]) != 0) |
| { |
| drop_bits(bs, nb); |
| s = tbl->look_sym[look]; |
| check_bit_buffer(bs, s); |
| r = get_bits(bs, s); |
| s = HUFF_EXTEND(r, s); |
| } |
| else |
| { /* slow_DECODE(s, HUFF_LOOKAHEAD+1)) < 0); */ |
| long code; |
| nb=HUFF_LOOKAHEAD+1; |
| check_bit_buffer(bs, nb); |
| code = get_bits(bs, nb); |
| while (code > tbl->maxcode[nb]) |
| { |
| code <<= 1; |
| check_bit_buffer(bs, 1); |
| code |= get_bits(bs, 1); |
| nb++; |
| } |
| if (nb > 16) /* error in Huffman */ |
| { |
| s=0; /* fake a zero, this is most safe */ |
| } |
| else |
| { |
| s = tbl->pub[16 + tbl->valptr[nb] + ((int) (code - tbl->mincode[nb])) ]; |
| check_bit_buffer(bs, s); |
| r = get_bits(bs, s); |
| s = HUFF_EXTEND(r, s); |
| } |
| } /* end slow decode */ |
| return s; |
| } |
| |
| INLINE int huff_decode_ac(struct bitstream* bs, struct derived_tbl* tbl) |
| { |
| int nb, look, s; |
| |
| check_bit_buffer(bs, HUFF_LOOKAHEAD); |
| look = peek_bits(bs, HUFF_LOOKAHEAD); |
| if ((nb = tbl->look_nbits[look]) != 0) |
| { |
| drop_bits(bs, nb); |
| s = tbl->look_sym[look]; |
| } |
| else |
| { /* slow_DECODE(s, HUFF_LOOKAHEAD+1)) < 0); */ |
| long code; |
| nb=HUFF_LOOKAHEAD+1; |
| check_bit_buffer(bs, nb); |
| code = get_bits(bs, nb); |
| while (code > tbl->maxcode[nb]) |
| { |
| code <<= 1; |
| check_bit_buffer(bs, 1); |
| code |= get_bits(bs, 1); |
| nb++; |
| } |
| if (nb > 16) /* error in Huffman */ |
| { |
| s=0; /* fake a zero, this is most safe */ |
| } |
| else |
| { |
| s = tbl->pub[16 + tbl->valptr[nb] + ((int) (code - tbl->mincode[nb])) ]; |
| } |
| } /* end slow decode */ |
| return s; |
| } |
| |
| |
| #ifdef HAVE_LCD_COLOR |
| |
| /* JPEG decoder variant for YUV decoding, into 3 different planes */ |
| /* Note: it keeps the original color subsampling, even if resized. */ |
| int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel[3], |
| int downscale, void (*pf_progress)(int current, int total)) |
| { |
| struct bitstream bs; /* bitstream "object" */ |
| int block[64]; /* decoded DCT coefficients */ |
| |
| int width, height; |
| int skip_line[3]; /* bytes from one line to the next (skip_line) */ |
| int skip_strip[3], skip_mcu[3]; /* bytes to next DCT row / column */ |
| |
| int i, x, y; /* loop counter */ |
| |
| unsigned char* p_line[3] = {p_pixel[0], p_pixel[1], p_pixel[2]}; |
| unsigned char* p_byte[3]; /* bitmap pointer */ |
| |
| void (*pf_idct)(unsigned char*, int*, int*, int); /* selected IDCT */ |
| int k_need; /* AC coefficients needed up to here */ |
| int zero_need; /* init the block with this many zeros */ |
| |
| int last_dc_val[3] = {0, 0, 0}; /* or 128 for chroma? */ |
| int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */ |
| int restart = p_jpeg->restart_interval; /* MCUs until restart marker */ |
| |
| /* pick the IDCT we want, determine how to work with coefs */ |
| if (downscale == 1) |
| { |
| pf_idct = idct8x8; |
| k_need = 64; /* all */ |
| zero_need = 63; /* all */ |
| } |
| else if (downscale == 2) |
| { |
| pf_idct = idct4x4; |
| k_need = 25; /* this far in zig-zag to cover 4*4 */ |
| zero_need = 27; /* clear this far in linear order */ |
| } |
| else if (downscale == 4) |
| { |
| pf_idct = idct2x2; |
| k_need = 5; /* this far in zig-zag to cover 2*2 */ |
| zero_need = 9; /* clear this far in linear order */ |
| } |
| else if (downscale == 8) |
| { |
| pf_idct = idct1x1; |
| k_need = 0; /* no AC, not needed */ |
| zero_need = 0; /* no AC, not needed */ |
| } |
| else return -1; /* not supported */ |
| |
| /* init bitstream, fake a restart to make it start */ |
| bs.next_input_byte = p_jpeg->p_entropy_data; |
| bs.bits_left = 0; |
| bs.input_end = p_jpeg->p_entropy_end; |
| |
| width = p_jpeg->x_phys / downscale; |
| height = p_jpeg->y_phys / downscale; |
| for (i=0; i<3; i++) /* calculate some strides */ |
| { |
| skip_line[i] = width / p_jpeg->subsample_x[i]; |
| skip_strip[i] = skip_line[i] |
| * (height / p_jpeg->y_mbl) / p_jpeg->subsample_y[i]; |
| skip_mcu[i] = width/p_jpeg->x_mbl / p_jpeg->subsample_x[i]; |
| } |
| |
| /* prepare offsets about where to store the different blocks */ |
| store_offs[p_jpeg->store_pos[0]] = 0; |
| store_offs[p_jpeg->store_pos[1]] = 8 / downscale; /* to the right */ |
| store_offs[p_jpeg->store_pos[2]] = width * 8 / downscale; /* below */ |
| store_offs[p_jpeg->store_pos[3]] = store_offs[1] + store_offs[2]; /* r+b */ |
| |
| for(y=0; y<p_jpeg->y_mbl && bs.next_input_byte <= bs.input_end; y++) |
| { |
| for (i=0; i<3; i++) /* scan line init */ |
| { |
| p_byte[i] = p_line[i]; |
| p_line[i] += skip_strip[i]; |
| } |
| for (x=0; x<p_jpeg->x_mbl; x++) |
| { |
| int blkn; |
| |
| /* Outer loop handles each block in the MCU */ |
| for (blkn = 0; blkn < p_jpeg->blocks; blkn++) |
| { /* Decode a single block's worth of coefficients */ |
| int k = 1; /* coefficient index */ |
| int s, r; /* huffman values */ |
| int ci = p_jpeg->mcu_membership[blkn]; /* component index */ |
| int ti = p_jpeg->tab_membership[blkn]; /* table index */ |
| struct derived_tbl* dctbl = &p_jpeg->dc_derived_tbls[ti]; |
| struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti]; |
| |
| /* Section F.2.2.1: decode the DC coefficient difference */ |
| s = huff_decode_dc(&bs, dctbl); |
| |
| last_dc_val[ci] += s; |
| block[0] = last_dc_val[ci]; /* output it (assumes zag[0] = 0) */ |
| |
| /* coefficient buffer must be cleared */ |
| MEMSET(block+1, 0, zero_need*sizeof(block[0])); |
| |
| /* Section F.2.2.2: decode the AC coefficients */ |
| for (; k < k_need; k++) |
| { |
| s = huff_decode_ac(&bs, actbl); |
| r = s >> 4; |
| s &= 15; |
| |
| if (s) |
| { |
| k += r; |
| check_bit_buffer(&bs, s); |
| r = get_bits(&bs, s); |
| block[zag[k]] = HUFF_EXTEND(r, s); |
| } |
| else |
| { |
| if (r != 15) |
| { |
| k = 64; |
| break; |
| } |
| k += r; |
| } |
| } /* for k */ |
| /* In this path we just discard the values */ |
| for (; k < 64; k++) |
| { |
| s = huff_decode_ac(&bs, actbl); |
| r = s >> 4; |
| s &= 15; |
| |
| if (s) |
| { |
| k += r; |
| check_bit_buffer(&bs, s); |
| drop_bits(&bs, s); |
| } |
| else |
| { |
| if (r != 15) |
| break; |
| k += r; |
| } |
| } /* for k */ |
| |
| if (ci == 0) |
| { /* Y component needs to bother about block store */ |
| pf_idct(p_byte[0]+store_offs[blkn], block, |
| p_jpeg->qt_idct[ti], skip_line[0]); |
| } |
| else |
| { /* chroma */ |
| pf_idct(p_byte[ci], block, p_jpeg->qt_idct[ti], |
| skip_line[ci]); |
| } |
| } /* for blkn */ |
| p_byte[0] += skip_mcu[0]; /* unrolled for (i=0; i<3; i++) loop */ |
| p_byte[1] += skip_mcu[1]; |
| p_byte[2] += skip_mcu[2]; |
| if (p_jpeg->restart_interval && --restart == 0) |
| { /* if a restart marker is due: */ |
| restart = p_jpeg->restart_interval; /* count again */ |
| search_restart(&bs); /* align the bitstream */ |
| last_dc_val[0] = last_dc_val[1] = |
| last_dc_val[2] = 0; /* reset decoder */ |
| } |
| } /* for x */ |
| if (pf_progress != NULL) |
| pf_progress(y, p_jpeg->y_mbl-1); /* notify about decoding progress */ |
| } /* for y */ |
| |
| return 0; /* success */ |
| } |
| #else /* !HAVE_LCD_COLOR */ |
| |
| /* a JPEG decoder specialized in decoding only the luminance (b&w) */ |
| int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel[1], int downscale, |
| void (*pf_progress)(int current, int total)) |
| { |
| struct bitstream bs; /* bitstream "object" */ |
| int block[64]; /* decoded DCT coefficients */ |
| |
| int width, height; |
| int skip_line; /* bytes from one line to the next (skip_line) */ |
| int skip_strip, skip_mcu; /* bytes to next DCT row / column */ |
| |
| int x, y; /* loop counter */ |
| |
| unsigned char* p_line = p_pixel[0]; |
| unsigned char* p_byte; /* bitmap pointer */ |
| |
| void (*pf_idct)(unsigned char*, int*, int*, int); /* selected IDCT */ |
| int k_need; /* AC coefficients needed up to here */ |
| int zero_need; /* init the block with this many zeros */ |
| |
| int last_dc_val = 0; |
| int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */ |
| int restart = p_jpeg->restart_interval; /* MCUs until restart marker */ |
| |
| /* pick the IDCT we want, determine how to work with coefs */ |
| if (downscale == 1) |
| { |
| pf_idct = idct8x8; |
| k_need = 64; /* all */ |
| zero_need = 63; /* all */ |
| } |
| else if (downscale == 2) |
| { |
| pf_idct = idct4x4; |
| k_need = 25; /* this far in zig-zag to cover 4*4 */ |
| zero_need = 27; /* clear this far in linear order */ |
| } |
| else if (downscale == 4) |
| { |
| pf_idct = idct2x2; |
| k_need = 5; /* this far in zig-zag to cover 2*2 */ |
| zero_need = 9; /* clear this far in linear order */ |
| } |
| else if (downscale == 8) |
| { |
| pf_idct = idct1x1; |
| k_need = 0; /* no AC, not needed */ |
| zero_need = 0; /* no AC, not needed */ |
| } |
| else return -1; /* not supported */ |
| |
| /* init bitstream, fake a restart to make it start */ |
| bs.next_input_byte = p_jpeg->p_entropy_data; |
| bs.bits_left = 0; |
| bs.input_end = p_jpeg->p_entropy_end; |
| |
| width = p_jpeg->x_phys / downscale; |
| height = p_jpeg->y_phys / downscale; |
| skip_line = width; |
| skip_strip = skip_line * (height / p_jpeg->y_mbl); |
| skip_mcu = (width/p_jpeg->x_mbl); |
| |
| /* prepare offsets about where to store the different blocks */ |
| store_offs[p_jpeg->store_pos[0]] = 0; |
| store_offs[p_jpeg->store_pos[1]] = 8 / downscale; /* to the right */ |
| store_offs[p_jpeg->store_pos[2]] = width * 8 / downscale; /* below */ |
| store_offs[p_jpeg->store_pos[3]] = store_offs[1] + store_offs[2]; /* r+b */ |
| |
| for(y=0; y<p_jpeg->y_mbl && bs.next_input_byte <= bs.input_end; y++) |
| { |
| p_byte = p_line; |
| p_line += skip_strip; |
| for (x=0; x<p_jpeg->x_mbl; x++) |
| { |
| int blkn; |
| |
| /* Outer loop handles each block in the MCU */ |
| for (blkn = 0; blkn < p_jpeg->blocks; blkn++) |
| { /* Decode a single block's worth of coefficients */ |
| int k = 1; /* coefficient index */ |
| int s, r; /* huffman values */ |
| int ci = p_jpeg->mcu_membership[blkn]; /* component index */ |
| int ti = p_jpeg->tab_membership[blkn]; /* table index */ |
| struct derived_tbl* dctbl = &p_jpeg->dc_derived_tbls[ti]; |
| struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti]; |
| |
| /* Section F.2.2.1: decode the DC coefficient difference */ |
| s = huff_decode_dc(&bs, dctbl); |
| |
| if (ci == 0) /* only for Y component */ |
| { |
| last_dc_val += s; |
| block[0] = last_dc_val; /* output it (assumes zag[0] = 0) */ |
| |
| /* coefficient buffer must be cleared */ |
| MEMSET(block+1, 0, zero_need*sizeof(block[0])); |
| |
| /* Section F.2.2.2: decode the AC coefficients */ |
| for (; k < k_need; k++) |
| { |
| s = huff_decode_ac(&bs, actbl); |
| r = s >> 4; |
| s &= 15; |
| |
| if (s) |
| { |
| k += r; |
| check_bit_buffer(&bs, s); |
| r = get_bits(&bs, s); |
| block[zag[k]] = HUFF_EXTEND(r, s); |
| } |
| else |
| { |
| if (r != 15) |
| { |
| k = 64; |
| break; |
| } |
| k += r; |
| } |
| } /* for k */ |
| } |
| /* In this path we just discard the values */ |
| for (; k < 64; k++) |
| { |
| s = huff_decode_ac(&bs, actbl); |
| r = s >> 4; |
| s &= 15; |
| |
| if (s) |
| { |
| k += r; |
| check_bit_buffer(&bs, s); |
| drop_bits(&bs, s); |
| } |
| else |
| { |
| if (r != 15) |
| break; |
| k += r; |
| } |
| } /* for k */ |
| |
| if (ci == 0) |
| { /* only for Y component */ |
| pf_idct(p_byte+store_offs[blkn], block, p_jpeg->qt_idct[ti], |
| skip_line); |
| } |
| } /* for blkn */ |
| p_byte += skip_mcu; |
| if (p_jpeg->restart_interval && --restart == 0) |
| { /* if a restart marker is due: */ |
| restart = p_jpeg->restart_interval; /* count again */ |
| search_restart(&bs); /* align the bitstream */ |
| last_dc_val = 0; /* reset decoder */ |
| } |
| } /* for x */ |
| if (pf_progress != NULL) |
| pf_progress(y, p_jpeg->y_mbl-1); /* notify about decoding progress */ |
| } /* for y */ |
| |
| return 0; /* success */ |
| } |
| #endif /* !HAVE_LCD_COLOR */ |
| |
| /**************** end JPEG code ********************/ |
| |
| |
| |
| /**************** begin Application ********************/ |
| |
| |
| /************************* Types ***************************/ |
| |
| struct t_disp |
| { |
| #ifdef HAVE_LCD_COLOR |
| unsigned char* bitmap[3]; /* Y, Cr, Cb */ |
| int csub_x, csub_y; |
| #else |
| unsigned char* bitmap[1]; /* Y only */ |
| #endif |
| int width; |
| int height; |
| int stride; |
| int x, y; |
| }; |
| |
| /************************* Globals ***************************/ |
| |
| /* decompressed image in the possible sizes (1,2,4,8), wasting the other */ |
| struct t_disp disp[9]; |
| |
| /* my memory pool (from the mp3 buffer) */ |
| char print[32]; /* use a common snprintf() buffer */ |
| unsigned char* buf; /* up to here currently used by image(s) */ |
| |
| /* the remaining free part of the buffer for compressed+uncompressed images */ |
| unsigned char* buf_images; |
| |
| ssize_t buf_size, buf_images_size; |
| /* the root of the images, hereafter are decompresed ones */ |
| unsigned char* buf_root; |
| int root_size; |
| |
| int ds, ds_min, ds_max; /* downscaling and limits */ |
| static struct jpeg jpg; /* too large for stack */ |
| |
| static struct tree_context *tree; |
| |
| /* the current full file name */ |
| static char np_file[MAX_PATH]; |
| int curfile = 0, direction = DIR_NONE, entries = 0; |
| |
| /* list of the jpeg files */ |
| char **file_pt; |
| /* are we using the plugin buffer or the audio buffer? */ |
| bool plug_buf = false; |
| |
| |
| /************************* Implementation ***************************/ |
| |
| #ifdef HAVE_LCD_COLOR |
| /* |
| * Conversion of full 0-255 range YCrCb to RGB: |
| * |R| |1.000000 -0.000001 1.402000| |Y'| |
| * |G| = |1.000000 -0.334136 -0.714136| |Pb| |
| * |B| |1.000000 1.772000 0.000000| |Pr| |
| * Scaled (yields s15-bit output): |
| * |R| |128 0 179| |Y | |
| * |G| = |128 -43 -91| |Cb - 128| |
| * |B| |128 227 0| |Cr - 128| |
| */ |
| #define YFAC 128 |
| #define RVFAC 179 |
| #define GUFAC (-43) |
| #define GVFAC (-91) |
| #define BUFAC 227 |
| #define YUV_WHITE (255*YFAC) |
| #define NODITHER_DELTA (127*YFAC) |
| #define COMPONENT_SHIFT 15 |
| #define MATRIX_SHIFT 7 |
| |
| static inline int clamp_component(int x) |
| { |
| if ((unsigned)x > YUV_WHITE) |
| x = x < 0 ? 0 : YUV_WHITE; |
| return x; |
| } |
| |
| static inline int clamp_component_bits(int x, int bits) |
| { |
| if ((unsigned)x > (1u << bits) - 1) |
| x = x < 0 ? 0 : (1 << bits) - 1; |
| return x; |
| } |
| |
| static inline int component_to_lcd(int x, int bits, int delta) |
| { |
| /* Formula used in core bitmap loader. */ |
| return (((1 << bits) - 1)*x + (x >> (8 - bits)) + delta) >> COMPONENT_SHIFT; |
| } |
| |
| static inline int lcd_to_component(int x, int bits, int delta) |
| { |
| /* Reasonable, approximate reversal to get a full range back from the |
| quantized value. */ |
| return YUV_WHITE*x / ((1 << bits) - 1); |
| (void)delta; |
| } |
| |
| #define RED 0 |
| #define GRN 1 |
| #define BLU 2 |
| |
| struct rgb_err |
| { |
| int16_t errbuf[LCD_WIDTH+2]; /* Error record for line below */ |
| } rgb_err_buffers[3]; |
| |
| fb_data rgb_linebuf[LCD_WIDTH]; /* Line buffer for scrolling when |
| DITHER_DIFFUSION is set */ |
| |
| struct rgb_pixel |
| { |
| int r, g, b; /* Current pixel components in s16.0 */ |
| int inc; /* Current line increment (-1 or 1) */ |
| int row; /* Current row in source image */ |
| int col; /* Current column in source image */ |
| int ce[3]; /* Errors to apply to current pixel */ |
| struct rgb_err *e; /* RED, GRN, BLU */ |
| int epos; /* Current position in error record */ |
| }; |
| |
| struct rgb_pixel *pixel; |
| |
| /** round and truncate to lcd depth **/ |
| static fb_data pixel_to_lcd_colour(void) |
| { |
| struct rgb_pixel *p = pixel; |
| int r, g, b; |
| |
| r = component_to_lcd(p->r, LCD_RED_BITS, NODITHER_DELTA); |
| r = clamp_component_bits(r, LCD_RED_BITS); |
| |
| g = component_to_lcd(p->g, LCD_GREEN_BITS, NODITHER_DELTA); |
| g = clamp_component_bits(g, LCD_GREEN_BITS); |
| |
| b = component_to_lcd(p->b, LCD_BLUE_BITS, NODITHER_DELTA); |
| b = clamp_component_bits(b, LCD_BLUE_BITS); |
| |
| return LCD_RGBPACK_LCD(r, g, b); |
| } |
| |
| /** write a monochrome pixel to the colour LCD **/ |
| static fb_data pixel_to_lcd_gray(void) |
| { |
| int r, g, b; |
| |
| g = clamp_component(pixel->g); |
| r = component_to_lcd(g, LCD_RED_BITS, NODITHER_DELTA); |
| b = component_to_lcd(g, LCD_BLUE_BITS, NODITHER_DELTA); |
| g = component_to_lcd(g, LCD_GREEN_BITS, NODITHER_DELTA); |
| |
| return LCD_RGBPACK_LCD(r, g, b); |
| } |
| |
| /** |
| * Bayer ordered dithering - swiped from the core bitmap loader. |
| */ |
| static fb_data pixel_odither_to_lcd(void) |
| { |
| /* canonical ordered dither matrix */ |
| static const unsigned char dither_matrix[16][16] = { |
| { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, |
| { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, |
| { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, |
| { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, |
| { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, |
| { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, |
| { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, |
| { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, |
| { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, |
| { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, |
| { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, |
| { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, |
| { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, |
| { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, |
| { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, |
| { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } |
| }; |
| |
| struct rgb_pixel *p = pixel; |
| int r, g, b, delta; |
| |
| delta = dither_matrix[p->col & 15][p->row & 15] << MATRIX_SHIFT; |
| |
| r = component_to_lcd(p->r, LCD_RED_BITS, delta); |
| r = clamp_component_bits(r, LCD_RED_BITS); |
| |
| g = component_to_lcd(p->g, LCD_GREEN_BITS, delta); |
| g = clamp_component_bits(g, LCD_GREEN_BITS); |
| |
| b = component_to_lcd(p->b, LCD_BLUE_BITS, delta); |
| b = clamp_component_bits(b, LCD_BLUE_BITS); |
| |
| p->col += p->inc; |
| |
| return LCD_RGBPACK_LCD(r, g, b); |
| } |
| |
| /** |
| * Floyd/Steinberg dither to lcd depth. |
| * |
| * Apply filter to each component in serpentine pattern. Kernel shown for |
| * L->R scan. Kernel is reversed for R->L. |
| * * 7 |
| * 3 5 1 (1/16) |
| */ |
| static inline void distribute_error(int *ce, struct rgb_err *e, |
| int err, int epos, int inc) |
| { |
| *ce = (7*err >> 4) + e->errbuf[epos+inc]; |
| e->errbuf[epos+inc] = err >> 4; |
| e->errbuf[epos] += 5*err >> 4; |
| e->errbuf[epos-inc] += 3*err >> 4; |
| } |
| |
| static fb_data pixel_fsdither_to_lcd(void) |
| { |
| struct rgb_pixel *p = pixel; |
| int rc, gc, bc, r, g, b; |
| int inc, epos; |
| |
| /* Full components with error terms */ |
| rc = p->r + p->ce[RED]; |
| r = component_to_lcd(rc, LCD_RED_BITS, 0); |
| r = clamp_component_bits(r, LCD_RED_BITS); |
| |
| gc = p->g + p->ce[GRN]; |
| g = component_to_lcd(gc, LCD_GREEN_BITS, 0); |
| g = clamp_component_bits(g, LCD_GREEN_BITS); |
| |
| bc = p->b + p->ce[BLU]; |
| b = component_to_lcd(bc, LCD_BLUE_BITS, 0); |
| b = clamp_component_bits(b, LCD_BLUE_BITS); |
| |
| /* Get pixel errors */ |
| rc -= lcd_to_component(r, LCD_RED_BITS, 0); |
| gc -= lcd_to_component(g, LCD_GREEN_BITS, 0); |
| bc -= lcd_to_component(b, LCD_BLUE_BITS, 0); |
| |
| /* Spead error to surrounding pixels. */ |
| inc = p->inc; |
| epos = p->epos; |
| p->epos += inc; |
| |
| distribute_error(&p->ce[RED], &p->e[RED], rc, epos, inc); |
| distribute_error(&p->ce[GRN], &p->e[GRN], gc, epos, inc); |
| distribute_error(&p->ce[BLU], &p->e[BLU], bc, epos, inc); |
| |
| /* Pack and return pixel */ |
| return LCD_RGBPACK_LCD(r, g, b); |
| } |
| |
| /* Functions for each output mode, colour then grayscale. */ |
| static fb_data (* const pixel_funcs[COLOUR_NUM_MODES][DITHER_NUM_MODES])(void) = |
| { |
| [COLOURMODE_COLOUR] = |
| { |
| [DITHER_NONE] = pixel_to_lcd_colour, |
| [DITHER_ORDERED] = pixel_odither_to_lcd, |
| [DITHER_DIFFUSION] = pixel_fsdither_to_lcd, |
| }, |
| [COLOURMODE_GRAY] = |
| { |
| [DITHER_NONE] = pixel_to_lcd_gray, |
| [DITHER_ORDERED] = pixel_odither_to_lcd, |
| [DITHER_DIFFUSION] = pixel_fsdither_to_lcd, |
| }, |
| }; |
| |
| /** |
| * Draw a partial YUV colour bitmap |
| * |
| * Runs serpentine pattern when dithering is DITHER_DIFFUSION, else scan is |
| * always L->R. |
| */ |
| void yuv_bitmap_part(unsigned char *src[3], int csub_x, int csub_y, |
| int src_x, int src_y, int stride, |
| int x, int y, int width, int height) |
| { |
| fb_data *dst, *dst_end; |
| fb_data (*pixel_func)(void); |
| struct rgb_pixel px; |
| |
| if (x + width > LCD_WIDTH) |
| width = LCD_WIDTH - x; /* Clip right */ |
| if (x < 0) |
| width += x, x = 0; /* Clip left */ |
| if (width <= 0) |
| return; /* nothing left to do */ |
| |
| if (y + height > LCD_HEIGHT) |
| height = LCD_HEIGHT - y; /* Clip bottom */ |
| if (y < 0) |
| height += y, y = 0; /* Clip top */ |
| if (height <= 0) |
| return; /* nothing left to do */ |
| |
| pixel = &px; |
| |
| dst = rb->lcd_framebuffer + LCD_WIDTH * y + x; |
| dst_end = dst + LCD_WIDTH * height; |
| |
| if (jpeg_settings.colour_mode == COLOURMODE_GRAY) |
| csub_y = 0; /* Ignore Cb, Cr */ |
| |
| pixel_func = pixel_funcs[jpeg_settings.colour_mode] |
| [jpeg_settings.dither_mode]; |
| |
| if (jpeg_settings.dither_mode == DITHER_DIFFUSION) |
| { |
| /* Reset error terms. */ |
| px.e = rgb_err_buffers; |
| px.ce[RED] = px.ce[GRN] = px.ce[BLU] = 0; |
| rb->memset(px.e, 0, 3*sizeof (struct rgb_err)); |
| } |
| |
| do |
| { |
| fb_data *dst_row, *row_end; |
| const unsigned char *ysrc; |
| px.inc = 1; |
| |
| if (jpeg_settings.dither_mode == DITHER_DIFFUSION) |
| { |
| /* Use R->L scan on odd lines */ |
| px.inc -= (src_y & 1) << 1; |
| px.epos = x + 1; |
| |
| if (px.inc < 0) |
| px.epos += width - 1; |
| } |
| |
| if (px.inc == 1) |
| { |
| /* Scan is L->R */ |
| dst_row = dst; |
| row_end = dst_row + width; |
| px.col = src_x; |
| } |
| else |
| { |
| /* Scan is R->L */ |
| row_end = dst - 1; |
| dst_row = row_end + width; |
| px.col = src_x + width - 1; |
| } |
| |
| ysrc = src[0] + stride * src_y + px.col; |
| px.row = src_y; |
| |
| /* Do one row of pixels */ |
| if (csub_y) /* colour */ |
| { |
| /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ |
| const unsigned char *usrc, *vsrc; |
| |
| usrc = src[1] + (stride/csub_x) * (src_y/csub_y) |
| + (px.col/csub_x); |
| vsrc = src[2] + (stride/csub_x) * (src_y/csub_y) |
| + (px.col/csub_x); |
| int xphase = px.col % csub_x; |
| int xphase_reset = px.inc * csub_x; |
| int y, v, u, rv, guv, bu; |
| |
| v = *vsrc - 128; |
| vsrc += px.inc; |
| u = *usrc - 128; |
| usrc += px.inc; |
| rv = RVFAC*v; |
| guv = GUFAC*u + GVFAC*v; |
| bu = BUFAC*u; |
| |
| while (1) |
| { |
| y = YFAC*(*ysrc); |
| ysrc += px.inc; |
| px.r = y + rv; |
| px.g = y + guv; |
| px.b = y + bu; |
| |
| *dst_row = pixel_func(); |
| dst_row += px.inc; |
| |
| if (dst_row == row_end) |
| break; |
| |
| xphase += px.inc; |
| if ((unsigned)xphase < (unsigned)csub_x) |
| continue; |
| |
| /* fetch new chromas */ |
| v = *vsrc - 128; |
| vsrc += px.inc; |
| u = *usrc - 128; |
| usrc += px.inc; |
| rv = RVFAC*v; |
| guv = GUFAC*u + GVFAC*v; |
| bu = BUFAC*u; |
| |
| xphase -= xphase_reset; |
| } |
| } |
| else /* monochrome */ |
| { |
| do |
| { |
| /* Set all components the same for dithering purposes */ |
| px.g = px.r = px.b = YFAC*(*ysrc); |
| *dst_row = pixel_func(); |
| ysrc += px.inc; |
| dst_row += px.inc; |
| } |
| while (dst_row != row_end); |
| } |
| |
| src_y++; |
| dst += LCD_WIDTH; |
| } |
| while (dst < dst_end); |
| } |
| |
| #endif /* HAVE_LCD_COLOR */ |
| |
| |
| /* support function for qsort() */ |
| static int compare(const void* p1, const void* p2) |
| { |
| return rb->strcasecmp(*((char **)p1), *((char **)p2)); |
| } |
| |
| bool jpg_ext(const char ext[]) |
| { |
| if(!ext) |
| return false; |
| if(!rb->strcasecmp(ext,".jpg") || |
| !rb->strcasecmp(ext,".jpe") || |
| !rb->strcasecmp(ext,".jpeg")) |
| return true; |
| else |
| return false; |
| } |
| |
| /*Read directory contents for scrolling. */ |
| void get_pic_list(void) |
| { |
| int i; |
| long int str_len = 0; |
| char *pname; |
| tree = rb->tree_get_context(); |
| |
| #if PLUGIN_BUFFER_SIZE >= MIN_MEM |
| file_pt = rb->plugin_get_buffer((size_t *)&buf_size); |
| #else |
| file_pt = rb->plugin_get_audio_buffer((size_t *)&buf_size); |
| #endif |
| |
| for(i = 0; i < tree->filesindir; i++) |
| { |
| if(jpg_ext(rb->strrchr(&tree->name_buffer[str_len],'.'))) |
| file_pt[entries++] = &tree->name_buffer[str_len]; |
| |
| str_len += rb->strlen(&tree->name_buffer[str_len]) + 1; |
| } |
| |
| rb->qsort(file_pt, entries, sizeof(char**), compare); |
| |
| /* Remove path and leave only the name.*/ |
| pname = rb->strrchr(np_file,'/'); |
| pname++; |
| |
| /* Find Selected File. */ |
| for(i = 0; i < entries; i++) |
| if(!rb->strcmp(file_pt[i], pname)) |
| curfile = i; |
| } |
| |
| int change_filename(int direct) |
| { |
| int count = 0; |
| direction = direct; |
| |
| if(direct == DIR_PREV) |
| { |
| do |
| { |
| count++; |
| if(curfile == 0) |
| curfile = entries - 1; |
| else |
| curfile--; |
| }while(file_pt[curfile] == '\0' && count < entries); |
| /* we "erase" the file name if we encounter |
| * a non-supported file, so skip it now */ |
| } |
| else /* DIR_NEXT/DIR_NONE */ |
| { |
| do |
| { |
| count++; |
| if(curfile == entries - 1) |
| curfile = 0; |
| else |
| curfile++; |
| }while(file_pt[curfile] == '\0' && count < entries); |
| } |
| |
| if(count == entries && file_pt[curfile] == '\0') |
| { |
| rb->splash(HZ, "No supported files"); |
| return PLUGIN_ERROR; |
| } |
| if(rb->strlen(tree->currdir) > 1) |
| { |
| rb->strcpy(np_file, tree->currdir); |
| rb->strcat(np_file, "/"); |
| } |
| else |
| rb->strcpy(np_file, tree->currdir); |
| |
| rb->strcat(np_file, file_pt[curfile]); |
| |
| return PLUGIN_OTHER; |
| } |
| |
| /* switch off overlay, for handling SYS_ events */ |
| void cleanup(void *parameter) |
| { |
| (void)parameter; |
| #ifdef USEGSLIB |
| grey_show(false); |
| #endif |
| } |
| |
| #define VSCROLL (LCD_HEIGHT/8) |
| #define HSCROLL (LCD_WIDTH/10) |
| |
| #define ZOOM_IN 100 /* return codes for below function */ |
| #define ZOOM_OUT 101 |
| |
| #ifdef HAVE_LCD_COLOR |
| bool set_option_grayscale(void) |
| { |
| bool gray = jpeg_settings.colour_mode == COLOURMODE_GRAY; |
| rb->set_bool("Grayscale", &gray); |
| jpeg_settings.colour_mode = gray ? COLOURMODE_GRAY : COLOURMODE_COLOUR; |
| return false; |
| } |
| |
| bool set_option_dithering(void) |
| { |
| static const struct opt_items dithering[DITHER_NUM_MODES] = { |
| [DITHER_NONE] = { "Off", -1 }, |
| [DITHER_ORDERED] = { "Ordered", -1 }, |
| [DITHER_DIFFUSION] = { "Diffusion", -1 }, |
| }; |
| |
| rb->set_option("Dithering", &jpeg_settings.dither_mode, INT, |
| dithering, DITHER_NUM_MODES, NULL); |
| return false; |
| } |
| |
| static void display_options(void) |
| { |
| static const struct menu_item items[] = { |
| { "Grayscale", set_option_grayscale }, |
| { "Dithering", set_option_dithering }, |
| }; |
| |
| int m = menu_init(rb, items, ARRAYLEN(items), |
| NULL, NULL, NULL, NULL); |
| menu_run(m); |
| menu_exit(m); |
| } |
| #endif /* HAVE_LCD_COLOR */ |
| |
| int show_menu(void) /* return 1 to quit */ |
| { |
| #if LCD_DEPTH > 1 |
| rb->lcd_set_backdrop(old_backdrop); |
| #ifdef HAVE_LCD_COLOR |
| rb->lcd_set_foreground(rb->global_settings->fg_color); |
| rb->lcd_set_background(rb->global_settings->bg_color); |
| #else |
| rb->lcd_set_foreground(LCD_BLACK); |
| rb->lcd_set_background(LCD_WHITE); |
| #endif |
| |