| OLD | NEW |
| 1 // Copyright 2011 Google Inc. All Rights Reserved. | 1 // Copyright 2011 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // This code is licensed under the same terms as WebM: | 3 // This code is licensed under the same terms as WebM: |
| 4 // Software License Agreement: http://www.webmproject.org/license/software/ | 4 // Software License Agreement: http://www.webmproject.org/license/software/ |
| 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ | 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ |
| 6 // ----------------------------------------------------------------------------- | 6 // ----------------------------------------------------------------------------- |
| 7 // | 7 // |
| 8 // WebP encoder: main entry point | 8 // WebP encoder: main entry point |
| 9 // | 9 // |
| 10 // Author: Skal (pascal.massimino@gmail.com) | 10 // Author: Skal (pascal.massimino@gmail.com) |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 uint8_t* const left = enc->preds_ - 1; | 86 uint8_t* const left = enc->preds_ - 1; |
| 87 for (i = -1; i < 4 * enc->mb_w_; ++i) { | 87 for (i = -1; i < 4 * enc->mb_w_; ++i) { |
| 88 top[i] = B_DC_PRED; | 88 top[i] = B_DC_PRED; |
| 89 } | 89 } |
| 90 for (i = 0; i < 4 * enc->mb_h_; ++i) { | 90 for (i = 0; i < 4 * enc->mb_h_; ++i) { |
| 91 left[i * enc->preds_w_] = B_DC_PRED; | 91 left[i * enc->preds_w_] = B_DC_PRED; |
| 92 } | 92 } |
| 93 enc->nz_[-1] = 0; // constant | 93 enc->nz_[-1] = 0; // constant |
| 94 } | 94 } |
| 95 | 95 |
| 96 // Map configured quality level to coding tools used. | 96 // Mapping from config->method_ to coding tools used. |
| 97 //-------------+---+---+---+---+---+---+ | 97 //-------------------+---+---+---+---+---+---+---+ |
| 98 // Quality | 0 | 1 | 2 | 3 | 4 | 5 + | 98 // Method | 0 | 1 | 2 | 3 |(4)| 5 | 6 | |
| 99 //-------------+---+---+---+---+---+---+ | 99 //-------------------+---+---+---+---+---+---+---+ |
| 100 // dynamic prob| ~ | x | x | x | x | x | | 100 // fast probe | x | | | x | | | | |
| 101 //-------------+---+---+---+---+---+---+ | 101 //-------------------+---+---+---+---+---+---+---+ |
| 102 // rd-opt modes| | | x | x | x | x | | 102 // dynamic proba | ~ | x | x | x | x | x | x | |
| 103 //-------------+---+---+---+---+---+---+ | 103 //-------------------+---+---+---+---+---+---+---+ |
| 104 // fast i4/i16 | x | x | | | | | | 104 // fast mode analysis| | | | | x | x | x | |
| 105 //-------------+---+---+---+---+---+---+ | 105 //-------------------+---+---+---+---+---+---+---+ |
| 106 // rd-opt i4/16| | | x | x | x | x | | 106 // basic rd-opt | | | | x | x | x | x | |
| 107 //-------------+---+---+---+---+---+---+ | 107 //-------------------+---+---+---+---+---+---+---+ |
| 108 // Trellis | | x | | | x | x | | 108 // disto-score i4/16 | | | x | | | | | |
| 109 //-------------+---+---+---+---+---+---+ | 109 //-------------------+---+---+---+---+---+---+---+ |
| 110 // full-SNS | | | | | | x | | 110 // rd-opt i4/16 | | | ~ | x | x | x | x | |
| 111 //-------------+---+---+---+---+---+---+ | 111 //-------------------+---+---+---+---+---+---+---+ |
| 112 // token buffer (opt)| | | | x | x | x | x | |
| 113 //-------------------+---+---+---+---+---+---+---+ |
| 114 // Trellis | | | | | | x |Ful| |
| 115 //-------------------+---+---+---+---+---+---+---+ |
| 116 // full-SNS | | | | | x | x | x | |
| 117 //-------------------+---+---+---+---+---+---+---+ |
| 112 | 118 |
| 113 static void MapConfigToTools(VP8Encoder* const enc) { | 119 static void MapConfigToTools(VP8Encoder* const enc) { |
| 114 const int method = enc->config_->method; | 120 const WebPConfig* const config = enc->config_; |
| 115 const int limit = 100 - enc->config_->partition_limit; | 121 const int method = config->method; |
| 122 const int limit = 100 - config->partition_limit; |
| 116 enc->method_ = method; | 123 enc->method_ = method; |
| 117 enc->rd_opt_level_ = (method >= 6) ? 3 | 124 enc->rd_opt_level_ = (method >= 6) ? RD_OPT_TRELLIS_ALL |
| 118 : (method >= 5) ? 2 | 125 : (method >= 5) ? RD_OPT_TRELLIS |
| 119 : (method >= 3) ? 1 | 126 : (method >= 3) ? RD_OPT_BASIC |
| 120 : 0; | 127 : RD_OPT_NONE; |
| 121 enc->max_i4_header_bits_ = | 128 enc->max_i4_header_bits_ = |
| 122 256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block | 129 256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block |
| 123 (limit * limit) / (100 * 100); // ... modulated with a quadratic curve. | 130 (limit * limit) / (100 * 100); // ... modulated with a quadratic curve. |
| 131 |
| 132 enc->thread_level_ = config->thread_level; |
| 133 |
| 134 enc->do_search_ = (config->target_size > 0 || config->target_PSNR > 0); |
| 135 if (!config->low_memory) { |
| 136 #if !defined(DISABLE_TOKEN_BUFFER) |
| 137 enc->use_tokens_ = (method >= 3) && !enc->do_search_; |
| 138 #endif |
| 139 if (enc->use_tokens_) { |
| 140 enc->num_parts_ = 1; // doesn't work with multi-partition |
| 141 } |
| 142 } |
| 124 } | 143 } |
| 125 | 144 |
| 126 // Memory scaling with dimensions: | 145 // Memory scaling with dimensions: |
| 127 // memory (bytes) ~= 2.25 * w + 0.0625 * w * h | 146 // memory (bytes) ~= 2.25 * w + 0.0625 * w * h |
| 128 // | 147 // |
| 129 // Typical memory footprint (768x510 picture) | 148 // Typical memory footprint (768x510 picture) |
| 130 // Memory used: | 149 // Memory used: |
| 131 // encoder: 33919 | 150 // encoder: 33919 |
| 132 // block cache: 2880 | 151 // block cache: 2880 |
| 133 // info: 3072 | 152 // info: 3072 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 VP8DefaultProbas(enc); | 271 VP8DefaultProbas(enc); |
| 253 ResetSegmentHeader(enc); | 272 ResetSegmentHeader(enc); |
| 254 ResetFilterHeader(enc); | 273 ResetFilterHeader(enc); |
| 255 ResetBoundaryPredictions(enc); | 274 ResetBoundaryPredictions(enc); |
| 256 | 275 |
| 257 VP8EncInitAlpha(enc); | 276 VP8EncInitAlpha(enc); |
| 258 #ifdef WEBP_EXPERIMENTAL_FEATURES | 277 #ifdef WEBP_EXPERIMENTAL_FEATURES |
| 259 VP8EncInitLayer(enc); | 278 VP8EncInitLayer(enc); |
| 260 #endif | 279 #endif |
| 261 | 280 |
| 281 VP8TBufferInit(&enc->tokens_); |
| 262 return enc; | 282 return enc; |
| 263 } | 283 } |
| 264 | 284 |
| 265 static void DeleteVP8Encoder(VP8Encoder* enc) { | 285 static int DeleteVP8Encoder(VP8Encoder* enc) { |
| 286 int ok = 1; |
| 266 if (enc != NULL) { | 287 if (enc != NULL) { |
| 267 VP8EncDeleteAlpha(enc); | 288 ok = VP8EncDeleteAlpha(enc); |
| 268 #ifdef WEBP_EXPERIMENTAL_FEATURES | 289 #ifdef WEBP_EXPERIMENTAL_FEATURES |
| 269 VP8EncDeleteLayer(enc); | 290 VP8EncDeleteLayer(enc); |
| 270 #endif | 291 #endif |
| 292 VP8TBufferClear(&enc->tokens_); |
| 271 free(enc); | 293 free(enc); |
| 272 } | 294 } |
| 295 return ok; |
| 273 } | 296 } |
| 274 | 297 |
| 275 //------------------------------------------------------------------------------ | 298 //------------------------------------------------------------------------------ |
| 276 | 299 |
| 277 static double GetPSNR(uint64_t err, uint64_t size) { | 300 static double GetPSNR(uint64_t err, uint64_t size) { |
| 278 return err ? 10. * log10(255. * 255. * size / err) : 99.; | 301 return err ? 10. * log10(255. * 255. * size / err) : 99.; |
| 279 } | 302 } |
| 280 | 303 |
| 281 static void FinalizePSNR(const VP8Encoder* const enc) { | 304 static void FinalizePSNR(const VP8Encoder* const enc) { |
| 282 WebPAuxStats* stats = enc->pic_->stats; | 305 WebPAuxStats* stats = enc->pic_->stats; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 // user abort requested | 348 // user abort requested |
| 326 WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT); | 349 WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT); |
| 327 return 0; | 350 return 0; |
| 328 } | 351 } |
| 329 } | 352 } |
| 330 return 1; // ok | 353 return 1; // ok |
| 331 } | 354 } |
| 332 //------------------------------------------------------------------------------ | 355 //------------------------------------------------------------------------------ |
| 333 | 356 |
| 334 int WebPEncode(const WebPConfig* config, WebPPicture* pic) { | 357 int WebPEncode(const WebPConfig* config, WebPPicture* pic) { |
| 335 int ok; | 358 int ok = 0; |
| 336 | 359 |
| 337 if (pic == NULL) | 360 if (pic == NULL) |
| 338 return 0; | 361 return 0; |
| 339 WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far | 362 WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far |
| 340 if (config == NULL) // bad params | 363 if (config == NULL) // bad params |
| 341 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); | 364 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); |
| 342 if (!WebPValidateConfig(config)) | 365 if (!WebPValidateConfig(config)) |
| 343 return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); | 366 return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); |
| 344 if (pic->width <= 0 || pic->height <= 0) | 367 if (pic->width <= 0 || pic->height <= 0) |
| 345 return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); | 368 return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); |
| 346 if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) | 369 if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) |
| 347 return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); | 370 return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); |
| 348 | 371 |
| 349 if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats)); | 372 if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats)); |
| 350 | 373 |
| 351 if (!config->lossless) { | 374 if (!config->lossless) { |
| 352 VP8Encoder* enc = NULL; | 375 VP8Encoder* enc = NULL; |
| 353 if (pic->y == NULL || pic->u == NULL || pic->v == NULL) { | 376 if (pic->y == NULL || pic->u == NULL || pic->v == NULL) { |
| 354 if (pic->argb != NULL) { | 377 if (pic->argb != NULL) { |
| 355 if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0; | 378 if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0; |
| 356 } else { | 379 } else { |
| 357 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); | 380 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); |
| 358 } | 381 } |
| 359 } | 382 } |
| 360 | 383 |
| 361 enc = InitVP8Encoder(config, pic); | 384 enc = InitVP8Encoder(config, pic); |
| 362 if (enc == NULL) return 0; // pic->error is already set. | 385 if (enc == NULL) return 0; // pic->error is already set. |
| 363 // Note: each of the tasks below account for 20% in the progress report. | 386 // Note: each of the tasks below account for 20% in the progress report. |
| 364 ok = VP8EncAnalyze(enc) | 387 ok = VP8EncAnalyze(enc); |
| 365 && VP8StatLoop(enc) | 388 |
| 366 && VP8EncLoop(enc) | 389 // Analysis is done, proceed to actual coding. |
| 367 && VP8EncFinishAlpha(enc) | 390 ok = ok && VP8EncStartAlpha(enc); // possibly done in parallel |
| 391 if (!enc->use_tokens_) { |
| 392 ok = VP8EncLoop(enc); |
| 393 } else { |
| 394 ok = VP8EncTokenLoop(enc); |
| 395 } |
| 396 ok = ok && VP8EncFinishAlpha(enc); |
| 368 #ifdef WEBP_EXPERIMENTAL_FEATURES | 397 #ifdef WEBP_EXPERIMENTAL_FEATURES |
| 369 && VP8EncFinishLayer(enc) | 398 ok = ok && VP8EncFinishLayer(enc); |
| 370 #endif | 399 #endif |
| 371 && VP8EncWrite(enc); | 400 |
| 401 ok = ok && VP8EncWrite(enc); |
| 372 StoreStats(enc); | 402 StoreStats(enc); |
| 373 if (!ok) { | 403 if (!ok) { |
| 374 VP8EncFreeBitWriters(enc); | 404 VP8EncFreeBitWriters(enc); |
| 375 } | 405 } |
| 376 DeleteVP8Encoder(enc); | 406 ok &= DeleteVP8Encoder(enc); // must always be called, even if !ok |
| 377 } else { | 407 } else { |
| 378 if (pic->argb == NULL) | 408 if (pic->argb == NULL) |
| 379 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); | 409 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); |
| 380 | 410 |
| 381 ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem. | 411 ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem. |
| 382 } | 412 } |
| 383 | 413 |
| 384 return ok; | 414 return ok; |
| 385 } | 415 } |
| 386 | 416 |
| 387 #if defined(__cplusplus) || defined(c_plusplus) | 417 #if defined(__cplusplus) || defined(c_plusplus) |
| 388 } // extern "C" | 418 } // extern "C" |
| 389 #endif | 419 #endif |
| OLD | NEW |