mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 10:25:46 +01:00 
			
		
		
		
	make the token page size be variable instead of fixed 8192
also changed the token-page layout a little bit to remove a not-needed field. This reduces the number of malloc()/free() calls substantially with minimal increase in memory consumption (~2%). For the tail of large sources, the number of malloc calls goes typically from ~10000 to ~100 (e.g.: bryce_big.jpg: 22711 -> 105) Change-Id: Ib847f41e618ed8c303d26b76da982fbc48de45b9
This commit is contained in:
		| @@ -27,23 +27,27 @@ | ||||
| #if !defined(DISABLE_TOKEN_BUFFER) | ||||
|  | ||||
| // we use pages to reduce the number of memcpy() | ||||
| #define MAX_NUM_TOKEN 8192          // max number of token per page | ||||
| #define MIN_PAGE_SIZE 8192          // minimum number of token per page | ||||
| #define FIXED_PROBA_BIT (1u << 14) | ||||
|  | ||||
| typedef uint16_t token_t;  // bit#15: bit | ||||
|                            // bit #14: constant proba or idx | ||||
|                            // bits 0..13: slot or constant proba | ||||
| struct VP8Tokens { | ||||
|   uint16_t tokens_[MAX_NUM_TOKEN];  // bit#15: bit | ||||
|                                     // bit #14: constant proba or idx | ||||
|                                     // bits 0..13: slot or constant proba | ||||
|   VP8Tokens* next_; | ||||
|   VP8Tokens* next_;        // pointer to next page | ||||
| }; | ||||
| // Token data is located in memory just after the next_ field. | ||||
| // This macro is used to return their address and hide the trick. | ||||
| #define TOKEN_DATA(p) ((token_t*)&(p)[1]) | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| void VP8TBufferInit(VP8TBuffer* const b) { | ||||
| void VP8TBufferInit(VP8TBuffer* const b, int page_size) { | ||||
|   b->tokens_ = NULL; | ||||
|   b->pages_ = NULL; | ||||
|   b->last_page_ = &b->pages_; | ||||
|   b->left_ = 0; | ||||
|   b->page_size_ = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size; | ||||
|   b->error_ = 0; | ||||
| } | ||||
|  | ||||
| @@ -55,22 +59,26 @@ void VP8TBufferClear(VP8TBuffer* const b) { | ||||
|       WebPSafeFree((void*)p); | ||||
|       p = next; | ||||
|     } | ||||
|     VP8TBufferInit(b); | ||||
|     VP8TBufferInit(b, b->page_size_); | ||||
|   } | ||||
| } | ||||
|  | ||||
| static int TBufferNewPage(VP8TBuffer* const b) { | ||||
|   VP8Tokens* const page = | ||||
|       b->error_ ? NULL : (VP8Tokens*)WebPSafeMalloc(1ULL, sizeof(*page)); | ||||
|   VP8Tokens* page = NULL; | ||||
|   const size_t size = sizeof(*page) + b->page_size_ * sizeof(token_t); | ||||
|   if (!b->error_) { | ||||
|     page = (VP8Tokens*)WebPSafeMalloc(1ULL, size); | ||||
|   } | ||||
|   if (page == NULL) { | ||||
|     b->error_ = 1; | ||||
|     return 0; | ||||
|   } | ||||
|   page->next_ = NULL; | ||||
|  | ||||
|   *b->last_page_ = page; | ||||
|   b->last_page_ = &page->next_; | ||||
|   b->left_ = MAX_NUM_TOKEN; | ||||
|   b->tokens_ = page->tokens_; | ||||
|   page->next_ = NULL; | ||||
|   b->left_ = b->page_size_; | ||||
|   b->tokens_ = TOKEN_DATA(page); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| @@ -197,8 +205,9 @@ void VP8TokenToStats(const VP8TBuffer* const b, proba_t* const stats) { | ||||
|   while (p != NULL) { | ||||
|     const int N = (p->next_ == NULL) ? b->left_ : 0; | ||||
|     int n = MAX_NUM_TOKEN; | ||||
|     const token_t* const tokens = TOKEN_DATA(p); | ||||
|     while (n-- > N) { | ||||
|       const uint16_t token = p->tokens_[n]; | ||||
|       const token_t token = tokens[n]; | ||||
|       if (!(token & FIXED_PROBA_BIT)) { | ||||
|         Record((token >> 15) & 1, stats + (token & 0x3fffu)); | ||||
|       } | ||||
| @@ -220,9 +229,10 @@ int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw, | ||||
|   while (p != NULL) { | ||||
|     const VP8Tokens* const next = p->next_; | ||||
|     const int N = (next == NULL) ? b->left_ : 0; | ||||
|     int n = MAX_NUM_TOKEN; | ||||
|     int n = b->page_size_; | ||||
|     const token_t* const tokens = TOKEN_DATA(p); | ||||
|     while (n-- > N) { | ||||
|       const uint16_t token = p->tokens_[n]; | ||||
|       const token_t token = tokens[n]; | ||||
|       const int bit = (token >> 15) & 1; | ||||
|       if (token & FIXED_PROBA_BIT) { | ||||
|         VP8PutBit(bw, bit, token & 0xffu);  // constant proba | ||||
| @@ -245,9 +255,10 @@ size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) { | ||||
|   while (p != NULL) { | ||||
|     const VP8Tokens* const next = p->next_; | ||||
|     const int N = (next == NULL) ? b->left_ : 0; | ||||
|     int n = MAX_NUM_TOKEN; | ||||
|     int n = b->page_size_; | ||||
|     const token_t* const tokens = TOKEN_DATA(p); | ||||
|     while (n-- > N) { | ||||
|       const uint16_t token = p->tokens_[n]; | ||||
|       const token_t token = tokens[n]; | ||||
|       const int bit = token & (1 << 15); | ||||
|       if (token & FIXED_PROBA_BIT) { | ||||
|         size += VP8BitCost(bit, token & 0xffu); | ||||
|   | ||||
| @@ -363,12 +363,14 @@ typedef struct { | ||||
|   VP8Tokens* pages_;        // first page | ||||
|   VP8Tokens** last_page_;   // last page | ||||
|   uint16_t* tokens_;        // set to (*last_page_)->tokens_ | ||||
|   int left_;          // how many free tokens left before the page is full. | ||||
|   int left_;                // how many free tokens left before the page is full | ||||
|   int page_size_;           // number of tokens per page | ||||
| #endif | ||||
|   int error_;         // true in case of malloc error | ||||
| } VP8TBuffer; | ||||
|  | ||||
| void VP8TBufferInit(VP8TBuffer* const b);    // initialize an empty buffer | ||||
| // initialize an empty buffer | ||||
| void VP8TBufferInit(VP8TBuffer* const b, int page_size); | ||||
| void VP8TBufferClear(VP8TBuffer* const b);   // de-allocate pages memory | ||||
|  | ||||
| #if !defined(DISABLE_TOKEN_BUFFER) | ||||
|   | ||||
| @@ -258,7 +258,12 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config, | ||||
|   VP8EncInitLayer(enc); | ||||
| #endif | ||||
|  | ||||
|   VP8TBufferInit(&enc->tokens_); | ||||
|   // lower quality means smaller output -> we modulate a little the page | ||||
|   // size based on quality. This is just a crude 1rst-order prediction. | ||||
|   { | ||||
|     const float scale = 1.f + config->quality * 5.f / 100.f;  // in [1,6] | ||||
|     VP8TBufferInit(&enc->tokens_, (int)(mb_w * mb_h * 4 * scale)); | ||||
|   } | ||||
|   return enc; | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user