acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_sjpg.c (33092B)
1 /** 2 * @file lv_sjpg.c 3 * 4 */ 5 6 /*---------------------------------------------------------------------------------------------------------------------------------- 7 / Added normal JPG support [7/10/2020] 8 / ---------- 9 / SJPEG is a custom created modified JPEG file format for small embedded platforms. 10 / It will contain multiple JPEG fragments all embedded into a single file with a custom header. 11 / This makes JPEG decoding easier using any JPEG library. Overall file size will be almost 12 / similar to the parent jpeg file. We can generate sjpeg from any jpeg using a python script 13 / provided along with this project. 14 / (by vinodstanur | 2020 ) 15 / SJPEG FILE STRUCTURE 16 / -------------------------------------------------------------------------------------------------------------------------------- 17 / Bytes | Value | 18 / -------------------------------------------------------------------------------------------------------------------------------- 19 / 20 / 0 - 7 | "_SJPG__" followed by '\0' 21 / 22 / 8 - 13 | "V1.00" followed by '\0' [VERSION OF SJPG FILE for future compatibiliby] 23 / 24 / 14 - 15 | X_RESOLUTION (width) [little endian] 25 / 26 / 16 - 17 | Y_RESOLUTION (height) [little endian] 27 / 28 / 18 - 19 | TOTAL_FRAMES inside sjpeg [little endian] 29 / 30 / 20 - 21 | JPEG BLOCK WIDTH (16 normally) [little endian] 31 / 32 / 22 - [(TOTAL_FRAMES*2 )] | SIZE OF EACH JPEG SPLIT FRAGMENTS (FRAME_INFO_ARRAY) 33 / 34 / SJPEG data | Each JPEG frame can be extracted from SJPEG data by parsing the FRAME_INFO_ARRAY one time. 35 / 36 /---------------------------------------------------------------------------------------------------------------------------------- 37 / JPEG DECODER 38 / ------------ 39 / We are using TJpgDec - Tiny JPEG Decompressor library from ELM-CHAN for decoding each split-jpeg fragments. 40 / The tjpgd.c and tjpgd.h is not modified and those are used as it is. So if any update comes for the tiny-jpeg, 41 / just replace those files with updated files. 42 /---------------------------------------------------------------------------------------------------------------------------------*/ 43 44 /********************* 45 * INCLUDES 46 *********************/ 47 48 #include "../../../lvgl.h" 49 #if LV_USE_SJPG 50 51 #include "tjpgd.h" 52 #include "lv_sjpg.h" 53 #include "../../../misc/lv_fs.h" 54 55 /********************* 56 * DEFINES 57 *********************/ 58 #define TJPGD_WORKBUFF_SIZE 4096 //Recommended by TJPGD libray 59 60 //NEVER EDIT THESE OFFSET VALUES 61 #define SJPEG_VERSION_OFFSET 8 62 #define SJPEG_X_RES_OFFSET 14 63 #define SJPEG_y_RES_OFFSET 16 64 #define SJPEG_TOTAL_FRAMES_OFFSET 18 65 #define SJPEG_BLOCK_WIDTH_OFFSET 20 66 #define SJPEG_FRAME_INFO_ARRAY_OFFSET 22 67 68 /********************** 69 * TYPEDEFS 70 **********************/ 71 72 enum io_source_type { 73 SJPEG_IO_SOURCE_C_ARRAY, 74 SJPEG_IO_SOURCE_DISK, 75 }; 76 77 typedef struct { 78 enum io_source_type type; 79 lv_fs_file_t lv_file; 80 uint8_t * img_cache_buff; 81 int img_cache_x_res; 82 int img_cache_y_res; 83 uint8_t * raw_sjpg_data; //Used when type==SJPEG_IO_SOURCE_C_ARRAY. 84 uint32_t raw_sjpg_data_size; //Num bytes pointed to by raw_sjpg_data. 85 uint32_t raw_sjpg_data_next_read_pos; //Used for all types. 86 } io_source_t; 87 88 89 typedef struct { 90 uint8_t * sjpeg_data; 91 uint32_t sjpeg_data_size; 92 int sjpeg_x_res; 93 int sjpeg_y_res; 94 int sjpeg_total_frames; 95 int sjpeg_single_frame_height; 96 int sjpeg_cache_frame_index; 97 uint8_t ** frame_base_array; //to save base address of each split frames upto sjpeg_total_frames. 98 int * frame_base_offset; //to save base offset for fseek 99 uint8_t * frame_cache; 100 uint8_t * workb; //JPG work buffer for jpeg library 101 JDEC * tjpeg_jd; 102 io_source_t io; 103 } SJPEG; 104 105 /********************** 106 * STATIC PROTOTYPES 107 **********************/ 108 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header); 109 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc); 110 static lv_res_t decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, 111 lv_coord_t len, uint8_t * buf); 112 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc); 113 static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata); 114 static int is_jpg(const uint8_t * raw_data, size_t len); 115 static void lv_sjpg_cleanup(SJPEG * sjpeg); 116 static void lv_sjpg_free(SJPEG * sjpeg); 117 118 /********************** 119 * STATIC VARIABLES 120 **********************/ 121 122 /********************** 123 * MACROS 124 **********************/ 125 126 /********************** 127 * GLOBAL FUNCTIONS 128 **********************/ 129 void lv_split_jpeg_init(void) 130 { 131 lv_img_decoder_t * dec = lv_img_decoder_create(); 132 lv_img_decoder_set_info_cb(dec, decoder_info); 133 lv_img_decoder_set_open_cb(dec, decoder_open); 134 lv_img_decoder_set_close_cb(dec, decoder_close); 135 lv_img_decoder_set_read_line_cb(dec, decoder_read_line); 136 } 137 138 /********************** 139 * STATIC FUNCTIONS 140 **********************/ 141 /** 142 * Get info about an SJPG / JPG image 143 * @param decoder pointer to the decoder where this function belongs 144 * @param src can be file name or pointer to a C array 145 * @param header store the info here 146 * @return LV_RES_OK: no error; LV_RES_INV: can't get the info 147 */ 148 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header) 149 { 150 LV_UNUSED(decoder); 151 152 /*Check whether the type `src` is known by the decoder*/ 153 /* Read the SJPG/JPG header and find `width` and `height` */ 154 155 lv_img_src_t src_type = lv_img_src_get_type(src); /*Get the source type*/ 156 157 lv_res_t ret = LV_RES_OK; 158 159 if(src_type == LV_IMG_SRC_VARIABLE) { 160 const lv_img_dsc_t * img_dsc = src; 161 uint8_t * raw_sjpeg_data = (uint8_t *)img_dsc->data; 162 const uint32_t raw_sjpeg_data_size = img_dsc->data_size; 163 164 if(!strncmp((char *)raw_sjpeg_data, "_SJPG__", strlen("_SJPG__"))) { 165 166 raw_sjpeg_data += 14; //seek to res info ... refer sjpeg format 167 header->always_zero = 0; 168 header->cf = LV_IMG_CF_RAW; 169 170 header->w = *raw_sjpeg_data++; 171 header->w |= *raw_sjpeg_data++ << 8; 172 173 header->h = *raw_sjpeg_data++; 174 header->h |= *raw_sjpeg_data++ << 8; 175 176 return ret; 177 178 } 179 else if(is_jpg(raw_sjpeg_data, raw_sjpeg_data_size) == true) { 180 header->always_zero = 0; 181 header->cf = LV_IMG_CF_RAW; 182 183 uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE); 184 if(!workb_temp) return LV_RES_INV; 185 186 io_source_t io_source_temp; 187 io_source_temp.type = SJPEG_IO_SOURCE_C_ARRAY; 188 io_source_temp.raw_sjpg_data = raw_sjpeg_data; 189 io_source_temp.raw_sjpg_data_size = raw_sjpeg_data_size; 190 io_source_temp.raw_sjpg_data_next_read_pos = 0; 191 192 JDEC jd_tmp; 193 194 JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp); 195 if(rc == JDR_OK) { 196 header->w = jd_tmp.width; 197 header->h = jd_tmp.height; 198 199 } 200 else { 201 ret = LV_RES_INV; 202 goto end; 203 } 204 205 end: 206 lv_mem_free(workb_temp); 207 208 return ret; 209 210 } 211 } 212 else if(src_type == LV_IMG_SRC_FILE) { 213 const char * fn = src; 214 if(strcmp(lv_fs_get_ext(fn), "sjpg") == 0) { 215 216 uint8_t buff[22]; 217 memset(buff, 0, sizeof(buff)); 218 219 lv_fs_file_t file; 220 lv_fs_res_t res = lv_fs_open(&file, fn, LV_FS_MODE_RD); 221 if(res != LV_FS_RES_OK) return 78; 222 223 uint32_t rn; 224 res = lv_fs_read(&file, buff, 8, &rn); 225 if(res != LV_FS_RES_OK || rn != 8) { 226 lv_fs_close(&file); 227 return LV_RES_INV; 228 } 229 230 if(strcmp((char *)buff, "_SJPG__") == 0) { 231 lv_fs_seek(&file, 14, LV_FS_SEEK_SET); 232 res = lv_fs_read(&file, buff, 4, &rn); 233 if(res != LV_FS_RES_OK || rn != 4) { 234 lv_fs_close(&file); 235 return LV_RES_INV; 236 } 237 header->always_zero = 0; 238 header->cf = LV_IMG_CF_RAW; 239 uint8_t * raw_sjpeg_data = buff; 240 header->w = *raw_sjpeg_data++; 241 header->w |= *raw_sjpeg_data++ << 8; 242 header->h = *raw_sjpeg_data++; 243 header->h |= *raw_sjpeg_data++ << 8; 244 lv_fs_close(&file); 245 return LV_RES_OK; 246 247 } 248 } 249 else if(strcmp(lv_fs_get_ext(fn), "jpg") == 0) { 250 lv_fs_file_t file; 251 lv_fs_res_t res = lv_fs_open(&file, fn, LV_FS_MODE_RD); 252 if(res != LV_FS_RES_OK) return 78; 253 254 uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE); 255 if(!workb_temp) { 256 lv_fs_close(&file); 257 return LV_RES_INV; 258 } 259 260 io_source_t io_source_temp; 261 io_source_temp.type = SJPEG_IO_SOURCE_DISK; 262 io_source_temp.raw_sjpg_data_next_read_pos = 0; 263 io_source_temp.img_cache_buff = NULL; 264 io_source_temp.lv_file = file; 265 JDEC jd_tmp; 266 267 JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp); 268 lv_mem_free(workb_temp); 269 lv_fs_close(&file); 270 271 if(rc == JDR_OK) { 272 header->always_zero = 0; 273 header->cf = LV_IMG_CF_RAW; 274 header->w = jd_tmp.width; 275 header->h = jd_tmp.height; 276 return LV_RES_OK; 277 } 278 } 279 } 280 return LV_RES_INV; 281 } 282 283 static int img_data_cb(JDEC * jd, void * data, JRECT * rect) 284 { 285 io_source_t * io = jd->device; 286 uint8_t * cache = io->img_cache_buff; 287 const int xres = io->img_cache_x_res; 288 uint8_t * buf = data; 289 const int INPUT_PIXEL_SIZE = 3; 290 const int row_width = rect->right - rect->left + 1; // Row width in pixels. 291 const int row_size = row_width * INPUT_PIXEL_SIZE; // Row size (bytes). 292 293 for(int y = rect->top; y <= rect->bottom; y++) { 294 int row_offset = y * xres * INPUT_PIXEL_SIZE + rect->left * INPUT_PIXEL_SIZE; 295 memcpy(cache + row_offset, buf, row_size); 296 buf += row_size; 297 } 298 299 return 1; 300 } 301 302 static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata) 303 { 304 io_source_t * io = jd->device; 305 306 if(!io) return 0; 307 308 if(io->type == SJPEG_IO_SOURCE_C_ARRAY) { 309 const uint32_t bytes_left = io->raw_sjpg_data_size - io->raw_sjpg_data_next_read_pos; 310 const uint32_t to_read = ndata <= bytes_left ? (uint32_t)ndata : bytes_left; 311 if(to_read == 0) 312 return 0; 313 if(buff) { 314 memcpy(buff, io->raw_sjpg_data + io->raw_sjpg_data_next_read_pos, to_read); 315 } 316 io->raw_sjpg_data_next_read_pos += to_read; 317 return to_read; 318 } 319 else if(io->type == SJPEG_IO_SOURCE_DISK) { 320 321 lv_fs_file_t * lv_file_p = &(io->lv_file); 322 323 if(buff) { 324 uint32_t rn = 0; 325 lv_fs_read(lv_file_p, buff, (uint32_t)ndata, &rn); 326 return rn; 327 } 328 else { 329 uint32_t pos; 330 lv_fs_tell(lv_file_p, &pos); 331 lv_fs_seek(lv_file_p, (uint32_t)(ndata + pos), LV_FS_SEEK_SET); 332 return ndata; 333 } 334 } 335 return 0; 336 } 337 338 /** 339 * Open SJPG image and return the decided image 340 * @param decoder pointer to the decoder where this function belongs 341 * @param dsc pointer to a descriptor which describes this decoding session 342 * @return LV_RES_OK: no error; LV_RES_INV: can't get the info 343 */ 344 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) 345 { 346 LV_UNUSED(decoder); 347 lv_res_t lv_ret = LV_RES_OK; 348 349 if(dsc->src_type == LV_IMG_SRC_VARIABLE) { 350 uint8_t * data; 351 SJPEG * sjpeg = (SJPEG *) dsc->user_data; 352 const uint32_t raw_sjpeg_data_size = ((lv_img_dsc_t *)dsc->src)->data_size; 353 if(sjpeg == NULL) { 354 sjpeg = lv_mem_alloc(sizeof(SJPEG)); 355 if(!sjpeg) return LV_RES_INV; 356 357 memset(sjpeg, 0, sizeof(SJPEG)); 358 359 dsc->user_data = sjpeg; 360 sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data; 361 sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size; 362 } 363 364 if(!strncmp((char *) sjpeg->sjpeg_data, "_SJPG__", strlen("_SJPG__"))) { 365 366 data = sjpeg->sjpeg_data; 367 data += 14; 368 369 sjpeg->sjpeg_x_res = *data++; 370 sjpeg->sjpeg_x_res |= *data++ << 8; 371 372 sjpeg->sjpeg_y_res = *data++; 373 sjpeg->sjpeg_y_res |= *data++ << 8; 374 375 sjpeg->sjpeg_total_frames = *data++; 376 sjpeg->sjpeg_total_frames |= *data++ << 8; 377 378 sjpeg->sjpeg_single_frame_height = *data++; 379 sjpeg->sjpeg_single_frame_height |= *data++ << 8; 380 381 sjpeg->frame_base_array = lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames); 382 if(! sjpeg->frame_base_array) { 383 lv_sjpg_cleanup(sjpeg); 384 sjpeg = NULL; 385 return LV_RES_INV; 386 } 387 388 sjpeg->frame_base_offset = NULL; 389 390 uint8_t * img_frame_base = data + sjpeg->sjpeg_total_frames * 2; 391 sjpeg->frame_base_array[0] = img_frame_base; 392 393 for(int i = 1; i < sjpeg->sjpeg_total_frames; i++) { 394 int offset = *data++; 395 offset |= *data++ << 8; 396 sjpeg->frame_base_array[i] = sjpeg->frame_base_array[i - 1] + offset; 397 } 398 sjpeg->sjpeg_cache_frame_index = -1; 399 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3/*2*/); 400 if(! sjpeg->frame_cache) { 401 lv_sjpg_cleanup(sjpeg); 402 sjpeg = NULL; 403 return LV_RES_INV; 404 } 405 sjpeg->io.img_cache_buff = sjpeg->frame_cache; 406 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res; 407 sjpeg->workb = lv_mem_alloc(TJPGD_WORKBUFF_SIZE); 408 if(! sjpeg->workb) { 409 lv_sjpg_cleanup(sjpeg); 410 sjpeg = NULL; 411 return LV_RES_INV; 412 } 413 414 sjpeg->tjpeg_jd = lv_mem_alloc(sizeof(JDEC)); 415 if(! sjpeg->tjpeg_jd) { 416 lv_sjpg_cleanup(sjpeg); 417 sjpeg = NULL; 418 return LV_RES_INV; 419 } 420 sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY; 421 sjpeg->io.lv_file.file_d = NULL; 422 dsc->img_data = NULL; 423 return lv_ret; 424 } 425 else if(is_jpg(sjpeg->sjpeg_data, raw_sjpeg_data_size) == true) { 426 427 uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE); 428 if(! workb_temp) { 429 lv_sjpg_cleanup(sjpeg); 430 sjpeg = NULL; 431 return LV_RES_INV; 432 } 433 io_source_t io_source_temp; 434 io_source_temp.type = SJPEG_IO_SOURCE_C_ARRAY; 435 io_source_temp.raw_sjpg_data = sjpeg->sjpeg_data; 436 io_source_temp.raw_sjpg_data_size = sjpeg->sjpeg_data_size; 437 io_source_temp.raw_sjpg_data_next_read_pos = 0; 438 439 JDEC jd_tmp; 440 JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp); 441 lv_mem_free(workb_temp); 442 443 444 if(rc == JDR_OK) { 445 sjpeg->sjpeg_x_res = jd_tmp.width; 446 sjpeg->sjpeg_y_res = jd_tmp.height; 447 sjpeg->sjpeg_total_frames = 1; 448 sjpeg->sjpeg_single_frame_height = jd_tmp.height; 449 450 sjpeg->frame_base_array = lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames); 451 if(! sjpeg->frame_base_array) { 452 lv_sjpg_cleanup(sjpeg); 453 sjpeg = NULL; 454 return LV_RES_INV; 455 } 456 sjpeg->frame_base_offset = NULL; 457 458 uint8_t * img_frame_base = sjpeg->sjpeg_data; 459 sjpeg->frame_base_array[0] = img_frame_base; 460 461 sjpeg->sjpeg_cache_frame_index = -1; 462 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3); 463 if(! sjpeg->frame_cache) { 464 lv_sjpg_cleanup(sjpeg); 465 sjpeg = NULL; 466 return LV_RES_INV; 467 } 468 469 sjpeg->io.img_cache_buff = sjpeg->frame_cache; 470 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res; 471 sjpeg->workb = lv_mem_alloc(TJPGD_WORKBUFF_SIZE); 472 if(! sjpeg->workb) { 473 lv_sjpg_cleanup(sjpeg); 474 sjpeg = NULL; 475 return LV_RES_INV; 476 } 477 478 sjpeg->tjpeg_jd = lv_mem_alloc(sizeof(JDEC)); 479 if(! sjpeg->tjpeg_jd) { 480 lv_sjpg_cleanup(sjpeg); 481 sjpeg = NULL; 482 return LV_RES_INV; 483 } 484 485 sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY; 486 sjpeg->io.lv_file.file_d = NULL; 487 dsc->img_data = NULL; 488 return lv_ret; 489 } 490 else { 491 lv_ret = LV_RES_INV; 492 goto end; 493 } 494 495 end: 496 lv_mem_free(workb_temp); 497 498 return lv_ret; 499 } 500 } 501 else if(dsc->src_type == LV_IMG_SRC_FILE) { 502 /* If all fine, then the file will be kept open */ 503 const char * fn = dsc->src; 504 uint8_t * data; 505 506 if(strcmp(lv_fs_get_ext(fn), "sjpg") == 0) { 507 508 uint8_t buff[22]; 509 memset(buff, 0, sizeof(buff)); 510 511 512 lv_fs_file_t lv_file; 513 lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD); 514 if(res != LV_FS_RES_OK) { 515 return 78; 516 } 517 518 519 uint32_t rn; 520 res = lv_fs_read(&lv_file, buff, 22, &rn); 521 if(res != LV_FS_RES_OK || rn != 22) { 522 lv_fs_close(&lv_file); 523 return LV_RES_INV; 524 } 525 526 if(strcmp((char *)buff, "_SJPG__") == 0) { 527 528 SJPEG * sjpeg = (SJPEG *) dsc->user_data; 529 if(sjpeg == NULL) { 530 sjpeg = lv_mem_alloc(sizeof(SJPEG)); 531 532 if(! sjpeg) { 533 lv_fs_close(&lv_file); 534 return LV_RES_INV; 535 } 536 memset(sjpeg, 0, sizeof(SJPEG)); 537 538 dsc->user_data = sjpeg; 539 sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data; 540 sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size; 541 } 542 data = buff; 543 data += 14; 544 545 sjpeg->sjpeg_x_res = *data++; 546 sjpeg->sjpeg_x_res |= *data++ << 8; 547 548 sjpeg->sjpeg_y_res = *data++; 549 sjpeg->sjpeg_y_res |= *data++ << 8; 550 551 sjpeg->sjpeg_total_frames = *data++; 552 sjpeg->sjpeg_total_frames |= *data++ << 8; 553 554 sjpeg->sjpeg_single_frame_height = *data++; 555 sjpeg->sjpeg_single_frame_height |= *data++ << 8; 556 557 sjpeg->frame_base_array = NULL;//lv_mem_alloc( sizeof(uint8_t *) * sjpeg->sjpeg_total_frames ); 558 sjpeg->frame_base_offset = lv_mem_alloc(sizeof(int) * sjpeg->sjpeg_total_frames); 559 if(! sjpeg->frame_base_offset) { 560 lv_fs_close(&lv_file); 561 lv_sjpg_cleanup(sjpeg); 562 return LV_RES_INV; 563 } 564 int img_frame_start_offset = (SJPEG_FRAME_INFO_ARRAY_OFFSET + sjpeg->sjpeg_total_frames * 2); 565 sjpeg->frame_base_offset[0] = img_frame_start_offset; //pointer used to save integer for now... 566 567 for(int i = 1; i < sjpeg->sjpeg_total_frames; i++) { 568 res = lv_fs_read(&lv_file, buff, 2, &rn); 569 if(res != LV_FS_RES_OK || rn != 2) { 570 lv_fs_close(&lv_file); 571 return LV_RES_INV; 572 } 573 574 data = buff; 575 int offset = *data++; 576 offset |= *data++ << 8; 577 sjpeg->frame_base_offset[i] = sjpeg->frame_base_offset[i - 1] + offset; 578 } 579 580 sjpeg->sjpeg_cache_frame_index = -1; //INVALID AT BEGINNING for a forced compare mismatch at first time. 581 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3); 582 if(! sjpeg->frame_cache) { 583 lv_fs_close(&lv_file); 584 lv_sjpg_cleanup(sjpeg); 585 return LV_RES_INV; 586 } 587 sjpeg->io.img_cache_buff = sjpeg->frame_cache; 588 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res; 589 sjpeg->workb = lv_mem_alloc(TJPGD_WORKBUFF_SIZE); 590 if(! sjpeg->workb) { 591 lv_fs_close(&lv_file); 592 lv_sjpg_cleanup(sjpeg); 593 return LV_RES_INV; 594 } 595 596 sjpeg->tjpeg_jd = lv_mem_alloc(sizeof(JDEC)); 597 if(! sjpeg->tjpeg_jd) { 598 lv_fs_close(&lv_file); 599 lv_sjpg_cleanup(sjpeg); 600 return LV_RES_INV; 601 } 602 603 sjpeg->io.type = SJPEG_IO_SOURCE_DISK; 604 sjpeg->io.lv_file = lv_file; 605 dsc->img_data = NULL; 606 return LV_RES_OK; 607 } 608 } 609 else if(strcmp(lv_fs_get_ext(fn), "jpg") == 0) { 610 611 lv_fs_file_t lv_file; 612 lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD); 613 if(res != LV_FS_RES_OK) { 614 return LV_RES_INV; 615 } 616 617 SJPEG * sjpeg = (SJPEG *) dsc->user_data; 618 if(sjpeg == NULL) { 619 sjpeg = lv_mem_alloc(sizeof(SJPEG)); 620 if(! sjpeg) { 621 lv_fs_close(&lv_file); 622 return LV_RES_INV; 623 } 624 625 memset(sjpeg, 0, sizeof(SJPEG)); 626 dsc->user_data = sjpeg; 627 sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data; 628 sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size; 629 } 630 631 uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE); 632 if(! workb_temp) { 633 lv_fs_close(&lv_file); 634 lv_sjpg_cleanup(sjpeg); 635 return LV_RES_INV; 636 } 637 638 io_source_t io_source_temp; 639 io_source_temp.type = SJPEG_IO_SOURCE_DISK; 640 io_source_temp.raw_sjpg_data_next_read_pos = 0; 641 io_source_temp.img_cache_buff = NULL; 642 io_source_temp.lv_file = lv_file; 643 644 JDEC jd_tmp; 645 646 JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp); 647 648 lv_mem_free(workb_temp); 649 650 651 if(rc == JDR_OK) { 652 sjpeg->sjpeg_x_res = jd_tmp.width; 653 sjpeg->sjpeg_y_res = jd_tmp.height; 654 sjpeg->sjpeg_total_frames = 1; 655 sjpeg->sjpeg_single_frame_height = jd_tmp.height; 656 657 sjpeg->frame_base_array = NULL; 658 sjpeg->frame_base_offset = lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames); 659 if(! sjpeg->frame_base_offset) { 660 lv_fs_close(&lv_file); 661 lv_sjpg_cleanup(sjpeg); 662 return LV_RES_INV; 663 } 664 665 int img_frame_start_offset = 0; 666 sjpeg->frame_base_offset[0] = img_frame_start_offset; 667 668 sjpeg->sjpeg_cache_frame_index = -1; 669 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3); 670 if(! sjpeg->frame_cache) { 671 lv_fs_close(&lv_file); 672 lv_sjpg_cleanup(sjpeg); 673 return LV_RES_INV; 674 } 675 676 sjpeg->io.img_cache_buff = sjpeg->frame_cache; 677 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res; 678 sjpeg->workb = lv_mem_alloc(TJPGD_WORKBUFF_SIZE); 679 if(! sjpeg->workb) { 680 lv_fs_close(&lv_file); 681 lv_sjpg_cleanup(sjpeg); 682 return LV_RES_INV; 683 } 684 685 sjpeg->tjpeg_jd = lv_mem_alloc(sizeof(JDEC)); 686 if(! sjpeg->tjpeg_jd) { 687 lv_fs_close(&lv_file); 688 lv_sjpg_cleanup(sjpeg); 689 return LV_RES_INV; 690 } 691 692 sjpeg->io.type = SJPEG_IO_SOURCE_DISK; 693 sjpeg->io.lv_file = lv_file; 694 dsc->img_data = NULL; 695 return LV_RES_OK; 696 697 } 698 else { 699 if(dsc->user_data) lv_mem_free(dsc->user_data); 700 lv_fs_close(&lv_file); 701 return LV_RES_INV; 702 } 703 } 704 } 705 706 return LV_RES_INV; 707 } 708 709 /** 710 * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. 711 * Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL) 712 * @param decoder pointer to the decoder the function associated with 713 * @param dsc pointer to decoder descriptor 714 * @param x start x coordinate 715 * @param y start y coordinate 716 * @param len number of pixels to decode 717 * @param buf a buffer to store the decoded pixels 718 * @return LV_RES_OK: ok; LV_RES_INV: failed 719 */ 720 721 static lv_res_t decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, 722 lv_coord_t len, uint8_t * buf) 723 { 724 LV_UNUSED(decoder); 725 if(dsc->src_type == LV_IMG_SRC_VARIABLE) { 726 SJPEG * sjpeg = (SJPEG *) dsc->user_data; 727 JRESULT rc; 728 729 int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height; 730 731 /*If line not from cache, refresh cache */ 732 if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) { 733 sjpeg->io.raw_sjpg_data = sjpeg->frame_base_array[ sjpeg_req_frame_index ]; 734 if(sjpeg_req_frame_index == (sjpeg->sjpeg_total_frames - 1)) { 735 /*This is the last frame. */ 736 const uint32_t frame_offset = (uint32_t)(sjpeg->io.raw_sjpg_data - sjpeg->sjpeg_data); 737 sjpeg->io.raw_sjpg_data_size = sjpeg->sjpeg_data_size - frame_offset; 738 } 739 else { 740 sjpeg->io.raw_sjpg_data_size = 741 (uint32_t)(sjpeg->frame_base_array[sjpeg_req_frame_index + 1] - sjpeg->io.raw_sjpg_data); 742 } 743 sjpeg->io.raw_sjpg_data_next_read_pos = 0; 744 rc = jd_prepare(sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io)); 745 if(rc != JDR_OK) return LV_RES_INV; 746 rc = jd_decomp(sjpeg->tjpeg_jd, img_data_cb, 0); 747 if(rc != JDR_OK) return LV_RES_INV; 748 sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index; 749 } 750 751 int offset = 0; 752 uint8_t * cache = (uint8_t *)sjpeg->frame_cache + x * 3 + (y % sjpeg->sjpeg_single_frame_height) * sjpeg->sjpeg_x_res * 753 3; 754 755 #if LV_COLOR_DEPTH == 32 756 for(int i = 0; i < len; i++) { 757 buf[offset + 3] = 0xff; 758 buf[offset + 2] = *cache++; 759 buf[offset + 1] = *cache++; 760 buf[offset + 0] = *cache++; 761 offset += 4; 762 } 763 764 #elif LV_COLOR_DEPTH == 16 765 766 for(int i = 0; i < len; i++) { 767 uint16_t col_16bit = (*cache++ & 0xf8) << 8; 768 col_16bit |= (*cache++ & 0xFC) << 3; 769 col_16bit |= (*cache++ >> 3); 770 #if LV_BIG_ENDIAN_SYSTEM == 1 || LV_COLOR_16_SWAP == 1 771 buf[offset++] = col_16bit >> 8; 772 buf[offset++] = col_16bit & 0xff; 773 #else 774 buf[offset++] = col_16bit & 0xff; 775 buf[offset++] = col_16bit >> 8; 776 #endif // LV_BIG_ENDIAN_SYSTEM 777 } 778 779 #elif LV_COLOR_DEPTH == 8 780 781 for(int i = 0; i < len; i++) { 782 uint8_t col_8bit = (*cache++ & 0xC0); 783 col_8bit |= (*cache++ & 0xe0) >> 2; 784 col_8bit |= (*cache++ & 0xe0) >> 5; 785 buf[offset++] = col_8bit; 786 } 787 #else 788 #error Unsupported LV_COLOR_DEPTH 789 790 791 #endif // LV_COLOR_DEPTH 792 return LV_RES_OK; 793 } 794 else if(dsc->src_type == LV_IMG_SRC_FILE) { 795 SJPEG * sjpeg = (SJPEG *) dsc->user_data; 796 JRESULT rc; 797 int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height; 798 799 lv_fs_file_t * lv_file_p = &(sjpeg->io.lv_file); 800 if(!lv_file_p) goto end; 801 802 /*If line not from cache, refresh cache */ 803 if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) { 804 sjpeg->io.raw_sjpg_data_next_read_pos = (int)(sjpeg->frame_base_offset [ sjpeg_req_frame_index ]); 805 lv_fs_seek(&(sjpeg->io.lv_file), sjpeg->io.raw_sjpg_data_next_read_pos, LV_FS_SEEK_SET); 806 807 rc = jd_prepare(sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io)); 808 if(rc != JDR_OK) return LV_RES_INV; 809 810 rc = jd_decomp(sjpeg->tjpeg_jd, img_data_cb, 0); 811 if(rc != JDR_OK) return LV_RES_INV; 812 813 sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index; 814 } 815 816 int offset = 0; 817 uint8_t * cache = (uint8_t *)sjpeg->frame_cache + x * 3 + (y % sjpeg->sjpeg_single_frame_height) * sjpeg->sjpeg_x_res * 818 3; 819 820 #if LV_COLOR_DEPTH == 32 821 for(int i = 0; i < len; i++) { 822 buf[offset + 3] = 0xff; 823 buf[offset + 2] = *cache++; 824 buf[offset + 1] = *cache++; 825 buf[offset + 0] = *cache++; 826 offset += 4; 827 } 828 #elif LV_COLOR_DEPTH == 16 829 830 for(int i = 0; i < len; i++) { 831 uint16_t col_8bit = (*cache++ & 0xf8) << 8; 832 col_8bit |= (*cache++ & 0xFC) << 3; 833 col_8bit |= (*cache++ >> 3); 834 #if LV_BIG_ENDIAN_SYSTEM == 1 || LV_COLOR_16_SWAP == 1 835 buf[offset++] = col_8bit >> 8; 836 buf[offset++] = col_8bit & 0xff; 837 #else 838 buf[offset++] = col_8bit & 0xff; 839 buf[offset++] = col_8bit >> 8; 840 #endif // LV_BIG_ENDIAN_SYSTEM 841 } 842 843 #elif LV_COLOR_DEPTH == 8 844 845 for(int i = 0; i < len; i++) { 846 uint8_t col_8bit = (*cache++ & 0xC0); 847 col_8bit |= (*cache++ & 0xe0) >> 2; 848 col_8bit |= (*cache++ & 0xe0) >> 5; 849 buf[offset++] = col_8bit; 850 } 851 852 #else 853 #error Unsupported LV_COLOR_DEPTH 854 855 856 #endif // LV_COLOR_DEPTH 857 858 return LV_RES_OK; 859 } 860 end: 861 return LV_RES_INV; 862 } 863 864 /** 865 * Free the allocated resources 866 * @param decoder pointer to the decoder where this function belongs 867 * @param dsc pointer to a descriptor which describes this decoding session 868 */ 869 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) 870 { 871 LV_UNUSED(decoder); 872 /*Free all allocated data*/ 873 SJPEG * sjpeg = (SJPEG *) dsc->user_data; 874 if(!sjpeg) return; 875 876 switch(dsc->src_type) { 877 case LV_IMG_SRC_FILE: 878 if(sjpeg->io.lv_file.file_d) { 879 lv_fs_close(&(sjpeg->io.lv_file)); 880 } 881 lv_sjpg_cleanup(sjpeg); 882 break; 883 884 case LV_IMG_SRC_VARIABLE: 885 lv_sjpg_cleanup(sjpeg); 886 break; 887 888 default: 889 ; 890 } 891 } 892 893 static int is_jpg(const uint8_t * raw_data, size_t len) 894 { 895 const uint8_t jpg_signature[] = {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46}; 896 if(len < sizeof(jpg_signature)) return false; 897 return memcmp(jpg_signature, raw_data, sizeof(jpg_signature)) == 0; 898 } 899 900 static void lv_sjpg_free(SJPEG * sjpeg) 901 { 902 if(sjpeg->frame_cache) lv_mem_free(sjpeg->frame_cache); 903 if(sjpeg->frame_base_array) lv_mem_free(sjpeg->frame_base_array); 904 if(sjpeg->frame_base_offset) lv_mem_free(sjpeg->frame_base_offset); 905 if(sjpeg->tjpeg_jd) lv_mem_free(sjpeg->tjpeg_jd); 906 if(sjpeg->workb) lv_mem_free(sjpeg->workb); 907 } 908 909 static void lv_sjpg_cleanup(SJPEG * sjpeg) 910 { 911 if(! sjpeg) return; 912 913 lv_sjpg_free(sjpeg); 914 lv_mem_free(sjpeg); 915 } 916 917 #endif /*LV_USE_SJPG*/