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 // Alpha-plane compression. | 8 // Alpha-plane compression. |
9 // | 9 // |
10 // Author: Skal (pascal.massimino@gmail.com) | 10 // Author: Skal (pascal.massimino@gmail.com) |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 dst[i] = (src[i] << 8) | 0xff000000u; | 72 dst[i] = (src[i] << 8) | 0xff000000u; |
73 } | 73 } |
74 src += width; | 74 src += width; |
75 dst += picture.argb_stride; | 75 dst += picture.argb_stride; |
76 } | 76 } |
77 } | 77 } |
78 | 78 |
79 WebPConfigInit(&config); | 79 WebPConfigInit(&config); |
80 config.lossless = 1; | 80 config.lossless = 1; |
81 config.method = effort_level; // impact is very small | 81 config.method = effort_level; // impact is very small |
82 // Set moderate default quality setting for alpha. Higher qualities (80 and | 82 // Set a moderate default quality setting for alpha. |
83 // above) could be very slow. | 83 config.quality = 5.f * effort_level; |
84 config.quality = 10.f + 15.f * effort_level; | 84 assert(config.quality >= 0 && config.quality <= 100.f); |
85 if (config.quality > 100.f) config.quality = 100.f; | |
86 | 85 |
87 ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3); | 86 ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3); |
88 ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK); | 87 ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK); |
89 WebPPictureFree(&picture); | 88 WebPPictureFree(&picture); |
90 if (ok) { | 89 if (ok) { |
91 const uint8_t* const data = VP8LBitWriterFinish(&tmp_bw); | 90 const uint8_t* const buffer = VP8LBitWriterFinish(&tmp_bw); |
92 const size_t data_size = VP8LBitWriterNumBytes(&tmp_bw); | 91 const size_t buffer_size = VP8LBitWriterNumBytes(&tmp_bw); |
93 VP8BitWriterAppend(bw, data, data_size); | 92 VP8BitWriterAppend(bw, buffer, buffer_size); |
94 } | 93 } |
95 VP8LBitWriterDestroy(&tmp_bw); | 94 VP8LBitWriterDestroy(&tmp_bw); |
96 return ok && !bw->error_; | 95 return ok && !bw->error_; |
97 } | 96 } |
98 | 97 |
99 // ----------------------------------------------------------------------------- | 98 // ----------------------------------------------------------------------------- |
100 | 99 |
101 static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, | 100 static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, |
102 int method, int filter, int reduce_levels, | 101 int method, int filter, int reduce_levels, |
103 int effort_level, // in [0..6] range | 102 int effort_level, // in [0..6] range |
(...skipping 17 matching lines...) Expand all Loading... |
121 expected_size = | 120 expected_size = |
122 (method == ALPHA_NO_COMPRESSION) ? (ALPHA_HEADER_LEN + data_size) | 121 (method == ALPHA_NO_COMPRESSION) ? (ALPHA_HEADER_LEN + data_size) |
123 : (data_size >> 5); | 122 : (data_size >> 5); |
124 header = method | (filter << 2); | 123 header = method | (filter << 2); |
125 if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; | 124 if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; |
126 | 125 |
127 VP8BitWriterInit(bw, expected_size); | 126 VP8BitWriterInit(bw, expected_size); |
128 VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN); | 127 VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN); |
129 | 128 |
130 filter_func = WebPFilters[filter]; | 129 filter_func = WebPFilters[filter]; |
131 if (filter_func) { | 130 if (filter_func != NULL) { |
132 filter_func(data, width, height, 1, width, tmp_alpha); | 131 filter_func(data, width, height, width, tmp_alpha); |
133 alpha_src = tmp_alpha; | 132 alpha_src = tmp_alpha; |
134 } else { | 133 } else { |
135 alpha_src = data; | 134 alpha_src = data; |
136 } | 135 } |
137 | 136 |
138 if (method == ALPHA_NO_COMPRESSION) { | 137 if (method == ALPHA_NO_COMPRESSION) { |
139 ok = VP8BitWriterAppend(bw, alpha_src, width * height); | 138 ok = VP8BitWriterAppend(bw, alpha_src, width * height); |
140 ok = ok && !bw->error_; | 139 ok = ok && !bw->error_; |
141 } else { | 140 } else { |
142 ok = EncodeLossless(alpha_src, width, height, effort_level, bw, stats); | 141 ok = EncodeLossless(alpha_src, width, height, effort_level, bw, stats); |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 } | 279 } |
281 End: | 280 End: |
282 free(quant_alpha); | 281 free(quant_alpha); |
283 return ok; | 282 return ok; |
284 } | 283 } |
285 | 284 |
286 | 285 |
287 //------------------------------------------------------------------------------ | 286 //------------------------------------------------------------------------------ |
288 // Main calls | 287 // Main calls |
289 | 288 |
| 289 static int CompressAlphaJob(VP8Encoder* const enc, void* dummy) { |
| 290 const WebPConfig* config = enc->config_; |
| 291 uint8_t* alpha_data = NULL; |
| 292 size_t alpha_size = 0; |
| 293 const int effort_level = config->method; // maps to [0..6] |
| 294 const WEBP_FILTER_TYPE filter = |
| 295 (config->alpha_filtering == 0) ? WEBP_FILTER_NONE : |
| 296 (config->alpha_filtering == 1) ? WEBP_FILTER_FAST : |
| 297 WEBP_FILTER_BEST; |
| 298 if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression, |
| 299 filter, effort_level, &alpha_data, &alpha_size)) { |
| 300 return 0; |
| 301 } |
| 302 if (alpha_size != (uint32_t)alpha_size) { // Sanity check. |
| 303 free(alpha_data); |
| 304 return 0; |
| 305 } |
| 306 enc->alpha_data_size_ = (uint32_t)alpha_size; |
| 307 enc->alpha_data_ = alpha_data; |
| 308 (void)dummy; |
| 309 return 1; |
| 310 } |
| 311 |
290 void VP8EncInitAlpha(VP8Encoder* const enc) { | 312 void VP8EncInitAlpha(VP8Encoder* const enc) { |
291 enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_); | 313 enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_); |
292 enc->alpha_data_ = NULL; | 314 enc->alpha_data_ = NULL; |
293 enc->alpha_data_size_ = 0; | 315 enc->alpha_data_size_ = 0; |
| 316 if (enc->thread_level_ > 0) { |
| 317 WebPWorker* const worker = &enc->alpha_worker_; |
| 318 WebPWorkerInit(worker); |
| 319 worker->data1 = enc; |
| 320 worker->data2 = NULL; |
| 321 worker->hook = (WebPWorkerHook)CompressAlphaJob; |
| 322 } |
| 323 } |
| 324 |
| 325 int VP8EncStartAlpha(VP8Encoder* const enc) { |
| 326 if (enc->has_alpha_) { |
| 327 if (enc->thread_level_ > 0) { |
| 328 WebPWorker* const worker = &enc->alpha_worker_; |
| 329 if (!WebPWorkerReset(worker)) { // Makes sure worker is good to go. |
| 330 return 0; |
| 331 } |
| 332 WebPWorkerLaunch(worker); |
| 333 return 1; |
| 334 } else { |
| 335 return CompressAlphaJob(enc, NULL); // just do the job right away |
| 336 } |
| 337 } |
| 338 return 1; |
294 } | 339 } |
295 | 340 |
296 int VP8EncFinishAlpha(VP8Encoder* const enc) { | 341 int VP8EncFinishAlpha(VP8Encoder* const enc) { |
297 if (enc->has_alpha_) { | 342 if (enc->has_alpha_) { |
298 const WebPConfig* config = enc->config_; | 343 if (enc->thread_level_ > 0) { |
299 uint8_t* tmp_data = NULL; | 344 WebPWorker* const worker = &enc->alpha_worker_; |
300 size_t tmp_size = 0; | 345 if (!WebPWorkerSync(worker)) return 0; // error |
301 const int effort_level = config->method; // maps to [0..6] | |
302 const WEBP_FILTER_TYPE filter = | |
303 (config->alpha_filtering == 0) ? WEBP_FILTER_NONE : | |
304 (config->alpha_filtering == 1) ? WEBP_FILTER_FAST : | |
305 WEBP_FILTER_BEST; | |
306 | |
307 if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression, | |
308 filter, effort_level, &tmp_data, &tmp_size)) { | |
309 return 0; | |
310 } | 346 } |
311 if (tmp_size != (uint32_t)tmp_size) { // Sanity check. | |
312 free(tmp_data); | |
313 return 0; | |
314 } | |
315 enc->alpha_data_size_ = (uint32_t)tmp_size; | |
316 enc->alpha_data_ = tmp_data; | |
317 } | 347 } |
318 return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); | 348 return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); |
319 } | 349 } |
320 | 350 |
321 void VP8EncDeleteAlpha(VP8Encoder* const enc) { | 351 int VP8EncDeleteAlpha(VP8Encoder* const enc) { |
| 352 int ok = 1; |
| 353 if (enc->thread_level_ > 0) { |
| 354 WebPWorker* const worker = &enc->alpha_worker_; |
| 355 ok = WebPWorkerSync(worker); // finish anything left in flight |
| 356 WebPWorkerEnd(worker); // still need to end the worker, even if !ok |
| 357 } |
322 free(enc->alpha_data_); | 358 free(enc->alpha_data_); |
323 enc->alpha_data_ = NULL; | 359 enc->alpha_data_ = NULL; |
324 enc->alpha_data_size_ = 0; | 360 enc->alpha_data_size_ = 0; |
325 enc->has_alpha_ = 0; | 361 enc->has_alpha_ = 0; |
| 362 return ok; |
326 } | 363 } |
327 | 364 |
328 #if defined(__cplusplus) || defined(c_plusplus) | 365 #if defined(__cplusplus) || defined(c_plusplus) |
329 } // extern "C" | 366 } // extern "C" |
330 #endif | 367 #endif |
OLD | NEW |