mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 02:15:42 +01:00 
			
		
		
		
	~1% improvement of alpha compression
by packing the symbol map more efficiently. This is mainly useful in making it harder to generate invalid bitstream: before this change, one could code the same symbol twice. Now, it's impossible, since we code the position using empty symbol slots, instead of total position. * Fix the HasOnlyLeftChild() naming while at it. Change-Id: I63c56c80a4f04a86ac83eded1e3306329815b6c9
This commit is contained in:
		
				
					committed by
					
						 James Zern
						James Zern
					
				
			
			
				
	
			
			
			
						parent
						
							3bc1b14191
						
					
				
				
					commit
					0a7102ba60
				
			| @@ -188,8 +188,8 @@ static WEBP_INLINE int IsLeaf(const TCoder* const c, int pos) { | |||||||
|   return (2 * pos > c->num_symbols_); |   return (2 * pos > c->num_symbols_); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Returns true if node has no child. | // Returns true if node has no right child. | ||||||
| static WEBP_INLINE int HasOnlyRightChild(const TCoder* const c, int pos) { | static WEBP_INLINE int HasOnlyLeftChild(const TCoder* const c, int pos) { | ||||||
|   return (2 * pos == c->num_symbols_); |   return (2 * pos == c->num_symbols_); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -202,6 +202,8 @@ static int NewNode(TCoder* const c, int s) { | |||||||
|   const int pos = 1 + c->num_symbols_; |   const int pos = 1 + c->num_symbols_; | ||||||
|   assert(c); |   assert(c); | ||||||
|   assert(c->num_symbols_ < c->num_nodes_); |   assert(c->num_symbols_ < c->num_nodes_); | ||||||
|  |   assert(c->symbols_[s] == INVALID_POS); | ||||||
|  |   assert(c->nodes_[pos].symbol_ == INVALID_SYMBOL); | ||||||
|   c->symbols_[s] = pos; |   c->symbols_[s] = pos; | ||||||
|   ResetNode(&c->nodes_[pos], s); |   ResetNode(&c->nodes_[pos], s); | ||||||
|   ++c->num_symbols_; |   ++c->num_symbols_; | ||||||
| @@ -319,6 +321,7 @@ static WEBP_INLINE void CodeSymbol(VP8BitWriter* const bw, int s, | |||||||
|                                    int max_value) { |                                    int max_value) { | ||||||
|   int i, up = 1; |   int i, up = 1; | ||||||
|   assert(bw); |   assert(bw); | ||||||
|  |   assert(s < max_value); | ||||||
|   for (i = 0; up < max_value; up <<= 1, ++i) { |   for (i = 0; up < max_value; up <<= 1, ++i) { | ||||||
|     int den = (max_value >> 1) & ~(up - 1); |     int den = (max_value >> 1) & ~(up - 1); | ||||||
|     if (max_value & up) den |= max_value & (up - 1); |     if (max_value & up) den |= max_value & (up - 1); | ||||||
| @@ -361,7 +364,11 @@ void TCoderEncode(TCoder* const c, int s, VP8BitWriter* const bw) { | |||||||
|   } |   } | ||||||
|   if (is_new_symbol) { |   if (is_new_symbol) { | ||||||
|     if (bw != NULL) { |     if (bw != NULL) { | ||||||
|       CodeSymbol(bw, s, c->num_nodes_); |       int k, count = 0; | ||||||
|  |       for (k = 0; k < s; ++k) { | ||||||
|  |         count += (c->symbols_[k] == INVALID_POS); | ||||||
|  |       } | ||||||
|  |       CodeSymbol(bw, count, c->num_nodes_ - c->num_symbols_); | ||||||
|     } |     } | ||||||
|     pos = NewNode(c, s); |     pos = NewNode(c, s); | ||||||
|   } else { |   } else { | ||||||
| @@ -376,7 +383,7 @@ void TCoderEncode(TCoder* const c, int s, VP8BitWriter* const bw) { | |||||||
|         const int is_stop = (i == length); |         const int is_stop = (i == length); | ||||||
|         if (VP8PutBit(bw, is_stop, symbol_proba)) { |         if (VP8PutBit(bw, is_stop, symbol_proba)) { | ||||||
|           break; |           break; | ||||||
|         } else if (!HasOnlyRightChild(c, parent)) { |         } else if (!HasOnlyLeftChild(c, parent)) { | ||||||
|           const int left_proba = node->probaL_; |           const int left_proba = node->probaL_; | ||||||
|           const int is_right = |           const int is_right = | ||||||
|               (pos >> (length - 1 - i)) & 1;  // extract bits #i |               (pos >> (length - 1 - i)) & 1;  // extract bits #i | ||||||
| @@ -414,10 +421,16 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) { | |||||||
|   } |   } | ||||||
|   // Code either the raw value, or the path downward to its node. |   // Code either the raw value, or the path downward to its node. | ||||||
|   if (is_new_symbol) { |   if (is_new_symbol) { | ||||||
|     s = DecodeSymbol(br, c->num_nodes_); |     int count = DecodeSymbol(br, c->num_nodes_ - c->num_symbols_); | ||||||
|     if (s >= c->num_nodes_) { |     // The 'count' value specifies the number of empty slots to jump | ||||||
|       br->eof_ = 1;   // will make decoding abort. |     // over. We skip the already-used ones. | ||||||
|       return 0; |     for (s = 0; s < c->num_nodes_; ++s) { | ||||||
|  |       if (c->symbols_[s] == INVALID_POS) { | ||||||
|  |         if (count-- == 0) break; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if (s == c->num_nodes_) { | ||||||
|  |       goto Error; | ||||||
|     } |     } | ||||||
|     pos = NewNode(c, s); |     pos = NewNode(c, s); | ||||||
|   } else { |   } else { | ||||||
| @@ -431,7 +444,7 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) { | |||||||
|         break;  // reached the stopping node for the coded symbol. |         break;  // reached the stopping node for the coded symbol. | ||||||
|       } else { |       } else { | ||||||
|         // Not yet done, keep traversing and branching. |         // Not yet done, keep traversing and branching. | ||||||
|         if (!HasOnlyRightChild(c, pos)) { |         if (!HasOnlyLeftChild(c, pos)) { | ||||||
|           const int left_proba = node->probaL_; |           const int left_proba = node->probaL_; | ||||||
|           const int is_right = VP8GetBit(br, left_proba); |           const int is_right = VP8GetBit(br, left_proba); | ||||||
|           pos = (pos << 1) | is_right; |           pos = (pos << 1) | is_right; | ||||||
| @@ -442,12 +455,17 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) { | |||||||
|         assert(pos <= c->num_nodes_); |         assert(pos <= c->num_nodes_); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |     assert(pos <= c->num_symbols_); | ||||||
|     s = c->nodes_[pos].symbol_; |     s = c->nodes_[pos].symbol_; | ||||||
|     assert(pos == SymbolToNode(c, s)); |     assert(pos == SymbolToNode(c, s)); | ||||||
|   } |   } | ||||||
|   assert(pos <= c->num_nodes_); |   assert(pos <= c->num_symbols_); | ||||||
|   UpdateTree(c, pos); |   UpdateTree(c, pos); | ||||||
|   return s; |   return s; | ||||||
|  |  | ||||||
|  |  Error: | ||||||
|  |   br->eof_ = 1;   // will make decoding abort. | ||||||
|  |   return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| // ----------------------------------------------------------------------------- | // ----------------------------------------------------------------------------- | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user