A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 310 lines 8.9 kB view raw
1/*************************************************************************** 2* __________ __ ___. 3* Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7* \/ \/ \/ \/ \/ 8* $Id$ 9* 10* JPEG image viewer 11* (This is a real mess if it has to be coded in one single C file) 12* 13* File scrolling addition (C) 2005 Alexander Spyridakis 14* Copyright (C) 2004 Jörg Hohensohn aka [IDC]Dragon 15* Heavily borrowed from the IJG implementation (C) Thomas G. Lane 16* Small & fast downscaling IDCT (C) 2002 by Guido Vollbeding JPEGclub.org 17* 18* This program is free software; you can redistribute it and/or 19* modify it under the terms of the GNU General Public License 20* as published by the Free Software Foundation; either version 2 21* of the License, or (at your option) any later version. 22* 23* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 24* KIND, either express or implied. 25* 26****************************************************************************/ 27 28#include "plugin.h" 29 30#include "../imageviewer.h" 31#include "jpeg_decoder.h" 32 33#ifdef HAVE_LCD_COLOR 34#include "yuv2rgb.h" 35#endif 36 37/**************** begin Application ********************/ 38 39/************************* Types ***************************/ 40 41struct t_disp 42{ 43#ifdef HAVE_LCD_COLOR 44 unsigned char* bitmap[3]; /* Y, Cr, Cb */ 45 int csub_x, csub_y; 46#else 47 unsigned char* bitmap[1]; /* Y only */ 48#endif 49 int stride; 50}; 51 52/************************* Globals ***************************/ 53 54/* decompressed image in the possible sizes (1,2,4,8), wasting the other */ 55static struct t_disp disp[9]; 56 57/* my memory pool (from the mp3 buffer) */ 58static char print[32]; /* use a common snprintf() buffer */ 59 60/* the root of the images, hereafter are decompresed ones */ 61static unsigned char* buf_root; 62static int root_size; 63 64/* up to here currently used by image(s) */ 65static unsigned char* buf_images; 66static ssize_t buf_images_size; 67 68static struct jpeg jpg; /* too large for stack */ 69 70/************************* Implementation ***************************/ 71 72static void draw_image_rect(struct image_info *info, 73 int x, int y, int width, int height) 74{ 75 struct t_disp* pdisp = (struct t_disp*)info->data; 76#ifdef HAVE_LCD_COLOR 77 yuv_bitmap_part( 78 pdisp->bitmap, pdisp->csub_x, pdisp->csub_y, 79 info->x + x, info->y + y, pdisp->stride, 80 x + MAX(0, (LCD_WIDTH - info->width) / 2), 81 y + MAX(0, (LCD_HEIGHT - info->height) / 2), 82 width, height, 83 iv->settings->jpeg_colour_mode, iv->settings->jpeg_dither_mode); 84#else 85 mylcd_ub_gray_bitmap_part( 86 pdisp->bitmap[0], info->x + x, info->y + y, pdisp->stride, 87 x + MAX(0, (LCD_WIDTH-info->width)/2), 88 y + MAX(0, (LCD_HEIGHT-info->height)/2), 89 width, height); 90#endif 91} 92 93static int img_mem(int ds) 94{ 95 int size; 96 struct jpeg *p_jpg = &jpg; 97 98 size = (p_jpg->x_phys/ds/p_jpg->subsample_x[0]) 99 * (p_jpg->y_phys/ds/p_jpg->subsample_y[0]); 100#ifdef HAVE_LCD_COLOR 101 if (p_jpg->blocks > 1) /* colour, add requirements for chroma */ 102 { 103 size += (p_jpg->x_phys/ds/p_jpg->subsample_x[1]) 104 * (p_jpg->y_phys/ds/p_jpg->subsample_y[1]); 105 size += (p_jpg->x_phys/ds/p_jpg->subsample_x[2]) 106 * (p_jpg->y_phys/ds/p_jpg->subsample_y[2]); 107 } 108#endif 109 return size; 110} 111 112static int load_image(char *filename, struct image_info *info, 113 unsigned char *buf, ssize_t *buf_size, 114 int offset, int filesize) 115{ 116 int fd; 117 unsigned char* buf_jpeg; /* compressed JPEG image */ 118 int status; 119 struct jpeg *p_jpg = &jpg; 120 121 rb->memset(&disp, 0, sizeof(disp)); 122 rb->memset(&jpg, 0, sizeof(jpg)); 123 124 fd = rb->open(filename, O_RDONLY); 125 if (fd < 0) 126 { 127 rb->splashf(HZ, "err opening %s: %d", filename, fd); 128 return PLUGIN_ERROR; 129 } 130 131 if (offset) 132 { 133 rb->lseek(fd, offset, SEEK_SET); 134 } 135 else 136 { 137 filesize = rb->filesize(fd); 138 } 139 140 /* allocate JPEG buffer */ 141 buf_jpeg = buf; 142 143 /* we can start the decompressed images behind it */ 144 buf_images = buf_root = buf + filesize; 145 buf_images_size = root_size = *buf_size - filesize; 146 147 if (buf_images_size <= 0) 148 { 149 rb->close(fd); 150 return PLUGIN_OUTOFMEM; 151 } 152 153 if(!iv->running_slideshow) 154 { 155 rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1); 156 rb->lcd_putsf(0, 1, "loading %d bytes", filesize); 157 rb->lcd_update(); 158 } 159 160 rb->read(fd, buf_jpeg, filesize); 161 rb->close(fd); 162 163 if(!iv->running_slideshow) 164 { 165 rb->lcd_puts(0, 2, "decoding markers"); 166 rb->lcd_update(); 167 } 168#ifdef DISK_SPINDOWN 169 else if(iv->immediate_ata_off) 170 { 171 /* running slideshow and time is long enough: power down disk */ 172 rb->storage_sleep(); 173 } 174#endif 175 176 /* process markers, unstuffing */ 177 status = process_markers(buf_jpeg, filesize, p_jpg); 178 179 if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0)) 180 { /* bad format or minimum components not contained */ 181#ifndef HAVE_LCD_COLOR 182 rb->splashf(HZ, "unsupported %d", status); 183 return PLUGIN_ERROR; 184#else 185 return PLUGIN_JPEG_PROGRESSIVE; 186#endif 187 } 188 189 if (!(status & DHT)) /* if no Huffman table present: */ 190 default_huff_tbl(p_jpg); /* use default */ 191 build_lut(p_jpg); /* derive Huffman and other lookup-tables */ 192 193 if(!iv->running_slideshow) 194 { 195 rb->lcd_putsf(0, 2, "image %dx%d", p_jpg->x_size, p_jpg->y_size); 196 rb->lcd_update(); 197 } 198 199 info->x_size = p_jpg->x_size; 200 info->y_size = p_jpg->y_size; 201 *buf_size = buf_images_size; 202 return PLUGIN_OK; 203} 204 205static int get_image(struct image_info *info, int frame, int ds) 206{ 207 (void)frame; 208 int w, h; /* used to center output */ 209 int size; /* decompressed image size */ 210 long time; /* measured ticks */ 211 int status; 212 struct jpeg* p_jpg = &jpg; 213 struct t_disp* p_disp = &disp[ds]; /* short cut */ 214 215 info->width = p_jpg->x_size / ds; 216 info->height = p_jpg->y_size / ds; 217 info->data = p_disp; 218 219 if (p_disp->bitmap[0] != NULL) 220 { 221 /* we still have it */ 222 return PLUGIN_OK; 223 } 224 225 /* assign image buffer */ 226 227 /* physical size needed for decoding */ 228 size = img_mem(ds); 229 if (buf_images_size <= size) 230 { /* have to discard the current */ 231 int i; 232 for (i=1; i<=8; i++) 233 disp[i].bitmap[0] = NULL; /* invalidate all bitmaps */ 234 buf_images = buf_root; /* start again from the beginning of the buffer */ 235 buf_images_size = root_size; 236 } 237 238#ifdef HAVE_LCD_COLOR 239 if (p_jpg->blocks > 1) /* colour jpeg */ 240 { 241 int i; 242 243 for (i = 1; i < 3; i++) 244 { 245 size = (p_jpg->x_phys / ds / p_jpg->subsample_x[i]) 246 * (p_jpg->y_phys / ds / p_jpg->subsample_y[i]); 247 p_disp->bitmap[i] = buf_images; 248 buf_images += size; 249 buf_images_size -= size; 250 } 251 p_disp->csub_x = p_jpg->subsample_x[1]; 252 p_disp->csub_y = p_jpg->subsample_y[1]; 253 } 254 else 255 { 256 p_disp->csub_x = p_disp->csub_y = 0; 257 p_disp->bitmap[1] = p_disp->bitmap[2] = buf_images; 258 } 259#endif 260 /* size may be less when decoded (if height is not block aligned) */ 261 size = (p_jpg->x_phys/ds) * (p_jpg->y_size/ds); 262 p_disp->bitmap[0] = buf_images; 263 buf_images += size; 264 buf_images_size -= size; 265 266 if(!iv->running_slideshow) 267 { 268 rb->lcd_putsf(0, 3, "decoding %d*%d", info->width, info->height); 269 rb->lcd_update(); 270 } 271 272 /* update image properties */ 273 p_disp->stride = p_jpg->x_phys / ds; /* use physical size for stride */ 274 275 /* the actual decoding */ 276 time = *rb->current_tick; 277#ifdef HAVE_ADJUSTABLE_CPU_FREQ 278 rb->cpu_boost(true); 279 status = jpeg_decode(p_jpg, p_disp->bitmap, ds, iv->cb_progress); 280 rb->cpu_boost(false); 281#else 282 status = jpeg_decode(p_jpg, p_disp->bitmap, ds, iv->cb_progress); 283#endif 284 if (status) 285 { 286 rb->splashf(HZ, "decode error %d", status); 287 return PLUGIN_ERROR; 288 } 289 time = *rb->current_tick - time; 290 291 if(!iv->running_slideshow) 292 { 293 rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ); 294 rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ 295 rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); 296 rb->lcd_update(); 297 } 298 299 return PLUGIN_OK; 300} 301 302const struct image_decoder image_decoder = { 303 false, 304 img_mem, 305 load_image, 306 get_image, 307 draw_image_rect, 308}; 309 310IMGDEC_HEADER