OLD | NEW |
1 // Copyright 2011 Google Inc. All Rights Reserved. | 1 // Copyright 2011 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 // VP8Iterator: block iterator | 10 // VP8Iterator: block iterator |
11 // | 11 // |
12 // Author: Skal (pascal.massimino@gmail.com) | 12 // Author: Skal (pascal.massimino@gmail.com) |
13 | 13 |
14 #include <string.h> | 14 #include <string.h> |
15 | 15 |
16 #include "./vp8enci.h" | 16 #include "./vp8enci.h" |
17 | 17 |
18 #if defined(__cplusplus) || defined(c_plusplus) | |
19 extern "C" { | |
20 #endif | |
21 | |
22 //------------------------------------------------------------------------------ | 18 //------------------------------------------------------------------------------ |
23 // VP8Iterator | 19 // VP8Iterator |
24 //------------------------------------------------------------------------------ | 20 //------------------------------------------------------------------------------ |
25 | 21 |
26 static void InitLeft(VP8EncIterator* const it) { | 22 static void InitLeft(VP8EncIterator* const it) { |
27 const VP8Encoder* const enc = it->enc_; | 23 it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = |
28 enc->y_left_[-1] = enc->u_left_[-1] = enc->v_left_[-1] = | |
29 (it->y_ > 0) ? 129 : 127; | 24 (it->y_ > 0) ? 129 : 127; |
30 memset(enc->y_left_, 129, 16); | 25 memset(it->y_left_, 129, 16); |
31 memset(enc->u_left_, 129, 8); | 26 memset(it->u_left_, 129, 8); |
32 memset(enc->v_left_, 129, 8); | 27 memset(it->v_left_, 129, 8); |
33 it->left_nz_[8] = 0; | 28 it->left_nz_[8] = 0; |
34 } | 29 } |
35 | 30 |
36 static void InitTop(VP8EncIterator* const it) { | 31 static void InitTop(VP8EncIterator* const it) { |
37 const VP8Encoder* const enc = it->enc_; | 32 const VP8Encoder* const enc = it->enc_; |
38 const size_t top_size = enc->mb_w_ * 16; | 33 const size_t top_size = enc->mb_w_ * 16; |
39 memset(enc->y_top_, 127, 2 * top_size); | 34 memset(enc->y_top_, 127, 2 * top_size); |
40 memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_)); | 35 memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_)); |
41 } | 36 } |
42 | 37 |
| 38 void VP8IteratorSetRow(VP8EncIterator* const it, int y) { |
| 39 VP8Encoder* const enc = it->enc_; |
| 40 it->x_ = 0; |
| 41 it->y_ = y; |
| 42 it->bw_ = &enc->parts_[y & (enc->num_parts_ - 1)]; |
| 43 it->preds_ = enc->preds_ + y * 4 * enc->preds_w_; |
| 44 it->nz_ = enc->nz_; |
| 45 it->mb_ = enc->mb_info_ + y * enc->mb_w_; |
| 46 it->y_top_ = enc->y_top_; |
| 47 it->uv_top_ = enc->uv_top_; |
| 48 InitLeft(it); |
| 49 } |
| 50 |
43 void VP8IteratorReset(VP8EncIterator* const it) { | 51 void VP8IteratorReset(VP8EncIterator* const it) { |
44 VP8Encoder* const enc = it->enc_; | 52 VP8Encoder* const enc = it->enc_; |
45 it->x_ = 0; | 53 VP8IteratorSetRow(it, 0); |
46 it->y_ = 0; | 54 VP8IteratorSetCountDown(it, enc->mb_w_ * enc->mb_h_); // default |
47 it->y_offset_ = 0; | |
48 it->uv_offset_ = 0; | |
49 it->mb_ = enc->mb_info_; | |
50 it->preds_ = enc->preds_; | |
51 it->nz_ = enc->nz_; | |
52 it->bw_ = &enc->parts_[0]; | |
53 it->done_ = enc->mb_w_* enc->mb_h_; | |
54 InitTop(it); | 55 InitTop(it); |
55 InitLeft(it); | 56 InitLeft(it); |
56 memset(it->bit_count_, 0, sizeof(it->bit_count_)); | 57 memset(it->bit_count_, 0, sizeof(it->bit_count_)); |
57 it->do_trellis_ = 0; | 58 it->do_trellis_ = 0; |
58 } | 59 } |
59 | 60 |
| 61 void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down) { |
| 62 it->count_down_ = it->count_down0_ = count_down; |
| 63 } |
| 64 |
| 65 int VP8IteratorIsDone(const VP8EncIterator* const it) { |
| 66 return (it->count_down_ <= 0); |
| 67 } |
| 68 |
60 void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) { | 69 void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) { |
61 it->enc_ = enc; | 70 it->enc_ = enc; |
62 it->y_stride_ = enc->pic_->y_stride; | 71 it->y_stride_ = enc->pic_->y_stride; |
63 it->uv_stride_ = enc->pic_->uv_stride; | 72 it->uv_stride_ = enc->pic_->uv_stride; |
64 // TODO(later): for multithreading, these should be owned by 'it'. | 73 it->yuv_in_ = (uint8_t*)DO_ALIGN(it->yuv_mem_); |
65 it->yuv_in_ = enc->yuv_in_; | 74 it->yuv_out_ = it->yuv_in_ + YUV_SIZE; |
66 it->yuv_out_ = enc->yuv_out_; | 75 it->yuv_out2_ = it->yuv_out_ + YUV_SIZE; |
67 it->yuv_out2_ = enc->yuv_out2_; | 76 it->yuv_p_ = it->yuv_out2_ + YUV_SIZE; |
68 it->yuv_p_ = enc->yuv_p_; | |
69 it->lf_stats_ = enc->lf_stats_; | 77 it->lf_stats_ = enc->lf_stats_; |
70 it->percent0_ = enc->percent_; | 78 it->percent0_ = enc->percent_; |
| 79 it->y_left_ = (uint8_t*)DO_ALIGN(it->yuv_left_mem_ + 1); |
| 80 it->u_left_ = it->y_left_ + 16 + 16; |
| 81 it->v_left_ = it->u_left_ + 16; |
71 VP8IteratorReset(it); | 82 VP8IteratorReset(it); |
72 } | 83 } |
73 | 84 |
74 int VP8IteratorProgress(const VP8EncIterator* const it, int delta) { | 85 int VP8IteratorProgress(const VP8EncIterator* const it, int delta) { |
75 VP8Encoder* const enc = it->enc_; | 86 VP8Encoder* const enc = it->enc_; |
76 if (delta && enc->pic_->progress_hook) { | 87 if (delta && enc->pic_->progress_hook != NULL) { |
77 const int percent = (enc->mb_h_ <= 1) | 88 const int done = it->count_down0_ - it->count_down_; |
| 89 const int percent = (it->count_down0_ <= 0) |
78 ? it->percent0_ | 90 ? it->percent0_ |
79 : it->percent0_ + delta * it->y_ / (enc->mb_h_ - 1); | 91 : it->percent0_ + delta * done / it->count_down0_; |
80 return WebPReportProgress(enc->pic_, percent, &enc->percent_); | 92 return WebPReportProgress(enc->pic_, percent, &enc->percent_); |
81 } | 93 } |
82 return 1; | 94 return 1; |
83 } | 95 } |
84 | 96 |
85 //------------------------------------------------------------------------------ | 97 //------------------------------------------------------------------------------ |
86 // Import the source samples into the cache. Takes care of replicating | 98 // Import the source samples into the cache. Takes care of replicating |
87 // boundary pixels if necessary. | 99 // boundary pixels if necessary. |
88 | 100 |
| 101 static WEBP_INLINE int MinSize(int a, int b) { return (a < b) ? a : b; } |
| 102 |
89 static void ImportBlock(const uint8_t* src, int src_stride, | 103 static void ImportBlock(const uint8_t* src, int src_stride, |
90 uint8_t* dst, int w, int h, int size) { | 104 uint8_t* dst, int w, int h, int size) { |
91 int i; | 105 int i; |
92 for (i = 0; i < h; ++i) { | 106 for (i = 0; i < h; ++i) { |
93 memcpy(dst, src, w); | 107 memcpy(dst, src, w); |
94 if (w < size) { | 108 if (w < size) { |
95 memset(dst + w, dst[w - 1], size - w); | 109 memset(dst + w, dst[w - 1], size - w); |
96 } | 110 } |
97 dst += BPS; | 111 dst += BPS; |
98 src += src_stride; | 112 src += src_stride; |
99 } | 113 } |
100 for (i = h; i < size; ++i) { | 114 for (i = h; i < size; ++i) { |
101 memcpy(dst, dst - BPS, size); | 115 memcpy(dst, dst - BPS, size); |
102 dst += BPS; | 116 dst += BPS; |
103 } | 117 } |
104 } | 118 } |
105 | 119 |
106 void VP8IteratorImport(const VP8EncIterator* const it) { | 120 static void ImportLine(const uint8_t* src, int src_stride, |
| 121 uint8_t* dst, int len, int total_len) { |
| 122 int i; |
| 123 for (i = 0; i < len; ++i, src += src_stride) dst[i] = *src; |
| 124 for (; i < total_len; ++i) dst[i] = dst[len - 1]; |
| 125 } |
| 126 |
| 127 void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32) { |
107 const VP8Encoder* const enc = it->enc_; | 128 const VP8Encoder* const enc = it->enc_; |
108 const int x = it->x_, y = it->y_; | 129 const int x = it->x_, y = it->y_; |
109 const WebPPicture* const pic = enc->pic_; | 130 const WebPPicture* const pic = enc->pic_; |
110 const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16; | 131 const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16; |
111 const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8; | 132 const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8; |
112 const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8; | 133 const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8; |
113 uint8_t* const ydst = it->yuv_in_ + Y_OFF; | 134 const int w = MinSize(pic->width - x * 16, 16); |
114 uint8_t* const udst = it->yuv_in_ + U_OFF; | 135 const int h = MinSize(pic->height - y * 16, 16); |
115 uint8_t* const vdst = it->yuv_in_ + V_OFF; | 136 const int uv_w = (w + 1) >> 1; |
116 int w = (pic->width - x * 16); | 137 const int uv_h = (h + 1) >> 1; |
117 int h = (pic->height - y * 16); | |
118 | 138 |
119 if (w > 16) w = 16; | 139 ImportBlock(ysrc, pic->y_stride, it->yuv_in_ + Y_OFF, w, h, 16); |
120 if (h > 16) h = 16; | 140 ImportBlock(usrc, pic->uv_stride, it->yuv_in_ + U_OFF, uv_w, uv_h, 8); |
| 141 ImportBlock(vsrc, pic->uv_stride, it->yuv_in_ + V_OFF, uv_w, uv_h, 8); |
121 | 142 |
122 // Luma plane | 143 if (tmp_32 == NULL) return; |
123 ImportBlock(ysrc, pic->y_stride, ydst, w, h, 16); | |
124 | 144 |
125 { // U/V planes | 145 // Import source (uncompressed) samples into boundary. |
126 const int uv_w = (w + 1) >> 1; | 146 if (x == 0) { |
127 const int uv_h = (h + 1) >> 1; | 147 InitLeft(it); |
128 ImportBlock(usrc, pic->uv_stride, udst, uv_w, uv_h, 8); | 148 } else { |
129 ImportBlock(vsrc, pic->uv_stride, vdst, uv_w, uv_h, 8); | 149 if (y == 0) { |
| 150 it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = 127; |
| 151 } else { |
| 152 it->y_left_[-1] = ysrc[- 1 - pic->y_stride]; |
| 153 it->u_left_[-1] = usrc[- 1 - pic->uv_stride]; |
| 154 it->v_left_[-1] = vsrc[- 1 - pic->uv_stride]; |
| 155 } |
| 156 ImportLine(ysrc - 1, pic->y_stride, it->y_left_, h, 16); |
| 157 ImportLine(usrc - 1, pic->uv_stride, it->u_left_, uv_h, 8); |
| 158 ImportLine(vsrc - 1, pic->uv_stride, it->v_left_, uv_h, 8); |
| 159 } |
| 160 |
| 161 it->y_top_ = tmp_32 + 0; |
| 162 it->uv_top_ = tmp_32 + 16; |
| 163 if (y == 0) { |
| 164 memset(tmp_32, 127, 32 * sizeof(*tmp_32)); |
| 165 } else { |
| 166 ImportLine(ysrc - pic->y_stride, 1, tmp_32, w, 16); |
| 167 ImportLine(usrc - pic->uv_stride, 1, tmp_32 + 16, uv_w, 8); |
| 168 ImportLine(vsrc - pic->uv_stride, 1, tmp_32 + 16 + 8, uv_w, 8); |
130 } | 169 } |
131 } | 170 } |
132 | 171 |
133 //------------------------------------------------------------------------------ | 172 //------------------------------------------------------------------------------ |
134 // Copy back the compressed samples into user space if requested. | 173 // Copy back the compressed samples into user space if requested. |
135 | 174 |
136 static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride, | 175 static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride, |
137 int w, int h) { | 176 int w, int h) { |
138 while (h-- > 0) { | 177 while (h-- > 0) { |
139 memcpy(dst, src, w); | 178 memcpy(dst, src, w); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 nz |= (left_nz[0] << 3) | (left_nz[1] << 7); | 274 nz |= (left_nz[0] << 3) | (left_nz[1] << 7); |
236 nz |= (left_nz[2] << 11); | 275 nz |= (left_nz[2] << 11); |
237 nz |= (left_nz[4] << 17) | (left_nz[6] << 21); | 276 nz |= (left_nz[4] << 17) | (left_nz[6] << 21); |
238 | 277 |
239 *it->nz_ = nz; | 278 *it->nz_ = nz; |
240 } | 279 } |
241 | 280 |
242 #undef BIT | 281 #undef BIT |
243 | 282 |
244 //------------------------------------------------------------------------------ | 283 //------------------------------------------------------------------------------ |
245 // Advance to the next position, doing the bookeeping. | 284 // Advance to the next position, doing the bookkeeping. |
246 | 285 |
247 int VP8IteratorNext(VP8EncIterator* const it, | 286 void VP8IteratorSaveBoundary(VP8EncIterator* const it) { |
248 const uint8_t* const block_to_save) { | |
249 VP8Encoder* const enc = it->enc_; | 287 VP8Encoder* const enc = it->enc_; |
250 if (block_to_save) { | 288 const int x = it->x_, y = it->y_; |
251 const int x = it->x_, y = it->y_; | 289 const uint8_t* const ysrc = it->yuv_out_ + Y_OFF; |
252 const uint8_t* const ysrc = block_to_save + Y_OFF; | 290 const uint8_t* const uvsrc = it->yuv_out_ + U_OFF; |
253 const uint8_t* const usrc = block_to_save + U_OFF; | 291 if (x < enc->mb_w_ - 1) { // left |
254 if (x < enc->mb_w_ - 1) { // left | 292 int i; |
255 int i; | 293 for (i = 0; i < 16; ++i) { |
256 for (i = 0; i < 16; ++i) { | 294 it->y_left_[i] = ysrc[15 + i * BPS]; |
257 enc->y_left_[i] = ysrc[15 + i * BPS]; | |
258 } | |
259 for (i = 0; i < 8; ++i) { | |
260 enc->u_left_[i] = usrc[7 + i * BPS]; | |
261 enc->v_left_[i] = usrc[15 + i * BPS]; | |
262 } | |
263 // top-left (before 'top'!) | |
264 enc->y_left_[-1] = enc->y_top_[x * 16 + 15]; | |
265 enc->u_left_[-1] = enc->uv_top_[x * 16 + 0 + 7]; | |
266 enc->v_left_[-1] = enc->uv_top_[x * 16 + 8 + 7]; | |
267 } | 295 } |
268 if (y < enc->mb_h_ - 1) { // top | 296 for (i = 0; i < 8; ++i) { |
269 memcpy(enc->y_top_ + x * 16, ysrc + 15 * BPS, 16); | 297 it->u_left_[i] = uvsrc[7 + i * BPS]; |
270 memcpy(enc->uv_top_ + x * 16, usrc + 7 * BPS, 8 + 8); | 298 it->v_left_[i] = uvsrc[15 + i * BPS]; |
271 } | 299 } |
| 300 // top-left (before 'top'!) |
| 301 it->y_left_[-1] = it->y_top_[15]; |
| 302 it->u_left_[-1] = it->uv_top_[0 + 7]; |
| 303 it->v_left_[-1] = it->uv_top_[8 + 7]; |
272 } | 304 } |
| 305 if (y < enc->mb_h_ - 1) { // top |
| 306 memcpy(it->y_top_, ysrc + 15 * BPS, 16); |
| 307 memcpy(it->uv_top_, uvsrc + 7 * BPS, 8 + 8); |
| 308 } |
| 309 } |
273 | 310 |
274 it->mb_++; | 311 int VP8IteratorNext(VP8EncIterator* const it) { |
275 it->preds_ += 4; | 312 it->preds_ += 4; |
276 it->nz_++; | 313 it->mb_ += 1; |
277 it->x_++; | 314 it->nz_ += 1; |
278 if (it->x_ == enc->mb_w_) { | 315 it->y_top_ += 16; |
279 it->x_ = 0; | 316 it->uv_top_ += 16; |
280 it->y_++; | 317 it->x_ += 1; |
281 it->bw_ = &enc->parts_[it->y_ & (enc->num_parts_ - 1)]; | 318 if (it->x_ == it->enc_->mb_w_) { |
282 it->preds_ = enc->preds_ + it->y_ * 4 * enc->preds_w_; | 319 VP8IteratorSetRow(it, ++it->y_); |
283 it->nz_ = enc->nz_; | |
284 InitLeft(it); | |
285 } | 320 } |
286 return (0 < --it->done_); | 321 return (0 < --it->count_down_); |
287 } | 322 } |
288 | 323 |
289 //------------------------------------------------------------------------------ | 324 //------------------------------------------------------------------------------ |
290 // Helper function to set mode properties | 325 // Helper function to set mode properties |
291 | 326 |
292 void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) { | 327 void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) { |
293 uint8_t* preds = it->preds_; | 328 uint8_t* preds = it->preds_; |
294 int y; | 329 int y; |
295 for (y = 0; y < 4; ++y) { | 330 for (y = 0; y < 4; ++y) { |
296 memset(preds, mode, 4); | 331 memset(preds, mode, 4); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 | 398 |
364 void VP8IteratorStartI4(VP8EncIterator* const it) { | 399 void VP8IteratorStartI4(VP8EncIterator* const it) { |
365 const VP8Encoder* const enc = it->enc_; | 400 const VP8Encoder* const enc = it->enc_; |
366 int i; | 401 int i; |
367 | 402 |
368 it->i4_ = 0; // first 4x4 sub-block | 403 it->i4_ = 0; // first 4x4 sub-block |
369 it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[0]; | 404 it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[0]; |
370 | 405 |
371 // Import the boundary samples | 406 // Import the boundary samples |
372 for (i = 0; i < 17; ++i) { // left | 407 for (i = 0; i < 17; ++i) { // left |
373 it->i4_boundary_[i] = enc->y_left_[15 - i]; | 408 it->i4_boundary_[i] = it->y_left_[15 - i]; |
374 } | 409 } |
375 for (i = 0; i < 16; ++i) { // top | 410 for (i = 0; i < 16; ++i) { // top |
376 it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i]; | 411 it->i4_boundary_[17 + i] = it->y_top_[i]; |
377 } | 412 } |
378 // top-right samples have a special case on the far right of the picture | 413 // top-right samples have a special case on the far right of the picture |
379 if (it->x_ < enc->mb_w_ - 1) { | 414 if (it->x_ < enc->mb_w_ - 1) { |
380 for (i = 16; i < 16 + 4; ++i) { | 415 for (i = 16; i < 16 + 4; ++i) { |
381 it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i]; | 416 it->i4_boundary_[17 + i] = it->y_top_[i]; |
382 } | 417 } |
383 } else { // else, replicate the last valid pixel four times | 418 } else { // else, replicate the last valid pixel four times |
384 for (i = 16; i < 16 + 4; ++i) { | 419 for (i = 16; i < 16 + 4; ++i) { |
385 it->i4_boundary_[17 + i] = it->i4_boundary_[17 + 15]; | 420 it->i4_boundary_[17 + i] = it->i4_boundary_[17 + 15]; |
386 } | 421 } |
387 } | 422 } |
388 VP8IteratorNzToBytes(it); // import the non-zero context | 423 VP8IteratorNzToBytes(it); // import the non-zero context |
389 } | 424 } |
390 | 425 |
391 int VP8IteratorRotateI4(VP8EncIterator* const it, | 426 int VP8IteratorRotateI4(VP8EncIterator* const it, |
(...skipping 20 matching lines...) Expand all Loading... |
412 if (it->i4_ == 16) { // we're done | 447 if (it->i4_ == 16) { // we're done |
413 return 0; | 448 return 0; |
414 } | 449 } |
415 | 450 |
416 it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[it->i4_]; | 451 it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[it->i4_]; |
417 return 1; | 452 return 1; |
418 } | 453 } |
419 | 454 |
420 //------------------------------------------------------------------------------ | 455 //------------------------------------------------------------------------------ |
421 | 456 |
422 #if defined(__cplusplus) || defined(c_plusplus) | |
423 } // extern "C" | |
424 #endif | |
OLD | NEW |