diff options
Diffstat (limited to 'apps/plugins/jpeg.c')
-rw-r--r-- | apps/plugins/jpeg.c | 207 |
1 files changed, 146 insertions, 61 deletions
diff --git a/apps/plugins/jpeg.c b/apps/plugins/jpeg.c index 32eedd5d0d..002012ca8c 100644 --- a/apps/plugins/jpeg.c +++ b/apps/plugins/jpeg.c | |||
@@ -2872,15 +2872,14 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale, | |||
2872 | int k_need; /* AC coefficients needed up to here */ | 2872 | int k_need; /* AC coefficients needed up to here */ |
2873 | int zero_need; /* init the block with this many zeros */ | 2873 | int zero_need; /* init the block with this many zeros */ |
2874 | 2874 | ||
2875 | int last_dc_val[4]; | 2875 | int last_dc_val = 0; |
2876 | int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */ | 2876 | int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */ |
2877 | MEMSET(&last_dc_val, 0, sizeof(last_dc_val)); | ||
2878 | 2877 | ||
2879 | /* pick the IDCT we want, determine how to work with coefs */ | 2878 | /* pick the IDCT we want, determine how to work with coefs */ |
2880 | if (downscale == 1) | 2879 | if (downscale == 1) |
2881 | { | 2880 | { |
2882 | pf_idct = idct8x8; | 2881 | pf_idct = idct8x8; |
2883 | k_need = 63; /* all */ | 2882 | k_need = 64; /* all */ |
2884 | zero_need = 63; /* all */ | 2883 | zero_need = 63; /* all */ |
2885 | } | 2884 | } |
2886 | else if (downscale == 2) | 2885 | else if (downscale == 2) |
@@ -2940,14 +2939,17 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale, | |||
2940 | struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti]; | 2939 | struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti]; |
2941 | 2940 | ||
2942 | /* Section F.2.2.1: decode the DC coefficient difference */ | 2941 | /* Section F.2.2.1: decode the DC coefficient difference */ |
2943 | last_dc_val[ci] += huff_decode_dc(&bs, dctbl); | 2942 | s = huff_decode_dc(&bs, dctbl); |
2944 | block[0] = last_dc_val[ci]; /* output it (assumes zag[0] = 0) */ | ||
2945 | 2943 | ||
2946 | /* Section F.2.2.2: decode the AC coefficients */ | ||
2947 | if (ci == 0) /* only for Y component */ | 2944 | if (ci == 0) /* only for Y component */ |
2948 | { | 2945 | { |
2946 | last_dc_val += s; | ||
2947 | block[0] = last_dc_val; /* output it (assumes zag[0] = 0) */ | ||
2948 | |||
2949 | /* coefficient buffer must be cleared */ | 2949 | /* coefficient buffer must be cleared */ |
2950 | MEMSET(block+1, 0, zero_need*sizeof(int)); | 2950 | MEMSET(block+1, 0, zero_need*sizeof(int)); |
2951 | |||
2952 | /* Section F.2.2.2: decode the AC coefficients */ | ||
2951 | for (; k < k_need; k++) | 2953 | for (; k < k_need; k++) |
2952 | { | 2954 | { |
2953 | s = huff_decode_ac(&bs, actbl); | 2955 | s = huff_decode_ac(&bs, actbl); |
@@ -3027,6 +3029,18 @@ struct t_disp | |||
3027 | }; | 3029 | }; |
3028 | 3030 | ||
3029 | 3031 | ||
3032 | /************************* Globals ***************************/ | ||
3033 | |||
3034 | /* decompressed image in the possible sizes (1,2,4,8), wasting the other */ | ||
3035 | struct t_disp disp[9]; | ||
3036 | |||
3037 | /* my memory pool (from the mp3 buffer) */ | ||
3038 | char print[32]; /* use a common snprintf() buffer */ | ||
3039 | unsigned char* buf; /* up to here currently used by image(s) */ | ||
3040 | int buf_size; | ||
3041 | unsigned char* buf_root; /* the root of the images */ | ||
3042 | int root_size; | ||
3043 | |||
3030 | /************************* Implementation ***************************/ | 3044 | /************************* Implementation ***************************/ |
3031 | 3045 | ||
3032 | #define ZOOM_IN 100 // return codes for below function | 3046 | #define ZOOM_IN 100 // return codes for below function |
@@ -3148,6 +3162,7 @@ int wait_for_button(void) | |||
3148 | /* callback updating a progress meter while JPEG decoding */ | 3162 | /* callback updating a progress meter while JPEG decoding */ |
3149 | void cb_progess(int current, int total) | 3163 | void cb_progess(int current, int total) |
3150 | { | 3164 | { |
3165 | rb->yield(); /* be nice to the other threads */ | ||
3151 | rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8, | 3166 | rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8, |
3152 | current*100/total, 0 /*Grow_Right*/); | 3167 | current*100/total, 0 /*Grow_Right*/); |
3153 | rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); | 3168 | rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); |
@@ -3170,7 +3185,7 @@ int min_downscale(int x, int y, int bufsize) | |||
3170 | int downscale = 8; | 3185 | int downscale = 8; |
3171 | 3186 | ||
3172 | if ((x/8) * (y/8) > bufsize) | 3187 | if ((x/8) * (y/8) > bufsize) |
3173 | return 0; /* error, too large even 1:8, doesn't fit */ | 3188 | return 0; /* error, too large, even 1:8 doesn't fit */ |
3174 | 3189 | ||
3175 | while ((x*2/downscale) * (y*2/downscale) < bufsize | 3190 | while ((x*2/downscale) * (y*2/downscale) < bufsize |
3176 | && downscale > 1) | 3191 | && downscale > 1) |
@@ -3180,6 +3195,7 @@ int min_downscale(int x, int y, int bufsize) | |||
3180 | return downscale; | 3195 | return downscale; |
3181 | } | 3196 | } |
3182 | 3197 | ||
3198 | |||
3183 | /* how far can we zoom out, to fit image into the LCD */ | 3199 | /* how far can we zoom out, to fit image into the LCD */ |
3184 | int max_downscale(int x, int y) | 3200 | int max_downscale(int x, int y) |
3185 | { | 3201 | { |
@@ -3195,6 +3211,98 @@ int max_downscale(int x, int y) | |||
3195 | } | 3211 | } |
3196 | 3212 | ||
3197 | 3213 | ||
3214 | /* return decoded or cached image */ | ||
3215 | struct t_disp* get_image(struct jpeg* p_jpg, int ds) | ||
3216 | { | ||
3217 | int w, h; /* used to center output */ | ||
3218 | int size; /* decompressed image size */ | ||
3219 | long time; /* measured ticks */ | ||
3220 | int status; | ||
3221 | |||
3222 | struct t_disp* p_disp = &disp[ds]; /* short cut */ | ||
3223 | |||
3224 | if (p_disp->bitmap != NULL) | ||
3225 | { | ||
3226 | return p_disp; /* we still have it */ | ||
3227 | } | ||
3228 | |||
3229 | /* assign image buffer */ | ||
3230 | |||
3231 | /* physical size needed for decoding */ | ||
3232 | size = (p_jpg->x_phys/ds) * (p_jpg->y_phys / ds); | ||
3233 | if (buf_size <= size) | ||
3234 | { /* have to discard the current */ | ||
3235 | int i; | ||
3236 | for (i=1; i<=8; i++) | ||
3237 | disp[i].bitmap = NULL; /* invalidate all bitmaps */ | ||
3238 | buf = buf_root; /* start again from the beginning of the buffer */ | ||
3239 | buf_size = root_size; | ||
3240 | } | ||
3241 | |||
3242 | /* size may be less when decoded (if height is not block aligned) */ | ||
3243 | size = (p_jpg->x_phys/ds) * (p_jpg->y_size / ds); | ||
3244 | p_disp->bitmap = buf; | ||
3245 | buf += size; | ||
3246 | buf_size -= size; | ||
3247 | |||
3248 | rb->snprintf(print, sizeof(print), "decoding %d*%d", | ||
3249 | p_jpg->x_size/ds, p_jpg->y_size/ds); | ||
3250 | rb->lcd_puts(0, 3, print); | ||
3251 | rb->lcd_update(); | ||
3252 | |||
3253 | /* update image properties */ | ||
3254 | p_disp->width = p_jpg->x_size/ds; | ||
3255 | p_disp->stride = p_jpg->x_phys / ds; /* use physical size for stride */ | ||
3256 | p_disp->height = p_jpg->y_size/ds; | ||
3257 | |||
3258 | /* the actual decoding */ | ||
3259 | time = *rb->current_tick; | ||
3260 | status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progess); | ||
3261 | if (status) | ||
3262 | { | ||
3263 | rb->splash(HZ*2, true, "decode error %d", status); | ||
3264 | return NULL; | ||
3265 | } | ||
3266 | time = *rb->current_tick - time; | ||
3267 | rb->snprintf(print, sizeof(print), " %d.%02d sec ", time/HZ, time%HZ); | ||
3268 | rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ | ||
3269 | rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); | ||
3270 | rb->lcd_update(); | ||
3271 | |||
3272 | return p_disp; | ||
3273 | } | ||
3274 | |||
3275 | |||
3276 | /* set the view to the given center point, limit if necessary */ | ||
3277 | void set_view (struct t_disp* p_disp, int cx, int cy) | ||
3278 | { | ||
3279 | int x, y; | ||
3280 | |||
3281 | /* plain center to available width/height */ | ||
3282 | x = cx - MIN(LCD_WIDTH, p_disp->width) / 2; | ||
3283 | y = cy - MIN(LCD_HEIGHT, p_disp->height) / 2; | ||
3284 | |||
3285 | /* limit against upper image size */ | ||
3286 | x = MIN(p_disp->width - LCD_WIDTH, x); | ||
3287 | y = MIN(p_disp->height - LCD_HEIGHT, y); | ||
3288 | |||
3289 | /* limit against negative side */ | ||
3290 | x = MAX(0, x); | ||
3291 | y = MAX(0, y); | ||
3292 | |||
3293 | p_disp->x = x; /* set the values */ | ||
3294 | p_disp->y = y; | ||
3295 | } | ||
3296 | |||
3297 | |||
3298 | /* calculate the view center based on the bitmap position */ | ||
3299 | void get_view(struct t_disp* p_disp, int* p_cx, int* p_cy) | ||
3300 | { | ||
3301 | *p_cx = p_disp->x + MIN(LCD_WIDTH, p_disp->width) / 2; | ||
3302 | *p_cy = p_disp->y + MIN(LCD_HEIGHT, p_disp->height) / 2; | ||
3303 | } | ||
3304 | |||
3305 | |||
3198 | /* load, decode, display the image */ | 3306 | /* load, decode, display the image */ |
3199 | int main(char* filename) | 3307 | int main(char* filename) |
3200 | { | 3308 | { |
@@ -3202,18 +3310,12 @@ int main(char* filename) | |||
3202 | int filesize; | 3310 | int filesize; |
3203 | int grayscales; | 3311 | int grayscales; |
3204 | int graysize; // helper | 3312 | int graysize; // helper |
3205 | char print[32]; | ||
3206 | unsigned char* buf; | ||
3207 | int buf_size; | ||
3208 | unsigned char* buf_jpeg; /* compressed JPEG image */ | 3313 | unsigned char* buf_jpeg; /* compressed JPEG image */ |
3209 | struct t_disp disp; /* decompressed image */ | ||
3210 | long time; /* measured ticks */ | ||
3211 | |||
3212 | static struct jpeg jpg; /* too large for stack */ | 3314 | static struct jpeg jpg; /* too large for stack */ |
3213 | int status; | 3315 | int status; |
3214 | int ds, ds_min, ds_max; /* scaling and limits */ | 3316 | int ds, ds_min, ds_max; /* scaling and limits */ |
3215 | 3317 | struct t_disp* p_disp; /* currenly displayed image */ | |
3216 | buf = rb->plugin_get_mp3_buffer(&buf_size); | 3318 | int cx, cy; /* view center */ |
3217 | 3319 | ||
3218 | fd = rb->open(filename, O_RDONLY); | 3320 | fd = rb->open(filename, O_RDONLY); |
3219 | if (fd < 0) | 3321 | if (fd < 0) |
@@ -3223,6 +3325,10 @@ int main(char* filename) | |||
3223 | } | 3325 | } |
3224 | filesize = rb->filesize(fd); | 3326 | filesize = rb->filesize(fd); |
3225 | 3327 | ||
3328 | rb->memset(&disp, 0, sizeof(disp)); | ||
3329 | |||
3330 | buf = rb->plugin_get_mp3_buffer(&buf_size); /* start munching memory */ | ||
3331 | |||
3226 | 3332 | ||
3227 | /* initialize the grayscale buffer: | 3333 | /* initialize the grayscale buffer: |
3228 | * 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve | 3334 | * 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve |
@@ -3279,6 +3385,8 @@ int main(char* filename) | |||
3279 | buf_size += filesize; | 3385 | buf_size += filesize; |
3280 | buf += jpg.words_in_buffer * sizeof(short); /* real space */ | 3386 | buf += jpg.words_in_buffer * sizeof(short); /* real space */ |
3281 | buf_size -= jpg.words_in_buffer * sizeof(short); | 3387 | buf_size -= jpg.words_in_buffer * sizeof(short); |
3388 | buf_root = buf; /* we can start the images here */ | ||
3389 | root_size = buf_size; | ||
3282 | 3390 | ||
3283 | rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size); | 3391 | rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size); |
3284 | rb->lcd_puts(0, 2, print); | 3392 | rb->lcd_puts(0, 2, print); |
@@ -3294,47 +3402,30 @@ int main(char* filename) | |||
3294 | return PLUGIN_ERROR; | 3402 | return PLUGIN_ERROR; |
3295 | } | 3403 | } |
3296 | ds = ds_max; /* initials setting */ | 3404 | ds = ds_max; /* initials setting */ |
3297 | 3405 | cx = jpg.x_size/ds/2; /* center the view */ | |
3298 | /* assign image buffer */ | 3406 | cy = jpg.y_size/ds/2; |
3299 | rb->memset(&disp, 0, sizeof(disp)); | ||
3300 | disp.bitmap = buf; | ||
3301 | 3407 | ||
3302 | do /* loop the image prepare and decoding when zoomed */ | 3408 | do /* loop the image prepare and decoding when zoomed */ |
3303 | { | 3409 | { |
3304 | int w, h; /* used to center output */ | 3410 | p_disp = get_image(&jpg, ds); /* decode or fetch from cache */ |
3305 | rb->snprintf(print, sizeof(print), "decoding %d*%d", | 3411 | if (p_disp == NULL) |
3306 | jpg.x_size/ds, jpg.y_size/ds); | ||
3307 | rb->lcd_puts(0, 3, print); | ||
3308 | rb->lcd_update(); | ||
3309 | |||
3310 | /* update image properties */ | ||
3311 | disp.width = jpg.x_size/ds; | ||
3312 | disp.stride = jpg.x_phys / ds; /* use physical size for stride */ | ||
3313 | disp.height = jpg.y_size/ds; | ||
3314 | disp.x = MAX(0, (disp.width - LCD_WIDTH) / 2); /* center view */ | ||
3315 | disp.y = MAX(0, (disp.height - LCD_HEIGHT) / 2); | ||
3316 | |||
3317 | /* the actual decoding */ | ||
3318 | time = *rb->current_tick; | ||
3319 | status = jpeg_decode(&jpg, disp.bitmap, ds, cb_progess); | ||
3320 | if (status) | ||
3321 | { | ||
3322 | rb->splash(HZ*2, true, "decode error %d", status); | ||
3323 | return PLUGIN_ERROR; | 3412 | return PLUGIN_ERROR; |
3324 | } | 3413 | |
3325 | time = *rb->current_tick - time; | 3414 | set_view(p_disp, cx, cy); |
3326 | rb->snprintf(print, sizeof(print), " %d.%02d sec ", time/HZ, time%HZ); | 3415 | |
3327 | rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ | 3416 | rb->snprintf(print, sizeof(print), "showing %d*%d", |
3328 | rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); | 3417 | p_disp->width, p_disp->height); |
3418 | rb->lcd_puts(0, 3, print); | ||
3329 | rb->lcd_update(); | 3419 | rb->lcd_update(); |
3330 | 3420 | ||
3331 | gray_clear_display(); | 3421 | gray_clear_display(); |
3332 | gray_drawgraymap( | 3422 | gray_drawgraymap( |
3333 | disp.bitmap + disp.y * disp.stride + disp.x, | 3423 | p_disp->bitmap + p_disp->y * p_disp->stride + p_disp->x, |
3334 | MAX(0, (LCD_WIDTH - disp.width) / 2), | 3424 | MAX(0, (LCD_WIDTH - p_disp->width) / 2), |
3335 | MAX(0, (LCD_HEIGHT - disp.height) / 2), | 3425 | MAX(0, (LCD_HEIGHT - p_disp->height) / 2), |
3336 | MIN(LCD_WIDTH, disp.width), MIN(LCD_HEIGHT, disp.height), | 3426 | MIN(LCD_WIDTH, p_disp->width), |
3337 | disp.stride); | 3427 | MIN(LCD_HEIGHT, p_disp->height), |
3428 | p_disp->stride); | ||
3338 | 3429 | ||
3339 | gray_show_display(true); /* switch on grayscale overlay */ | 3430 | gray_show_display(true); /* switch on grayscale overlay */ |
3340 | 3431 | ||
@@ -3343,16 +3434,15 @@ int main(char* filename) | |||
3343 | */ | 3434 | */ |
3344 | while (1) | 3435 | while (1) |
3345 | { | 3436 | { |
3346 | status = scroll_bmp(&disp); | 3437 | status = scroll_bmp(p_disp); |
3347 | if (status == ZOOM_IN) | 3438 | if (status == ZOOM_IN) |
3348 | { | 3439 | { |
3349 | if (ds > ds_min) | 3440 | if (ds > ds_min) |
3350 | { | 3441 | { |
3351 | ds /= 2; /* reduce downscaling to zoom in */ | 3442 | ds /= 2; /* reduce downscaling to zoom in */ |
3352 | /* FixMe: maintain center | 3443 | get_view(p_disp, &cx, &cy); |
3353 | disp.x = disp.x * 2 + LCD_WIDTH/2; | 3444 | cx *= 2; /* prepare the position in the new image */ |
3354 | disp.y = disp.y * 2 + LCD_HEIGHT/2; | 3445 | cy *= 2; |
3355 | */ | ||
3356 | } | 3446 | } |
3357 | else | 3447 | else |
3358 | continue; | 3448 | continue; |
@@ -3363,14 +3453,9 @@ int main(char* filename) | |||
3363 | if (ds < ds_max) | 3453 | if (ds < ds_max) |
3364 | { | 3454 | { |
3365 | ds *= 2; /* increase downscaling to zoom out */ | 3455 | ds *= 2; /* increase downscaling to zoom out */ |
3366 | /* FixMe: maintain center, if possible | 3456 | get_view(p_disp, &cx, &cy); |
3367 | disp.x = (disp.x - LCD_WIDTH/2) / 2; | 3457 | cx /= 2; /* prepare the position in the new image */ |
3368 | disp.x = MIN(0, disp.x); | 3458 | cy /= 2; |
3369 | disp.x = MAX(disp.width/2 - LCD_WIDTH, disp.x); | ||
3370 | disp.y = (disp.y - LCD_HEIGHT/2) / 2; | ||
3371 | disp.y = MIN(0, disp.y); | ||
3372 | disp.y = MAX(disp.height/2 - LCD_HEIGHT, disp.y); | ||
3373 | */ | ||
3374 | } | 3459 | } |
3375 | else | 3460 | else |
3376 | continue; | 3461 | continue; |