| OLD | NEW |
| 1 // Copyright 2010 Google Inc. All Rights Reserved. | 1 // Copyright 2010 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 // Frame-reconstruction function. Memory allocation. | 10 // Frame-reconstruction function. Memory allocation. |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_; | 170 const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_; |
| 171 dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3; | 171 dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3; |
| 172 } | 172 } |
| 173 all_amp |= dqm->dither_; | 173 all_amp |= dqm->dither_; |
| 174 } | 174 } |
| 175 if (all_amp != 0) { | 175 if (all_amp != 0) { |
| 176 VP8InitRandom(&dec->dithering_rg_, 1.0f); | 176 VP8InitRandom(&dec->dithering_rg_, 1.0f); |
| 177 dec->dither_ = 1; | 177 dec->dither_ = 1; |
| 178 } | 178 } |
| 179 } | 179 } |
| 180 #if WEBP_DECODER_ABI_VERSION > 0x0203 |
| 181 // potentially allow alpha dithering |
| 182 dec->alpha_dithering_ = options->alpha_dithering_strength; |
| 183 if (dec->alpha_dithering_ > 100) { |
| 184 dec->alpha_dithering_ = 100; |
| 185 } else if (dec->alpha_dithering_ < 0) { |
| 186 dec->alpha_dithering_ = 0; |
| 187 } |
| 188 #endif |
| 180 } | 189 } |
| 181 } | 190 } |
| 182 | 191 |
| 183 // minimal amp that will provide a non-zero dithering effect | 192 // minimal amp that will provide a non-zero dithering effect |
| 184 #define MIN_DITHER_AMP 4 | 193 #define MIN_DITHER_AMP 4 |
| 185 #define DITHER_DESCALE 4 | 194 #define DITHER_DESCALE 4 |
| 186 #define DITHER_DESCALE_ROUNDER (1 << (DITHER_DESCALE - 1)) | 195 #define DITHER_DESCALE_ROUNDER (1 << (DITHER_DESCALE - 1)) |
| 187 #define DITHER_AMP_BITS 8 | 196 #define DITHER_AMP_BITS 8 |
| 188 #define DITHER_AMP_CENTER (1 << DITHER_AMP_BITS) | 197 #define DITHER_AMP_CENTER (1 << DITHER_AMP_BITS) |
| 189 | 198 |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_); | 349 (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_); |
| 341 if (dec->mt_method_ == 0) { | 350 if (dec->mt_method_ == 0) { |
| 342 // ctx->id_ and ctx->f_info_ are already set | 351 // ctx->id_ and ctx->f_info_ are already set |
| 343 ctx->mb_y_ = dec->mb_y_; | 352 ctx->mb_y_ = dec->mb_y_; |
| 344 ctx->filter_row_ = filter_row; | 353 ctx->filter_row_ = filter_row; |
| 345 ReconstructRow(dec, ctx); | 354 ReconstructRow(dec, ctx); |
| 346 ok = FinishRow(dec, io); | 355 ok = FinishRow(dec, io); |
| 347 } else { | 356 } else { |
| 348 WebPWorker* const worker = &dec->worker_; | 357 WebPWorker* const worker = &dec->worker_; |
| 349 // Finish previous job *before* updating context | 358 // Finish previous job *before* updating context |
| 350 ok &= WebPWorkerSync(worker); | 359 ok &= WebPGetWorkerInterface()->Sync(worker); |
| 351 assert(worker->status_ == OK); | 360 assert(worker->status_ == OK); |
| 352 if (ok) { // spawn a new deblocking/output job | 361 if (ok) { // spawn a new deblocking/output job |
| 353 ctx->io_ = *io; | 362 ctx->io_ = *io; |
| 354 ctx->id_ = dec->cache_id_; | 363 ctx->id_ = dec->cache_id_; |
| 355 ctx->mb_y_ = dec->mb_y_; | 364 ctx->mb_y_ = dec->mb_y_; |
| 356 ctx->filter_row_ = filter_row; | 365 ctx->filter_row_ = filter_row; |
| 357 if (dec->mt_method_ == 2) { // swap macroblock data | 366 if (dec->mt_method_ == 2) { // swap macroblock data |
| 358 VP8MBData* const tmp = ctx->mb_data_; | 367 VP8MBData* const tmp = ctx->mb_data_; |
| 359 ctx->mb_data_ = dec->mb_data_; | 368 ctx->mb_data_ = dec->mb_data_; |
| 360 dec->mb_data_ = tmp; | 369 dec->mb_data_ = tmp; |
| 361 } else { | 370 } else { |
| 362 // perform reconstruction directly in main thread | 371 // perform reconstruction directly in main thread |
| 363 ReconstructRow(dec, ctx); | 372 ReconstructRow(dec, ctx); |
| 364 } | 373 } |
| 365 if (filter_row) { // swap filter info | 374 if (filter_row) { // swap filter info |
| 366 VP8FInfo* const tmp = ctx->f_info_; | 375 VP8FInfo* const tmp = ctx->f_info_; |
| 367 ctx->f_info_ = dec->f_info_; | 376 ctx->f_info_ = dec->f_info_; |
| 368 dec->f_info_ = tmp; | 377 dec->f_info_ = tmp; |
| 369 } | 378 } |
| 370 WebPWorkerLaunch(worker); // (reconstruct)+filter in parallel | 379 // (reconstruct)+filter in parallel |
| 380 WebPGetWorkerInterface()->Launch(worker); |
| 371 if (++dec->cache_id_ == dec->num_caches_) { | 381 if (++dec->cache_id_ == dec->num_caches_) { |
| 372 dec->cache_id_ = 0; | 382 dec->cache_id_ = 0; |
| 373 } | 383 } |
| 374 } | 384 } |
| 375 } | 385 } |
| 376 return ok; | 386 return ok; |
| 377 } | 387 } |
| 378 | 388 |
| 379 //------------------------------------------------------------------------------ | 389 //------------------------------------------------------------------------------ |
| 380 // Finish setting up the decoding parameter once user's setup() is called. | 390 // Finish setting up the decoding parameter once user's setup() is called. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 dec->br_mb_y_ = dec->mb_h_; | 440 dec->br_mb_y_ = dec->mb_h_; |
| 431 } | 441 } |
| 432 } | 442 } |
| 433 PrecomputeFilterStrengths(dec); | 443 PrecomputeFilterStrengths(dec); |
| 434 return VP8_STATUS_OK; | 444 return VP8_STATUS_OK; |
| 435 } | 445 } |
| 436 | 446 |
| 437 int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { | 447 int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { |
| 438 int ok = 1; | 448 int ok = 1; |
| 439 if (dec->mt_method_ > 0) { | 449 if (dec->mt_method_ > 0) { |
| 440 ok = WebPWorkerSync(&dec->worker_); | 450 ok = WebPGetWorkerInterface()->Sync(&dec->worker_); |
| 441 } | 451 } |
| 442 | 452 |
| 443 if (io->teardown != NULL) { | 453 if (io->teardown != NULL) { |
| 444 io->teardown(io); | 454 io->teardown(io); |
| 445 } | 455 } |
| 446 return ok; | 456 return ok; |
| 447 } | 457 } |
| 448 | 458 |
| 449 //------------------------------------------------------------------------------ | 459 //------------------------------------------------------------------------------ |
| 450 // For multi-threaded decoding we need to use 3 rows of 16 pixels as delay line. | 460 // For multi-threaded decoding we need to use 3 rows of 16 pixels as delay line. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 471 // io->put: [ 0..15][16..31][ 0..15][... | 481 // io->put: [ 0..15][16..31][ 0..15][... |
| 472 | 482 |
| 473 #define MT_CACHE_LINES 3 | 483 #define MT_CACHE_LINES 3 |
| 474 #define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case | 484 #define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case |
| 475 | 485 |
| 476 // Initialize multi/single-thread worker | 486 // Initialize multi/single-thread worker |
| 477 static int InitThreadContext(VP8Decoder* const dec) { | 487 static int InitThreadContext(VP8Decoder* const dec) { |
| 478 dec->cache_id_ = 0; | 488 dec->cache_id_ = 0; |
| 479 if (dec->mt_method_ > 0) { | 489 if (dec->mt_method_ > 0) { |
| 480 WebPWorker* const worker = &dec->worker_; | 490 WebPWorker* const worker = &dec->worker_; |
| 481 if (!WebPWorkerReset(worker)) { | 491 if (!WebPGetWorkerInterface()->Reset(worker)) { |
| 482 return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, | 492 return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, |
| 483 "thread initialization failed."); | 493 "thread initialization failed."); |
| 484 } | 494 } |
| 485 worker->data1 = dec; | 495 worker->data1 = dec; |
| 486 worker->data2 = (void*)&dec->thread_ctx_.io_; | 496 worker->data2 = (void*)&dec->thread_ctx_.io_; |
| 487 worker->hook = (WebPWorkerHook)FinishRow; | 497 worker->hook = (WebPWorkerHook)FinishRow; |
| 488 dec->num_caches_ = | 498 dec->num_caches_ = |
| 489 (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; | 499 (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; |
| 490 } else { | 500 } else { |
| 491 dec->num_caches_ = ST_CACHE_LINES; | 501 dec->num_caches_ = ST_CACHE_LINES; |
| 492 } | 502 } |
| 493 return 1; | 503 return 1; |
| 494 } | 504 } |
| 495 | 505 |
| 496 int VP8GetThreadMethod(const WebPDecoderOptions* const options, | 506 int VP8GetThreadMethod(const WebPDecoderOptions* const options, |
| 497 const WebPHeaderStructure* const headers, | 507 const WebPHeaderStructure* const headers, |
| 498 int width, int height) { | 508 int width, int height) { |
| 499 if (options == NULL || options->use_threads == 0) { | 509 if (options == NULL || options->use_threads == 0) { |
| 500 return 0; | 510 return 0; |
| 501 } | 511 } |
| 502 (void)headers; | 512 (void)headers; |
| 503 (void)width; | 513 (void)width; |
| 504 (void)height; | 514 (void)height; |
| 505 assert(!headers->is_lossless); | 515 assert(headers == NULL || !headers->is_lossless); |
| 506 #if defined(WEBP_USE_THREAD) | 516 #if defined(WEBP_USE_THREAD) |
| 507 if (width < MIN_WIDTH_FOR_THREADS) return 0; | 517 if (width < MIN_WIDTH_FOR_THREADS) return 0; |
| 508 // TODO(skal): tune the heuristic further | 518 // TODO(skal): tune the heuristic further |
| 509 #if 0 | 519 #if 0 |
| 510 if (height < 2 * width) return 2; | 520 if (height < 2 * width) return 2; |
| 511 #endif | 521 #endif |
| 512 return 2; | 522 return 2; |
| 513 #else // !WEBP_USE_THREAD | 523 #else // !WEBP_USE_THREAD |
| 514 return 0; | 524 return 0; |
| 515 #endif | 525 #endif |
| (...skipping 26 matching lines...) Expand all Loading... |
| 542 const uint64_t alpha_size = (dec->alpha_data_ != NULL) ? | 552 const uint64_t alpha_size = (dec->alpha_data_ != NULL) ? |
| 543 (uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL; | 553 (uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL; |
| 544 const uint64_t needed = (uint64_t)intra_pred_mode_size | 554 const uint64_t needed = (uint64_t)intra_pred_mode_size |
| 545 + top_size + mb_info_size + f_info_size | 555 + top_size + mb_info_size + f_info_size |
| 546 + yuv_size + mb_data_size | 556 + yuv_size + mb_data_size |
| 547 + cache_size + alpha_size + ALIGN_MASK; | 557 + cache_size + alpha_size + ALIGN_MASK; |
| 548 uint8_t* mem; | 558 uint8_t* mem; |
| 549 | 559 |
| 550 if (needed != (size_t)needed) return 0; // check for overflow | 560 if (needed != (size_t)needed) return 0; // check for overflow |
| 551 if (needed > dec->mem_size_) { | 561 if (needed > dec->mem_size_) { |
| 552 free(dec->mem_); | 562 WebPSafeFree(dec->mem_); |
| 553 dec->mem_size_ = 0; | 563 dec->mem_size_ = 0; |
| 554 dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t)); | 564 dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t)); |
| 555 if (dec->mem_ == NULL) { | 565 if (dec->mem_ == NULL) { |
| 556 return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, | 566 return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, |
| 557 "no memory during frame initialization."); | 567 "no memory during frame initialization."); |
| 558 } | 568 } |
| 559 // down-cast is ok, thanks to WebPSafeAlloc() above. | 569 // down-cast is ok, thanks to WebPSafeAlloc() above. |
| 560 dec->mem_size_ = (size_t)needed; | 570 dec->mem_size_ = (size_t)needed; |
| 561 } | 571 } |
| 562 | 572 |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 for (j = 0; j < 8; ++j) { | 819 for (j = 0; j < 8; ++j) { |
| 810 memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8); | 820 memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8); |
| 811 memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8); | 821 memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8); |
| 812 } | 822 } |
| 813 } | 823 } |
| 814 } | 824 } |
| 815 } | 825 } |
| 816 | 826 |
| 817 //------------------------------------------------------------------------------ | 827 //------------------------------------------------------------------------------ |
| 818 | 828 |
| OLD | NEW |