1 // Copyright 2011 Google Inc. 2 // 3 // This code is licensed under the same terms as WebM: 4 // Software License Agreement: http://www.webmproject.org/license/software/ 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ 6 // ----------------------------------------------------------------------------- 7 // 8 // frame coding and analysis 9 // 10 // Author: Skal (pascal.massimino (at) gmail.com) 11 12 #include <stdlib.h> 13 #include <string.h> 14 #include <assert.h> 15 #include <math.h> 16 17 #include "vp8enci.h" 18 #include "cost.h" 19 20 #if defined(__cplusplus) || defined(c_plusplus) 21 extern "C" { 22 #endif 23 24 #define SEGMENT_VISU 0 25 #define DEBUG_SEARCH 0 // useful to track search convergence 26 27 // On-the-fly info about the current set of residuals. Handy to avoid 28 // passing zillions of params. 29 typedef struct { 30 int first; 31 int last; 32 const int16_t* coeffs; 33 34 int coeff_type; 35 ProbaArray* prob; 36 StatsArray* stats; 37 CostArray* cost; 38 } VP8Residual; 39 40 //----------------------------------------------------------------------------- 41 // Tables for level coding 42 43 const uint8_t VP8EncBands[16 + 1] = { 44 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 45 0 // sentinel 46 }; 47 48 static const uint8_t kCat3[] = { 173, 148, 140 }; 49 static const uint8_t kCat4[] = { 176, 155, 140, 135 }; 50 static const uint8_t kCat5[] = { 180, 157, 141, 134, 130 }; 51 static const uint8_t kCat6[] = 52 { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 }; 53 54 //----------------------------------------------------------------------------- 55 // Reset the statistics about: number of skips, token proba, level cost,... 56 57 static void ResetStats(VP8Encoder* const enc, int precalc_cost) { 58 VP8Proba* const proba = &enc->proba_; 59 if (precalc_cost) VP8CalculateLevelCosts(proba); 60 proba->nb_skip_ = 0; 61 } 62 63 //----------------------------------------------------------------------------- 64 // Skip decision probability 65 66 static int CalcSkipProba(uint64_t nb, uint64_t total) { 67 return (int)(total ? (total - nb) * 255 / total : 255); 68 } 69 70 // Returns the bit-cost for coding the skip probability. 71 static int FinalizeSkipProba(VP8Encoder* const enc) { 72 VP8Proba* const proba = &enc->proba_; 73 const int nb_mbs = enc->mb_w_ * enc->mb_h_; 74 const int nb_events = proba->nb_skip_; 75 int size; 76 proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); 77 proba->use_skip_proba_ = (proba->skip_proba_ < 250); 78 size = 256; // 'use_skip_proba' bit 79 if (proba->use_skip_proba_) { 80 size += nb_events * VP8BitCost(1, proba->skip_proba_) 81 + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); 82 size += 8 * 256; // cost of signaling the skip_proba_ itself. 83 } 84 return size; 85 } 86 87 //----------------------------------------------------------------------------- 88 // Recording of token probabilities. 89 90 static void ResetTokenStats(VP8Encoder* const enc) { 91 VP8Proba* const proba = &enc->proba_; 92 memset(proba->stats_, 0, sizeof(proba->stats_)); 93 } 94 95 // Record proba context used 96 static int Record(int bit, uint64_t* const stats) { 97 stats[0] += bit; 98 stats[1] += 1; 99 return bit; 100 } 101 102 // We keep the table free variant around for reference, in case. 103 #define USE_LEVEL_CODE_TABLE 104 105 // Simulate block coding, but only record statistics. 106 // Note: no need to record the fixed probas. 107 static int RecordCoeffs(int ctx, VP8Residual* res) { 108 int n = res->first; 109 uint64_t (*s)[2] = res->stats[VP8EncBands[n]][ctx]; 110 if (!Record(res->last >= 0, s[0])) { 111 return 0; 112 } 113 114 while (1) { 115 int v = res->coeffs[n++]; 116 if (!Record(v != 0, s[1])) { 117 s = res->stats[VP8EncBands[n]][0]; 118 continue; 119 } 120 if (!Record(2u < (unsigned int)(v + 1), s[2])) { // v = -1 or 1 121 s = res->stats[VP8EncBands[n]][1]; 122 } else { 123 v = abs(v); 124 #if !defined(USE_LEVEL_CODE_TABLE) 125 if (!Record(v > 4, s[3])) { 126 if (Record(v != 2, s[4])) 127 Record(v == 4, s[5]); 128 } else if (!Record(v > 10, s[6])) { 129 Record(v > 6, s[7]); 130 } else if (!Record((v >= 3 + (8 << 2)), s[8])) { 131 Record((v >= 3 + (8 << 1)), s[9]); 132 } else { 133 Record((v >= 3 + (8 << 3)), s[10]); 134 } 135 #else 136 if (v > MAX_VARIABLE_LEVEL) 137 v = MAX_VARIABLE_LEVEL; 138 139 { 140 const int bits = VP8LevelCodes[v - 1][1]; 141 int pattern = VP8LevelCodes[v - 1][0]; 142 int i; 143 for (i = 0; (pattern >>= 1) != 0; ++i) { 144 const int mask = 2 << i; 145 if (pattern & 1) Record(!!(bits & mask), s[3 + i]); 146 } 147 } 148 #endif 149 s = res->stats[VP8EncBands[n]][2]; 150 } 151 if (n == 16 || !Record(n <= res->last, s[0])) { 152 return 1; 153 } 154 } 155 } 156 157 // Collect statistics and deduce probabilities for next coding pass. 158 // Return the total bit-cost for coding the probability updates. 159 static int CalcTokenProba(uint64_t nb, uint64_t total) { 160 return (int)(nb ? ((total - nb) * 255 + total / 2) / total : 255); 161 } 162 163 static int FinalizeTokenProbas(VP8Encoder* const enc) { 164 VP8Proba* const proba = &enc->proba_; 165 int size = 0; 166 int t, b, c, p; 167 for (t = 0; t < NUM_TYPES; ++t) { 168 for (b = 0; b < NUM_BANDS; ++b) { 169 for (c = 0; c < NUM_CTX; ++c) { 170 for (p = 0; p < NUM_PROBAS; ++p) { 171 const uint64_t* const cnt = proba->stats_[t][b][c][p]; 172 const int update_proba = VP8CoeffsUpdateProba[t][b][c][p]; 173 const int old_p = VP8CoeffsProba0[t][b][c][p]; 174 const int new_p = CalcTokenProba(cnt[0], cnt[1]); 175 const uint64_t old_cost = VP8BranchCost(cnt[0], cnt[1], old_p) 176 + VP8BitCost(0, update_proba); 177 const uint64_t new_cost = VP8BranchCost(cnt[0], cnt[1], new_p) 178 + VP8BitCost(1, update_proba) + 8 * 256; 179 const int use_new_p = (old_cost > new_cost); 180 size += VP8BitCost(use_new_p, update_proba); 181 if (use_new_p) { // only use proba that seem meaningful enough. 182 proba->coeffs_[t][b][c][p] = new_p; 183 size += 8 * 256; 184 } else { 185 proba->coeffs_[t][b][c][p] = old_p; 186 } 187 } 188 } 189 } 190 } 191 return size; 192 } 193 194 //----------------------------------------------------------------------------- 195 // helper functions for residuals struct VP8Residual. 196 197 static void InitResidual(int first, int coeff_type, 198 VP8Encoder* const enc, VP8Residual* const res) { 199 res->coeff_type = coeff_type; 200 res->prob = enc->proba_.coeffs_[coeff_type]; 201 res->stats = enc->proba_.stats_[coeff_type]; 202 res->cost = enc->proba_.level_cost_[coeff_type]; 203 res->first = first; 204 } 205 206 static void SetResidualCoeffs(const int16_t* const coeffs, 207 VP8Residual* const res) { 208 int n; 209 res->last = -1; 210 for (n = 15; n >= res->first; --n) { 211 if (coeffs[n]) { 212 res->last = n; 213 break; 214 } 215 } 216 res->coeffs = coeffs; 217 } 218 219 //----------------------------------------------------------------------------- 220 // Mode costs 221 222 static int GetResidualCost(int ctx, const VP8Residual* const res) { 223 int n = res->first; 224 const uint8_t* p = res->prob[VP8EncBands[n]][ctx]; 225 const uint16_t *t = res->cost[VP8EncBands[n]][ctx]; 226 int cost; 227 228 cost = VP8BitCost(res->last >= 0, p[0]); 229 if (res->last < 0) { 230 return cost; 231 } 232 while (n <= res->last) { 233 const int v = res->coeffs[n++]; 234 if (v == 0) { 235 cost += VP8LevelCost(t, 0); 236 p = res->prob[VP8EncBands[n]][0]; 237 t = res->cost[VP8EncBands[n]][0]; 238 continue; 239 } else if (2u >= (unsigned int)(v + 1)) { // v = -1 or 1 240 cost += VP8LevelCost(t, 1); 241 p = res->prob[VP8EncBands[n]][1]; 242 t = res->cost[VP8EncBands[n]][1]; 243 } else { 244 cost += VP8LevelCost(t, abs(v)); 245 p = res->prob[VP8EncBands[n]][2]; 246 t = res->cost[VP8EncBands[n]][2]; 247 } 248 if (n < 16) { 249 cost += VP8BitCost(n <= res->last, p[0]); 250 } 251 } 252 return cost; 253 } 254 255 int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) { 256 const int x = (it->i4_ & 3), y = (it->i4_ >> 2); 257 VP8Residual res; 258 int R = 0; 259 int ctx; 260 261 InitResidual(0, 3, it->enc_, &res); 262 ctx = it->top_nz_[x] + it->left_nz_[y]; 263 SetResidualCoeffs(levels, &res); 264 R += GetResidualCost(ctx, &res); 265 return R; 266 } 267 268 int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) { 269 VP8Residual res; 270 int x, y; 271 int R = 0; 272 273 VP8IteratorNzToBytes(it); // re-import the non-zero context 274 275 // DC 276 InitResidual(0, 1, it->enc_, &res); 277 SetResidualCoeffs(rd->y_dc_levels, &res); 278 R += GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res); 279 280 // AC 281 InitResidual(1, 0, it->enc_, &res); 282 for (y = 0; y < 4; ++y) { 283 for (x = 0; x < 4; ++x) { 284 const int ctx = it->top_nz_[x] + it->left_nz_[y]; 285 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); 286 R += GetResidualCost(ctx, &res); 287 it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0); 288 } 289 } 290 return R; 291 } 292 293 int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) { 294 VP8Residual res; 295 int ch, x, y; 296 int R = 0; 297 298 VP8IteratorNzToBytes(it); // re-import the non-zero context 299 300 InitResidual(0, 2, it->enc_, &res); 301 for (ch = 0; ch <= 2; ch += 2) { 302 for (y = 0; y < 2; ++y) { 303 for (x = 0; x < 2; ++x) { 304 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); 306 R += GetResidualCost(ctx, &res); 307 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0); 308 } 309 } 310 } 311 return R; 312 } 313 314 //----------------------------------------------------------------------------- 315 // Coefficient coding 316 317 static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) { 318 int n = res->first; 319 const uint8_t* p = res->prob[VP8EncBands[n]][ctx]; 320 if (!VP8PutBit(bw, res->last >= 0, p[0])) { 321 return 0; 322 } 323 324 while (n < 16) { 325 const int c = res->coeffs[n++]; 326 const int sign = c < 0; 327 int v = sign ? -c : c; 328 if (!VP8PutBit(bw, v != 0, p[1])) { 329 p = res->prob[VP8EncBands[n]][0]; 330 continue; 331 } 332 if (!VP8PutBit(bw, v > 1, p[2])) { 333 p = res->prob[VP8EncBands[n]][1]; 334 } else { 335 if (!VP8PutBit(bw, v > 4, p[3])) { 336 if (VP8PutBit(bw, v != 2, p[4])) 337 VP8PutBit(bw, v == 4, p[5]); 338 } else if (!VP8PutBit(bw, v > 10, p[6])) { 339 if (!VP8PutBit(bw, v > 6, p[7])) { 340 VP8PutBit(bw, v == 6, 159); 341 } else { 342 VP8PutBit(bw, v >= 9, 165); 343 VP8PutBit(bw, !(v & 1), 145); 344 } 345 } else { 346 int mask; 347 const uint8_t* tab; 348 if (v < 3 + (8 << 1)) { // kCat3 (3b) 349 VP8PutBit(bw, 0, p[8]); 350 VP8PutBit(bw, 0, p[9]); 351 v -= 3 + (8 << 0); 352 mask = 1 << 2; 353 tab = kCat3; 354 } else if (v < 3 + (8 << 2)) { // kCat4 (4b) 355 VP8PutBit(bw, 0, p[8]); 356 VP8PutBit(bw, 1, p[9]); 357 v -= 3 + (8 << 1); 358 mask = 1 << 3; 359 tab = kCat4; 360 } else if (v < 3 + (8 << 3)) { // kCat5 (5b) 361 VP8PutBit(bw, 1, p[8]); 362 VP8PutBit(bw, 0, p[10]); 363 v -= 3 + (8 << 2); 364 mask = 1 << 4; 365 tab = kCat5; 366 } else { // kCat6 (11b) 367 VP8PutBit(bw, 1, p[8]); 368 VP8PutBit(bw, 1, p[10]); 369 v -= 3 + (8 << 3); 370 mask = 1 << 10; 371 tab = kCat6; 372 } 373 while (mask) { 374 VP8PutBit(bw, !!(v & mask), *tab++); 375 mask >>= 1; 376 } 377 } 378 p = res->prob[VP8EncBands[n]][2]; 379 } 380 VP8PutBitUniform(bw, sign); 381 if (n == 16 || !VP8PutBit(bw, n <= res->last, p[0])) { 382 return 1; // EOB 383 } 384 } 385 return 1; 386 } 387 388 static void CodeResiduals(VP8BitWriter* const bw, 389 VP8EncIterator* const it, 390 const VP8ModeScore* const rd) { 391 int x, y, ch; 392 VP8Residual res; 393 uint64_t pos1, pos2, pos3; 394 const int i16 = (it->mb_->type_ == 1); 395 const int segment = it->mb_->segment_; 396 397 VP8IteratorNzToBytes(it); 398 399 pos1 = VP8BitWriterPos(bw); 400 if (i16) { 401 InitResidual(0, 1, it->enc_, &res); 402 SetResidualCoeffs(rd->y_dc_levels, &res); 403 it->top_nz_[8] = it->left_nz_[8] = 404 PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res); 405 InitResidual(1, 0, it->enc_, &res); 406 } else { 407 InitResidual(0, 3, it->enc_, &res); 408 } 409 410 // luma-AC 411 for (y = 0; y < 4; ++y) { 412 for (x = 0; x < 4; ++x) { 413 const int ctx = it->top_nz_[x] + it->left_nz_[y]; 414 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); 415 it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res); 416 } 417 } 418 pos2 = VP8BitWriterPos(bw); 419 420 // U/V 421 InitResidual(0, 2, it->enc_, &res); 422 for (ch = 0; ch <= 2; ch += 2) { 423 for (y = 0; y < 2; ++y) { 424 for (x = 0; x < 2; ++x) { 425 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); 427 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = 428 PutCoeffs(bw, ctx, &res); 429 } 430 } 431 } 432 pos3 = VP8BitWriterPos(bw); 433 it->luma_bits_ = pos2 - pos1; 434 it->uv_bits_ = pos3 - pos2; 435 it->bit_count_[segment][i16] += it->luma_bits_; 436 it->bit_count_[segment][2] += it->uv_bits_; 437 VP8IteratorBytesToNz(it); 438 } 439 440 // Same as CodeResiduals, but doesn't actually write anything. 441 // Instead, it just records the event distribution. 442 static void RecordResiduals(VP8EncIterator* const it, 443 const VP8ModeScore* const rd) { 444 int x, y, ch; 445 VP8Residual res; 446 447 VP8IteratorNzToBytes(it); 448 449 if (it->mb_->type_ == 1) { // i16x16 450 InitResidual(0, 1, it->enc_, &res); 451 SetResidualCoeffs(rd->y_dc_levels, &res); 452 it->top_nz_[8] = it->left_nz_[8] = 453 RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res); 454 InitResidual(1, 0, it->enc_, &res); 455 } else { 456 InitResidual(0, 3, it->enc_, &res); 457 } 458 459 // luma-AC 460 for (y = 0; y < 4; ++y) { 461 for (x = 0; x < 4; ++x) { 462 const int ctx = it->top_nz_[x] + it->left_nz_[y]; 463 SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); 464 it->top_nz_[x] = it->left_nz_[y] = RecordCoeffs(ctx, &res); 465 } 466 } 467 468 // U/V 469 InitResidual(0, 2, it->enc_, &res); 470 for (ch = 0; ch <= 2; ch += 2) { 471 for (y = 0; y < 2; ++y) { 472 for (x = 0; x < 2; ++x) { 473 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); 475 it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = 476 RecordCoeffs(ctx, &res); 477 } 478 } 479 } 480 481 VP8IteratorBytesToNz(it); 482 } 483 484 //----------------------------------------------------------------------------- 485 // ExtraInfo map / Debug function 486 487 #if SEGMENT_VISU 488 static void SetBlock(uint8_t* p, int value, int size) { 489 int y; 490 for (y = 0; y < size; ++y) { 491 memset(p, value, size); 492 p += BPS; 493 } 494 } 495 #endif 496 497 static void ResetSSE(VP8Encoder* const enc) { 498 memset(enc->sse_, 0, sizeof(enc->sse_)); 499 enc->sse_count_ = 0; 500 } 501 502 static void StoreSSE(const VP8EncIterator* const it) { 503 VP8Encoder* const enc = it->enc_; 504 const uint8_t* const in = it->yuv_in_; 505 const uint8_t* const out = it->yuv_out_; 506 // Note: not totally accurate at boundary. And doesn't include in-loop filter. 507 enc->sse_[0] += VP8SSE16x16(in + Y_OFF, out + Y_OFF); 508 enc->sse_[1] += VP8SSE8x8(in + U_OFF, out + U_OFF); 509 enc->sse_[2] += VP8SSE8x8(in + V_OFF, out + V_OFF); 510 enc->sse_count_ += 16 * 16; 511 } 512 513 static void StoreSideInfo(const VP8EncIterator* const it) { 514 VP8Encoder* const enc = it->enc_; 515 const VP8MBInfo* const mb = it->mb_; 516 WebPPicture* const pic = enc->pic_; 517 518 if (pic->stats) { 519 StoreSSE(it); 520 enc->block_count_[0] += (mb->type_ == 0); 521 enc->block_count_[1] += (mb->type_ == 1); 522 enc->block_count_[2] += (mb->skip_ != 0); 523 } 524 525 if (pic->extra_info) { 526 uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_]; 527 switch(pic->extra_info_type) { 528 case 1: *info = mb->type_; break; 529 case 2: *info = mb->segment_; break; 530 case 3: *info = enc->dqm_[mb->segment_].quant_; break; 531 case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break; 532 case 5: *info = mb->uv_mode_; break; 533 case 6: { 534 const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); 535 *info = (b > 255) ? 255 : b; break; 536 } 537 default: *info = 0; break; 538 }; 539 } 540 #if SEGMENT_VISU // visualize segments and prediction modes 541 SetBlock(it->yuv_out_ + Y_OFF, mb->segment_ * 64, 16); 542 SetBlock(it->yuv_out_ + U_OFF, it->preds_[0] * 64, 8); 543 SetBlock(it->yuv_out_ + V_OFF, mb->uv_mode_ * 64, 8); 544 #endif 545 } 546 547 //----------------------------------------------------------------------------- 548 // Main loops 549 // 550 // VP8EncLoop(): does the final bitstream coding. 551 552 static void ResetAfterSkip(VP8EncIterator* const it) { 553 if (it->mb_->type_ == 1) { 554 *it->nz_ = 0; // reset all predictors 555 it->left_nz_[8] = 0; 556 } else { 557 *it->nz_ &= (1 << 24); // preserve the dc_nz bit 558 } 559 } 560 561 int VP8EncLoop(VP8Encoder* const enc) { 562 int i, s, p; 563 VP8EncIterator it; 564 VP8ModeScore info; 565 const int dont_use_skip = !enc->proba_.use_skip_proba_; 566 const int rd_opt = enc->rd_opt_level_; 567 const int kAverageBytesPerMB = 5; // TODO: have a kTable[quality/10] 568 const int bytes_per_parts = 569 enc->mb_w_ * enc->mb_h_ * kAverageBytesPerMB / enc->num_parts_; 570 571 // Initialize the bit-writers 572 for (p = 0; p < enc->num_parts_; ++p) { 573 VP8BitWriterInit(enc->parts_ + p, bytes_per_parts); 574 } 575 576 ResetStats(enc, rd_opt != 0); 577 ResetSSE(enc); 578 579 VP8IteratorInit(enc, &it); 580 VP8InitFilter(&it); 581 do { 582 VP8IteratorImport(&it); 583 // Warning! order is important: first call VP8Decimate() and 584 // *then* decide how to code the skip decision if there's one. 585 if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) { 586 CodeResiduals(it.bw_, &it, &info); 587 } else { // reset predictors after a skip 588 ResetAfterSkip(&it); 589 } 590 #ifdef WEBP_EXPERIMENTAL_FEATURES 591 if (enc->has_alpha_) { 592 VP8EncCodeAlphaBlock(&it); 593 } 594 if (enc->use_layer_) { 595 VP8EncCodeLayerBlock(&it); 596 } 597 #endif 598 StoreSideInfo(&it); 599 VP8StoreFilterStats(&it); 600 VP8IteratorExport(&it); 601 } while (VP8IteratorNext(&it, it.yuv_out_)); 602 VP8AdjustFilterStrength(&it); 603 604 // Finalize the partitions 605 for (p = 0; p < enc->num_parts_; ++p) { 606 VP8BitWriterFinish(enc->parts_ + p); 607 } 608 // and byte counters 609 if (enc->pic_->stats) { 610 for (i = 0; i <= 2; ++i) { 611 for (s = 0; s < NUM_MB_SEGMENTS; ++s) { 612 enc->residual_bytes_[i][s] = (int)((it.bit_count_[s][i] + 7) >> 3); 613 } 614 } 615 } 616 return 1; 617 } 618 619 //----------------------------------------------------------------------------- 620 // VP8StatLoop(): only collect statistics (number of skips, token usage, ...) 621 // This is used for deciding optimal probabilities. It also 622 // modifies the quantizer value if some target (size, PNSR) 623 // was specified. 624 625 #define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better 626 627 static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs, 628 float* const PSNR) { 629 VP8EncIterator it; 630 uint64_t size = 0; 631 uint64_t distortion = 0; 632 const uint64_t pixel_count = nb_mbs * 384; 633 634 // Make sure the quality parameter is inside valid bounds 635 if (q < 0.) { 636 q = 0; 637 } else if (q > 100.) { 638 q = 100; 639 } 640 641 VP8SetSegmentParams(enc, q); // setup segment quantizations and filters 642 643 ResetStats(enc, rd_opt != 0); 644 ResetTokenStats(enc); 645 646 VP8IteratorInit(enc, &it); 647 do { 648 VP8ModeScore info; 649 VP8IteratorImport(&it); 650 if (VP8Decimate(&it, &info, rd_opt)) { 651 // Just record the number of skips and act like skip_proba is not used. 652 enc->proba_.nb_skip_++; 653 } 654 RecordResiduals(&it, &info); 655 size += info.R; 656 distortion += info.D; 657 } while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0); 658 size += FinalizeSkipProba(enc); 659 size += FinalizeTokenProbas(enc); 660 size += enc->segment_hdr_.size_; 661 size = ((size + 1024) >> 11) + kHeaderSizeEstimate; 662 663 if (PSNR) { 664 *PSNR = (float)(10.* log10(255. * 255. * pixel_count / distortion)); 665 } 666 return (int)size; 667 } 668 669 // successive refinement increments. 670 static const int dqs[] = { 20, 15, 10, 8, 6, 4, 2, 1, 0 }; 671 672 int VP8StatLoop(VP8Encoder* const enc) { 673 const int do_search = 674 (enc->config_->target_size > 0 || enc->config_->target_PSNR > 0); 675 const int fast_probe = (enc->method_ < 2 && !do_search); 676 float q = enc->config_->quality; 677 int pass; 678 int nb_mbs; 679 680 // Fast mode: quick analysis pass over few mbs. Better than nothing. 681 nb_mbs = enc->mb_w_ * enc->mb_h_; 682 if (fast_probe && nb_mbs > 100) nb_mbs = 100; 683 684 // No target size: just do several pass without changing 'q' 685 if (!do_search) { 686 for (pass = 0; pass < enc->config_->pass; ++pass) { 687 const int rd_opt = (enc->method_ > 2); 688 OneStatPass(enc, q, rd_opt, nb_mbs, NULL); 689 } 690 return 1; 691 } 692 693 // binary search for a size close to target 694 for (pass = 0; pass < enc->config_->pass && (dqs[pass] > 0); ++pass) { 695 const int rd_opt = 1; 696 float PSNR; 697 int criterion; 698 const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR); 699 #if DEBUG_SEARCH 700 printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q); 701 #endif 702 703 if (enc->config_->target_PSNR > 0) { 704 criterion = (PSNR < enc->config_->target_PSNR); 705 } else { 706 criterion = (size < enc->config_->target_size); 707 } 708 // dichotomize 709 if (criterion) { 710 q += dqs[pass]; 711 } else { 712 q -= dqs[pass]; 713 } 714 } 715 return 1; 716 } 717 718 //----------------------------------------------------------------------------- 719 720 #if defined(__cplusplus) || defined(c_plusplus) 721 } // extern "C" 722 #endif 723