diff --git a/Kconfig b/Kconfig index abace5098a..bcc5f5488a 100644 --- a/Kconfig +++ b/Kconfig @@ -1113,6 +1113,11 @@ menu "LVGL configuration" config LV_USE_GIF bool "GIF decoder library" + if LV_USE_GIF + config LV_GIF_CACHE_DECODE_DATA + bool "Use extra 16KB RAM to cache decoded data to accerlate" + endif + config LV_USE_RLE bool "RLE compressed bin image decoder library" diff --git a/lv_conf_template.h b/lv_conf_template.h index 5cd9611a9b..90becd27ae 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -614,6 +614,11 @@ /*GIF decoder library*/ #define LV_USE_GIF 0 +#if LV_USE_GIF +/*GIF decoder accelerate*/ +#define LV_GIF_CACHE_DECODE_DATA 0 +#endif + /*Decode bin images to RAM*/ #define LV_BIN_DECODER_RAM_LOAD 0 diff --git a/src/libs/gif/gifdec.c b/src/libs/gif/gifdec.c index ee347ca45f..4d53dcca70 100644 --- a/src/libs/gif/gifdec.c +++ b/src/libs/gif/gifdec.c @@ -23,6 +23,12 @@ typedef struct Table { Entry * entries; } Table; +#if LV_GIF_CACHE_DECODE_DATA +#define LZW_MAXBITS 12 +#define LZW_TABLE_SIZE (1 << LZW_MAXBITS) +#define LZW_CACHE_SIZE (LZW_TABLE_SIZE * 4) +#endif + static gd_GIF * gif_open(gd_GIF * gif); static bool f_gif_open(gd_GIF * gif, const void * path, bool is_file); static void f_gif_read(gd_GIF * gif, void * buf, size_t len); @@ -107,8 +113,11 @@ static gd_GIF * gif_open(gd_GIF * gif_base) /* Aspect Ratio */ f_gif_read(gif_base, &aspect, 1); /* Create gd_GIF Structure. */ +#if LV_GIF_CACHE_DECODE_DATA + gif = lv_malloc(sizeof(gd_GIF) + 5 * width * height + LZW_CACHE_SIZE); + #else gif = lv_malloc(sizeof(gd_GIF) + 5 * width * height); - + #endif if(!gif) goto fail; memcpy(gif, gif_base, sizeof(gd_GIF)); gif->width = width; @@ -125,6 +134,9 @@ static gd_GIF * gif_open(gd_GIF * gif_base) memset(gif->frame, gif->bgindex, gif->width * gif->height); } bgcolor = &gif->palette->colors[gif->bgindex * 3]; + #if LV_GIF_CACHE_DECODE_DATA + gif->lzw_cache = gif->frame + width * height; + #endif #ifdef GIFDEC_FILL_BG GIFDEC_FILL_BG(gif->canvas, gif->width * gif->height, 1, gif->width * gif->height, bgcolor, 0xff); @@ -276,6 +288,177 @@ read_ext(gd_GIF * gif) } } +static uint16_t +get_key(gd_GIF *gif, int key_size, uint8_t *sub_len, uint8_t *shift, uint8_t *byte) +{ + int bits_read; + int rpad; + int frag_size; + uint16_t key; + + key = 0; + for (bits_read = 0; bits_read < key_size; bits_read += frag_size) { + rpad = (*shift + bits_read) % 8; + if (rpad == 0) { + /* Update byte. */ + if (*sub_len == 0) { + f_gif_read(gif, sub_len, 1); /* Must be nonzero! */ + if (*sub_len == 0) return 0x1000; + } + f_gif_read(gif, byte, 1); + (*sub_len)--; + } + frag_size = MIN(key_size - bits_read, 8 - rpad); + key |= ((uint16_t) ((*byte) >> rpad)) << bits_read; + } + /* Clear extra bits to the left. */ + key &= (1 << key_size) - 1; + *shift = (*shift + key_size) % 8; + return key; +} + +#if LV_GIF_CACHE_DECODE_DATA +static int +read_image_data(gd_GIF *gif, int interlace) +{ + uint8_t sub_len, shift, byte; + int ret = 0; + int key_size; + int y, pass, linesize; + uint8_t *ptr = NULL; + uint8_t *ptr_init = NULL; + size_t start, end; + uint16_t key, clear_code, stop_code, curr_code; + int frm_off, frm_size,curr_size,top_slot,new_codes,slot; + /* The first value of the value sequence corresponding to key */ + int first_value; + int last_key; + uint8_t *sp = NULL; + uint8_t *p_stack = NULL; + uint8_t *p_suffix = NULL; + uint16_t *p_prefix = NULL; + + /* get initial key size and clear code, stop code */ + f_gif_read(gif, &byte, 1); + key_size = (int) byte; + clear_code = 1 << key_size; + stop_code = clear_code + 1; + key = 0; + + start = f_gif_seek(gif, 0, LV_FS_SEEK_CUR); + discard_sub_blocks(gif); + end = f_gif_seek(gif, 0, LV_FS_SEEK_CUR); + f_gif_seek(gif, start, LV_FS_SEEK_SET); + + linesize = gif->width; + ptr_init = &gif->frame[gif->fy * linesize + gif->fx]; + ptr = ptr_init; + sub_len = shift = 0; + /* decoder */ + pass = 0; + y = 0; + p_stack = gif->lzw_cache; + p_suffix = gif->lzw_cache + LZW_TABLE_SIZE; + p_prefix = (uint16_t*)(gif->lzw_cache + LZW_TABLE_SIZE * 2); + frm_off = 0; + frm_size = gif->fw * gif->fh; + curr_size = key_size + 1; + top_slot = 1 << curr_size; + new_codes = clear_code + 2; + slot = new_codes; + first_value = -1; + last_key = -1; + sp = p_stack; + + while (frm_off < frm_size) { + /* copy data to frame buffer */ + while (sp > p_stack) { + *ptr++ = *(--sp); + frm_off += 1; + /* read one line */ + if ((ptr - ptr_init) == gif->fw) { + if (interlace) { + switch(pass) { + case 0: + case 1: + y += 8; + ptr_init += linesize * 8; + break; + case 2: + y += 4; + ptr_init += linesize * 4; + break; + case 3: + y += 2; + ptr_init += linesize * 2; + break; + default: + break; + } + while (y >= gif->fh) { + y = 4 >> pass; + ptr_init = ptr_init + linesize * y; + pass++; + } + } else { + ptr_init += linesize; + } + ptr = ptr_init; + } + } + + key = get_key(gif, curr_size, &sub_len, &shift, &byte); + + if (key == stop_code || key >= LZW_TABLE_SIZE) + break; + + if (key == clear_code) { + curr_size = key_size + 1; + slot = new_codes; + top_slot = 1 << curr_size; + first_value = last_key = -1; + sp = p_stack; + continue; + } + + curr_code = key; + /* + * If the current code is a code that will be added to the decoding + * dictionary, it is composed of the data list corresponding to the + * previous key and its first data. + * */ + if (curr_code == slot && first_value >= 0) { + *sp++ = first_value; + curr_code = last_key; + }else if(curr_code >= slot) + break; + + while (curr_code >= new_codes) { + *sp++ = p_suffix[curr_code]; + curr_code = p_prefix[curr_code]; + } + *sp++ = curr_code; + + /* Add code to decoding dictionary */ + if (slot < top_slot && last_key >= 0) { + p_suffix[slot] = curr_code; + p_prefix[slot++] = last_key; + } + first_value = curr_code; + last_key = key; + if (slot >= top_slot) { + if (curr_size < LZW_MAXBITS) { + top_slot <<= 1; + curr_size += 1; + } + } + } + + if (key == stop_code) f_gif_read(gif, &sub_len, 1); /* Must be zero! */ + f_gif_seek(gif, end, LV_FS_SEEK_SET); + return ret; +} +#else static Table * new_table(int key_size) { @@ -318,35 +501,6 @@ add_entry(Table ** tablep, uint16_t length, uint16_t prefix, uint8_t suffix) return 0; } -static uint16_t -get_key(gd_GIF * gif, int key_size, uint8_t * sub_len, uint8_t * shift, uint8_t * byte) -{ - int bits_read; - int rpad; - int frag_size; - uint16_t key; - - key = 0; - for(bits_read = 0; bits_read < key_size; bits_read += frag_size) { - rpad = (*shift + bits_read) % 8; - if(rpad == 0) { - /* Update byte. */ - if(*sub_len == 0) { - f_gif_read(gif, sub_len, 1); /* Must be nonzero! */ - if(*sub_len == 0) return 0x1000; - } - f_gif_read(gif, byte, 1); - (*sub_len)--; - } - frag_size = MIN(key_size - bits_read, 8 - rpad); - key |= ((uint16_t)((*byte) >> rpad)) << bits_read; - } - /* Clear extra bits to the left. */ - key &= (1 << key_size) - 1; - *shift = (*shift + key_size) % 8; - return key; -} - /* Compute output index of y-th input line, in frame of height h. */ static int interlaced_line_index(int h, int y) @@ -444,6 +598,8 @@ read_image_data(gd_GIF * gif, int interlace) return 0; } +#endif + /* Read image. * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */ static int diff --git a/src/libs/gif/gifdec.h b/src/libs/gif/gifdec.h index 3383266221..71cb9ffbfb 100644 --- a/src/libs/gif/gifdec.h +++ b/src/libs/gif/gifdec.h @@ -43,6 +43,9 @@ typedef struct _gd_GIF { uint16_t fx, fy, fw, fh; uint8_t bgindex; uint8_t * canvas, * frame; + #if LV_GIF_CACHE_DECODE_DATA + uint8_t *lzw_cache; + #endif } gd_GIF; gd_GIF * gd_open_gif_file(const char * fname); diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 9811fefcd0..f6575338c3 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -2050,6 +2050,17 @@ #define LV_USE_GIF 0 #endif #endif +#if LV_USE_GIF +/*GIF decoder accelerate*/ +#ifndef LV_GIF_CACHE_DECODE_DATA + #ifdef CONFIG_LV_GIF_CACHE_DECODE_DATA + #define LV_GIF_CACHE_DECODE_DATA CONFIG_LV_GIF_CACHE_DECODE_DATA + #else + #define LV_GIF_CACHE_DECODE_DATA 0 + #endif +#endif +#endif + /*Decode bin images to RAM*/ #ifndef LV_BIN_DECODER_RAM_LOAD