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 |