forked from len0rd/rockbox
Add ability to imageviewer to view current track embedded/folder album art Add "View Album Art" WPS context menu item Change-Id: I49caebd38e5e3e2910d418bbeaa5e51da0e6bd93
266 lines
7.1 KiB
C
266 lines
7.1 KiB
C
#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 offset, int filesize)
|
|
{
|
|
(void)filesize;
|
|
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 (offset)
|
|
{
|
|
POS(offset);
|
|
}
|
|
|
|
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
|