mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 02:15:42 +01:00 
			
		
		
		
	add stats for lossless
* Extend AuxStats with new fields it's slightly ABI-incompatible, but i guess it's ok for 0.1.99+ I expect to add more stats later, possibly (predictor stats, etc.) * Have cwebp report the features used by lossless compression (either for alpha or full lossless coding) * Print the PSNR for alpha (useful in case of -alpha_q) * clean-up alpha.c signatures + misc cleanup (added const '* const ptr', etc.) Change-Id: I157a21581f1793cb0c6cc0882e7b0a2dde68a970
This commit is contained in:
		| @@ -614,6 +614,25 @@ static void PrintValues(const int values[4]) { | ||||
|   fprintf(stderr, "|\n"); | ||||
| } | ||||
|  | ||||
| static void PrintFullLosslessInfo(const WebPAuxStats* const stats, | ||||
|                                   const char* const description) { | ||||
|   fprintf(stderr, "Lossless-%s compressed size: %d bytes\n", | ||||
|           description, stats->lossless_size); | ||||
|   if (stats->lossless_features) { | ||||
|     fprintf(stderr, "  * Lossless features used:"); | ||||
|     if (stats->lossless_features & 1) fprintf(stderr, " PREDICTION"); | ||||
|     if (stats->lossless_features & 2) fprintf(stderr, " CROSS-COLOR-TRANSFORM"); | ||||
|     if (stats->lossless_features & 4) fprintf(stderr, " SUBTRACT-GREEN"); | ||||
|     if (stats->lossless_features & 8) fprintf(stderr, " PALETTE"); | ||||
|     fprintf(stderr, "\n"); | ||||
|   } | ||||
|   fprintf(stderr, "  * Precision Bits: histogram=%d transform=%d cache=%d\n", | ||||
|           stats->histogram_bits, stats->transform_bits, stats->cache_bits); | ||||
|   if (stats->palette_size > 0) { | ||||
|     fprintf(stderr, "  * Palette size:   %d\n", stats->palette_size); | ||||
|   } | ||||
| } | ||||
|  | ||||
| static void PrintExtraInfoLossless(const WebPPicture* const pic, | ||||
|                                    int short_output, | ||||
|                                    const char* const file_name) { | ||||
| @@ -624,6 +643,7 @@ static void PrintExtraInfoLossless(const WebPPicture* const pic, | ||||
|     fprintf(stderr, "File:      %s\n", file_name); | ||||
|     fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height); | ||||
|     fprintf(stderr, "Output:    %d bytes\n", stats->coded_size); | ||||
|     PrintFullLosslessInfo(stats, "ARGB"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -658,9 +678,9 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output, | ||||
|               100.f * stats->header_bytes[0] / stats->coded_size, | ||||
|               stats->header_bytes[1], | ||||
|               100.f * stats->header_bytes[1] / stats->coded_size); | ||||
|       if (stats->alpha_data_size) { | ||||
|         fprintf(stderr, "             transparency:   %6d\n", | ||||
|                 stats->alpha_data_size); | ||||
|       if (stats->alpha_data_size > 0) { | ||||
|         fprintf(stderr, "             transparency:   %6d (%.1f dB)\n", | ||||
|                 stats->alpha_data_size, stats->PSNR[4]); | ||||
|       } | ||||
|       if (stats->layer_data_size) { | ||||
|         fprintf(stderr, "             enhancement:    %6d\n", | ||||
| @@ -686,8 +706,11 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output, | ||||
|       fprintf(stderr, " segments total:  "); | ||||
|       PrintByteCount(totals, stats->coded_size, NULL); | ||||
|     } | ||||
|     if (stats->lossless_size > 0) { | ||||
|       PrintFullLosslessInfo(stats, "alpha"); | ||||
|     } | ||||
|   } | ||||
|   if (pic->extra_info) { | ||||
|   if (pic->extra_info != NULL) { | ||||
|     const int mb_w = (pic->width + 15) / 16; | ||||
|     const int mb_h = (pic->height + 15) / 16; | ||||
|     const int type = pic->extra_info_type; | ||||
| @@ -1100,8 +1123,10 @@ int main(int argc, const char *argv[]) { | ||||
|       fprintf(stderr, "be performed, but its results discarded.\n\n"); | ||||
|     } | ||||
|   } | ||||
|   picture.stats = &stats; | ||||
|   stats.user_data = (void*)in_file; | ||||
|   if (!quiet) { | ||||
|     picture.stats = &stats; | ||||
|     stats.user_data = (void*)in_file; | ||||
|   } | ||||
|  | ||||
|   // Compress | ||||
|   if (verbose) { | ||||
|   | ||||
							
								
								
									
										117
									
								
								src/enc/alpha.c
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								src/enc/alpha.c
									
									
									
									
									
								
							| @@ -22,19 +22,15 @@ extern "C" { | ||||
| #endif | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // int EncodeAlpha(const uint8_t* data, int width, int height, int stride, | ||||
| //                 int quality, int method, int filter, int effort_level, | ||||
| //                 uint8_t** output, size_t* output_size) | ||||
| // | ||||
| // Encodes the given alpha data 'data' of size 'stride'x'height' via specified | ||||
| // compression method 'method'. The pre-processing (Quantization) is | ||||
| // performed if 'quality' is less than 100. For such cases, the encoding is | ||||
| // lossy. Valid ranges for 'quality' is [0, 100] and 'method' is [0, 1]: | ||||
| // Encodes the given alpha data via specified compression method 'method'. | ||||
| // The pre-processing (quantization) is performed if 'quality' is less than 100. | ||||
| // For such cases, the encoding is lossy. The valid range is [0, 100] for | ||||
| // 'quality' and [0, 1] for 'method': | ||||
| //   'method = 0' - No compression; | ||||
| //   'method = 1' - Use lossless coder on the alpha plane only | ||||
| // 'filter' values [0, 4] correspond to prediction modes none, horizontal, | ||||
| // vertical & gradient filters. The prediction mode 4 will try all the | ||||
| // prediction modes (0 to 3) and pick the best prediction mode. | ||||
| // prediction modes 0 to 3 and pick the best one. | ||||
| // 'effort_level': specifies how much effort must be spent to try and reduce | ||||
| //  the compressed output size. In range 0 (quick) to 6 (slow). | ||||
| // | ||||
| @@ -50,10 +46,10 @@ extern "C" { | ||||
|  | ||||
| #include "../enc/vp8li.h" | ||||
|  | ||||
| static int EncodeLossless(const uint8_t* data, int width, int height, | ||||
| static int EncodeLossless(const uint8_t* const data, int width, int height, | ||||
|                           int effort_level,  // in [0..6] range | ||||
|                           VP8BitWriter* const bw) { | ||||
|  | ||||
|                           VP8BitWriter* const bw, | ||||
|                           WebPAuxStats* const stats) { | ||||
|   int ok = 0; | ||||
|   WebPConfig config; | ||||
|   WebPPicture picture; | ||||
| @@ -63,6 +59,7 @@ static int EncodeLossless(const uint8_t* data, int width, int height, | ||||
|   picture.width = width; | ||||
|   picture.height = height; | ||||
|   picture.use_argb = 1; | ||||
|   picture.stats = stats; | ||||
|   if (!WebPPictureAlloc(&picture)) return 0; | ||||
|  | ||||
|   // Transfer the alpha values to the green channel. | ||||
| @@ -101,10 +98,12 @@ static int EncodeLossless(const uint8_t* data, int width, int height, | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
|  | ||||
| static int EncodeAlphaInternal(const uint8_t* data, int width, int height, | ||||
| static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, | ||||
|                                int method, int filter, int reduce_levels, | ||||
|                                int effort_level,  // in [0..6] range | ||||
|                                uint8_t* tmp_alpha, VP8BitWriter* const bw) { | ||||
|                                uint8_t* const tmp_alpha, | ||||
|                                VP8BitWriter* const bw, | ||||
|                                WebPAuxStats* const stats) { | ||||
|   int ok = 0; | ||||
|   const uint8_t* alpha_src; | ||||
|   WebPFilterFunc filter_func; | ||||
| @@ -139,7 +138,7 @@ static int EncodeAlphaInternal(const uint8_t* data, int width, int height, | ||||
|     ok = VP8BitWriterAppend(bw, alpha_src, width * height); | ||||
|     ok = ok && !bw->error_; | ||||
|   } else { | ||||
|     ok = EncodeLossless(alpha_src, width, height, effort_level, bw); | ||||
|     ok = EncodeLossless(alpha_src, width, height, effort_level, bw, stats); | ||||
|     VP8BitWriterFinish(bw); | ||||
|   } | ||||
|   return ok; | ||||
| @@ -157,19 +156,25 @@ static void CopyPlane(const uint8_t* src, int src_stride, | ||||
|   } | ||||
| } | ||||
|  | ||||
| static int EncodeAlpha(const uint8_t* data, int width, int height, int stride, | ||||
| static int EncodeAlpha(VP8Encoder* const enc, | ||||
|                        int quality, int method, int filter, | ||||
|                        int effort_level, | ||||
|                        uint8_t** output, size_t* output_size) { | ||||
|                        uint8_t** const output, size_t* const output_size) { | ||||
|   const WebPPicture* const pic = enc->pic_; | ||||
|   const int width = pic->width; | ||||
|   const int height = pic->height; | ||||
|  | ||||
|   uint8_t* quant_alpha = NULL; | ||||
|   const size_t data_size = width * height; | ||||
|   uint64_t sse = 0; | ||||
|   int ok = 1; | ||||
|   const int reduce_levels = (quality < 100); | ||||
|  | ||||
|   // quick sanity checks | ||||
|   assert(data != NULL && output != NULL && output_size != NULL); | ||||
|   assert(enc != NULL && pic != NULL && pic->a != NULL); | ||||
|   assert(output != NULL && output_size != NULL); | ||||
|   assert(width > 0 && height > 0); | ||||
|   assert(stride >= width); | ||||
|   assert(pic->a_stride >= width); | ||||
|   assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST); | ||||
|  | ||||
|   if (quality < 0 || quality > 100) { | ||||
| @@ -186,7 +191,7 @@ static int EncodeAlpha(const uint8_t* data, int width, int height, int stride, | ||||
|   } | ||||
|  | ||||
|   // Extract alpha data (width x height) from raw_data (stride x height). | ||||
|   CopyPlane(data, stride, quant_alpha, width, width, height); | ||||
|   CopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height); | ||||
|  | ||||
|   if (reduce_levels) {  // No Quantization required for 'quality = 100'. | ||||
|     // 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence | ||||
| @@ -194,24 +199,22 @@ static int EncodeAlpha(const uint8_t* data, int width, int height, int stride, | ||||
|     // and Quality:]70, 100] -> Levels:]16, 256]. | ||||
|     const int alpha_levels = (quality <= 70) ? (2 + quality / 5) | ||||
|                                              : (16 + (quality - 70) * 8); | ||||
|     ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, NULL); | ||||
|     ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse); | ||||
|   } | ||||
|  | ||||
|   if (ok) { | ||||
|     VP8BitWriter bw; | ||||
|     size_t best_score; | ||||
|     int test_filter; | ||||
|     uint8_t* filtered_alpha = NULL; | ||||
|  | ||||
|     // We always test WEBP_FILTER_NONE first. | ||||
|     ok = EncodeAlphaInternal(quant_alpha, width, height, | ||||
|                              method, WEBP_FILTER_NONE, reduce_levels, | ||||
|                              effort_level, NULL, &bw); | ||||
|                              effort_level, NULL, &bw, pic->stats); | ||||
|     if (!ok) { | ||||
|       VP8BitWriterWipeOut(&bw); | ||||
|       goto End; | ||||
|     } | ||||
|     best_score = VP8BitWriterSize(&bw); | ||||
|  | ||||
|     if (filter == WEBP_FILTER_FAST) {  // Quick estimate of a second candidate? | ||||
|       filter = EstimateBestFilter(quant_alpha, width, height, width); | ||||
| @@ -228,35 +231,46 @@ static int EncodeAlpha(const uint8_t* data, int width, int height, int stride, | ||||
|     } | ||||
|  | ||||
|     // Try the other mode(s). | ||||
|     for (test_filter = WEBP_FILTER_HORIZONTAL; | ||||
|          ok && (test_filter <= WEBP_FILTER_GRADIENT); | ||||
|          ++test_filter) { | ||||
|       VP8BitWriter tmp_bw; | ||||
|       if (filter != WEBP_FILTER_BEST && test_filter != filter) { | ||||
|         continue; | ||||
|       } | ||||
|  | ||||
|       ok = EncodeAlphaInternal(quant_alpha, width, height, | ||||
|                                method, test_filter, reduce_levels, | ||||
|                                effort_level, filtered_alpha, &tmp_bw); | ||||
|       if (ok) { | ||||
|         const size_t score = VP8BitWriterSize(&tmp_bw); | ||||
|         if (score < best_score) { | ||||
|           // swap bitwriter objects. | ||||
|           VP8BitWriter tmp = tmp_bw; | ||||
|           tmp_bw = bw; | ||||
|           bw = tmp; | ||||
|           best_score = score; | ||||
|     { | ||||
|       WebPAuxStats best_stats; | ||||
|       size_t best_score = VP8BitWriterSize(&bw); | ||||
|       if (pic->stats != NULL) best_stats = *pic->stats; | ||||
|       for (test_filter = WEBP_FILTER_HORIZONTAL; | ||||
|            ok && (test_filter <= WEBP_FILTER_GRADIENT); | ||||
|            ++test_filter) { | ||||
|         VP8BitWriter tmp_bw; | ||||
|         if (filter != WEBP_FILTER_BEST && test_filter != filter) { | ||||
|           continue; | ||||
|         } | ||||
|       } else { | ||||
|         VP8BitWriterWipeOut(&bw); | ||||
|         ok = EncodeAlphaInternal(quant_alpha, width, height, | ||||
|                                  method, test_filter, reduce_levels, | ||||
|                                  effort_level, filtered_alpha, &tmp_bw, | ||||
|                                  pic->stats); | ||||
|         if (ok) { | ||||
|           const size_t score = VP8BitWriterSize(&tmp_bw); | ||||
|           if (score < best_score) { | ||||
|             // swap bitwriter objects. | ||||
|             VP8BitWriter tmp = tmp_bw; | ||||
|             tmp_bw = bw; | ||||
|             bw = tmp; | ||||
|             best_score = score; | ||||
|             if (pic->stats != NULL) best_stats = *pic->stats; | ||||
|           } | ||||
|         } else { | ||||
|           VP8BitWriterWipeOut(&bw); | ||||
|         } | ||||
|         VP8BitWriterWipeOut(&tmp_bw); | ||||
|       } | ||||
|       VP8BitWriterWipeOut(&tmp_bw); | ||||
|       if (pic->stats != NULL) *pic->stats = best_stats; | ||||
|     } | ||||
|  Ok: | ||||
|     if (ok) { | ||||
|       *output_size = VP8BitWriterSize(&bw); | ||||
|       *output = VP8BitWriterBuf(&bw); | ||||
|       if (pic->stats != NULL) {         // need stats? | ||||
|         pic->stats->coded_size += *output_size; | ||||
|         enc->sse_[3] = sse; | ||||
|       } | ||||
|     } | ||||
|     free(filtered_alpha); | ||||
|   } | ||||
| @@ -269,16 +283,15 @@ static int EncodeAlpha(const uint8_t* data, int width, int height, int stride, | ||||
| //------------------------------------------------------------------------------ | ||||
| // Main calls | ||||
|  | ||||
| void VP8EncInitAlpha(VP8Encoder* enc) { | ||||
| void VP8EncInitAlpha(VP8Encoder* const enc) { | ||||
|   enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_); | ||||
|   enc->alpha_data_ = NULL; | ||||
|   enc->alpha_data_size_ = 0; | ||||
| } | ||||
|  | ||||
| int VP8EncFinishAlpha(VP8Encoder* enc) { | ||||
| int VP8EncFinishAlpha(VP8Encoder* const enc) { | ||||
|   if (enc->has_alpha_) { | ||||
|     const WebPConfig* config = enc->config_; | ||||
|     const WebPPicture* pic = enc->pic_; | ||||
|     uint8_t* tmp_data = NULL; | ||||
|     size_t tmp_size = 0; | ||||
|     const int effort_level = config->method;  // maps to [0..6] | ||||
| @@ -287,9 +300,7 @@ int VP8EncFinishAlpha(VP8Encoder* enc) { | ||||
|         (config->alpha_filtering == 1) ? WEBP_FILTER_FAST : | ||||
|                                          WEBP_FILTER_BEST; | ||||
|  | ||||
|     assert(pic->a); | ||||
|     if (!EncodeAlpha(pic->a, pic->width, pic->height, pic->a_stride, | ||||
|                      config->alpha_quality, config->alpha_compression, | ||||
|     if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression, | ||||
|                      filter, effort_level, &tmp_data, &tmp_size)) { | ||||
|       return 0; | ||||
|     } | ||||
| @@ -303,7 +314,7 @@ int VP8EncFinishAlpha(VP8Encoder* enc) { | ||||
|   return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); | ||||
| } | ||||
|  | ||||
| void VP8EncDeleteAlpha(VP8Encoder* enc) { | ||||
| void VP8EncDeleteAlpha(VP8Encoder* const enc) { | ||||
|   free(enc->alpha_data_); | ||||
|   enc->alpha_data_ = NULL; | ||||
|   enc->alpha_data_size_ = 0; | ||||
|   | ||||
| @@ -402,7 +402,7 @@ struct VP8Encoder { | ||||
|  | ||||
|   // probabilities and statistics | ||||
|   VP8Proba proba_; | ||||
|   uint64_t sse_[3];        // sum of Y/U/V squared errors for all macroblocks | ||||
|   uint64_t sse_[4];        // sum of Y/U/V/A squared errors for all macroblocks | ||||
|   uint64_t sse_count_;     // pixel count for the sse_[] stats | ||||
|   int      coded_size_; | ||||
|   int      residual_bytes_[3][4]; | ||||
| @@ -488,9 +488,9 @@ void VP8SetSegmentParams(VP8Encoder* const enc, float quality); | ||||
| int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt); | ||||
|  | ||||
|   // in alpha.c | ||||
| void VP8EncInitAlpha(VP8Encoder* enc);           // initialize alpha compression | ||||
| int VP8EncFinishAlpha(VP8Encoder* enc);          // finalize compressed data | ||||
| void VP8EncDeleteAlpha(VP8Encoder* enc);         // delete compressed data | ||||
| void VP8EncInitAlpha(VP8Encoder* const enc);    // initialize alpha compression | ||||
| int VP8EncFinishAlpha(VP8Encoder* const enc);   // finalize compressed data | ||||
| void VP8EncDeleteAlpha(VP8Encoder* const enc);  // delete compressed data | ||||
|  | ||||
|   // in layer.c | ||||
| void VP8EncInitLayer(VP8Encoder* const enc);     // init everything | ||||
|   | ||||
| @@ -610,7 +610,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw, | ||||
|  | ||||
| // Check if it would be a good idea to subtract green from red and blue. We | ||||
| // only impact entropy in red/blue components, don't bother to look at others. | ||||
| static int EvalAndApplySubtractGreen(const VP8LEncoder* const enc, | ||||
| static int EvalAndApplySubtractGreen(VP8LEncoder* const enc, | ||||
|                                      int width, int height, | ||||
|                                      VP8LBitWriter* const bw) { | ||||
|   if (!enc->use_palette_) { | ||||
| @@ -639,7 +639,8 @@ static int EvalAndApplySubtractGreen(const VP8LEncoder* const enc, | ||||
|     free(histo); | ||||
|  | ||||
|     // Check if subtracting green yields low entropy. | ||||
|     if (bit_cost_after < bit_cost_before) { | ||||
|     enc->use_subtract_green_ = (bit_cost_after < bit_cost_before); | ||||
|     if (enc->use_subtract_green_) { | ||||
|       VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); | ||||
|       VP8LWriteBits(bw, 2, SUBTRACT_GREEN); | ||||
|       VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height); | ||||
| @@ -938,6 +939,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | ||||
|   const int width = picture->width; | ||||
|   const int height = picture->height; | ||||
|   VP8LEncoder* const enc = VP8LEncoderNew(config, picture); | ||||
|   const size_t byte_position = VP8LBitWriterNumBytes(bw); | ||||
|  | ||||
|   if (enc == NULL) { | ||||
|     err = VP8_ENC_ERROR_OUT_OF_MEMORY; | ||||
| @@ -1017,6 +1019,20 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, | ||||
|     goto Error; | ||||
|   } | ||||
|  | ||||
|   if (picture->stats != NULL) { | ||||
|     WebPAuxStats* const stats = picture->stats; | ||||
|     stats->lossless_features = 0; | ||||
|     if (enc->use_predict_) stats->lossless_features |= 1; | ||||
|     if (enc->use_cross_color_) stats->lossless_features |= 2; | ||||
|     if (enc->use_subtract_green_) stats->lossless_features |= 4; | ||||
|     if (enc->use_palette_) stats->lossless_features |= 8; | ||||
|     stats->histogram_bits = enc->histo_bits_; | ||||
|     stats->transform_bits = enc->transform_bits_; | ||||
|     stats->cache_bits = enc->cache_bits_; | ||||
|     stats->palette_size = enc->palette_size_; | ||||
|     stats->lossless_size = VP8LBitWriterNumBytes(bw) - byte_position; | ||||
|   } | ||||
|  | ||||
|  Error: | ||||
|   VP8LEncoderDelete(enc); | ||||
|   return err; | ||||
| @@ -1045,6 +1061,16 @@ int VP8LEncodeImage(const WebPConfig* const config, | ||||
|     err = VP8_ENC_ERROR_USER_ABORT; | ||||
|     goto Error; | ||||
|   } | ||||
|   // Reset stats (for pure lossless coding) | ||||
|   if (picture->stats != NULL) { | ||||
|     WebPAuxStats* const stats = picture->stats; | ||||
|     memset(stats, 0, sizeof(*stats)); | ||||
|     stats->PSNR[0] = 99.; | ||||
|     stats->PSNR[1] = 99.; | ||||
|     stats->PSNR[2] = 99.; | ||||
|     stats->PSNR[3] = 99.; | ||||
|     stats->PSNR[4] = 99.; | ||||
|   } | ||||
|  | ||||
|   // Write image size. | ||||
|   VP8LBitWriterInit(&bw, (width * height) >> 1); | ||||
| @@ -1075,15 +1101,10 @@ int VP8LEncodeImage(const WebPConfig* const config, | ||||
|  | ||||
|   if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort; | ||||
|  | ||||
|   // Collect some stats if needed. | ||||
|   // Save size. | ||||
|   if (picture->stats != NULL) { | ||||
|     WebPAuxStats* const stats = picture->stats; | ||||
|     memset(stats, 0, sizeof(*stats)); | ||||
|     stats->PSNR[0] = 99.; | ||||
|     stats->PSNR[1] = 99.; | ||||
|     stats->PSNR[2] = 99.; | ||||
|     stats->PSNR[3] = 99.; | ||||
|     stats->coded_size = (int)coded_size; | ||||
|     picture->stats->coded_size += (int)coded_size; | ||||
|     picture->stats->lossless_size = (int)coded_size; | ||||
|   } | ||||
|  | ||||
|   if (picture->extra_info != NULL) { | ||||
|   | ||||
| @@ -38,6 +38,7 @@ typedef struct { | ||||
|  | ||||
|   // Encoding parameters derived from image characteristics. | ||||
|   int use_cross_color_; | ||||
|   int use_subtract_green_; | ||||
|   int use_predict_; | ||||
|   int use_palette_; | ||||
|   int palette_size_; | ||||
|   | ||||
| @@ -284,6 +284,7 @@ static void FinalizePSNR(const VP8Encoder* const enc) { | ||||
|   stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4); | ||||
|   stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4); | ||||
|   stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2); | ||||
|   stats->PSNR[4] = (float)GetPSNR(sse[3], size); | ||||
| } | ||||
|  | ||||
| static void StoreStats(VP8Encoder* const enc) { | ||||
|   | ||||
| @@ -157,7 +157,7 @@ typedef struct WebPPicture WebPPicture;   // main structure for I/O | ||||
| typedef struct { | ||||
|   int coded_size;         // final size | ||||
|  | ||||
|   float PSNR[4];          // peak-signal-to-noise ratio for Y/U/V/All | ||||
|   float PSNR[5];          // peak-signal-to-noise ratio for Y/U/V/All/Alpha | ||||
|   int block_count[3];     // number of intra4/intra16/skipped macroblocks | ||||
|   int header_bytes[2];    // approximate number of bytes spent for header | ||||
|                           // and mode-partition #0 | ||||
| @@ -173,7 +173,16 @@ typedef struct { | ||||
|   void* user_data;        // this field is free to be set to any value and | ||||
|                           // used during callbacks (like progress-report e.g.). | ||||
|  | ||||
|   uint32_t pad[6];        // padding for later use | ||||
|   // lossless encoder statistics | ||||
|   uint32_t lossless_features;  // bit0:predictor bit1:cross-color transform | ||||
|                                // bit2:subtract-green bit3:color indexing | ||||
|   int histogram_bits;          // number of precision bits of histogram | ||||
|   int transform_bits;          // precision bits for transform | ||||
|   int cache_bits;              // number of bits for color cache lookup | ||||
|   int palette_size;            // number of color in palette, if used | ||||
|   int lossless_size;           // final lossless size | ||||
|  | ||||
|   uint32_t pad[4];        // padding for later use | ||||
| } WebPAuxStats; | ||||
|  | ||||
| // Signature for output function. Should return true if writing was successful. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user