mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-13 15:12:30 -05:00
imageviewer: Initial support for JPEG progressive images. Add decoder
Added jpeg decoder jpegp.c using RAINBOW lib. Currently enabled only for pictures not supported by old decoder (as old decoder more optimized for low mem targets) Someone TODO: * Old decoder has optimized downscale logic which new decoder doesn't have (it gives big difference in required memory and time for decoding). This logic should be ported/adapted if possible. * Add smooth downscaling. * Grayscale support Change-Id: Ie96bc62848b51cc6a3942f8e069ec6ab02dc1c56
This commit is contained in:
parent
64ad7354b6
commit
b8238f7b20
19 changed files with 599 additions and 22 deletions
260
apps/plugins/imageviewer/jpegp/jpegp.c
Normal file
260
apps/plugins/imageviewer/jpegp/jpegp.c
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
#include "jpeg81.h"
|
||||
#include "idct.h"
|
||||
#include "GETC.h"
|
||||
#include "rb_glue.h"
|
||||
|
||||
#include "../imageviewer.h"
|
||||
|
||||
|
||||
/**************** begin Application ********************/
|
||||
|
||||
/************************* Types ***************************/
|
||||
|
||||
struct t_disp
|
||||
{
|
||||
unsigned char* bitmap;
|
||||
};
|
||||
|
||||
/************************* Globals ***************************/
|
||||
|
||||
/* decompressed image in the possible sizes (1,2,4,8), wasting the other */
|
||||
static struct t_disp disp[9];
|
||||
|
||||
static struct JPEGD jpg; /* too large for stack */
|
||||
|
||||
/************************* Implementation ***************************/
|
||||
|
||||
static void draw_image_rect(struct image_info *info,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
struct t_disp* pdisp = (struct t_disp*)info->data;
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
rb->lcd_bitmap_part(
|
||||
(fb_data*)pdisp->bitmap, info->x + x, info->y + y,
|
||||
STRIDE(SCREEN_MAIN, info->width, info->height),
|
||||
x + MAX(0, (LCD_WIDTH-info->width)/2),
|
||||
y + MAX(0, (LCD_HEIGHT-info->height)/2),
|
||||
width, height);
|
||||
#else
|
||||
mylcd_ub_gray_bitmap_part(
|
||||
pdisp->bitmap, info->x + x, info->y + y, info->width,
|
||||
x + MAX(0, (LCD_WIDTH-info->width)/2),
|
||||
y + MAX(0, (LCD_HEIGHT-info->height)/2),
|
||||
width, height);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int img_mem(int ds)
|
||||
{
|
||||
struct JPEGD* j = &jpg;
|
||||
return j->Y/ds * j->X/ds*sizeof(fb_data);
|
||||
}
|
||||
|
||||
/* my memory pool (from the mp3 buffer) */
|
||||
static char print[32]; /* use a common snprintf() buffer */
|
||||
|
||||
static void scaled_dequantization_and_idct(void)
|
||||
{
|
||||
struct JPEGD* j = &jpg;
|
||||
// The following code is based on RAINBOW lib jpeg2bmp example:
|
||||
// https://github.com/Halicery/vc_rainbow/blob/605c045a564dad8e2df84e48914eac3d2d8d4a9b/jpeg2bmp.c
|
||||
|
||||
printf("Scaled de-quantization and IDCT.. ");
|
||||
int c, i, n;
|
||||
|
||||
// Pre-scale quant-tables
|
||||
int SQ[4][64];
|
||||
for (c=0; c<4 && j->QT[c][0]; c++)
|
||||
{
|
||||
int *q= j->QT[c], *sq= SQ[c];
|
||||
for (i=0; i<64; i++) sq[i]= q[i] * SCALEM[zigzag[i]];
|
||||
}
|
||||
|
||||
// DEQUANT + IDCT
|
||||
for (c=0; c<j->Nf; c++)
|
||||
{
|
||||
struct COMP *C= j->Components+c;
|
||||
//int *q= j->QT[C->Qi];
|
||||
int *sq= SQ[C->Qi];
|
||||
|
||||
for (n=0; n < C->du_size; n++)
|
||||
{
|
||||
/*
|
||||
// <--- scaled idct
|
||||
int k, t[64];
|
||||
TCOEF *coef= du[x];
|
||||
t[0]= coef[0] * q[0] + 1024; // dequant DC and level-shift (8-bit)
|
||||
for (k=1; k<64; k++) t[zigzag[k]] = coef[k] * q[k]; // dequant AC (+zigzag)
|
||||
idct_s(t, coef);
|
||||
*/
|
||||
|
||||
// <--- scaled idct with dequant
|
||||
idct_sq( C->du[ (n / C->du_w) * C->du_width + n % C->du_w ], sq );
|
||||
}
|
||||
}
|
||||
printf("done\n");
|
||||
}
|
||||
|
||||
static int load_image(char *filename, struct image_info *info,
|
||||
unsigned char *buf, ssize_t *buf_size)
|
||||
{
|
||||
int status;
|
||||
struct JPEGD *p_jpg = &jpg;
|
||||
|
||||
memset(&disp, 0, sizeof(disp));
|
||||
memset(&jpg, 0, sizeof(jpg));
|
||||
|
||||
init_mem_pool(buf, *buf_size);
|
||||
|
||||
if (!OPEN(filename))
|
||||
{
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
if (!iv->running_slideshow)
|
||||
{
|
||||
rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1);
|
||||
rb->lcd_puts(0, 2, "decoding...");
|
||||
rb->lcd_update();
|
||||
}
|
||||
long time; /* measured ticks */
|
||||
|
||||
/* the actual decoding */
|
||||
time = *rb->current_tick;
|
||||
status = JPEGDecode(p_jpg);
|
||||
time = *rb->current_tick - time;
|
||||
|
||||
CLOSE();
|
||||
|
||||
if (status < 0)
|
||||
{ /* bad format or minimum components not contained */
|
||||
if (status == JPEGENUMERR_MALLOC)
|
||||
{
|
||||
return PLUGIN_OUTOFMEM;
|
||||
}
|
||||
rb->splashf(HZ, "unsupported %d", status);
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
if (!iv->running_slideshow)
|
||||
{
|
||||
rb->lcd_putsf(0, 2, "image %dx%d", p_jpg->X, p_jpg->Y);
|
||||
int w, h; /* used to center output */
|
||||
rb->snprintf(print, sizeof(print), "jpegp %ld.%02ld sec ", time/HZ, time%HZ);
|
||||
rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
|
||||
rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
|
||||
rb->lcd_update();
|
||||
//rb->sleep(100);
|
||||
}
|
||||
|
||||
info->x_size = p_jpg->X;
|
||||
info->y_size = p_jpg->Y;
|
||||
|
||||
#ifdef DISK_SPINDOWN
|
||||
if (iv->running_slideshow && iv->immediate_ata_off)
|
||||
{
|
||||
/* running slideshow and time is long enough: power down disk */
|
||||
rb->storage_sleep();
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( 3 != p_jpg->Nf )
|
||||
return PLUGIN_ERROR;
|
||||
|
||||
scaled_dequantization_and_idct();
|
||||
|
||||
*buf_size = freeze_mem_pool();
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
static int get_image(struct image_info *info, int frame, int ds)
|
||||
{
|
||||
(void)frame;
|
||||
struct JPEGD* p_jpg = &jpg;
|
||||
struct t_disp* p_disp = &disp[ds]; /* short cut */
|
||||
|
||||
info->width = p_jpg->X / ds;
|
||||
info->height = p_jpg->Y / ds;
|
||||
info->data = p_disp;
|
||||
|
||||
if (p_disp->bitmap != NULL)
|
||||
{
|
||||
/* we still have it */
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
struct JPEGD* j = p_jpg;
|
||||
int mem = img_mem(ds);
|
||||
|
||||
p_disp->bitmap = malloc(mem);
|
||||
|
||||
if (!p_disp->bitmap)
|
||||
{
|
||||
clear_mem_pool();
|
||||
memset(&disp, 0, sizeof(disp));
|
||||
p_disp->bitmap = malloc(mem);
|
||||
if (!p_disp->bitmap)
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
fb_data *bmp = (fb_data *)p_disp->bitmap;
|
||||
|
||||
// The following code is based on RAINBOW lib jpeg2bmp example:
|
||||
// https://github.com/Halicery/vc_rainbow/blob/605c045a564dad8e2df84e48914eac3d2d8d4a9b/jpeg2bmp.c
|
||||
// Primitive yuv-rgb converter for all sub-sampling types, 24-bit BMP only
|
||||
printf("YUV-to-RGB conversion.. ");
|
||||
int h0 = j->Hmax / j->Components[0].Hi;
|
||||
int v0 = j->Vmax / j->Components[0].Vi;
|
||||
int h1 = j->Hmax / j->Components[1].Hi;
|
||||
int v1 = j->Vmax / j->Components[1].Vi;
|
||||
int h2 = j->Hmax / j->Components[2].Hi;
|
||||
int v2 = j->Vmax / j->Components[2].Vi;
|
||||
|
||||
int x, y;
|
||||
for (y = 0; y < j->Y; y++)
|
||||
{
|
||||
if (y%ds != 0)
|
||||
continue;
|
||||
|
||||
TCOEF *C0 =
|
||||
j->Components[0].du[j->Components[0].du_width * ((y / v0) / 8)] + 8 * ((y / v0) & 7);
|
||||
TCOEF *C1 =
|
||||
j->Components[1].du[j->Components[1].du_width * ((y / v1) / 8)] + 8 * ((y / v1) & 7);
|
||||
TCOEF *C2 =
|
||||
j->Components[2].du[j->Components[2].du_width * ((y / v2) / 8)] + 8 * ((y / v2) & 7);
|
||||
|
||||
for (x = 0; x < j->X; x++)
|
||||
{
|
||||
if (x%ds != 0)
|
||||
continue;
|
||||
|
||||
TCOEF c0 = C0[(x / h0 / 8) * 64 + ((x / h0) & 7)];
|
||||
TCOEF c1 = C1[(x / h1 / 8) * 64 + ((x / h1) & 7)];
|
||||
TCOEF c2 = C2[(x / h2 / 8) * 64 + ((x / h2) & 7)];
|
||||
|
||||
// ITU BT.601 full-range YUV-to-RGB integer approximation
|
||||
{
|
||||
int y = (c0 << 5) + 16;
|
||||
int u = c1 - 128;
|
||||
int v = c2 - 128;
|
||||
|
||||
int b = CLIP[(y + 57 * u)>>5]; // B;
|
||||
int g = CLIP[(y - 11 * u - 23 * v)>>5]; // G
|
||||
int r = CLIP[(y + 45 * v)>>5]; // R;
|
||||
*bmp++= FB_RGBPACK(r,g,b);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct image_decoder image_decoder = {
|
||||
false,
|
||||
img_mem,
|
||||
load_image,
|
||||
get_image,
|
||||
draw_image_rect,
|
||||
};
|
||||
|
||||
IMGDEC_HEADER
|
||||
Loading…
Add table
Add a link
Reference in a new issue