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 // frame coding and analysis | 8 // frame coding and analysis |
9 // | 9 // |
10 // Author: Skal (pascal.massimino@gmail.com) | 10 // Author: Skal (pascal.massimino@gmail.com) |
11 | 11 |
12 #include <stdlib.h> | 12 #include <stdlib.h> |
13 #include <string.h> | 13 #include <string.h> |
14 #include <assert.h> | |
15 #include <math.h> | 14 #include <math.h> |
16 | 15 |
17 #include "vp8enci.h" | 16 #include "./vp8enci.h" |
18 #include "cost.h" | 17 #include "./cost.h" |
19 | 18 |
20 #if defined(__cplusplus) || defined(c_plusplus) | 19 #if defined(__cplusplus) || defined(c_plusplus) |
21 extern "C" { | 20 extern "C" { |
22 #endif | 21 #endif |
23 | 22 |
24 #define SEGMENT_VISU 0 | 23 #define SEGMENT_VISU 0 |
25 #define DEBUG_SEARCH 0 // useful to track search convergence | 24 #define DEBUG_SEARCH 0 // useful to track search convergence |
26 | 25 |
27 // On-the-fly info about the current set of residuals. Handy to avoid | 26 // On-the-fly info about the current set of residuals. Handy to avoid |
28 // passing zillions of params. | 27 // passing zillions of params. |
(...skipping 27 matching lines...) Expand all Loading... |
56 | 55 |
57 static void ResetStats(VP8Encoder* const enc, int precalc_cost) { | 56 static void ResetStats(VP8Encoder* const enc, int precalc_cost) { |
58 VP8Proba* const proba = &enc->proba_; | 57 VP8Proba* const proba = &enc->proba_; |
59 if (precalc_cost) VP8CalculateLevelCosts(proba); | 58 if (precalc_cost) VP8CalculateLevelCosts(proba); |
60 proba->nb_skip_ = 0; | 59 proba->nb_skip_ = 0; |
61 } | 60 } |
62 | 61 |
63 //------------------------------------------------------------------------------ | 62 //------------------------------------------------------------------------------ |
64 // Skip decision probability | 63 // Skip decision probability |
65 | 64 |
| 65 #define SKIP_PROBA_THRESHOLD 250 // value below which using skip_proba is OK. |
| 66 |
66 static int CalcSkipProba(uint64_t nb, uint64_t total) { | 67 static int CalcSkipProba(uint64_t nb, uint64_t total) { |
67 return (int)(total ? (total - nb) * 255 / total : 255); | 68 return (int)(total ? (total - nb) * 255 / total : 255); |
68 } | 69 } |
69 | 70 |
70 // Returns the bit-cost for coding the skip probability. | 71 // Returns the bit-cost for coding the skip probability. |
71 static int FinalizeSkipProba(VP8Encoder* const enc) { | 72 static int FinalizeSkipProba(VP8Encoder* const enc) { |
72 VP8Proba* const proba = &enc->proba_; | 73 VP8Proba* const proba = &enc->proba_; |
73 const int nb_mbs = enc->mb_w_ * enc->mb_h_; | 74 const int nb_mbs = enc->mb_w_ * enc->mb_h_; |
74 const int nb_events = proba->nb_skip_; | 75 const int nb_events = proba->nb_skip_; |
75 int size; | 76 int size; |
76 proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); | 77 proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); |
77 proba->use_skip_proba_ = (proba->skip_proba_ < 250); | 78 proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD); |
78 size = 256; // 'use_skip_proba' bit | 79 size = 256; // 'use_skip_proba' bit |
79 if (proba->use_skip_proba_) { | 80 if (proba->use_skip_proba_) { |
80 size += nb_events * VP8BitCost(1, proba->skip_proba_) | 81 size += nb_events * VP8BitCost(1, proba->skip_proba_) |
81 + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); | 82 + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); |
82 size += 8 * 256; // cost of signaling the skip_proba_ itself. | 83 size += 8 * 256; // cost of signaling the skip_proba_ itself. |
83 } | 84 } |
84 return size; | 85 return size; |
85 } | 86 } |
86 | 87 |
87 //------------------------------------------------------------------------------ | 88 //------------------------------------------------------------------------------ |
88 // Recording of token probabilities. | 89 // Recording of token probabilities. |
89 | 90 |
90 static void ResetTokenStats(VP8Encoder* const enc) { | 91 static void ResetTokenStats(VP8Encoder* const enc) { |
91 VP8Proba* const proba = &enc->proba_; | 92 VP8Proba* const proba = &enc->proba_; |
92 memset(proba->stats_, 0, sizeof(proba->stats_)); | 93 memset(proba->stats_, 0, sizeof(proba->stats_)); |
93 } | 94 } |
94 | 95 |
95 // Record proba context used | 96 // Record proba context used |
96 static int Record(int bit, uint64_t* const stats) { | 97 static int Record(int bit, uint64_t* const stats) { |
97 stats[0] += bit; | 98 stats[0] += bit; |
98 stats[1] += 1; | 99 stats[1] += 1; |
99 return bit; | 100 return bit; |
100 } | 101 } |
101 | 102 |
102 // We keep the table free variant around for reference, in case. | 103 // We keep the table free variant around for reference, in case. |
103 #define USE_LEVEL_CODE_TABLE | 104 #define USE_LEVEL_CODE_TABLE |
104 | 105 |
105 // Simulate block coding, but only record statistics. | 106 // Simulate block coding, but only record statistics. |
106 // Note: no need to record the fixed probas. | 107 // Note: no need to record the fixed probas. |
107 static int RecordCoeffs(int ctx, VP8Residual* res) { | 108 static int RecordCoeffs(int ctx, const VP8Residual* const res) { |
108 int n = res->first; | 109 int n = res->first; |
109 uint64_t (*s)[2] = res->stats[VP8EncBands[n]][ctx]; | 110 uint64_t (*s)[2] = res->stats[VP8EncBands[n]][ctx]; |
110 if (!Record(res->last >= 0, s[0])) { | 111 if (!Record(res->last >= 0, s[0])) { |
111 return 0; | 112 return 0; |
112 } | 113 } |
113 | 114 |
114 while (1) { | 115 while (1) { |
115 int v = res->coeffs[n++]; | 116 int v = res->coeffs[n++]; |
116 if (!Record(v != 0, s[1])) { | 117 if (!Record(v != 0, s[1])) { |
117 s = res->stats[VP8EncBands[n]][0]; | 118 s = res->stats[VP8EncBands[n]][0]; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 res->coeffs = coeffs; | 217 res->coeffs = coeffs; |
217 } | 218 } |
218 | 219 |
219 //------------------------------------------------------------------------------ | 220 //------------------------------------------------------------------------------ |
220 // Mode costs | 221 // Mode costs |
221 | 222 |
222 static int GetResidualCost(int ctx, const VP8Residual* const res) { | 223 static int GetResidualCost(int ctx, const VP8Residual* const res) { |
223 int n = res->first; | 224 int n = res->first; |
224 const uint8_t* p = res->prob[VP8EncBands[n]][ctx]; | 225 const uint8_t* p = res->prob[VP8EncBands[n]][ctx]; |
225 const uint16_t *t = res->cost[VP8EncBands[n]][ctx]; | 226 const uint16_t *t = res->cost[VP8EncBands[n]][ctx]; |
| 227 int last_p0 = p[0]; |
226 int cost; | 228 int cost; |
227 | 229 |
228 cost = VP8BitCost(res->last >= 0, p[0]); | |
229 if (res->last < 0) { | 230 if (res->last < 0) { |
230 return cost; | 231 return VP8BitCost(0, last_p0); |
231 } | 232 } |
| 233 cost = 0; |
232 while (n <= res->last) { | 234 while (n <= res->last) { |
233 const int v = res->coeffs[n++]; | 235 const int v = res->coeffs[n]; |
| 236 const int b = VP8EncBands[n + 1]; |
| 237 ++n; |
234 if (v == 0) { | 238 if (v == 0) { |
235 cost += VP8LevelCost(t, 0); | 239 cost += VP8LevelCost(t, 0); |
236 p = res->prob[VP8EncBands[n]][0]; | 240 p = res->prob[b][0]; |
237 t = res->cost[VP8EncBands[n]][0]; | 241 t = res->cost[b][0]; |
238 continue; | 242 continue; |
239 } else if (2u >= (unsigned int)(v + 1)) { // v = -1 or 1 | 243 } |
| 244 cost += VP8BitCost(1, last_p0); |
| 245 if (2u >= (unsigned int)(v + 1)) { // v = -1 or 1 |
240 cost += VP8LevelCost(t, 1); | 246 cost += VP8LevelCost(t, 1); |
241 p = res->prob[VP8EncBands[n]][1]; | 247 p = res->prob[b][1]; |
242 t = res->cost[VP8EncBands[n]][1]; | 248 t = res->cost[b][1]; |
243 } else { | 249 } else { |
244 cost += VP8LevelCost(t, abs(v)); | 250 cost += VP8LevelCost(t, abs(v)); |
245 p = res->prob[VP8EncBands[n]][2]; | 251 p = res->prob[b][2]; |
246 t = res->cost[VP8EncBands[n]][2]; | 252 t = res->cost[b][2]; |
247 } | 253 } |
248 if (n < 16) { | 254 last_p0 = p[0]; |
249 cost += VP8BitCost(n <= res->last, p[0]); | |
250 } | |
251 } | 255 } |
| 256 if (n < 16) cost += VP8BitCost(0, last_p0); |
252 return cost; | 257 return cost; |
253 } | 258 } |
254 | 259 |
255 int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) { | 260 int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) { |
256 const int x = (it->i4_ & 3), y = (it->i4_ >> 2); | 261 const int x = (it->i4_ & 3), y = (it->i4_ >> 2); |
257 VP8Residual res; | 262 VP8Residual res; |
| 263 VP8Encoder* const enc = it->enc_; |
258 int R = 0; | 264 int R = 0; |
259 int ctx; | 265 int ctx; |
260 | 266 |
261 InitResidual(0, 3, it->enc_, &res); | 267 InitResidual(0, 3, enc, &res); |
262 ctx = it->top_nz_[x] + it->left_nz_[y]; | 268 ctx = it->top_nz_[x] + it->left_nz_[y]; |
263 SetResidualCoeffs(levels, &res); | 269 SetResidualCoeffs(levels, &res); |
264 R += GetResidualCost(ctx, &res); | 270 R += GetResidualCost(ctx, &res); |
265 return R; | 271 return R; |
266 } | 272 } |
267 | 273 |
268 int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) { | 274 int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) { |
269 VP8Residual res; | 275 VP8Residual res; |
| 276 VP8Encoder* const enc = it->enc_; |
270 int x, y; | 277 int x, y; |
271 int R = 0; | 278 int R = 0; |
272 | 279 |
273 VP8IteratorNzToBytes(it); // re-import the non-zero context | 280 VP8IteratorNzToBytes(it); // re-import the non-zero context |
274 | 281 |
275 // DC | 282 // DC |
276 InitResidual(0, 1, it->enc_, &res); | 283 InitResidual(0, 1, enc, &res); |
277 SetResidualCoeffs(rd->y_dc_levels, &res); | 284 SetResidualCoeffs(rd->y_dc_levels, &res); |
278 R += GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res); | 285 R += GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res); |
279 | 286 |
280 // AC | 287 // AC |
281 InitResidual(1, 0, it->enc_, &res); | 288 InitResidual(1, 0, enc, &res); |
282 for (y = 0; y < 4; ++y) { | 289 for (y = 0; y < 4; ++y) { |
283 for (x = 0; x < 4; ++x) { | 290 for (x = 0; x < 4; ++x) { |
284 const int ctx = it->top_nz_[x] + it->left_nz_[y]; | 291 const int ctx = it->top_nz_[x] + it->left_nz_[y]; |
285 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); | 292 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); |
286 R += GetResidualCost(ctx, &res); | 293 R += GetResidualCost(ctx, &res); |
287 it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0); | 294 it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0); |
288 } | 295 } |
289 } | 296 } |
290 return R; | 297 return R; |
291 } | 298 } |
292 | 299 |
293 int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) { | 300 int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) { |
294 VP8Residual res; | 301 VP8Residual res; |
| 302 VP8Encoder* const enc = it->enc_; |
295 int ch, x, y; | 303 int ch, x, y; |
296 int R = 0; | 304 int R = 0; |
297 | 305 |
298 VP8IteratorNzToBytes(it); // re-import the non-zero context | 306 VP8IteratorNzToBytes(it); // re-import the non-zero context |
299 | 307 |
300 InitResidual(0, 2, it->enc_, &res); | 308 InitResidual(0, 2, enc, &res); |
301 for (ch = 0; ch <= 2; ch += 2) { | 309 for (ch = 0; ch <= 2; ch += 2) { |
302 for (y = 0; y < 2; ++y) { | 310 for (y = 0; y < 2; ++y) { |
303 for (x = 0; x < 2; ++x) { | 311 for (x = 0; x < 2; ++x) { |
304 const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; | 312 const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; |
305 SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); | 313 SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); |
306 R += GetResidualCost(ctx, &res); | 314 R += GetResidualCost(ctx, &res); |
307 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0); | 315 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0); |
308 } | 316 } |
309 } | 317 } |
310 } | 318 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 } | 394 } |
387 | 395 |
388 static void CodeResiduals(VP8BitWriter* const bw, | 396 static void CodeResiduals(VP8BitWriter* const bw, |
389 VP8EncIterator* const it, | 397 VP8EncIterator* const it, |
390 const VP8ModeScore* const rd) { | 398 const VP8ModeScore* const rd) { |
391 int x, y, ch; | 399 int x, y, ch; |
392 VP8Residual res; | 400 VP8Residual res; |
393 uint64_t pos1, pos2, pos3; | 401 uint64_t pos1, pos2, pos3; |
394 const int i16 = (it->mb_->type_ == 1); | 402 const int i16 = (it->mb_->type_ == 1); |
395 const int segment = it->mb_->segment_; | 403 const int segment = it->mb_->segment_; |
| 404 VP8Encoder* const enc = it->enc_; |
396 | 405 |
397 VP8IteratorNzToBytes(it); | 406 VP8IteratorNzToBytes(it); |
398 | 407 |
399 pos1 = VP8BitWriterPos(bw); | 408 pos1 = VP8BitWriterPos(bw); |
400 if (i16) { | 409 if (i16) { |
401 InitResidual(0, 1, it->enc_, &res); | 410 InitResidual(0, 1, enc, &res); |
402 SetResidualCoeffs(rd->y_dc_levels, &res); | 411 SetResidualCoeffs(rd->y_dc_levels, &res); |
403 it->top_nz_[8] = it->left_nz_[8] = | 412 it->top_nz_[8] = it->left_nz_[8] = |
404 PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res); | 413 PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res); |
405 InitResidual(1, 0, it->enc_, &res); | 414 InitResidual(1, 0, enc, &res); |
406 } else { | 415 } else { |
407 InitResidual(0, 3, it->enc_, &res); | 416 InitResidual(0, 3, enc, &res); |
408 } | 417 } |
409 | 418 |
410 // luma-AC | 419 // luma-AC |
411 for (y = 0; y < 4; ++y) { | 420 for (y = 0; y < 4; ++y) { |
412 for (x = 0; x < 4; ++x) { | 421 for (x = 0; x < 4; ++x) { |
413 const int ctx = it->top_nz_[x] + it->left_nz_[y]; | 422 const int ctx = it->top_nz_[x] + it->left_nz_[y]; |
414 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); | 423 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); |
415 it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res); | 424 it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res); |
416 } | 425 } |
417 } | 426 } |
418 pos2 = VP8BitWriterPos(bw); | 427 pos2 = VP8BitWriterPos(bw); |
419 | 428 |
420 // U/V | 429 // U/V |
421 InitResidual(0, 2, it->enc_, &res); | 430 InitResidual(0, 2, enc, &res); |
422 for (ch = 0; ch <= 2; ch += 2) { | 431 for (ch = 0; ch <= 2; ch += 2) { |
423 for (y = 0; y < 2; ++y) { | 432 for (y = 0; y < 2; ++y) { |
424 for (x = 0; x < 2; ++x) { | 433 for (x = 0; x < 2; ++x) { |
425 const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; | 434 const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; |
426 SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); | 435 SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); |
427 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = | 436 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = |
428 PutCoeffs(bw, ctx, &res); | 437 PutCoeffs(bw, ctx, &res); |
429 } | 438 } |
430 } | 439 } |
431 } | 440 } |
432 pos3 = VP8BitWriterPos(bw); | 441 pos3 = VP8BitWriterPos(bw); |
433 it->luma_bits_ = pos2 - pos1; | 442 it->luma_bits_ = pos2 - pos1; |
434 it->uv_bits_ = pos3 - pos2; | 443 it->uv_bits_ = pos3 - pos2; |
435 it->bit_count_[segment][i16] += it->luma_bits_; | 444 it->bit_count_[segment][i16] += it->luma_bits_; |
436 it->bit_count_[segment][2] += it->uv_bits_; | 445 it->bit_count_[segment][2] += it->uv_bits_; |
437 VP8IteratorBytesToNz(it); | 446 VP8IteratorBytesToNz(it); |
438 } | 447 } |
439 | 448 |
440 // Same as CodeResiduals, but doesn't actually write anything. | 449 // Same as CodeResiduals, but doesn't actually write anything. |
441 // Instead, it just records the event distribution. | 450 // Instead, it just records the event distribution. |
442 static void RecordResiduals(VP8EncIterator* const it, | 451 static void RecordResiduals(VP8EncIterator* const it, |
443 const VP8ModeScore* const rd) { | 452 const VP8ModeScore* const rd) { |
444 int x, y, ch; | 453 int x, y, ch; |
445 VP8Residual res; | 454 VP8Residual res; |
| 455 VP8Encoder* const enc = it->enc_; |
446 | 456 |
447 VP8IteratorNzToBytes(it); | 457 VP8IteratorNzToBytes(it); |
448 | 458 |
449 if (it->mb_->type_ == 1) { // i16x16 | 459 if (it->mb_->type_ == 1) { // i16x16 |
450 InitResidual(0, 1, it->enc_, &res); | 460 InitResidual(0, 1, enc, &res); |
451 SetResidualCoeffs(rd->y_dc_levels, &res); | 461 SetResidualCoeffs(rd->y_dc_levels, &res); |
452 it->top_nz_[8] = it->left_nz_[8] = | 462 it->top_nz_[8] = it->left_nz_[8] = |
453 RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res); | 463 RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res); |
454 InitResidual(1, 0, it->enc_, &res); | 464 InitResidual(1, 0, enc, &res); |
455 } else { | 465 } else { |
456 InitResidual(0, 3, it->enc_, &res); | 466 InitResidual(0, 3, enc, &res); |
457 } | 467 } |
458 | 468 |
459 // luma-AC | 469 // luma-AC |
460 for (y = 0; y < 4; ++y) { | 470 for (y = 0; y < 4; ++y) { |
461 for (x = 0; x < 4; ++x) { | 471 for (x = 0; x < 4; ++x) { |
462 const int ctx = it->top_nz_[x] + it->left_nz_[y]; | 472 const int ctx = it->top_nz_[x] + it->left_nz_[y]; |
463 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); | 473 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); |
464 it->top_nz_[x] = it->left_nz_[y] = RecordCoeffs(ctx, &res); | 474 it->top_nz_[x] = it->left_nz_[y] = RecordCoeffs(ctx, &res); |
465 } | 475 } |
466 } | 476 } |
467 | 477 |
468 // U/V | 478 // U/V |
469 InitResidual(0, 2, it->enc_, &res); | 479 InitResidual(0, 2, enc, &res); |
470 for (ch = 0; ch <= 2; ch += 2) { | 480 for (ch = 0; ch <= 2; ch += 2) { |
471 for (y = 0; y < 2; ++y) { | 481 for (y = 0; y < 2; ++y) { |
472 for (x = 0; x < 2; ++x) { | 482 for (x = 0; x < 2; ++x) { |
473 const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; | 483 const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; |
474 SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); | 484 SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); |
475 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = | 485 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = |
476 RecordCoeffs(ctx, &res); | 486 RecordCoeffs(ctx, &res); |
477 } | 487 } |
478 } | 488 } |
479 } | 489 } |
480 | 490 |
481 VP8IteratorBytesToNz(it); | 491 VP8IteratorBytesToNz(it); |
482 } | 492 } |
483 | 493 |
484 //------------------------------------------------------------------------------ | 494 //------------------------------------------------------------------------------ |
| 495 // Token buffer |
| 496 |
| 497 #ifdef USE_TOKEN_BUFFER |
| 498 |
| 499 void VP8TBufferInit(VP8TBuffer* const b) { |
| 500 b->rows_ = NULL; |
| 501 b->tokens_ = NULL; |
| 502 b->last_ = &b->rows_; |
| 503 b->left_ = 0; |
| 504 b->error_ = 0; |
| 505 } |
| 506 |
| 507 int VP8TBufferNewPage(VP8TBuffer* const b) { |
| 508 VP8Tokens* const page = b->error_ ? NULL : (VP8Tokens*)malloc(sizeof(*page)); |
| 509 if (page == NULL) { |
| 510 b->error_ = 1; |
| 511 return 0; |
| 512 } |
| 513 *b->last_ = page; |
| 514 b->last_ = &page->next_; |
| 515 b->left_ = MAX_NUM_TOKEN; |
| 516 b->tokens_ = page->tokens_; |
| 517 return 1; |
| 518 } |
| 519 |
| 520 void VP8TBufferClear(VP8TBuffer* const b) { |
| 521 if (b != NULL) { |
| 522 const VP8Tokens* p = b->rows_; |
| 523 while (p != NULL) { |
| 524 const VP8Tokens* const next = p->next_; |
| 525 free((void*)p); |
| 526 p = next; |
| 527 } |
| 528 VP8TBufferInit(b); |
| 529 } |
| 530 } |
| 531 |
| 532 int VP8EmitTokens(const VP8TBuffer* const b, VP8BitWriter* const bw, |
| 533 const uint8_t* const probas) { |
| 534 VP8Tokens* p = b->rows_; |
| 535 if (b->error_) return 0; |
| 536 while (p != NULL) { |
| 537 const int N = (p->next_ == NULL) ? b->left_ : 0; |
| 538 int n = MAX_NUM_TOKEN; |
| 539 while (n-- > N) { |
| 540 VP8PutBit(bw, (p->tokens_[n] >> 15) & 1, probas[p->tokens_[n] & 0x7fff]); |
| 541 } |
| 542 p = p->next_; |
| 543 } |
| 544 return 1; |
| 545 } |
| 546 |
| 547 #define TOKEN_ID(b, ctx, p) ((p) + NUM_PROBAS * ((ctx) + (b) * NUM_CTX)) |
| 548 |
| 549 static int RecordCoeffTokens(int ctx, const VP8Residual* const res, |
| 550 VP8TBuffer* tokens) { |
| 551 int n = res->first; |
| 552 int b = VP8EncBands[n]; |
| 553 if (!VP8AddToken(tokens, res->last >= 0, TOKEN_ID(b, ctx, 0))) { |
| 554 return 0; |
| 555 } |
| 556 |
| 557 while (n < 16) { |
| 558 const int c = res->coeffs[n++]; |
| 559 const int sign = c < 0; |
| 560 int v = sign ? -c : c; |
| 561 const int base_id = TOKEN_ID(b, ctx, 0); |
| 562 if (!VP8AddToken(tokens, v != 0, base_id + 1)) { |
| 563 b = VP8EncBands[n]; |
| 564 ctx = 0; |
| 565 continue; |
| 566 } |
| 567 if (!VP8AddToken(tokens, v > 1, base_id + 2)) { |
| 568 b = VP8EncBands[n]; |
| 569 ctx = 1; |
| 570 } else { |
| 571 if (!VP8AddToken(tokens, v > 4, base_id + 3)) { |
| 572 if (VP8AddToken(tokens, v != 2, base_id + 4)) |
| 573 VP8AddToken(tokens, v == 4, base_id + 5); |
| 574 } else if (!VP8AddToken(tokens, v > 10, base_id + 6)) { |
| 575 if (!VP8AddToken(tokens, v > 6, base_id + 7)) { |
| 576 // VP8AddToken(tokens, v == 6, 159); |
| 577 } else { |
| 578 // VP8AddToken(tokens, v >= 9, 165); |
| 579 // VP8AddToken(tokens, !(v & 1), 145); |
| 580 } |
| 581 } else { |
| 582 int mask; |
| 583 const uint8_t* tab; |
| 584 if (v < 3 + (8 << 1)) { // kCat3 (3b) |
| 585 VP8AddToken(tokens, 0, base_id + 8); |
| 586 VP8AddToken(tokens, 0, base_id + 9); |
| 587 v -= 3 + (8 << 0); |
| 588 mask = 1 << 2; |
| 589 tab = kCat3; |
| 590 } else if (v < 3 + (8 << 2)) { // kCat4 (4b) |
| 591 VP8AddToken(tokens, 0, base_id + 8); |
| 592 VP8AddToken(tokens, 1, base_id + 9); |
| 593 v -= 3 + (8 << 1); |
| 594 mask = 1 << 3; |
| 595 tab = kCat4; |
| 596 } else if (v < 3 + (8 << 3)) { // kCat5 (5b) |
| 597 VP8AddToken(tokens, 1, base_id + 8); |
| 598 VP8AddToken(tokens, 0, base_id + 10); |
| 599 v -= 3 + (8 << 2); |
| 600 mask = 1 << 4; |
| 601 tab = kCat5; |
| 602 } else { // kCat6 (11b) |
| 603 VP8AddToken(tokens, 1, base_id + 8); |
| 604 VP8AddToken(tokens, 1, base_id + 10); |
| 605 v -= 3 + (8 << 3); |
| 606 mask = 1 << 10; |
| 607 tab = kCat6; |
| 608 } |
| 609 while (mask) { |
| 610 // VP8AddToken(tokens, !!(v & mask), *tab++); |
| 611 mask >>= 1; |
| 612 } |
| 613 } |
| 614 ctx = 2; |
| 615 } |
| 616 b = VP8EncBands[n]; |
| 617 // VP8PutBitUniform(bw, sign); |
| 618 if (n == 16 || !VP8AddToken(tokens, n <= res->last, TOKEN_ID(b, ctx, 0))) { |
| 619 return 1; // EOB |
| 620 } |
| 621 } |
| 622 return 1; |
| 623 } |
| 624 |
| 625 static void RecordTokens(VP8EncIterator* const it, |
| 626 const VP8ModeScore* const rd, VP8TBuffer tokens[2]) { |
| 627 int x, y, ch; |
| 628 VP8Residual res; |
| 629 VP8Encoder* const enc = it->enc_; |
| 630 |
| 631 VP8IteratorNzToBytes(it); |
| 632 if (it->mb_->type_ == 1) { // i16x16 |
| 633 InitResidual(0, 1, enc, &res); |
| 634 SetResidualCoeffs(rd->y_dc_levels, &res); |
| 635 // TODO(skal): FIX -> it->top_nz_[8] = it->left_nz_[8] = |
| 636 RecordCoeffTokens(it->top_nz_[8] + it->left_nz_[8], &res, &tokens[0]); |
| 637 InitResidual(1, 0, enc, &res); |
| 638 } else { |
| 639 InitResidual(0, 3, enc, &res); |
| 640 } |
| 641 |
| 642 // luma-AC |
| 643 for (y = 0; y < 4; ++y) { |
| 644 for (x = 0; x < 4; ++x) { |
| 645 const int ctx = it->top_nz_[x] + it->left_nz_[y]; |
| 646 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); |
| 647 it->top_nz_[x] = it->left_nz_[y] = |
| 648 RecordCoeffTokens(ctx, &res, &tokens[0]); |
| 649 } |
| 650 } |
| 651 |
| 652 // U/V |
| 653 InitResidual(0, 2, enc, &res); |
| 654 for (ch = 0; ch <= 2; ch += 2) { |
| 655 for (y = 0; y < 2; ++y) { |
| 656 for (x = 0; x < 2; ++x) { |
| 657 const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; |
| 658 SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); |
| 659 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = |
| 660 RecordCoeffTokens(ctx, &res, &tokens[1]); |
| 661 } |
| 662 } |
| 663 } |
| 664 } |
| 665 |
| 666 #endif // USE_TOKEN_BUFFER |
| 667 |
| 668 //------------------------------------------------------------------------------ |
485 // ExtraInfo map / Debug function | 669 // ExtraInfo map / Debug function |
486 | 670 |
487 #if SEGMENT_VISU | 671 #if SEGMENT_VISU |
488 static void SetBlock(uint8_t* p, int value, int size) { | 672 static void SetBlock(uint8_t* p, int value, int size) { |
489 int y; | 673 int y; |
490 for (y = 0; y < size; ++y) { | 674 for (y = 0; y < size; ++y) { |
491 memset(p, value, size); | 675 memset(p, value, size); |
492 p += BPS; | 676 p += BPS; |
493 } | 677 } |
494 } | 678 } |
(...skipping 13 matching lines...) Expand all Loading... |
508 enc->sse_[1] += VP8SSE8x8(in + U_OFF, out + U_OFF); | 692 enc->sse_[1] += VP8SSE8x8(in + U_OFF, out + U_OFF); |
509 enc->sse_[2] += VP8SSE8x8(in + V_OFF, out + V_OFF); | 693 enc->sse_[2] += VP8SSE8x8(in + V_OFF, out + V_OFF); |
510 enc->sse_count_ += 16 * 16; | 694 enc->sse_count_ += 16 * 16; |
511 } | 695 } |
512 | 696 |
513 static void StoreSideInfo(const VP8EncIterator* const it) { | 697 static void StoreSideInfo(const VP8EncIterator* const it) { |
514 VP8Encoder* const enc = it->enc_; | 698 VP8Encoder* const enc = it->enc_; |
515 const VP8MBInfo* const mb = it->mb_; | 699 const VP8MBInfo* const mb = it->mb_; |
516 WebPPicture* const pic = enc->pic_; | 700 WebPPicture* const pic = enc->pic_; |
517 | 701 |
518 if (pic->stats) { | 702 if (pic->stats != NULL) { |
519 StoreSSE(it); | 703 StoreSSE(it); |
520 enc->block_count_[0] += (mb->type_ == 0); | 704 enc->block_count_[0] += (mb->type_ == 0); |
521 enc->block_count_[1] += (mb->type_ == 1); | 705 enc->block_count_[1] += (mb->type_ == 1); |
522 enc->block_count_[2] += (mb->skip_ != 0); | 706 enc->block_count_[2] += (mb->skip_ != 0); |
523 } | 707 } |
524 | 708 |
525 if (pic->extra_info) { | 709 if (pic->extra_info != NULL) { |
526 uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_]; | 710 uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_]; |
527 switch(pic->extra_info_type) { | 711 switch (pic->extra_info_type) { |
528 case 1: *info = mb->type_; break; | 712 case 1: *info = mb->type_; break; |
529 case 2: *info = mb->segment_; break; | 713 case 2: *info = mb->segment_; break; |
530 case 3: *info = enc->dqm_[mb->segment_].quant_; break; | 714 case 3: *info = enc->dqm_[mb->segment_].quant_; break; |
531 case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break; | 715 case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break; |
532 case 5: *info = mb->uv_mode_; break; | 716 case 5: *info = mb->uv_mode_; break; |
533 case 6: { | 717 case 6: { |
534 const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); | 718 const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); |
535 *info = (b > 255) ? 255 : b; break; | 719 *info = (b > 255) ? 255 : b; break; |
536 } | 720 } |
537 default: *info = 0; break; | 721 default: *info = 0; break; |
(...skipping 15 matching lines...) Expand all Loading... |
553 if (it->mb_->type_ == 1) { | 737 if (it->mb_->type_ == 1) { |
554 *it->nz_ = 0; // reset all predictors | 738 *it->nz_ = 0; // reset all predictors |
555 it->left_nz_[8] = 0; | 739 it->left_nz_[8] = 0; |
556 } else { | 740 } else { |
557 *it->nz_ &= (1 << 24); // preserve the dc_nz bit | 741 *it->nz_ &= (1 << 24); // preserve the dc_nz bit |
558 } | 742 } |
559 } | 743 } |
560 | 744 |
561 int VP8EncLoop(VP8Encoder* const enc) { | 745 int VP8EncLoop(VP8Encoder* const enc) { |
562 int i, s, p; | 746 int i, s, p; |
| 747 int ok = 1; |
563 VP8EncIterator it; | 748 VP8EncIterator it; |
564 VP8ModeScore info; | 749 VP8ModeScore info; |
565 const int dont_use_skip = !enc->proba_.use_skip_proba_; | 750 const int dont_use_skip = !enc->proba_.use_skip_proba_; |
566 const int rd_opt = enc->rd_opt_level_; | 751 const int rd_opt = enc->rd_opt_level_; |
567 const int kAverageBytesPerMB = 5; // TODO: have a kTable[quality/10] | 752 const int kAverageBytesPerMB = 5; // TODO: have a kTable[quality/10] |
568 const int bytes_per_parts = | 753 const int bytes_per_parts = |
569 enc->mb_w_ * enc->mb_h_ * kAverageBytesPerMB / enc->num_parts_; | 754 enc->mb_w_ * enc->mb_h_ * kAverageBytesPerMB / enc->num_parts_; |
570 | 755 |
571 // Initialize the bit-writers | 756 // Initialize the bit-writers |
572 for (p = 0; p < enc->num_parts_; ++p) { | 757 for (p = 0; p < enc->num_parts_; ++p) { |
573 VP8BitWriterInit(enc->parts_ + p, bytes_per_parts); | 758 VP8BitWriterInit(enc->parts_ + p, bytes_per_parts); |
574 } | 759 } |
575 | 760 |
576 ResetStats(enc, rd_opt != 0); | 761 ResetStats(enc, rd_opt != 0); |
577 ResetSSE(enc); | 762 ResetSSE(enc); |
578 | 763 |
579 VP8IteratorInit(enc, &it); | 764 VP8IteratorInit(enc, &it); |
580 VP8InitFilter(&it); | 765 VP8InitFilter(&it); |
581 do { | 766 do { |
582 VP8IteratorImport(&it); | 767 VP8IteratorImport(&it); |
583 // Warning! order is important: first call VP8Decimate() and | 768 // Warning! order is important: first call VP8Decimate() and |
584 // *then* decide how to code the skip decision if there's one. | 769 // *then* decide how to code the skip decision if there's one. |
585 if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) { | 770 if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) { |
586 CodeResiduals(it.bw_, &it, &info); | 771 CodeResiduals(it.bw_, &it, &info); |
587 } else { // reset predictors after a skip | 772 } else { // reset predictors after a skip |
588 ResetAfterSkip(&it); | 773 ResetAfterSkip(&it); |
589 } | 774 } |
590 #ifdef WEBP_EXPERIMENTAL_FEATURES | 775 #ifdef WEBP_EXPERIMENTAL_FEATURES |
591 if (enc->has_alpha_) { | |
592 VP8EncCodeAlphaBlock(&it); | |
593 } | |
594 if (enc->use_layer_) { | 776 if (enc->use_layer_) { |
595 VP8EncCodeLayerBlock(&it); | 777 VP8EncCodeLayerBlock(&it); |
596 } | 778 } |
597 #endif | 779 #endif |
598 StoreSideInfo(&it); | 780 StoreSideInfo(&it); |
599 VP8StoreFilterStats(&it); | 781 VP8StoreFilterStats(&it); |
600 VP8IteratorExport(&it); | 782 VP8IteratorExport(&it); |
601 } while (VP8IteratorNext(&it, it.yuv_out_)); | 783 ok = VP8IteratorProgress(&it, 20); |
602 VP8AdjustFilterStrength(&it); | 784 } while (ok && VP8IteratorNext(&it, it.yuv_out_)); |
603 | 785 |
604 // Finalize the partitions | 786 if (ok) { // Finalize the partitions, check for extra errors. |
605 for (p = 0; p < enc->num_parts_; ++p) { | 787 for (p = 0; p < enc->num_parts_; ++p) { |
606 VP8BitWriterFinish(enc->parts_ + p); | 788 VP8BitWriterFinish(enc->parts_ + p); |
| 789 ok &= !enc->parts_[p].error_; |
| 790 } |
607 } | 791 } |
608 // and byte counters | 792 |
609 if (enc->pic_->stats) { | 793 if (ok) { // All good. Finish up. |
610 for (i = 0; i <= 2; ++i) { | 794 if (enc->pic_->stats) { // finalize byte counters... |
611 for (s = 0; s < NUM_MB_SEGMENTS; ++s) { | 795 for (i = 0; i <= 2; ++i) { |
612 enc->residual_bytes_[i][s] = (int)((it.bit_count_[s][i] + 7) >> 3); | 796 for (s = 0; s < NUM_MB_SEGMENTS; ++s) { |
| 797 enc->residual_bytes_[i][s] = (int)((it.bit_count_[s][i] + 7) >> 3); |
| 798 } |
613 } | 799 } |
614 } | 800 } |
| 801 VP8AdjustFilterStrength(&it); // ...and store filter stats. |
| 802 } else { |
| 803 // Something bad happened -> need to do some memory cleanup. |
| 804 VP8EncFreeBitWriters(enc); |
615 } | 805 } |
616 return 1; | 806 |
| 807 return ok; |
617 } | 808 } |
618 | 809 |
619 //------------------------------------------------------------------------------ | 810 //------------------------------------------------------------------------------ |
620 // VP8StatLoop(): only collect statistics (number of skips, token usage, ...) | 811 // VP8StatLoop(): only collect statistics (number of skips, token usage, ...) |
621 // This is used for deciding optimal probabilities. It also | 812 // This is used for deciding optimal probabilities. It also |
622 // modifies the quantizer value if some target (size, PNSR) | 813 // modifies the quantizer value if some target (size, PNSR) |
623 // was specified. | 814 // was specified. |
624 | 815 |
625 #define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better | 816 #define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better |
626 | 817 |
627 static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs, | 818 static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs, |
628 float* const PSNR) { | 819 float* const PSNR, int percent_delta) { |
629 VP8EncIterator it; | 820 VP8EncIterator it; |
630 uint64_t size = 0; | 821 uint64_t size = 0; |
631 uint64_t distortion = 0; | 822 uint64_t distortion = 0; |
632 const uint64_t pixel_count = nb_mbs * 384; | 823 const uint64_t pixel_count = nb_mbs * 384; |
633 | 824 |
634 // Make sure the quality parameter is inside valid bounds | 825 // Make sure the quality parameter is inside valid bounds |
635 if (q < 0.) { | 826 if (q < 0.) { |
636 q = 0; | 827 q = 0; |
637 } else if (q > 100.) { | 828 } else if (q > 100.) { |
638 q = 100; | 829 q = 100; |
639 } | 830 } |
640 | 831 |
641 VP8SetSegmentParams(enc, q); // setup segment quantizations and filters | 832 VP8SetSegmentParams(enc, q); // setup segment quantizations and filters |
642 | 833 |
643 ResetStats(enc, rd_opt != 0); | 834 ResetStats(enc, rd_opt != 0); |
644 ResetTokenStats(enc); | 835 ResetTokenStats(enc); |
645 | 836 |
646 VP8IteratorInit(enc, &it); | 837 VP8IteratorInit(enc, &it); |
647 do { | 838 do { |
648 VP8ModeScore info; | 839 VP8ModeScore info; |
649 VP8IteratorImport(&it); | 840 VP8IteratorImport(&it); |
650 if (VP8Decimate(&it, &info, rd_opt)) { | 841 if (VP8Decimate(&it, &info, rd_opt)) { |
651 // Just record the number of skips and act like skip_proba is not used. | 842 // Just record the number of skips and act like skip_proba is not used. |
652 enc->proba_.nb_skip_++; | 843 enc->proba_.nb_skip_++; |
653 } | 844 } |
654 RecordResiduals(&it, &info); | 845 RecordResiduals(&it, &info); |
655 size += info.R; | 846 size += info.R; |
656 distortion += info.D; | 847 distortion += info.D; |
| 848 if (percent_delta && !VP8IteratorProgress(&it, percent_delta)) |
| 849 return 0; |
657 } while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0); | 850 } while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0); |
658 size += FinalizeSkipProba(enc); | 851 size += FinalizeSkipProba(enc); |
659 size += FinalizeTokenProbas(enc); | 852 size += FinalizeTokenProbas(enc); |
660 size += enc->segment_hdr_.size_; | 853 size += enc->segment_hdr_.size_; |
661 size = ((size + 1024) >> 11) + kHeaderSizeEstimate; | 854 size = ((size + 1024) >> 11) + kHeaderSizeEstimate; |
662 | 855 |
663 if (PSNR) { | 856 if (PSNR) { |
664 *PSNR = (float)(10.* log10(255. * 255. * pixel_count / distortion)); | 857 *PSNR = (float)(10.* log10(255. * 255. * pixel_count / distortion)); |
665 } | 858 } |
666 return (int)size; | 859 return (int)size; |
667 } | 860 } |
668 | 861 |
669 // successive refinement increments. | 862 // successive refinement increments. |
670 static const int dqs[] = { 20, 15, 10, 8, 6, 4, 2, 1, 0 }; | 863 static const int dqs[] = { 20, 15, 10, 8, 6, 4, 2, 1, 0 }; |
671 | 864 |
672 int VP8StatLoop(VP8Encoder* const enc) { | 865 int VP8StatLoop(VP8Encoder* const enc) { |
673 const int do_search = | 866 const int do_search = |
674 (enc->config_->target_size > 0 || enc->config_->target_PSNR > 0); | 867 (enc->config_->target_size > 0 || enc->config_->target_PSNR > 0); |
675 const int fast_probe = (enc->method_ < 2 && !do_search); | 868 const int fast_probe = (enc->method_ < 2 && !do_search); |
676 float q = enc->config_->quality; | 869 float q = enc->config_->quality; |
| 870 const int max_passes = enc->config_->pass; |
| 871 const int task_percent = 20; |
| 872 const int percent_per_pass = (task_percent + max_passes / 2) / max_passes; |
| 873 const int final_percent = enc->percent_ + task_percent; |
677 int pass; | 874 int pass; |
678 int nb_mbs; | 875 int nb_mbs; |
679 | 876 |
680 // Fast mode: quick analysis pass over few mbs. Better than nothing. | 877 // Fast mode: quick analysis pass over few mbs. Better than nothing. |
681 nb_mbs = enc->mb_w_ * enc->mb_h_; | 878 nb_mbs = enc->mb_w_ * enc->mb_h_; |
682 if (fast_probe && nb_mbs > 100) nb_mbs = 100; | 879 if (fast_probe && nb_mbs > 100) nb_mbs = 100; |
683 | 880 |
684 // No target size: just do several pass without changing 'q' | 881 // No target size: just do several pass without changing 'q' |
685 if (!do_search) { | 882 if (!do_search) { |
686 for (pass = 0; pass < enc->config_->pass; ++pass) { | 883 for (pass = 0; pass < max_passes; ++pass) { |
687 const int rd_opt = (enc->method_ > 2); | 884 const int rd_opt = (enc->method_ > 2); |
688 OneStatPass(enc, q, rd_opt, nb_mbs, NULL); | 885 if (!OneStatPass(enc, q, rd_opt, nb_mbs, NULL, percent_per_pass)) { |
| 886 return 0; |
| 887 } |
689 } | 888 } |
690 return 1; | 889 } else { |
691 } | 890 // binary search for a size close to target |
692 | 891 for (pass = 0; pass < max_passes && (dqs[pass] > 0); ++pass) { |
693 // binary search for a size close to target | 892 const int rd_opt = 1; |
694 for (pass = 0; pass < enc->config_->pass && (dqs[pass] > 0); ++pass) { | 893 float PSNR; |
695 const int rd_opt = 1; | 894 int criterion; |
696 float PSNR; | 895 const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR, |
697 int criterion; | 896 percent_per_pass); |
698 const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR); | |
699 #if DEBUG_SEARCH | 897 #if DEBUG_SEARCH |
700 printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q); | 898 printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q); |
701 #endif | 899 #endif |
702 | 900 if (!size) return 0; |
703 if (enc->config_->target_PSNR > 0) { | 901 if (enc->config_->target_PSNR > 0) { |
704 criterion = (PSNR < enc->config_->target_PSNR); | 902 criterion = (PSNR < enc->config_->target_PSNR); |
705 } else { | 903 } else { |
706 criterion = (size < enc->config_->target_size); | 904 criterion = (size < enc->config_->target_size); |
707 } | 905 } |
708 // dichotomize | 906 // dichotomize |
709 if (criterion) { | 907 if (criterion) { |
710 q += dqs[pass]; | 908 q += dqs[pass]; |
711 } else { | 909 } else { |
712 q -= dqs[pass]; | 910 q -= dqs[pass]; |
| 911 } |
713 } | 912 } |
714 } | 913 } |
715 return 1; | 914 return WebPReportProgress(enc->pic_, final_percent, &enc->percent_); |
716 } | 915 } |
717 | 916 |
718 //------------------------------------------------------------------------------ | 917 //------------------------------------------------------------------------------ |
719 | 918 |
720 #if defined(__cplusplus) || defined(c_plusplus) | 919 #if defined(__cplusplus) || defined(c_plusplus) |
721 } // extern "C" | 920 } // extern "C" |
722 #endif | 921 #endif |
OLD | NEW |