| 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 |