OLD | NEW |
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. |
(...skipping 29 matching lines...) Expand all Loading... |
40 // | 40 // |
41 // Returns 1 on successfully encoding the alpha and | 41 // Returns 1 on successfully encoding the alpha and |
42 // 0 if either: | 42 // 0 if either: |
43 // invalid quality or method, or | 43 // invalid quality or method, or |
44 // memory allocation for the compressed data fails. | 44 // memory allocation for the compressed data fails. |
45 | 45 |
46 #include "../enc/vp8li.h" | 46 #include "../enc/vp8li.h" |
47 | 47 |
48 static int EncodeLossless(const uint8_t* const data, int width, int height, | 48 static int EncodeLossless(const uint8_t* const data, int width, int height, |
49 int effort_level, // in [0..6] range | 49 int effort_level, // in [0..6] range |
50 VP8BitWriter* const bw, | 50 VP8LBitWriter* const bw, |
51 WebPAuxStats* const stats) { | 51 WebPAuxStats* const stats) { |
52 int ok = 0; | 52 int ok = 0; |
53 WebPConfig config; | 53 WebPConfig config; |
54 WebPPicture picture; | 54 WebPPicture picture; |
55 VP8LBitWriter tmp_bw; | |
56 | 55 |
57 WebPPictureInit(&picture); | 56 WebPPictureInit(&picture); |
58 picture.width = width; | 57 picture.width = width; |
59 picture.height = height; | 58 picture.height = height; |
60 picture.use_argb = 1; | 59 picture.use_argb = 1; |
61 picture.stats = stats; | 60 picture.stats = stats; |
62 if (!WebPPictureAlloc(&picture)) return 0; | 61 if (!WebPPictureAlloc(&picture)) return 0; |
63 | 62 |
64 // Transfer the alpha values to the green channel. | 63 // Transfer the alpha values to the green channel. |
65 { | 64 { |
(...skipping 11 matching lines...) Expand all Loading... |
77 | 76 |
78 WebPConfigInit(&config); | 77 WebPConfigInit(&config); |
79 config.lossless = 1; | 78 config.lossless = 1; |
80 config.method = effort_level; // impact is very small | 79 config.method = effort_level; // impact is very small |
81 // Set a low default quality for encoding alpha. Ensure that Alpha quality at | 80 // Set a low default quality for encoding alpha. Ensure that Alpha quality at |
82 // lower methods (3 and below) is less than the threshold for triggering | 81 // lower methods (3 and below) is less than the threshold for triggering |
83 // costly 'BackwardReferencesTraceBackwards'. | 82 // costly 'BackwardReferencesTraceBackwards'. |
84 config.quality = 8.f * effort_level; | 83 config.quality = 8.f * effort_level; |
85 assert(config.quality >= 0 && config.quality <= 100.f); | 84 assert(config.quality >= 0 && config.quality <= 100.f); |
86 | 85 |
87 ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3); | 86 ok = (VP8LEncodeStream(&config, &picture, bw) == VP8_ENC_OK); |
88 ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK); | |
89 WebPPictureFree(&picture); | 87 WebPPictureFree(&picture); |
90 if (ok) { | 88 ok = ok && !bw->error_; |
91 const uint8_t* const buffer = VP8LBitWriterFinish(&tmp_bw); | 89 if (!ok) { |
92 const size_t buffer_size = VP8LBitWriterNumBytes(&tmp_bw); | 90 VP8LBitWriterDestroy(bw); |
93 VP8BitWriterAppend(bw, buffer, buffer_size); | 91 return 0; |
94 } | 92 } |
95 VP8LBitWriterDestroy(&tmp_bw); | 93 return 1; |
96 return ok && !bw->error_; | 94 |
97 } | 95 } |
98 | 96 |
99 // ----------------------------------------------------------------------------- | 97 // ----------------------------------------------------------------------------- |
100 | 98 |
101 // Small struct to hold the result of a filter mode compression attempt. | 99 // Small struct to hold the result of a filter mode compression attempt. |
102 typedef struct { | 100 typedef struct { |
103 size_t score; | 101 size_t score; |
104 VP8BitWriter bw; | 102 VP8BitWriter bw; |
105 WebPAuxStats stats; | 103 WebPAuxStats stats; |
106 } FilterTrial; | 104 } FilterTrial; |
107 | 105 |
108 // This function always returns an initialized 'bw' object, even upon error. | 106 // This function always returns an initialized 'bw' object, even upon error. |
109 static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, | 107 static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, |
110 int method, int filter, int reduce_levels, | 108 int method, int filter, int reduce_levels, |
111 int effort_level, // in [0..6] range | 109 int effort_level, // in [0..6] range |
112 uint8_t* const tmp_alpha, | 110 uint8_t* const tmp_alpha, |
113 FilterTrial* result) { | 111 FilterTrial* result) { |
114 int ok = 0; | 112 int ok = 0; |
115 const uint8_t* alpha_src; | 113 const uint8_t* alpha_src; |
116 WebPFilterFunc filter_func; | 114 WebPFilterFunc filter_func; |
117 uint8_t header; | 115 uint8_t header; |
118 size_t expected_size; | |
119 const size_t data_size = width * height; | 116 const size_t data_size = width * height; |
| 117 const uint8_t* output = NULL; |
| 118 size_t output_size = 0; |
| 119 VP8LBitWriter tmp_bw; |
120 | 120 |
121 assert((uint64_t)data_size == (uint64_t)width * height); // as per spec | 121 assert((uint64_t)data_size == (uint64_t)width * height); // as per spec |
122 assert(filter >= 0 && filter < WEBP_FILTER_LAST); | 122 assert(filter >= 0 && filter < WEBP_FILTER_LAST); |
123 assert(method >= ALPHA_NO_COMPRESSION); | 123 assert(method >= ALPHA_NO_COMPRESSION); |
124 assert(method <= ALPHA_LOSSLESS_COMPRESSION); | 124 assert(method <= ALPHA_LOSSLESS_COMPRESSION); |
125 assert(sizeof(header) == ALPHA_HEADER_LEN); | 125 assert(sizeof(header) == ALPHA_HEADER_LEN); |
126 // TODO(skal): have a common function and #define's to validate alpha params. | 126 // TODO(skal): have a common function and #define's to validate alpha params. |
127 | 127 |
128 expected_size = | |
129 (method == ALPHA_NO_COMPRESSION) ? (ALPHA_HEADER_LEN + data_size) | |
130 : (data_size >> 5); | |
131 header = method | (filter << 2); | |
132 if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; | |
133 | |
134 VP8BitWriterInit(&result->bw, expected_size); | |
135 VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN); | |
136 | |
137 filter_func = WebPFilters[filter]; | 128 filter_func = WebPFilters[filter]; |
138 if (filter_func != NULL) { | 129 if (filter_func != NULL) { |
139 filter_func(data, width, height, width, tmp_alpha); | 130 filter_func(data, width, height, width, tmp_alpha); |
140 alpha_src = tmp_alpha; | 131 alpha_src = tmp_alpha; |
141 } else { | 132 } else { |
142 alpha_src = data; | 133 alpha_src = data; |
143 } | 134 } |
144 | 135 |
| 136 if (method != ALPHA_NO_COMPRESSION) { |
| 137 ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3); |
| 138 ok = ok && EncodeLossless(alpha_src, width, height, effort_level, |
| 139 &tmp_bw, &result->stats); |
| 140 if (ok) { |
| 141 output = VP8LBitWriterFinish(&tmp_bw); |
| 142 output_size = VP8LBitWriterNumBytes(&tmp_bw); |
| 143 if (output_size > data_size) { |
| 144 // compressed size is larger than source! Revert to uncompressed mode. |
| 145 method = ALPHA_NO_COMPRESSION; |
| 146 VP8LBitWriterDestroy(&tmp_bw); |
| 147 } |
| 148 } else { |
| 149 VP8LBitWriterDestroy(&tmp_bw); |
| 150 return 0; |
| 151 } |
| 152 } |
| 153 |
145 if (method == ALPHA_NO_COMPRESSION) { | 154 if (method == ALPHA_NO_COMPRESSION) { |
146 ok = VP8BitWriterAppend(&result->bw, alpha_src, width * height); | 155 output = alpha_src; |
147 ok = ok && !result->bw.error_; | 156 output_size = data_size; |
148 } else { | 157 ok = 1; |
149 ok = EncodeLossless(alpha_src, width, height, effort_level, | |
150 &result->bw, &result->stats); | |
151 VP8BitWriterFinish(&result->bw); | |
152 } | 158 } |
| 159 |
| 160 // Emit final result. |
| 161 header = method | (filter << 2); |
| 162 if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; |
| 163 |
| 164 VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size); |
| 165 ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN); |
| 166 ok = ok && VP8BitWriterAppend(&result->bw, output, output_size); |
| 167 |
| 168 if (method != ALPHA_NO_COMPRESSION) { |
| 169 VP8LBitWriterDestroy(&tmp_bw); |
| 170 } |
| 171 ok = ok && !result->bw.error_; |
153 result->score = VP8BitWriterSize(&result->bw); | 172 result->score = VP8BitWriterSize(&result->bw); |
154 return ok; | 173 return ok; |
155 } | 174 } |
156 | 175 |
157 // ----------------------------------------------------------------------------- | 176 // ----------------------------------------------------------------------------- |
158 | 177 |
159 // TODO(skal): move to dsp/ ? | 178 // TODO(skal): move to dsp/ ? |
160 static void CopyPlane(const uint8_t* src, int src_stride, | 179 static void CopyPlane(const uint8_t* src, int src_stride, |
161 uint8_t* dst, int dst_stride, int width, int height) { | 180 uint8_t* dst, int dst_stride, int width, int height) { |
162 while (height-- > 0) { | 181 while (height-- > 0) { |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 // still need to end the worker, even if !ok | 424 // still need to end the worker, even if !ok |
406 WebPGetWorkerInterface()->End(worker); | 425 WebPGetWorkerInterface()->End(worker); |
407 } | 426 } |
408 WebPSafeFree(enc->alpha_data_); | 427 WebPSafeFree(enc->alpha_data_); |
409 enc->alpha_data_ = NULL; | 428 enc->alpha_data_ = NULL; |
410 enc->alpha_data_size_ = 0; | 429 enc->alpha_data_size_ = 0; |
411 enc->has_alpha_ = 0; | 430 enc->has_alpha_ = 0; |
412 return ok; | 431 return ok; |
413 } | 432 } |
414 | 433 |
OLD | NEW |