mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 10:25:46 +01:00 
			
		
		
		
	Implement a cruncher for lossless at method 6.
Go over the whole compression step for each of the transforms and pick the best one. Change-Id: I3a1b1458348c468558be0fcf491038a5724c9364
This commit is contained in:
		| @@ -128,7 +128,10 @@ static int AnalyzeAndCreatePalette(const WebPPicture* const pic, | |||||||
|                                    uint32_t palette[MAX_PALETTE_SIZE], |                                    uint32_t palette[MAX_PALETTE_SIZE], | ||||||
|                                    int* const palette_size) { |                                    int* const palette_size) { | ||||||
|   const int num_colors = WebPGetColorPalette(pic, palette); |   const int num_colors = WebPGetColorPalette(pic, palette); | ||||||
|   if (num_colors > MAX_PALETTE_SIZE) return 0; |   if (num_colors > MAX_PALETTE_SIZE) { | ||||||
|  |     *palette_size = 0; | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|   *palette_size = num_colors; |   *palette_size = num_colors; | ||||||
|   qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort); |   qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort); | ||||||
|   if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) { |   if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) { | ||||||
| @@ -353,7 +356,10 @@ static int GetTransformBits(int method, int histo_bits) { | |||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int AnalyzeAndInit(VP8LEncoder* const enc) { | static int AnalyzeAndInit(VP8LEncoder* const enc, | ||||||
|  |                           int entropy_idx[kNumEntropyIx], | ||||||
|  |                           int* const num_entropy_idx, | ||||||
|  |                           int* const red_and_blue_always_zero) { | ||||||
|   const WebPPicture* const pic = enc->pic_; |   const WebPPicture* const pic = enc->pic_; | ||||||
|   const int width = pic->width; |   const int width = pic->width; | ||||||
|   const int height = pic->height; |   const int height = pic->height; | ||||||
| @@ -365,48 +371,48 @@ static int AnalyzeAndInit(VP8LEncoder* const enc) { | |||||||
|   // at max MAX_REFS_BLOCK_PER_IMAGE blocks used: |   // at max MAX_REFS_BLOCK_PER_IMAGE blocks used: | ||||||
|   int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1; |   int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1; | ||||||
|   int i; |   int i; | ||||||
|  |   int use_palette; | ||||||
|   assert(pic != NULL && pic->argb != NULL); |   assert(pic != NULL && pic->argb != NULL); | ||||||
|  |  | ||||||
|   enc->use_cross_color_ = 0; |   use_palette = | ||||||
|   enc->use_predict_ = 0; |  | ||||||
|   enc->use_subtract_green_ = 0; |  | ||||||
|   enc->use_palette_ = |  | ||||||
|       AnalyzeAndCreatePalette(pic, low_effort, |       AnalyzeAndCreatePalette(pic, low_effort, | ||||||
|                               enc->palette_, &enc->palette_size_); |                               enc->palette_, &enc->palette_size_); | ||||||
|  |  | ||||||
|   // TODO(jyrki): replace the decision to be based on an actual estimate |   // TODO(jyrki): replace the decision to be based on an actual estimate | ||||||
|   // of entropy, or even spatial variance of entropy. |   // of entropy, or even spatial variance of entropy. | ||||||
|   enc->histo_bits_ = GetHistoBits(method, enc->use_palette_, |   enc->histo_bits_ = GetHistoBits(method, use_palette, | ||||||
|                                   pic->width, pic->height); |                                   pic->width, pic->height); | ||||||
|   enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_); |   enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_); | ||||||
|  |  | ||||||
|   if (low_effort) { |   if (low_effort) { | ||||||
|     // AnalyzeEntropy is somewhat slow. |     // AnalyzeEntropy is somewhat slow. | ||||||
|     enc->use_predict_ = !enc->use_palette_; |     entropy_idx[0] = use_palette ? kPalette : kSpatialSubGreen; | ||||||
|     enc->use_subtract_green_ = !enc->use_palette_; |     *num_entropy_idx = 1; | ||||||
|     enc->use_cross_color_ = 0; |  | ||||||
|   } else { |   } else { | ||||||
|     int red_and_blue_always_zero; |  | ||||||
|     EntropyIx min_entropy_ix; |     EntropyIx min_entropy_ix; | ||||||
|     if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, |     if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, use_palette, | ||||||
|                         enc->use_palette_, |  | ||||||
|                         enc->palette_size_, enc->transform_bits_, |                         enc->palette_size_, enc->transform_bits_, | ||||||
|                         &min_entropy_ix, &red_and_blue_always_zero)) { |                         &min_entropy_ix, red_and_blue_always_zero)) { | ||||||
|       return 0; |       return 0; | ||||||
|     } |     } | ||||||
|     enc->use_palette_ = (min_entropy_ix == kPalette); |     if (method == 6 && config->quality == 100) { | ||||||
|     enc->use_subtract_green_ = |       // Go brute force on all transforms. | ||||||
|         (min_entropy_ix == kSubGreen) || (min_entropy_ix == kSpatialSubGreen); |       *num_entropy_idx = 0; | ||||||
|     enc->use_predict_ = |       for (i = 0; i < kNumEntropyIx; ++i) { | ||||||
|         (min_entropy_ix == kSpatial) || (min_entropy_ix == kSpatialSubGreen); |         if (i != kPalette || use_palette) { | ||||||
|     enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_; |           entropy_idx[(*num_entropy_idx)++] = i; | ||||||
|  |           assert(*num_entropy_idx <= kNumEntropyIx); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       // Only choose the guessed best transform. | ||||||
|  |       entropy_idx[0] = min_entropy_ix; | ||||||
|  |       *num_entropy_idx = 1; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0; |   if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0; | ||||||
|  |  | ||||||
|   // palette-friendly input typically uses less literals |  | ||||||
|   //  -> reduce block size a bit |  | ||||||
|   if (enc->use_palette_) refs_block_size /= 2; |  | ||||||
|   for (i = 0; i < 3; ++i) VP8LBackwardRefsInit(&enc->refs_[i], refs_block_size); |   for (i = 0; i < 3; ++i) VP8LBackwardRefsInit(&enc->refs_[i], refs_block_size); | ||||||
|  |  | ||||||
|   return 1; |   return 1; | ||||||
| @@ -1181,6 +1187,7 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, | |||||||
|     } |     } | ||||||
|     enc->transform_mem_ = mem; |     enc->transform_mem_ = mem; | ||||||
|     enc->transform_mem_size_ = (size_t)mem_size; |     enc->transform_mem_size_ = (size_t)mem_size; | ||||||
|  |     enc->argb_content_ = kEncoderNone; | ||||||
|   } |   } | ||||||
|   enc->argb_ = mem; |   enc->argb_ = mem; | ||||||
|   mem = (uint32_t*)WEBP_ALIGN(mem + image_size); |   mem = (uint32_t*)WEBP_ALIGN(mem + image_size); | ||||||
| @@ -1201,11 +1208,13 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) { | |||||||
|   int y; |   int y; | ||||||
|   err = AllocateTransformBuffer(enc, width, height); |   err = AllocateTransformBuffer(enc, width, height); | ||||||
|   if (err != VP8_ENC_OK) return err; |   if (err != VP8_ENC_OK) return err; | ||||||
|  |   if (enc->argb_content_ == kEncoderARGB) return VP8_ENC_OK; | ||||||
|   for (y = 0; y < height; ++y) { |   for (y = 0; y < height; ++y) { | ||||||
|     memcpy(enc->argb_ + y * width, |     memcpy(enc->argb_ + y * width, | ||||||
|            picture->argb + y * picture->argb_stride, |            picture->argb + y * picture->argb_stride, | ||||||
|            width * sizeof(*enc->argb_)); |            width * sizeof(*enc->argb_)); | ||||||
|   } |   } | ||||||
|  |   enc->argb_content_ = kEncoderARGB; | ||||||
|   assert(enc->current_width_ == width); |   assert(enc->current_width_ == width); | ||||||
|   return VP8_ENC_OK; |   return VP8_ENC_OK; | ||||||
| } | } | ||||||
| @@ -1383,6 +1392,7 @@ static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc, | |||||||
|   err = ApplyPalette(src, src_stride, |   err = ApplyPalette(src, src_stride, | ||||||
|                      enc->argb_, enc->current_width_, |                      enc->argb_, enc->current_width_, | ||||||
|                      palette, palette_size, width, height, xbits); |                      palette, palette_size, width, height, xbits); | ||||||
|  |   enc->argb_content_ = kEncoderPalette; | ||||||
|   return err; |   return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1441,7 +1451,7 @@ static WebPEncodingError EncodeDeltaPalettePredictorImage( | |||||||
|   err = EncodeImageNoHuffman( |   err = EncodeImageNoHuffman( | ||||||
|       bw, predictors, &enc->hash_chain_, |       bw, predictors, &enc->hash_chain_, | ||||||
|       (VP8LBackwardRefs*)&enc->refs_[0],  // cast const away |       (VP8LBackwardRefs*)&enc->refs_[0],  // cast const away | ||||||
|       (VP8LBackwardRefs*)&enc->refs_[1],  // cast const away |       (VP8LBackwardRefs*)&enc->refs_[1], | ||||||
|       transform_width, transform_height, quality, low_effort); |       transform_width, transform_height, quality, low_effort); | ||||||
|   WebPSafeFree(predictors); |   WebPSafeFree(predictors); | ||||||
|   return err; |   return err; | ||||||
| @@ -1461,6 +1471,7 @@ static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, | |||||||
|   } |   } | ||||||
|   enc->config_ = config; |   enc->config_ = config; | ||||||
|   enc->pic_ = picture; |   enc->pic_ = picture; | ||||||
|  |   enc->argb_content_ = kEncoderNone; | ||||||
|  |  | ||||||
|   VP8LEncDspInit(); |   VP8LEncDspInit(); | ||||||
|  |  | ||||||
| @@ -1494,8 +1505,14 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | |||||||
|   int hdr_size = 0; |   int hdr_size = 0; | ||||||
|   int data_size = 0; |   int data_size = 0; | ||||||
|   int use_delta_palette = 0; |   int use_delta_palette = 0; | ||||||
|  |   int entropy_idx[kNumEntropyIx]; | ||||||
|  |   int num_entropy_idx = 0; | ||||||
|  |   int i; | ||||||
|  |   int red_and_blue_always_zero = 0; | ||||||
|  |   size_t best_size = 0; | ||||||
|  |   VP8LBitWriter bw_init = *bw, bw_best; | ||||||
|  |  | ||||||
|   if (enc == NULL) { |   if (enc == NULL || !VP8LBitWriterInit(&bw_best, 0)) { | ||||||
|     err = VP8_ENC_ERROR_OUT_OF_MEMORY; |     err = VP8_ENC_ERROR_OUT_OF_MEMORY; | ||||||
|     goto Error; |     goto Error; | ||||||
|   } |   } | ||||||
| @@ -1503,21 +1520,42 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | |||||||
|   // --------------------------------------------------------------------------- |   // --------------------------------------------------------------------------- | ||||||
|   // Analyze image (entropy, num_palettes etc) |   // Analyze image (entropy, num_palettes etc) | ||||||
|  |  | ||||||
|   if (!AnalyzeAndInit(enc)) { |   if (!AnalyzeAndInit(enc, entropy_idx, &num_entropy_idx, | ||||||
|  |                       &red_and_blue_always_zero)) { | ||||||
|     err = VP8_ENC_ERROR_OUT_OF_MEMORY; |     err = VP8_ENC_ERROR_OUT_OF_MEMORY; | ||||||
|     goto Error; |     goto Error; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   for (i = 0; i < num_entropy_idx; ++i) { | ||||||
|  |     enc->use_palette_ = (entropy_idx[i] == kPalette); | ||||||
|  |     enc->use_subtract_green_ = (entropy_idx[i] == kSubGreen) || | ||||||
|  |                                (entropy_idx[i] == kSpatialSubGreen); | ||||||
|  |     enc->use_predict_ = (entropy_idx[i] == kSpatial) || | ||||||
|  |                         (entropy_idx[i] == kSpatialSubGreen); | ||||||
|  |     if (low_effort) { | ||||||
|  |       enc->use_cross_color_ = 0; | ||||||
|  |     } else { | ||||||
|  |       enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_; | ||||||
|  |     } | ||||||
|  |     // Reset any parameter in the encoder that is set in the previous iteration. | ||||||
|  |     enc->cache_bits_ = 0; | ||||||
|  |     VP8LBackwardRefsClear(&enc->refs_[0]); | ||||||
|  |     VP8LBackwardRefsClear(&enc->refs_[1]); | ||||||
|  |  | ||||||
|     // Apply near-lossless preprocessing. |     // Apply near-lossless preprocessing. | ||||||
|   use_near_lossless = |     use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ && | ||||||
|       (config->near_lossless < 100) && !enc->use_palette_ && !enc->use_predict_; |                         !enc->use_predict_; | ||||||
|     if (use_near_lossless) { |     if (use_near_lossless) { | ||||||
|       err = AllocateTransformBuffer(enc, width, height); |       err = AllocateTransformBuffer(enc, width, height); | ||||||
|       if (err != VP8_ENC_OK) goto Error; |       if (err != VP8_ENC_OK) goto Error; | ||||||
|     if (!VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) { |       if ((enc->argb_content_ != kEncoderNearLossless) && | ||||||
|  |           !VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) { | ||||||
|         err = VP8_ENC_ERROR_OUT_OF_MEMORY; |         err = VP8_ENC_ERROR_OUT_OF_MEMORY; | ||||||
|         goto Error; |         goto Error; | ||||||
|       } |       } | ||||||
|  |       enc->argb_content_ = kEncoderNearLossless; | ||||||
|  |     } else { | ||||||
|  |       enc->argb_content_ = kEncoderNone; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| #ifdef WEBP_EXPERIMENTAL_FEATURES | #ifdef WEBP_EXPERIMENTAL_FEATURES | ||||||
| @@ -1526,8 +1564,11 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | |||||||
|       enc->use_cross_color_ = 0; |       enc->use_cross_color_ = 0; | ||||||
|       enc->use_subtract_green_ = 0; |       enc->use_subtract_green_ = 0; | ||||||
|       enc->use_palette_ = 1; |       enc->use_palette_ = 1; | ||||||
|  |       if (enc->argb_content_ != kEncoderNearLossless && | ||||||
|  |           enc->argb_content_ != kEncoderPalette) { | ||||||
|         err = MakeInputImageCopy(enc); |         err = MakeInputImageCopy(enc); | ||||||
|         if (err != VP8_ENC_OK) goto Error; |         if (err != VP8_ENC_OK) goto Error; | ||||||
|  |       } | ||||||
|       err = WebPSearchOptimalDeltaPalette(enc); |       err = WebPSearchOptimalDeltaPalette(enc); | ||||||
|       if (err != VP8_ENC_OK) goto Error; |       if (err != VP8_ENC_OK) goto Error; | ||||||
|       if (enc->use_palette_) { |       if (enc->use_palette_) { | ||||||
| @@ -1546,19 +1587,21 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | |||||||
|       if (err != VP8_ENC_OK) goto Error; |       if (err != VP8_ENC_OK) goto Error; | ||||||
|       err = MapImageFromPalette(enc, use_delta_palette); |       err = MapImageFromPalette(enc, use_delta_palette); | ||||||
|       if (err != VP8_ENC_OK) goto Error; |       if (err != VP8_ENC_OK) goto Error; | ||||||
|     // If using a color cache, do not have it bigger than the number of colors. |       // If using a color cache, do not have it bigger than the number of | ||||||
|  |       // colors. | ||||||
|       if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { |       if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { | ||||||
|         enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1; |         enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     if (!use_delta_palette) { |     if (!use_delta_palette) { | ||||||
|       // In case image is not packed. |       // In case image is not packed. | ||||||
|     if (enc->argb_ == NULL) { |       if (enc->argb_content_ != kEncoderNearLossless && | ||||||
|  |           enc->argb_content_ != kEncoderPalette) { | ||||||
|         err = MakeInputImageCopy(enc); |         err = MakeInputImageCopy(enc); | ||||||
|         if (err != VP8_ENC_OK) goto Error; |         if (err != VP8_ENC_OK) goto Error; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|     // ------------------------------------------------------------------------- |       // ----------------------------------------------------------------------- | ||||||
|       // Apply transforms and write transform data. |       // Apply transforms and write transform data. | ||||||
|  |  | ||||||
|       if (enc->use_subtract_green_) { |       if (enc->use_subtract_green_) { | ||||||
| @@ -1572,15 +1615,15 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | |||||||
|       } |       } | ||||||
|  |  | ||||||
|       if (enc->use_cross_color_) { |       if (enc->use_cross_color_) { | ||||||
|       err = ApplyCrossColorFilter(enc, enc->current_width_, |         err = ApplyCrossColorFilter(enc, enc->current_width_, height, quality, | ||||||
|                                   height, quality, low_effort, bw); |                                     low_effort, bw); | ||||||
|         if (err != VP8_ENC_OK) goto Error; |         if (err != VP8_ENC_OK) goto Error; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     VP8LPutBits(bw, !TRANSFORM_PRESENT, 1);  // No more transforms. |     VP8LPutBits(bw, !TRANSFORM_PRESENT, 1);  // No more transforms. | ||||||
|  |  | ||||||
|   // --------------------------------------------------------------------------- |     // ------------------------------------------------------------------------- | ||||||
|     // Encode and write the transformed image. |     // Encode and write the transformed image. | ||||||
|     err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_, |     err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_, | ||||||
|                               enc->current_width_, height, quality, low_effort, |                               enc->current_width_, height, quality, low_effort, | ||||||
| @@ -1588,6 +1631,12 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | |||||||
|                               byte_position, &hdr_size, &data_size); |                               byte_position, &hdr_size, &data_size); | ||||||
|     if (err != VP8_ENC_OK) goto Error; |     if (err != VP8_ENC_OK) goto Error; | ||||||
|  |  | ||||||
|  |     // If we are better than what we already have. | ||||||
|  |     if (best_size == 0 || VP8LBitWriterNumBytes(bw) < best_size) { | ||||||
|  |       best_size = VP8LBitWriterNumBytes(bw); | ||||||
|  |       // Store the BitWriter. | ||||||
|  |       VP8LBitWriterSwap(bw, &bw_best); | ||||||
|  |       // Update the stats. | ||||||
|       if (picture->stats != NULL) { |       if (picture->stats != NULL) { | ||||||
|         WebPAuxStats* const stats = picture->stats; |         WebPAuxStats* const stats = picture->stats; | ||||||
|         stats->lossless_features = 0; |         stats->lossless_features = 0; | ||||||
| @@ -1603,9 +1652,15 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | |||||||
|         stats->lossless_hdr_size = hdr_size; |         stats->lossless_hdr_size = hdr_size; | ||||||
|         stats->lossless_data_size = data_size; |         stats->lossless_data_size = data_size; | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|  |     // Reset the bit writer for the following iteration if any. | ||||||
|  |     if (num_entropy_idx > 1) VP8LBitWriterReset(&bw_init, bw); | ||||||
|  |   } | ||||||
|  |   VP8LBitWriterSwap(&bw_best, bw); | ||||||
|  |  | ||||||
|  Error: |  Error: | ||||||
|   VP8LEncoderDelete(enc); |   VP8LEncoderDelete(enc); | ||||||
|  |   VP8LBitWriterWipeOut(&bw_best); | ||||||
|   return err; |   return err; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -27,11 +27,19 @@ extern "C" { | |||||||
| // maximum value of transform_bits_ in VP8LEncoder. | // maximum value of transform_bits_ in VP8LEncoder. | ||||||
| #define MAX_TRANSFORM_BITS 6 | #define MAX_TRANSFORM_BITS 6 | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |   kEncoderNone = 0, | ||||||
|  |   kEncoderARGB, | ||||||
|  |   kEncoderNearLossless, | ||||||
|  |   kEncoderPalette | ||||||
|  | } VP8LEncoderARGBContent; | ||||||
|  |  | ||||||
| typedef struct { | typedef struct { | ||||||
|   const WebPConfig* config_;      // user configuration and parameters |   const WebPConfig* config_;      // user configuration and parameters | ||||||
|   const WebPPicture* pic_;        // input picture. |   const WebPPicture* pic_;        // input picture. | ||||||
|  |  | ||||||
|   uint32_t* argb_;                       // Transformed argb image data. |   uint32_t* argb_;                       // Transformed argb image data. | ||||||
|  |   VP8LEncoderARGBContent argb_content_;  // Content type of the argb buffer. | ||||||
|   uint32_t* argb_scratch_;               // Scratch memory for argb rows |   uint32_t* argb_scratch_;               // Scratch memory for argb rows | ||||||
|                                          // (used for prediction). |                                          // (used for prediction). | ||||||
|   uint32_t* transform_data_;             // Scratch memory for transform data. |   uint32_t* transform_data_;             // Scratch memory for transform data. | ||||||
|   | |||||||
| @@ -246,6 +246,20 @@ void VP8LBitWriterWipeOut(VP8LBitWriter* const bw) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void VP8LBitWriterReset(const VP8LBitWriter* const bw_init, | ||||||
|  |                         VP8LBitWriter* const bw) { | ||||||
|  |   bw->bits_ = bw_init->bits_; | ||||||
|  |   bw->used_ = bw_init->used_; | ||||||
|  |   bw->cur_ = bw->buf_ + (bw_init->cur_ - bw_init->buf_); | ||||||
|  |   bw->error_ = bw_init->error_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst) { | ||||||
|  |   const VP8LBitWriter tmp = *src; | ||||||
|  |   *src = *dst; | ||||||
|  |   *dst = tmp; | ||||||
|  | } | ||||||
|  |  | ||||||
| void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) { | void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) { | ||||||
|   // If needed, make some room by flushing some bits out. |   // If needed, make some room by flushing some bits out. | ||||||
|   if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { |   if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { | ||||||
|   | |||||||
| @@ -110,6 +110,11 @@ int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size); | |||||||
| uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw); | uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw); | ||||||
| // Release any pending memory and zeroes the object. | // Release any pending memory and zeroes the object. | ||||||
| void VP8LBitWriterWipeOut(VP8LBitWriter* const bw); | void VP8LBitWriterWipeOut(VP8LBitWriter* const bw); | ||||||
|  | // Resets the cursor of the BitWriter bw to when it was like in bw_init. | ||||||
|  | void VP8LBitWriterReset(const VP8LBitWriter* const bw_init, | ||||||
|  |                         VP8LBitWriter* const bw); | ||||||
|  | // Swaps the memory held by two BitWriters. | ||||||
|  | void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst); | ||||||
|  |  | ||||||
| // Internal function for VP8LPutBits flushing 32 bits from the written state. | // Internal function for VP8LPutBits flushing 32 bits from the written state. | ||||||
| void VP8LPutBitsFlushBits(VP8LBitWriter* const bw); | void VP8LPutBitsFlushBits(VP8LBitWriter* const bw); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user