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*/