Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: third_party/libwebp/enc/alpha.c

Issue 1546003002: libwebp: update to 0.5.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase around clang-cl fix Created 4 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2011 Google Inc. All Rights Reserved. 1 // Copyright 2011 Google Inc. All Rights Reserved.
2 // 2 //
3 // Use of this source code is governed by a BSD-style license 3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source 4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found 5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may 6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree. 7 // be found in the AUTHORS file in the root of the source tree.
8 // ----------------------------------------------------------------------------- 8 // -----------------------------------------------------------------------------
9 // 9 //
10 // Alpha-plane compression. 10 // Alpha-plane compression.
11 // 11 //
12 // Author: Skal (pascal.massimino@gmail.com) 12 // Author: Skal (pascal.massimino@gmail.com)
13 13
14 #include <assert.h> 14 #include <assert.h>
15 #include <stdlib.h> 15 #include <stdlib.h>
16 16
17 #include "./vp8enci.h" 17 #include "./vp8enci.h"
18 #include "../dsp/dsp.h"
18 #include "../utils/filters.h" 19 #include "../utils/filters.h"
19 #include "../utils/quant_levels.h" 20 #include "../utils/quant_levels.h"
20 #include "../utils/utils.h" 21 #include "../utils/utils.h"
21 #include "../webp/format_constants.h" 22 #include "../webp/format_constants.h"
22 23
23 // ----------------------------------------------------------------------------- 24 // -----------------------------------------------------------------------------
24 // Encodes the given alpha data via specified compression method 'method'. 25 // Encodes the given alpha data via specified compression method 'method'.
25 // The pre-processing (quantization) is performed if 'quality' is less than 100. 26 // The pre-processing (quantization) is performed if 'quality' is less than 100.
26 // For such cases, the encoding is lossy. The valid range is [0, 100] for 27 // For such cases, the encoding is lossy. The valid range is [0, 100] for
27 // 'quality' and [0, 1] for 'method': 28 // 'quality' and [0, 1] for 'method':
(...skipping 26 matching lines...) Expand all
54 WebPPicture picture; 55 WebPPicture picture;
55 56
56 WebPPictureInit(&picture); 57 WebPPictureInit(&picture);
57 picture.width = width; 58 picture.width = width;
58 picture.height = height; 59 picture.height = height;
59 picture.use_argb = 1; 60 picture.use_argb = 1;
60 picture.stats = stats; 61 picture.stats = stats;
61 if (!WebPPictureAlloc(&picture)) return 0; 62 if (!WebPPictureAlloc(&picture)) return 0;
62 63
63 // Transfer the alpha values to the green channel. 64 // Transfer the alpha values to the green channel.
64 { 65 WebPDispatchAlphaToGreen(data, width, picture.width, picture.height,
65 int i, j; 66 picture.argb, picture.argb_stride);
66 uint32_t* dst = picture.argb;
67 const uint8_t* src = data;
68 for (j = 0; j < picture.height; ++j) {
69 for (i = 0; i < picture.width; ++i) {
70 dst[i] = src[i] << 8; // we leave A/R/B channels zero'd.
71 }
72 src += width;
73 dst += picture.argb_stride;
74 }
75 }
76 67
77 WebPConfigInit(&config); 68 WebPConfigInit(&config);
78 config.lossless = 1; 69 config.lossless = 1;
70 // Enable exact, or it would alter RGB values of transparent alpha, which is
71 // normally OK but not here since we are not encoding the input image but an
72 // internal encoding-related image containing necessary exact information in
73 // RGB channels.
74 config.exact = 1;
79 config.method = effort_level; // impact is very small 75 config.method = effort_level; // impact is very small
80 // Set a low default quality for encoding alpha. Ensure that Alpha quality at 76 // Set a low default quality for encoding alpha. Ensure that Alpha quality at
81 // lower methods (3 and below) is less than the threshold for triggering 77 // lower methods (3 and below) is less than the threshold for triggering
82 // costly 'BackwardReferencesTraceBackwards'. 78 // costly 'BackwardReferencesTraceBackwards'.
83 config.quality = 8.f * effort_level; 79 config.quality = 8.f * effort_level;
84 assert(config.quality >= 0 && config.quality <= 100.f); 80 assert(config.quality >= 0 && config.quality <= 100.f);
85 81
86 ok = (VP8LEncodeStream(&config, &picture, bw) == VP8_ENC_OK); 82 ok = (VP8LEncodeStream(&config, &picture, bw) == VP8_ENC_OK);
87 WebPPictureFree(&picture); 83 WebPPictureFree(&picture);
88 ok = ok && !bw->error_; 84 ok = ok && !bw->error_;
89 if (!ok) { 85 if (!ok) {
90 VP8LBitWriterDestroy(bw); 86 VP8LBitWriterWipeOut(bw);
91 return 0; 87 return 0;
92 } 88 }
93 return 1; 89 return 1;
94
95 } 90 }
96 91
97 // ----------------------------------------------------------------------------- 92 // -----------------------------------------------------------------------------
98 93
99 // Small struct to hold the result of a filter mode compression attempt. 94 // Small struct to hold the result of a filter mode compression attempt.
100 typedef struct { 95 typedef struct {
101 size_t score; 96 size_t score;
102 VP8BitWriter bw; 97 VP8BitWriter bw;
103 WebPAuxStats stats; 98 WebPAuxStats stats;
104 } FilterTrial; 99 } FilterTrial;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 if (method != ALPHA_NO_COMPRESSION) { 131 if (method != ALPHA_NO_COMPRESSION) {
137 ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3); 132 ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3);
138 ok = ok && EncodeLossless(alpha_src, width, height, effort_level, 133 ok = ok && EncodeLossless(alpha_src, width, height, effort_level,
139 &tmp_bw, &result->stats); 134 &tmp_bw, &result->stats);
140 if (ok) { 135 if (ok) {
141 output = VP8LBitWriterFinish(&tmp_bw); 136 output = VP8LBitWriterFinish(&tmp_bw);
142 output_size = VP8LBitWriterNumBytes(&tmp_bw); 137 output_size = VP8LBitWriterNumBytes(&tmp_bw);
143 if (output_size > data_size) { 138 if (output_size > data_size) {
144 // compressed size is larger than source! Revert to uncompressed mode. 139 // compressed size is larger than source! Revert to uncompressed mode.
145 method = ALPHA_NO_COMPRESSION; 140 method = ALPHA_NO_COMPRESSION;
146 VP8LBitWriterDestroy(&tmp_bw); 141 VP8LBitWriterWipeOut(&tmp_bw);
147 } 142 }
148 } else { 143 } else {
149 VP8LBitWriterDestroy(&tmp_bw); 144 VP8LBitWriterWipeOut(&tmp_bw);
150 return 0; 145 return 0;
151 } 146 }
152 } 147 }
153 148
154 if (method == ALPHA_NO_COMPRESSION) { 149 if (method == ALPHA_NO_COMPRESSION) {
155 output = alpha_src; 150 output = alpha_src;
156 output_size = data_size; 151 output_size = data_size;
157 ok = 1; 152 ok = 1;
158 } 153 }
159 154
160 // Emit final result. 155 // Emit final result.
161 header = method | (filter << 2); 156 header = method | (filter << 2);
162 if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; 157 if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
163 158
164 VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size); 159 VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size);
165 ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN); 160 ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
166 ok = ok && VP8BitWriterAppend(&result->bw, output, output_size); 161 ok = ok && VP8BitWriterAppend(&result->bw, output, output_size);
167 162
168 if (method != ALPHA_NO_COMPRESSION) { 163 if (method != ALPHA_NO_COMPRESSION) {
169 VP8LBitWriterDestroy(&tmp_bw); 164 VP8LBitWriterWipeOut(&tmp_bw);
170 } 165 }
171 ok = ok && !result->bw.error_; 166 ok = ok && !result->bw.error_;
172 result->score = VP8BitWriterSize(&result->bw); 167 result->score = VP8BitWriterSize(&result->bw);
173 return ok; 168 return ok;
174 } 169 }
175 170
176 // ----------------------------------------------------------------------------- 171 // -----------------------------------------------------------------------------
177 172
178 // TODO(skal): move to dsp/ ?
179 static void CopyPlane(const uint8_t* src, int src_stride,
180 uint8_t* dst, int dst_stride, int width, int height) {
181 while (height-- > 0) {
182 memcpy(dst, src, width);
183 src += src_stride;
184 dst += dst_stride;
185 }
186 }
187
188 static int GetNumColors(const uint8_t* data, int width, int height, 173 static int GetNumColors(const uint8_t* data, int width, int height,
189 int stride) { 174 int stride) {
190 int j; 175 int j;
191 int colors = 0; 176 int colors = 0;
192 uint8_t color[256] = { 0 }; 177 uint8_t color[256] = { 0 };
193 178
194 for (j = 0; j < height; ++j) { 179 for (j = 0; j < height; ++j) {
195 int i; 180 int i;
196 const uint8_t* const p = data + j * stride; 181 const uint8_t* const p = data + j * stride;
197 for (i = 0; i < width; ++i) { 182 for (i = 0; i < width; ++i) {
(...skipping 13 matching lines...) Expand all
211 static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height, 196 static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height,
212 int filter, int effort_level) { 197 int filter, int effort_level) {
213 uint32_t bit_map = 0U; 198 uint32_t bit_map = 0U;
214 if (filter == WEBP_FILTER_FAST) { 199 if (filter == WEBP_FILTER_FAST) {
215 // Quick estimate of the best candidate. 200 // Quick estimate of the best candidate.
216 int try_filter_none = (effort_level > 3); 201 int try_filter_none = (effort_level > 3);
217 const int kMinColorsForFilterNone = 16; 202 const int kMinColorsForFilterNone = 16;
218 const int kMaxColorsForFilterNone = 192; 203 const int kMaxColorsForFilterNone = 192;
219 const int num_colors = GetNumColors(alpha, width, height, width); 204 const int num_colors = GetNumColors(alpha, width, height, width);
220 // For low number of colors, NONE yields better compression. 205 // For low number of colors, NONE yields better compression.
221 filter = (num_colors <= kMinColorsForFilterNone) ? WEBP_FILTER_NONE : 206 filter = (num_colors <= kMinColorsForFilterNone)
222 EstimateBestFilter(alpha, width, height, width); 207 ? WEBP_FILTER_NONE
208 : WebPEstimateBestFilter(alpha, width, height, width);
223 bit_map |= 1 << filter; 209 bit_map |= 1 << filter;
224 // For large number of colors, try FILTER_NONE in addition to the best 210 // For large number of colors, try FILTER_NONE in addition to the best
225 // filter as well. 211 // filter as well.
226 if (try_filter_none || num_colors > kMaxColorsForFilterNone) { 212 if (try_filter_none || num_colors > kMaxColorsForFilterNone) {
227 bit_map |= FILTER_TRY_NONE; 213 bit_map |= FILTER_TRY_NONE;
228 } 214 }
229 } else if (filter == WEBP_FILTER_NONE) { 215 } else if (filter == WEBP_FILTER_NONE) {
230 bit_map = FILTER_TRY_NONE; 216 bit_map = FILTER_TRY_NONE;
231 } else { // WEBP_FILTER_BEST -> try all 217 } else { // WEBP_FILTER_BEST -> try all
232 bit_map = FILTER_TRY_ALL; 218 bit_map = FILTER_TRY_ALL;
(...skipping 10 matching lines...) Expand all
243 size_t data_size, int method, int filter, 229 size_t data_size, int method, int filter,
244 int reduce_levels, int effort_level, 230 int reduce_levels, int effort_level,
245 uint8_t** const output, 231 uint8_t** const output,
246 size_t* const output_size, 232 size_t* const output_size,
247 WebPAuxStats* const stats) { 233 WebPAuxStats* const stats) {
248 int ok = 1; 234 int ok = 1;
249 FilterTrial best; 235 FilterTrial best;
250 uint32_t try_map = 236 uint32_t try_map =
251 GetFilterMap(alpha, width, height, filter, effort_level); 237 GetFilterMap(alpha, width, height, filter, effort_level);
252 InitFilterTrial(&best); 238 InitFilterTrial(&best);
239
253 if (try_map != FILTER_TRY_NONE) { 240 if (try_map != FILTER_TRY_NONE) {
254 uint8_t* filtered_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size); 241 uint8_t* filtered_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
255 if (filtered_alpha == NULL) return 0; 242 if (filtered_alpha == NULL) return 0;
256 243
257 for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) { 244 for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) {
258 if (try_map & 1) { 245 if (try_map & 1) {
259 FilterTrial trial; 246 FilterTrial trial;
260 ok = EncodeAlphaInternal(alpha, width, height, method, filter, 247 ok = EncodeAlphaInternal(alpha, width, height, method, filter,
261 reduce_levels, effort_level, filtered_alpha, 248 reduce_levels, effort_level, filtered_alpha,
262 &trial); 249 &trial);
263 if (ok && trial.score < best.score) { 250 if (ok && trial.score < best.score) {
264 VP8BitWriterWipeOut(&best.bw); 251 VP8BitWriterWipeOut(&best.bw);
265 best = trial; 252 best = trial;
266 } else { 253 } else {
267 VP8BitWriterWipeOut(&trial.bw); 254 VP8BitWriterWipeOut(&trial.bw);
268 } 255 }
269 } 256 }
270 } 257 }
271 WebPSafeFree(filtered_alpha); 258 WebPSafeFree(filtered_alpha);
272 } else { 259 } else {
273 ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE, 260 ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE,
274 reduce_levels, effort_level, NULL, &best); 261 reduce_levels, effort_level, NULL, &best);
275 } 262 }
276 if (ok) { 263 if (ok) {
277 if (stats != NULL) *stats = best.stats; 264 if (stats != NULL) {
265 stats->lossless_features = best.stats.lossless_features;
266 stats->histogram_bits = best.stats.histogram_bits;
267 stats->transform_bits = best.stats.transform_bits;
268 stats->cache_bits = best.stats.cache_bits;
269 stats->palette_size = best.stats.palette_size;
270 stats->lossless_size = best.stats.lossless_size;
271 stats->lossless_hdr_size = best.stats.lossless_hdr_size;
272 stats->lossless_data_size = best.stats.lossless_data_size;
273 }
278 *output_size = VP8BitWriterSize(&best.bw); 274 *output_size = VP8BitWriterSize(&best.bw);
279 *output = VP8BitWriterBuf(&best.bw); 275 *output = VP8BitWriterBuf(&best.bw);
280 } else { 276 } else {
281 VP8BitWriterWipeOut(&best.bw); 277 VP8BitWriterWipeOut(&best.bw);
282 } 278 }
283 return ok; 279 return ok;
284 } 280 }
285 281
286 static int EncodeAlpha(VP8Encoder* const enc, 282 static int EncodeAlpha(VP8Encoder* const enc,
287 int quality, int method, int filter, 283 int quality, int method, int filter,
(...skipping 29 matching lines...) Expand all
317 // Don't filter, as filtering will make no impact on compressed size. 313 // Don't filter, as filtering will make no impact on compressed size.
318 filter = WEBP_FILTER_NONE; 314 filter = WEBP_FILTER_NONE;
319 } 315 }
320 316
321 quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size); 317 quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
322 if (quant_alpha == NULL) { 318 if (quant_alpha == NULL) {
323 return 0; 319 return 0;
324 } 320 }
325 321
326 // Extract alpha data (width x height) from raw_data (stride x height). 322 // Extract alpha data (width x height) from raw_data (stride x height).
327 CopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height); 323 WebPCopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height);
328 324
329 if (reduce_levels) { // No Quantization required for 'quality = 100'. 325 if (reduce_levels) { // No Quantization required for 'quality = 100'.
330 // 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence 326 // 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence
331 // mapped to moderate quality 70. Hence Quality:[0, 70] -> Levels:[2, 16] 327 // mapped to moderate quality 70. Hence Quality:[0, 70] -> Levels:[2, 16]
332 // and Quality:]70, 100] -> Levels:]16, 256]. 328 // and Quality:]70, 100] -> Levels:]16, 256].
333 const int alpha_levels = (quality <= 70) ? (2 + quality / 5) 329 const int alpha_levels = (quality <= 70) ? (2 + quality / 5)
334 : (16 + (quality - 70) * 8); 330 : (16 + (quality - 70) * 8);
335 ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse); 331 ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse);
336 } 332 }
337 333
338 if (ok) { 334 if (ok) {
335 VP8FiltersInit();
339 ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method, 336 ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method,
340 filter, reduce_levels, effort_level, output, 337 filter, reduce_levels, effort_level, output,
341 output_size, pic->stats); 338 output_size, pic->stats);
342 if (pic->stats != NULL) { // need stats? 339 if (pic->stats != NULL) { // need stats?
343 pic->stats->coded_size += (int)(*output_size); 340 pic->stats->coded_size += (int)(*output_size);
344 enc->sse_[3] = sse; 341 enc->sse_[3] = sse;
345 } 342 }
346 } 343 }
347 344
348 WebPSafeFree(quant_alpha); 345 WebPSafeFree(quant_alpha);
(...skipping 20 matching lines...) Expand all
369 WebPSafeFree(alpha_data); 366 WebPSafeFree(alpha_data);
370 return 0; 367 return 0;
371 } 368 }
372 enc->alpha_data_size_ = (uint32_t)alpha_size; 369 enc->alpha_data_size_ = (uint32_t)alpha_size;
373 enc->alpha_data_ = alpha_data; 370 enc->alpha_data_ = alpha_data;
374 (void)dummy; 371 (void)dummy;
375 return 1; 372 return 1;
376 } 373 }
377 374
378 void VP8EncInitAlpha(VP8Encoder* const enc) { 375 void VP8EncInitAlpha(VP8Encoder* const enc) {
376 WebPInitAlphaProcessing();
379 enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_); 377 enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_);
380 enc->alpha_data_ = NULL; 378 enc->alpha_data_ = NULL;
381 enc->alpha_data_size_ = 0; 379 enc->alpha_data_size_ = 0;
382 if (enc->thread_level_ > 0) { 380 if (enc->thread_level_ > 0) {
383 WebPWorker* const worker = &enc->alpha_worker_; 381 WebPWorker* const worker = &enc->alpha_worker_;
384 WebPGetWorkerInterface()->Init(worker); 382 WebPGetWorkerInterface()->Init(worker);
385 worker->data1 = enc; 383 worker->data1 = enc;
386 worker->data2 = NULL; 384 worker->data2 = NULL;
387 worker->hook = (WebPWorkerHook)CompressAlphaJob; 385 worker->hook = (WebPWorkerHook)CompressAlphaJob;
388 } 386 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 ok = WebPGetWorkerInterface()->Sync(worker); 421 ok = WebPGetWorkerInterface()->Sync(worker);
424 // still need to end the worker, even if !ok 422 // still need to end the worker, even if !ok
425 WebPGetWorkerInterface()->End(worker); 423 WebPGetWorkerInterface()->End(worker);
426 } 424 }
427 WebPSafeFree(enc->alpha_data_); 425 WebPSafeFree(enc->alpha_data_);
428 enc->alpha_data_ = NULL; 426 enc->alpha_data_ = NULL;
429 enc->alpha_data_size_ = 0; 427 enc->alpha_data_size_ = 0;
430 enc->has_alpha_ = 0; 428 enc->has_alpha_ = 0;
431 return ok; 429 return ok;
432 } 430 }
433
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698