| OLD | NEW |
| 1 // Copyright 2010 Google Inc. All Rights Reserved. | 1 // Copyright 2010 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 // Frame-reconstruction function. Memory allocation. | 8 // Frame-reconstruction function. Memory allocation. |
| 9 // | 9 // |
| 10 // Author: Skal (pascal.massimino@gmail.com) | 10 // Author: Skal (pascal.massimino@gmail.com) |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 static void FilterRow(const VP8Decoder* const dec) { | 90 static void FilterRow(const VP8Decoder* const dec) { |
| 91 int mb_x; | 91 int mb_x; |
| 92 const int mb_y = dec->thread_ctx_.mb_y_; | 92 const int mb_y = dec->thread_ctx_.mb_y_; |
| 93 assert(dec->thread_ctx_.filter_row_); | 93 assert(dec->thread_ctx_.filter_row_); |
| 94 for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { | 94 for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { |
| 95 DoFilter(dec, mb_x, mb_y); | 95 DoFilter(dec, mb_x, mb_y); |
| 96 } | 96 } |
| 97 } | 97 } |
| 98 | 98 |
| 99 //------------------------------------------------------------------------------ | 99 //------------------------------------------------------------------------------ |
| 100 // Precompute the filtering strength for each segment and each i4x4/i16x16 mode. |
| 100 | 101 |
| 101 void VP8StoreBlock(VP8Decoder* const dec) { | 102 static void PrecomputeFilterStrengths(VP8Decoder* const dec) { |
| 102 if (dec->filter_type_ > 0) { | 103 if (dec->filter_type_ > 0) { |
| 103 VP8FInfo* const info = dec->f_info_ + dec->mb_x_; | 104 int s; |
| 104 const int skip = dec->mb_info_[dec->mb_x_].skip_; | 105 const VP8FilterHeader* const hdr = &dec->filter_hdr_; |
| 105 int level = dec->filter_levels_[dec->segment_]; | 106 for (s = 0; s < NUM_MB_SEGMENTS; ++s) { |
| 106 if (dec->filter_hdr_.use_lf_delta_) { | 107 int i4x4; |
| 107 // TODO(skal): only CURRENT is handled for now. | 108 // First, compute the initial level |
| 108 level += dec->filter_hdr_.ref_lf_delta_[0]; | 109 int base_level; |
| 109 if (dec->is_i4x4_) { | 110 if (dec->segment_hdr_.use_segment_) { |
| 110 level += dec->filter_hdr_.mode_lf_delta_[0]; | 111 base_level = dec->segment_hdr_.filter_strength_[s]; |
| 112 if (!dec->segment_hdr_.absolute_delta_) { |
| 113 base_level += hdr->level_; |
| 114 } |
| 115 } else { |
| 116 base_level = hdr->level_; |
| 111 } | 117 } |
| 112 } | 118 for (i4x4 = 0; i4x4 <= 1; ++i4x4) { |
| 113 level = (level < 0) ? 0 : (level > 63) ? 63 : level; | 119 VP8FInfo* const info = &dec->fstrengths_[s][i4x4]; |
| 114 info->f_level_ = level; | 120 int level = base_level; |
| 121 if (hdr->use_lf_delta_) { |
| 122 // TODO(skal): only CURRENT is handled for now. |
| 123 level += hdr->ref_lf_delta_[0]; |
| 124 if (i4x4) { |
| 125 level += hdr->mode_lf_delta_[0]; |
| 126 } |
| 127 } |
| 128 level = (level < 0) ? 0 : (level > 63) ? 63 : level; |
| 129 info->f_level_ = level; |
| 115 | 130 |
| 116 if (dec->filter_hdr_.sharpness_ > 0) { | 131 if (hdr->sharpness_ > 0) { |
| 117 if (dec->filter_hdr_.sharpness_ > 4) { | 132 if (hdr->sharpness_ > 4) { |
| 118 level >>= 2; | 133 level >>= 2; |
| 119 } else { | 134 } else { |
| 120 level >>= 1; | 135 level >>= 1; |
| 136 } |
| 137 if (level > 9 - hdr->sharpness_) { |
| 138 level = 9 - hdr->sharpness_; |
| 139 } |
| 140 } |
| 141 info->f_ilevel_ = (level < 1) ? 1 : level; |
| 142 info->f_inner_ = 0; |
| 121 } | 143 } |
| 122 if (level > 9 - dec->filter_hdr_.sharpness_) { | |
| 123 level = 9 - dec->filter_hdr_.sharpness_; | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 info->f_ilevel_ = (level < 1) ? 1 : level; | |
| 128 info->f_inner_ = (!skip || dec->is_i4x4_); | |
| 129 } | |
| 130 { | |
| 131 // Transfer samples to row cache | |
| 132 int y; | |
| 133 const int y_offset = dec->cache_id_ * 16 * dec->cache_y_stride_; | |
| 134 const int uv_offset = dec->cache_id_ * 8 * dec->cache_uv_stride_; | |
| 135 uint8_t* const ydst = dec->cache_y_ + dec->mb_x_ * 16 + y_offset; | |
| 136 uint8_t* const udst = dec->cache_u_ + dec->mb_x_ * 8 + uv_offset; | |
| 137 uint8_t* const vdst = dec->cache_v_ + dec->mb_x_ * 8 + uv_offset; | |
| 138 for (y = 0; y < 16; ++y) { | |
| 139 memcpy(ydst + y * dec->cache_y_stride_, | |
| 140 dec->yuv_b_ + Y_OFF + y * BPS, 16); | |
| 141 } | |
| 142 for (y = 0; y < 8; ++y) { | |
| 143 memcpy(udst + y * dec->cache_uv_stride_, | |
| 144 dec->yuv_b_ + U_OFF + y * BPS, 8); | |
| 145 memcpy(vdst + y * dec->cache_uv_stride_, | |
| 146 dec->yuv_b_ + V_OFF + y * BPS, 8); | |
| 147 } | 144 } |
| 148 } | 145 } |
| 149 } | 146 } |
| 150 | 147 |
| 151 //------------------------------------------------------------------------------ | 148 //------------------------------------------------------------------------------ |
| 152 // This function is called after a row of macroblocks is finished decoding. | 149 // This function is called after a row of macroblocks is finished decoding. |
| 153 // It also takes into account the following restrictions: | 150 // It also takes into account the following restrictions: |
| 154 // * In case of in-loop filtering, we must hold off sending some of the bottom | 151 // * In case of in-loop filtering, we must hold off sending some of the bottom |
| 155 // pixels as they are yet unfiltered. They will be when the next macroblock | 152 // pixels as they are yet unfiltered. They will be when the next macroblock |
| 156 // row is decoded. Meanwhile, we must preserve them by rotating them in the | 153 // row is decoded. Meanwhile, we must preserve them by rotating them in the |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 // We need some 'extra' pixels on the right/bottom. | 329 // We need some 'extra' pixels on the right/bottom. |
| 333 dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4; | 330 dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4; |
| 334 dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4; | 331 dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4; |
| 335 if (dec->br_mb_x_ > dec->mb_w_) { | 332 if (dec->br_mb_x_ > dec->mb_w_) { |
| 336 dec->br_mb_x_ = dec->mb_w_; | 333 dec->br_mb_x_ = dec->mb_w_; |
| 337 } | 334 } |
| 338 if (dec->br_mb_y_ > dec->mb_h_) { | 335 if (dec->br_mb_y_ > dec->mb_h_) { |
| 339 dec->br_mb_y_ = dec->mb_h_; | 336 dec->br_mb_y_ = dec->mb_h_; |
| 340 } | 337 } |
| 341 } | 338 } |
| 339 PrecomputeFilterStrengths(dec); |
| 342 return VP8_STATUS_OK; | 340 return VP8_STATUS_OK; |
| 343 } | 341 } |
| 344 | 342 |
| 345 int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { | 343 int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { |
| 346 int ok = 1; | 344 int ok = 1; |
| 347 if (dec->use_threads_) { | 345 if (dec->use_threads_) { |
| 348 ok = WebPWorkerSync(&dec->worker_); | 346 ok = WebPWorkerSync(&dec->worker_); |
| 349 } | 347 } |
| 350 | 348 |
| 351 if (io->teardown) { | 349 if (io->teardown) { |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 + 16 * num_caches * dec->cache_y_stride_ + extra_uv; | 487 + 16 * num_caches * dec->cache_y_stride_ + extra_uv; |
| 490 dec->cache_v_ = dec->cache_u_ | 488 dec->cache_v_ = dec->cache_u_ |
| 491 + 8 * num_caches * dec->cache_uv_stride_ + extra_uv; | 489 + 8 * num_caches * dec->cache_uv_stride_ + extra_uv; |
| 492 dec->cache_id_ = 0; | 490 dec->cache_id_ = 0; |
| 493 } | 491 } |
| 494 mem += cache_size; | 492 mem += cache_size; |
| 495 | 493 |
| 496 // alpha plane | 494 // alpha plane |
| 497 dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL; | 495 dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL; |
| 498 mem += alpha_size; | 496 mem += alpha_size; |
| 497 assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_); |
| 499 | 498 |
| 500 // note: left-info is initialized once for all. | 499 // note: left-info is initialized once for all. |
| 501 memset(dec->mb_info_ - 1, 0, mb_info_size); | 500 memset(dec->mb_info_ - 1, 0, mb_info_size); |
| 502 | 501 |
| 503 // initialize top | 502 // initialize top |
| 504 memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size); | 503 memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size); |
| 505 | 504 |
| 506 return 1; | 505 return 1; |
| 507 } | 506 } |
| 508 | 507 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 } | 543 } |
| 545 } | 544 } |
| 546 return mode; | 545 return mode; |
| 547 } | 546 } |
| 548 | 547 |
| 549 static WEBP_INLINE void Copy32b(uint8_t* dst, uint8_t* src) { | 548 static WEBP_INLINE void Copy32b(uint8_t* dst, uint8_t* src) { |
| 550 *(uint32_t*)dst = *(uint32_t*)src; | 549 *(uint32_t*)dst = *(uint32_t*)src; |
| 551 } | 550 } |
| 552 | 551 |
| 553 void VP8ReconstructBlock(VP8Decoder* const dec) { | 552 void VP8ReconstructBlock(VP8Decoder* const dec) { |
| 553 int j; |
| 554 uint8_t* const y_dst = dec->yuv_b_ + Y_OFF; | 554 uint8_t* const y_dst = dec->yuv_b_ + Y_OFF; |
| 555 uint8_t* const u_dst = dec->yuv_b_ + U_OFF; | 555 uint8_t* const u_dst = dec->yuv_b_ + U_OFF; |
| 556 uint8_t* const v_dst = dec->yuv_b_ + V_OFF; | 556 uint8_t* const v_dst = dec->yuv_b_ + V_OFF; |
| 557 | 557 |
| 558 // Rotate in the left samples from previously decoded block. We move four | 558 // Rotate in the left samples from previously decoded block. We move four |
| 559 // pixels at a time for alignment reason, and because of in-loop filter. | 559 // pixels at a time for alignment reason, and because of in-loop filter. |
| 560 if (dec->mb_x_ > 0) { | 560 if (dec->mb_x_ > 0) { |
| 561 int j; | |
| 562 for (j = -1; j < 16; ++j) { | 561 for (j = -1; j < 16; ++j) { |
| 563 Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]); | 562 Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]); |
| 564 } | 563 } |
| 565 for (j = -1; j < 8; ++j) { | 564 for (j = -1; j < 8; ++j) { |
| 566 Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]); | 565 Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]); |
| 567 Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]); | 566 Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]); |
| 568 } | 567 } |
| 569 } else { | 568 } else { |
| 570 int j; | |
| 571 for (j = 0; j < 16; ++j) { | 569 for (j = 0; j < 16; ++j) { |
| 572 y_dst[j * BPS - 1] = 129; | 570 y_dst[j * BPS - 1] = 129; |
| 573 } | 571 } |
| 574 for (j = 0; j < 8; ++j) { | 572 for (j = 0; j < 8; ++j) { |
| 575 u_dst[j * BPS - 1] = 129; | 573 u_dst[j * BPS - 1] = 129; |
| 576 v_dst[j * BPS - 1] = 129; | 574 v_dst[j * BPS - 1] = 129; |
| 577 } | 575 } |
| 578 // Init top-left sample on left column too | 576 // Init top-left sample on left column too |
| 579 if (dec->mb_y_ > 0) { | 577 if (dec->mb_y_ > 0) { |
| 580 y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129; | 578 y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 } | 661 } |
| 664 | 662 |
| 665 // stash away top samples for next block | 663 // stash away top samples for next block |
| 666 if (dec->mb_y_ < dec->mb_h_ - 1) { | 664 if (dec->mb_y_ < dec->mb_h_ - 1) { |
| 667 memcpy(top_y, y_dst + 15 * BPS, 16); | 665 memcpy(top_y, y_dst + 15 * BPS, 16); |
| 668 memcpy(top_u, u_dst + 7 * BPS, 8); | 666 memcpy(top_u, u_dst + 7 * BPS, 8); |
| 669 memcpy(top_v, v_dst + 7 * BPS, 8); | 667 memcpy(top_v, v_dst + 7 * BPS, 8); |
| 670 } | 668 } |
| 671 } | 669 } |
| 672 } | 670 } |
| 671 // Transfer reconstructed samples from yuv_b_ cache to final destination. |
| 672 { |
| 673 const int y_offset = dec->cache_id_ * 16 * dec->cache_y_stride_; |
| 674 const int uv_offset = dec->cache_id_ * 8 * dec->cache_uv_stride_; |
| 675 uint8_t* const y_out = dec->cache_y_ + dec->mb_x_ * 16 + y_offset; |
| 676 uint8_t* const u_out = dec->cache_u_ + dec->mb_x_ * 8 + uv_offset; |
| 677 uint8_t* const v_out = dec->cache_v_ + dec->mb_x_ * 8 + uv_offset; |
| 678 for (j = 0; j < 16; ++j) { |
| 679 memcpy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16); |
| 680 } |
| 681 for (j = 0; j < 8; ++j) { |
| 682 memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8); |
| 683 memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8); |
| 684 } |
| 685 } |
| 673 } | 686 } |
| 674 | 687 |
| 675 //------------------------------------------------------------------------------ | 688 //------------------------------------------------------------------------------ |
| 676 | 689 |
| 677 #if defined(__cplusplus) || defined(c_plusplus) | 690 #if defined(__cplusplus) || defined(c_plusplus) |
| 678 } // extern "C" | 691 } // extern "C" |
| 679 #endif | 692 #endif |
| OLD | NEW |