mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 18:35:41 +01:00 
			
		
		
		
	reduce memory usage by allocating only one histo
instead of lz77+rle
* introduce VP8LBackwardRefs structure and simplify the code by not passing
  around {PixOrCopy/int} pairs.
More functions should be turned into using this struct (TODO(later)).
Change-Id: I69c5c9fa61dddd61a2abc2824d70b8606a1c55b6
			
			
This commit is contained in:
		
				
					committed by
					
						 James Zern
						James Zern
					
				
			
			
				
	
			
			
			
						parent
						
							fbb501b8ee
						
					
				
				
					commit
					31035f3b49
				
			
							
								
								
									
										141
									
								
								src/enc/vp8l.c
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								src/enc/vp8l.c
									
									
									
									
									
								
							| @@ -165,102 +165,107 @@ static void BundleColorMap(const uint32_t* const argb, | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TODO(urvang): should be moved to backward_reference.h and used more | ||||||
|  | // as function parameters. | ||||||
|  | typedef struct { | ||||||
|  |   PixOrCopy* refs; | ||||||
|  |   int size; | ||||||
|  | } VP8LBackwardRefs; | ||||||
|  |  | ||||||
|  | static void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs) { | ||||||
|  |   if (refs != NULL) { | ||||||
|  |     refs->refs = NULL; | ||||||
|  |     refs->size = 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) { | ||||||
|  |   if (refs != NULL) { | ||||||
|  |     free(refs->refs); | ||||||
|  |     VP8LInitBackwardRefs(refs); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| static int GetBackwardReferences(int width, int height, | static int GetBackwardReferences(int width, int height, | ||||||
|                                  const uint32_t* argb, |                                  const uint32_t* argb, | ||||||
|                                  int quality, int use_color_cache, |                                  int quality, int use_color_cache, | ||||||
|                                  int cache_bits, int use_2d_locality, |                                  int cache_bits, int use_2d_locality, | ||||||
|                                  PixOrCopy** backward_refs, |                                  VP8LBackwardRefs* const best) { | ||||||
|                                  int* backward_refs_size) { |  | ||||||
|   int ok = 0; |   int ok = 0; | ||||||
|   // Backward Reference using LZ77. |  | ||||||
|   int lz77_is_useful; |   int lz77_is_useful; | ||||||
|   int backward_refs_rle_size; |   VP8LBackwardRefs refs_rle, refs_lz77; | ||||||
|   int backward_refs_lz77_size; |  | ||||||
|   const int num_pix = width * height; |   const int num_pix = width * height; | ||||||
|   VP8LHistogram* histo_rle; |   refs_rle.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_rle.refs)); | ||||||
|   PixOrCopy* backward_refs_lz77 = (PixOrCopy*) |   refs_lz77.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_lz77.refs)); | ||||||
|       malloc(num_pix * sizeof(*backward_refs_lz77)); |  | ||||||
|   PixOrCopy* backward_refs_rle = (PixOrCopy*) |   VP8LInitBackwardRefs(best); | ||||||
|       malloc(num_pix * sizeof(*backward_refs_lz77)); |   if (refs_rle.refs == NULL || refs_lz77.refs == NULL) { | ||||||
|   VP8LHistogram* histo_lz77 = (VP8LHistogram*)malloc(2 * sizeof(*histo_lz77)); |  Error1: | ||||||
|   if (backward_refs_lz77 == NULL || backward_refs_rle == NULL || |     VP8LClearBackwardRefs(&refs_rle); | ||||||
|       histo_lz77 == NULL) { |     VP8LClearBackwardRefs(&refs_lz77); | ||||||
|     free(backward_refs_lz77); |  | ||||||
|     free(backward_refs_rle); |  | ||||||
|     goto End; |     goto End; | ||||||
|   } |   } | ||||||
|   *backward_refs = NULL; |  | ||||||
|   histo_rle = histo_lz77 + 1; |  | ||||||
|  |  | ||||||
|   if (!VP8LBackwardReferencesHashChain(width, height, use_color_cache, |   if (!VP8LBackwardReferencesHashChain(width, height, use_color_cache, | ||||||
|                                        argb, cache_bits, quality, |                                        argb, cache_bits, quality, | ||||||
|                                        backward_refs_lz77, |                                        refs_lz77.refs, &refs_lz77.size)) { | ||||||
|                                        &backward_refs_lz77_size)) { |  | ||||||
|     goto End; |     goto End; | ||||||
|   } |   } | ||||||
|   VP8LHistogramInit(histo_lz77, cache_bits); |  | ||||||
|   VP8LHistogramCreate(histo_lz77, backward_refs_lz77, backward_refs_lz77_size); |  | ||||||
|  |  | ||||||
|   // Backward Reference using RLE only. |   // Backward Reference using RLE only. | ||||||
|   VP8LBackwardReferencesRle(width, height, argb, backward_refs_rle, |   VP8LBackwardReferencesRle(width, height, argb, refs_rle.refs, &refs_rle.size); | ||||||
|                             &backward_refs_rle_size); |  | ||||||
|  |  | ||||||
|   VP8LHistogramInit(histo_rle, cache_bits); |   { | ||||||
|   VP8LHistogramCreate(histo_rle, backward_refs_rle, backward_refs_rle_size); |     int bit_cost_lz77, bit_cost_rle; | ||||||
|  |     VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo)); | ||||||
|   // Check if LZ77 is useful. |     if (histo == NULL) goto Error1; | ||||||
|   lz77_is_useful = (VP8LHistogramEstimateBits(histo_rle) > |     // Evaluate lz77 coding | ||||||
|                     VP8LHistogramEstimateBits(histo_lz77)); |     VP8LHistogramInit(histo, cache_bits); | ||||||
|  |     VP8LHistogramCreate(histo, refs_lz77.refs, refs_lz77.size); | ||||||
|  |     bit_cost_lz77 = (int)VP8LHistogramEstimateBits(histo); | ||||||
|  |     // Evaluate RLE coding | ||||||
|  |     VP8LHistogramInit(histo, cache_bits); | ||||||
|  |     VP8LHistogramCreate(histo, refs_rle.refs, refs_rle.size); | ||||||
|  |     bit_cost_rle = (int)VP8LHistogramEstimateBits(histo); | ||||||
|  |     // Decide if LZ77 is useful. | ||||||
|  |     lz77_is_useful = (bit_cost_lz77 < bit_cost_rle); | ||||||
|  |     free(histo); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // Choose appropriate backward reference. |   // Choose appropriate backward reference. | ||||||
|   if (lz77_is_useful) { |   if (lz77_is_useful) { | ||||||
|     // TraceBackwards is costly. Run it for higher qualities. |     // TraceBackwards is costly. Run it for higher qualities. | ||||||
|     const int try_lz77_trace_backwards = (quality >= 75); |     const int try_lz77_trace_backwards = (quality >= 75); | ||||||
|     free(backward_refs_rle); |     *best = refs_lz77;   // default guess: lz77 is better | ||||||
|  |     VP8LClearBackwardRefs(&refs_rle); | ||||||
|     if (try_lz77_trace_backwards) { |     if (try_lz77_trace_backwards) { | ||||||
|       const int recursion_level = (num_pix < 320 * 200) ? 1 : 0; |       const int recursion_level = (num_pix < 320 * 200) ? 1 : 0; | ||||||
|       int backward_refs_trace_size; |       VP8LBackwardRefs refs_trace; | ||||||
|       PixOrCopy* backward_refs_trace; |       refs_trace.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_trace.refs)); | ||||||
|       backward_refs_trace = |       if (refs_trace.refs == NULL) { | ||||||
|           (PixOrCopy*)malloc(num_pix * sizeof(*backward_refs_trace)); |  | ||||||
|       if (backward_refs_trace == NULL) { |  | ||||||
|         free(backward_refs_lz77); |  | ||||||
|         goto End; |         goto End; | ||||||
|       } |       } | ||||||
|       if (VP8LBackwardReferencesTraceBackwards(width, height, recursion_level, |       if (VP8LBackwardReferencesTraceBackwards(width, height, recursion_level, | ||||||
|                                                use_color_cache, argb, |                                                use_color_cache, | ||||||
|                                                cache_bits, backward_refs_trace, |                                                argb, cache_bits, | ||||||
|                                                &backward_refs_trace_size)) { |                                                refs_trace.refs, | ||||||
|         free(backward_refs_lz77); |                                                &refs_trace.size)) { | ||||||
|         *backward_refs = backward_refs_trace; |         VP8LClearBackwardRefs(&refs_lz77); | ||||||
|         *backward_refs_size = backward_refs_trace_size; |         *best = refs_trace; | ||||||
|       } else { |       } | ||||||
|         free(backward_refs_trace); |  | ||||||
|         *backward_refs = backward_refs_lz77; |  | ||||||
|         *backward_refs_size = backward_refs_lz77_size; |  | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|       *backward_refs = backward_refs_lz77; |     VP8LClearBackwardRefs(&refs_lz77); | ||||||
|       *backward_refs_size = backward_refs_lz77_size; |     *best = refs_rle; | ||||||
|     } |  | ||||||
|   } else { |  | ||||||
|     free(backward_refs_lz77); |  | ||||||
|     *backward_refs = backward_refs_rle; |  | ||||||
|     *backward_refs_size = backward_refs_rle_size; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (use_2d_locality) { |   if (use_2d_locality) {  // Use backward reference with 2D locality. | ||||||
|     // Use backward reference with 2D locality. |     VP8LBackwardReferences2DLocality(width, best->size, best->refs); | ||||||
|     VP8LBackwardReferences2DLocality(width, *backward_refs_size, |  | ||||||
|                                      *backward_refs); |  | ||||||
|   } |   } | ||||||
|   ok = 1; |   ok = 1; | ||||||
|  |  | ||||||
| End: | End: | ||||||
|   free(histo_lz77); |  | ||||||
|   if (!ok) { |   if (!ok) { | ||||||
|     free(*backward_refs); |     VP8LClearBackwardRefs(best); | ||||||
|     *backward_refs = NULL; |  | ||||||
|   } |   } | ||||||
|   return ok; |   return ok; | ||||||
| } | } | ||||||
| @@ -739,13 +744,12 @@ static int EncodeImageInternal(VP8LBitWriter* const bw, | |||||||
|   uint8_t** bit_lengths = NULL; |   uint8_t** bit_lengths = NULL; | ||||||
|   uint16_t** bit_codes = NULL; |   uint16_t** bit_codes = NULL; | ||||||
|   const int use_2d_locality = 1; |   const int use_2d_locality = 1; | ||||||
|   int backward_refs_size; |  | ||||||
|   const int use_color_cache = (cache_bits > 0); |   const int use_color_cache = (cache_bits > 0); | ||||||
|   const int color_cache_size = use_color_cache ? (1 << cache_bits) : 0; |   const int color_cache_size = use_color_cache ? (1 << cache_bits) : 0; | ||||||
|   const int histogram_image_xysize = VP8LSubSampleSize(width, histogram_bits) * |   const int histogram_image_xysize = VP8LSubSampleSize(width, histogram_bits) * | ||||||
|       VP8LSubSampleSize(height, histogram_bits); |       VP8LSubSampleSize(height, histogram_bits); | ||||||
|   VP8LHistogram** histogram_image; |   VP8LHistogram** histogram_image; | ||||||
|   PixOrCopy* backward_refs; |   VP8LBackwardRefs refs; | ||||||
|   const size_t histo_size = histogram_image_xysize * sizeof(uint32_t); |   const size_t histo_size = histogram_image_xysize * sizeof(uint32_t); | ||||||
|   uint32_t* const histogram_symbols = (uint32_t*)calloc(1, histo_size); |   uint32_t* const histogram_symbols = (uint32_t*)calloc(1, histo_size); | ||||||
|  |  | ||||||
| @@ -754,11 +758,11 @@ static int EncodeImageInternal(VP8LBitWriter* const bw, | |||||||
|   // Calculate backward references from ARGB image. |   // Calculate backward references from ARGB image. | ||||||
|   if (!GetBackwardReferences(width, height, argb, quality, |   if (!GetBackwardReferences(width, height, argb, quality, | ||||||
|                              use_color_cache, cache_bits, use_2d_locality, |                              use_color_cache, cache_bits, use_2d_locality, | ||||||
|                              &backward_refs, &backward_refs_size)) { |                              &refs)) { | ||||||
|     goto Error; |     goto Error; | ||||||
|   } |   } | ||||||
|   // Build histogram image & symbols from backward references. |   // Build histogram image & symbols from backward references. | ||||||
|   if (!GetHistImageSymbols(width, height, backward_refs, backward_refs_size, |   if (!GetHistImageSymbols(width, height, refs.refs, refs.size, | ||||||
|                            quality, histogram_bits, cache_bits, |                            quality, histogram_bits, cache_bits, | ||||||
|                            &histogram_image, &histogram_image_size, |                            &histogram_image, &histogram_image_size, | ||||||
|                            histogram_symbols)) { |                            histogram_symbols)) { | ||||||
| @@ -834,16 +838,15 @@ static int EncodeImageInternal(VP8LBitWriter* const bw, | |||||||
|                                     bit_codes[i]); |                                     bit_codes[i]); | ||||||
|   } |   } | ||||||
|   // Store actual literals. |   // Store actual literals. | ||||||
|   StoreImageToBitMask(bw, width, histogram_bits, backward_refs, |   StoreImageToBitMask(bw, width, histogram_bits, refs.refs, refs.size, | ||||||
|                       backward_refs_size, histogram_symbols, |                       histogram_symbols, bit_lengths, bit_codes); | ||||||
|                       bit_lengths, bit_codes); |  | ||||||
|   ok = 1; |   ok = 1; | ||||||
|  |  | ||||||
|  Error: |  Error: | ||||||
|   if (!ok) { |   if (!ok) { | ||||||
|     DeleteHistograms(histogram_image, histogram_image_size); |     DeleteHistograms(histogram_image, histogram_image_size); | ||||||
|   } |   } | ||||||
|   free(backward_refs); |   VP8LClearBackwardRefs(&refs); | ||||||
|   for (i = 0; i < 5 * histogram_image_size; ++i) { |   for (i = 0; i < 5 * histogram_image_size; ++i) { | ||||||
|     free(bit_lengths[i]); |     free(bit_lengths[i]); | ||||||
|     free(bit_codes[i]); |     free(bit_codes[i]); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user