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 |