OLD | NEW |
1 // Copyright 2011 Google Inc. | 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) |
11 | 11 |
12 #include <assert.h> | 12 #include <assert.h> |
13 #include <stdlib.h> | 13 #include <stdlib.h> |
14 #include <string.h> | 14 #include <string.h> |
15 #include <math.h> | 15 #include <math.h> |
16 | 16 |
17 #include "vp8enci.h" | 17 #include "./vp8enci.h" |
| 18 #include "./vp8li.h" |
| 19 #include "../utils/utils.h" |
18 | 20 |
19 // #define PRINT_MEMORY_INFO | 21 // #define PRINT_MEMORY_INFO |
20 | 22 |
21 #if defined(__cplusplus) || defined(c_plusplus) | 23 #if defined(__cplusplus) || defined(c_plusplus) |
22 extern "C" { | 24 extern "C" { |
23 #endif | 25 #endif |
24 | 26 |
25 #ifdef PRINT_MEMORY_INFO | 27 #ifdef PRINT_MEMORY_INFO |
26 #include <stdio.h> | 28 #include <stdio.h> |
27 #endif | 29 #endif |
(...skipping 10 matching lines...) Expand all Loading... |
38 | 40 |
39 static int DummyWriter(const uint8_t* data, size_t data_size, | 41 static int DummyWriter(const uint8_t* data, size_t data_size, |
40 const WebPPicture* const picture) { | 42 const WebPPicture* const picture) { |
41 // The following are to prevent 'unused variable' error message. | 43 // The following are to prevent 'unused variable' error message. |
42 (void)data; | 44 (void)data; |
43 (void)data_size; | 45 (void)data_size; |
44 (void)picture; | 46 (void)picture; |
45 return 1; | 47 return 1; |
46 } | 48 } |
47 | 49 |
48 int WebPPictureInitInternal(WebPPicture* const picture, int version) { | 50 int WebPPictureInitInternal(WebPPicture* picture, int version) { |
49 if (version != WEBP_ENCODER_ABI_VERSION) { | 51 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) { |
50 return 0; // caller/system version mismatch! | 52 return 0; // caller/system version mismatch! |
51 } | 53 } |
52 if (picture) { | 54 if (picture != NULL) { |
53 memset(picture, 0, sizeof(*picture)); | 55 memset(picture, 0, sizeof(*picture)); |
54 picture->writer = DummyWriter; | 56 picture->writer = DummyWriter; |
55 WebPEncodingSetError(picture, VP8_ENC_OK); | 57 WebPEncodingSetError(picture, VP8_ENC_OK); |
56 } | 58 } |
57 return 1; | 59 return 1; |
58 } | 60 } |
59 | 61 |
60 //------------------------------------------------------------------------------ | 62 //------------------------------------------------------------------------------ |
61 // VP8Encoder | 63 // VP8Encoder |
62 //------------------------------------------------------------------------------ | 64 //------------------------------------------------------------------------------ |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 // lf-stats: 2048 | 137 // lf-stats: 2048 |
136 // total: 68635 | 138 // total: 68635 |
137 // Transcient object sizes: | 139 // Transcient object sizes: |
138 // VP8EncIterator: 352 | 140 // VP8EncIterator: 352 |
139 // VP8ModeScore: 912 | 141 // VP8ModeScore: 912 |
140 // VP8SegmentInfo: 532 | 142 // VP8SegmentInfo: 532 |
141 // VP8Proba: 31032 | 143 // VP8Proba: 31032 |
142 // LFStats: 2048 | 144 // LFStats: 2048 |
143 // Picture size (yuv): 589824 | 145 // Picture size (yuv): 589824 |
144 | 146 |
145 static VP8Encoder* InitEncoder(const WebPConfig* const config, | 147 static VP8Encoder* InitVP8Encoder(const WebPConfig* const config, |
146 WebPPicture* const picture) { | 148 WebPPicture* const picture) { |
147 const int use_filter = | 149 const int use_filter = |
148 (config->filter_strength > 0) || (config->autofilter > 0); | 150 (config->filter_strength > 0) || (config->autofilter > 0); |
149 const int mb_w = (picture->width + 15) >> 4; | 151 const int mb_w = (picture->width + 15) >> 4; |
150 const int mb_h = (picture->height + 15) >> 4; | 152 const int mb_h = (picture->height + 15) >> 4; |
151 const int preds_w = 4 * mb_w + 1; | 153 const int preds_w = 4 * mb_w + 1; |
152 const int preds_h = 4 * mb_h + 1; | 154 const int preds_h = 4 * mb_h + 1; |
153 const size_t preds_size = preds_w * preds_h * sizeof(uint8_t); | 155 const size_t preds_size = preds_w * preds_h * sizeof(uint8_t); |
154 const int top_stride = mb_w * 16; | 156 const int top_stride = mb_w * 16; |
155 const size_t nz_size = (mb_w + 1) * sizeof(uint32_t); | 157 const size_t nz_size = (mb_w + 1) * sizeof(uint32_t); |
156 const size_t cache_size = (3 * YUV_SIZE + PRED_SIZE) * sizeof(uint8_t); | 158 const size_t cache_size = (3 * YUV_SIZE + PRED_SIZE) * sizeof(uint8_t); |
157 const size_t info_size = mb_w * mb_h * sizeof(VP8MBInfo); | 159 const size_t info_size = mb_w * mb_h * sizeof(VP8MBInfo); |
158 const size_t samples_size = (2 * top_stride + // top-luma/u/v | 160 const size_t samples_size = (2 * top_stride + // top-luma/u/v |
159 16 + 16 + 16 + 8 + 1 + // left y/u/v | 161 16 + 16 + 16 + 8 + 1 + // left y/u/v |
160 2 * ALIGN_CST) // align all | 162 2 * ALIGN_CST) // align all |
161 * sizeof(uint8_t); | 163 * sizeof(uint8_t); |
162 const size_t lf_stats_size = | 164 const size_t lf_stats_size = |
163 config->autofilter ? sizeof(LFStats) + ALIGN_CST : 0; | 165 config->autofilter ? sizeof(LFStats) + ALIGN_CST : 0; |
164 VP8Encoder* enc; | 166 VP8Encoder* enc; |
165 uint8_t* mem; | 167 uint8_t* mem; |
166 size_t size = sizeof(VP8Encoder) + ALIGN_CST // main struct | 168 const uint64_t size = (uint64_t)sizeof(VP8Encoder) // main struct |
167 + cache_size // working caches | 169 + ALIGN_CST // cache alignment |
168 + info_size // modes info | 170 + cache_size // working caches |
169 + preds_size // prediction modes | 171 + info_size // modes info |
170 + samples_size // top/left samples | 172 + preds_size // prediction modes |
171 + nz_size // coeff context bits | 173 + samples_size // top/left samples |
172 + lf_stats_size; // autofilter stats | 174 + nz_size // coeff context bits |
| 175 + lf_stats_size; // autofilter stats |
173 | 176 |
174 #ifdef PRINT_MEMORY_INFO | 177 #ifdef PRINT_MEMORY_INFO |
175 printf("===================================\n"); | 178 printf("===================================\n"); |
176 printf("Memory used:\n" | 179 printf("Memory used:\n" |
177 " encoder: %ld\n" | 180 " encoder: %ld\n" |
178 " block cache: %ld\n" | 181 " block cache: %ld\n" |
179 " info: %ld\n" | 182 " info: %ld\n" |
180 " preds: %ld\n" | 183 " preds: %ld\n" |
181 " top samples: %ld\n" | 184 " top samples: %ld\n" |
182 " non-zero: %ld\n" | 185 " non-zero: %ld\n" |
183 " lf-stats: %ld\n" | 186 " lf-stats: %ld\n" |
184 " total: %ld\n", | 187 " total: %ld\n", |
185 sizeof(VP8Encoder) + ALIGN_CST, cache_size, info_size, | 188 sizeof(VP8Encoder) + ALIGN_CST, cache_size, info_size, |
186 preds_size, samples_size, nz_size, lf_stats_size, size); | 189 preds_size, samples_size, nz_size, lf_stats_size, size); |
187 printf("Transcient object sizes:\n" | 190 printf("Transcient object sizes:\n" |
188 " VP8EncIterator: %ld\n" | 191 " VP8EncIterator: %ld\n" |
189 " VP8ModeScore: %ld\n" | 192 " VP8ModeScore: %ld\n" |
190 " VP8SegmentInfo: %ld\n" | 193 " VP8SegmentInfo: %ld\n" |
191 " VP8Proba: %ld\n" | 194 " VP8Proba: %ld\n" |
192 " LFStats: %ld\n", | 195 " LFStats: %ld\n", |
193 sizeof(VP8EncIterator), sizeof(VP8ModeScore), | 196 sizeof(VP8EncIterator), sizeof(VP8ModeScore), |
194 sizeof(VP8SegmentInfo), sizeof(VP8Proba), | 197 sizeof(VP8SegmentInfo), sizeof(VP8Proba), |
195 sizeof(LFStats)); | 198 sizeof(LFStats)); |
196 printf("Picture size (yuv): %ld\n", | 199 printf("Picture size (yuv): %ld\n", |
197 mb_w * mb_h * 384 * sizeof(uint8_t)); | 200 mb_w * mb_h * 384 * sizeof(uint8_t)); |
198 printf("===================================\n"); | 201 printf("===================================\n"); |
199 #endif | 202 #endif |
200 mem = (uint8_t*)malloc(size); | 203 mem = (uint8_t*)WebPSafeMalloc(size, sizeof(*mem)); |
201 if (mem == NULL) { | 204 if (mem == NULL) { |
202 WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); | 205 WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); |
203 return NULL; | 206 return NULL; |
204 } | 207 } |
205 enc = (VP8Encoder*)mem; | 208 enc = (VP8Encoder*)mem; |
206 mem = (uint8_t*)DO_ALIGN(mem + sizeof(*enc)); | 209 mem = (uint8_t*)DO_ALIGN(mem + sizeof(*enc)); |
207 memset(enc, 0, sizeof(*enc)); | 210 memset(enc, 0, sizeof(*enc)); |
208 enc->num_parts_ = 1 << config->partitions; | 211 enc->num_parts_ = 1 << config->partitions; |
209 enc->mb_w_ = mb_w; | 212 enc->mb_w_ = mb_w; |
210 enc->mb_h_ = mb_h; | 213 enc->mb_h_ = mb_h; |
(...skipping 24 matching lines...) Expand all Loading... |
235 enc->y_left_ = (uint8_t*)mem; | 238 enc->y_left_ = (uint8_t*)mem; |
236 mem += 16 + 16; | 239 mem += 16 + 16; |
237 enc->u_left_ = (uint8_t*)mem; | 240 enc->u_left_ = (uint8_t*)mem; |
238 mem += 16; | 241 mem += 16; |
239 enc->v_left_ = (uint8_t*)mem; | 242 enc->v_left_ = (uint8_t*)mem; |
240 mem += 8; | 243 mem += 8; |
241 | 244 |
242 enc->config_ = config; | 245 enc->config_ = config; |
243 enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2; | 246 enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2; |
244 enc->pic_ = picture; | 247 enc->pic_ = picture; |
| 248 enc->percent_ = 0; |
245 | 249 |
246 MapConfigToTools(enc); | 250 MapConfigToTools(enc); |
247 VP8EncDspInit(); | 251 VP8EncDspInit(); |
248 VP8DefaultProbas(enc); | 252 VP8DefaultProbas(enc); |
249 ResetSegmentHeader(enc); | 253 ResetSegmentHeader(enc); |
250 ResetFilterHeader(enc); | 254 ResetFilterHeader(enc); |
251 ResetBoundaryPredictions(enc); | 255 ResetBoundaryPredictions(enc); |
252 | 256 |
| 257 VP8EncInitAlpha(enc); |
253 #ifdef WEBP_EXPERIMENTAL_FEATURES | 258 #ifdef WEBP_EXPERIMENTAL_FEATURES |
254 VP8EncInitAlpha(enc); | |
255 VP8EncInitLayer(enc); | 259 VP8EncInitLayer(enc); |
256 #endif | 260 #endif |
257 | 261 |
258 return enc; | 262 return enc; |
259 } | 263 } |
260 | 264 |
261 static void DeleteEncoder(VP8Encoder* enc) { | 265 static void DeleteVP8Encoder(VP8Encoder* enc) { |
262 if (enc) { | 266 if (enc != NULL) { |
| 267 VP8EncDeleteAlpha(enc); |
263 #ifdef WEBP_EXPERIMENTAL_FEATURES | 268 #ifdef WEBP_EXPERIMENTAL_FEATURES |
264 VP8EncDeleteAlpha(enc); | |
265 VP8EncDeleteLayer(enc); | 269 VP8EncDeleteLayer(enc); |
266 #endif | 270 #endif |
267 free(enc); | 271 free(enc); |
268 } | 272 } |
269 } | 273 } |
270 | 274 |
271 //------------------------------------------------------------------------------ | 275 //------------------------------------------------------------------------------ |
272 | 276 |
273 static double GetPSNR(uint64_t err, uint64_t size) { | 277 static double GetPSNR(uint64_t err, uint64_t size) { |
274 return err ? 10. * log10(255. * 255. * size / err) : 99.; | 278 return err ? 10. * log10(255. * 255. * size / err) : 99.; |
275 } | 279 } |
276 | 280 |
277 static void FinalizePSNR(const VP8Encoder* const enc) { | 281 static void FinalizePSNR(const VP8Encoder* const enc) { |
278 WebPAuxStats* stats = enc->pic_->stats; | 282 WebPAuxStats* stats = enc->pic_->stats; |
279 const uint64_t size = enc->sse_count_; | 283 const uint64_t size = enc->sse_count_; |
280 const uint64_t* const sse = enc->sse_; | 284 const uint64_t* const sse = enc->sse_; |
281 stats->PSNR[0] = (float)GetPSNR(sse[0], size); | 285 stats->PSNR[0] = (float)GetPSNR(sse[0], size); |
282 stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4); | 286 stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4); |
283 stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4); | 287 stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4); |
284 stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2); | 288 stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2); |
| 289 stats->PSNR[4] = (float)GetPSNR(sse[3], size); |
285 } | 290 } |
286 | 291 |
287 static void StoreStats(VP8Encoder* const enc) { | 292 static void StoreStats(VP8Encoder* const enc) { |
288 WebPAuxStats* const stats = enc->pic_->stats; | 293 WebPAuxStats* const stats = enc->pic_->stats; |
289 if (stats) { | 294 if (stats != NULL) { |
290 int i, s; | 295 int i, s; |
291 for (i = 0; i < NUM_MB_SEGMENTS; ++i) { | 296 for (i = 0; i < NUM_MB_SEGMENTS; ++i) { |
292 stats->segment_level[i] = enc->dqm_[i].fstrength_; | 297 stats->segment_level[i] = enc->dqm_[i].fstrength_; |
293 stats->segment_quant[i] = enc->dqm_[i].quant_; | 298 stats->segment_quant[i] = enc->dqm_[i].quant_; |
294 for (s = 0; s <= 2; ++s) { | 299 for (s = 0; s <= 2; ++s) { |
295 stats->residual_bytes[s][i] = enc->residual_bytes_[s][i]; | 300 stats->residual_bytes[s][i] = enc->residual_bytes_[s][i]; |
296 } | 301 } |
297 } | 302 } |
298 FinalizePSNR(enc); | 303 FinalizePSNR(enc); |
299 stats->coded_size = enc->coded_size_; | 304 stats->coded_size = enc->coded_size_; |
300 for (i = 0; i < 3; ++i) { | 305 for (i = 0; i < 3; ++i) { |
301 stats->block_count[i] = enc->block_count_[i]; | 306 stats->block_count[i] = enc->block_count_[i]; |
302 } | 307 } |
303 } | 308 } |
| 309 WebPReportProgress(enc->pic_, 100, &enc->percent_); // done! |
304 } | 310 } |
305 | 311 |
306 int WebPEncodingSetError(WebPPicture* const pic, WebPEncodingError error) { | 312 int WebPEncodingSetError(const WebPPicture* const pic, |
307 assert((int)error <= VP8_ENC_ERROR_BAD_WRITE); | 313 WebPEncodingError error) { |
| 314 assert((int)error < VP8_ENC_ERROR_LAST); |
308 assert((int)error >= VP8_ENC_OK); | 315 assert((int)error >= VP8_ENC_OK); |
309 pic->error_code = error; | 316 ((WebPPicture*)pic)->error_code = error; |
310 return 0; | 317 return 0; |
311 } | 318 } |
312 | 319 |
| 320 int WebPReportProgress(const WebPPicture* const pic, |
| 321 int percent, int* const percent_store) { |
| 322 if (percent_store != NULL && percent != *percent_store) { |
| 323 *percent_store = percent; |
| 324 if (pic->progress_hook && !pic->progress_hook(percent, pic)) { |
| 325 // user abort requested |
| 326 WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT); |
| 327 return 0; |
| 328 } |
| 329 } |
| 330 return 1; // ok |
| 331 } |
313 //------------------------------------------------------------------------------ | 332 //------------------------------------------------------------------------------ |
314 | 333 |
315 int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) { | 334 int WebPEncode(const WebPConfig* config, WebPPicture* pic) { |
316 VP8Encoder* enc; | |
317 int ok; | 335 int ok; |
318 | 336 |
319 if (pic == NULL) | 337 if (pic == NULL) |
320 return 0; | 338 return 0; |
321 WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far | 339 WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far |
322 if (config == NULL) // bad params | 340 if (config == NULL) // bad params |
323 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); | 341 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); |
324 if (!WebPValidateConfig(config)) | 342 if (!WebPValidateConfig(config)) |
325 return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); | 343 return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); |
326 if (pic->width <= 0 || pic->height <= 0) | 344 if (pic->width <= 0 || pic->height <= 0) |
327 return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); | 345 return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); |
328 if (pic->y == NULL || pic->u == NULL || pic->v == NULL) | |
329 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); | |
330 if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) | 346 if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) |
331 return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); | 347 return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); |
332 | 348 |
333 enc = InitEncoder(config, pic); | 349 if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats)); |
334 if (enc == NULL) return 0; // pic->error is already set. | 350 |
335 ok = VP8EncAnalyze(enc) | 351 if (!config->lossless) { |
336 && VP8StatLoop(enc) | 352 VP8Encoder* enc = NULL; |
337 && VP8EncLoop(enc) | 353 if (pic->y == NULL || pic->u == NULL || pic->v == NULL) { |
| 354 if (pic->argb != NULL) { |
| 355 if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0; |
| 356 } else { |
| 357 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); |
| 358 } |
| 359 } |
| 360 |
| 361 enc = InitVP8Encoder(config, pic); |
| 362 if (enc == NULL) return 0; // pic->error is already set. |
| 363 // Note: each of the tasks below account for 20% in the progress report. |
| 364 ok = VP8EncAnalyze(enc) |
| 365 && VP8StatLoop(enc) |
| 366 && VP8EncLoop(enc) |
| 367 && VP8EncFinishAlpha(enc) |
338 #ifdef WEBP_EXPERIMENTAL_FEATURES | 368 #ifdef WEBP_EXPERIMENTAL_FEATURES |
339 && VP8EncFinishAlpha(enc) | 369 && VP8EncFinishLayer(enc) |
340 && VP8EncFinishLayer(enc) | |
341 #endif | 370 #endif |
342 && VP8EncWrite(enc); | 371 && VP8EncWrite(enc); |
343 StoreStats(enc); | 372 StoreStats(enc); |
344 DeleteEncoder(enc); | 373 if (!ok) { |
| 374 VP8EncFreeBitWriters(enc); |
| 375 } |
| 376 DeleteVP8Encoder(enc); |
| 377 } else { |
| 378 if (pic->argb == NULL) |
| 379 return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); |
| 380 |
| 381 ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem. |
| 382 } |
345 | 383 |
346 return ok; | 384 return ok; |
347 } | 385 } |
348 | 386 |
349 #if defined(__cplusplus) || defined(c_plusplus) | 387 #if defined(__cplusplus) || defined(c_plusplus) |
350 } // extern "C" | 388 } // extern "C" |
351 #endif | 389 #endif |
OLD | NEW |