| 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 // Quantization | 8 // Quantization |
| 9 // | 9 // |
| 10 // Author: Skal (pascal.massimino@gmail.com) | 10 // Author: Skal (pascal.massimino@gmail.com) |
| 11 | 11 |
| 12 #include <assert.h> | 12 #include <assert.h> |
| 13 #include <math.h> | 13 #include <math.h> |
| 14 | 14 |
| 15 #include "vp8enci.h" | 15 #include "./vp8enci.h" |
| 16 #include "cost.h" | 16 #include "./cost.h" |
| 17 | 17 |
| 18 #define DO_TRELLIS_I4 1 | 18 #define DO_TRELLIS_I4 1 |
| 19 #define DO_TRELLIS_I16 1 // not a huge gain, but ok at low bitrate. | 19 #define DO_TRELLIS_I16 1 // not a huge gain, but ok at low bitrate. |
| 20 #define DO_TRELLIS_UV 0 // disable trellis for UV. Risky. Not worth. | 20 #define DO_TRELLIS_UV 0 // disable trellis for UV. Risky. Not worth. |
| 21 #define USE_TDISTO 1 | 21 #define USE_TDISTO 1 |
| 22 | 22 |
| 23 #define MID_ALPHA 64 // neutral value for susceptibility | 23 #define MID_ALPHA 64 // neutral value for susceptibility |
| 24 #define MIN_ALPHA 30 // lowest usable value for susceptibility | 24 #define MIN_ALPHA 30 // lowest usable value for susceptibility |
| 25 #define MAX_ALPHA 100 // higher meaninful value for susceptibility | 25 #define MAX_ALPHA 100 // higher meaninful value for susceptibility |
| 26 | 26 |
| 27 #define SNS_TO_DQ 0.9 // Scaling constant between the sns value and the QP | 27 #define SNS_TO_DQ 0.9 // Scaling constant between the sns value and the QP |
| 28 // power-law modulation. Must be strictly less than 1. | 28 // power-law modulation. Must be strictly less than 1. |
| 29 | 29 |
| 30 #define MULT_8B(a, b) (((a) * (b) + 128) >> 8) | 30 #define MULT_8B(a, b) (((a) * (b) + 128) >> 8) |
| 31 | 31 |
| 32 #if defined(__cplusplus) || defined(c_plusplus) | 32 #if defined(__cplusplus) || defined(c_plusplus) |
| 33 extern "C" { | 33 extern "C" { |
| 34 #endif | 34 #endif |
| 35 | 35 |
| 36 //------------------------------------------------------------------------------ | 36 //------------------------------------------------------------------------------ |
| 37 | 37 |
| 38 static inline int clip(int v, int m, int M) { | 38 static WEBP_INLINE int clip(int v, int m, int M) { |
| 39 return v < m ? m : v > M ? M : v; | 39 return v < m ? m : v > M ? M : v; |
| 40 } | 40 } |
| 41 | 41 |
| 42 static const uint8_t kZigzag[16] = { | 42 static const uint8_t kZigzag[16] = { |
| 43 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 | 43 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 |
| 44 }; | 44 }; |
| 45 | 45 |
| 46 static const uint8_t kDcTable[128] = { | 46 static const uint8_t kDcTable[128] = { |
| 47 4, 5, 6, 7, 8, 9, 10, 10, | 47 4, 5, 6, 7, 8, 9, 10, 10, |
| 48 11, 12, 13, 14, 15, 16, 17, 17, | 48 11, 12, 13, 14, 15, 16, 17, 17, |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 // Must be ordered using {DC_PRED, TM_PRED, V_PRED, H_PRED} as index | 292 // Must be ordered using {DC_PRED, TM_PRED, V_PRED, H_PRED} as index |
| 293 const int VP8I16ModeOffsets[4] = { I16DC16, I16TM16, I16VE16, I16HE16 }; | 293 const int VP8I16ModeOffsets[4] = { I16DC16, I16TM16, I16VE16, I16HE16 }; |
| 294 const int VP8UVModeOffsets[4] = { C8DC8, C8TM8, C8VE8, C8HE8 }; | 294 const int VP8UVModeOffsets[4] = { C8DC8, C8TM8, C8VE8, C8HE8 }; |
| 295 | 295 |
| 296 // Must be indexed using {B_DC_PRED -> B_HU_PRED} as index | 296 // Must be indexed using {B_DC_PRED -> B_HU_PRED} as index |
| 297 const int VP8I4ModeOffsets[NUM_BMODES] = { | 297 const int VP8I4ModeOffsets[NUM_BMODES] = { |
| 298 I4DC4, I4TM4, I4VE4, I4HE4, I4RD4, I4VR4, I4LD4, I4VL4, I4HD4, I4HU4 | 298 I4DC4, I4TM4, I4VE4, I4HE4, I4RD4, I4VR4, I4LD4, I4VL4, I4HD4, I4HU4 |
| 299 }; | 299 }; |
| 300 | 300 |
| 301 void VP8MakeLuma16Preds(const VP8EncIterator* const it) { | 301 void VP8MakeLuma16Preds(const VP8EncIterator* const it) { |
| 302 VP8Encoder* const enc = it->enc_; | 302 const VP8Encoder* const enc = it->enc_; |
| 303 const uint8_t* left = it->x_ ? enc->y_left_ : NULL; | 303 const uint8_t* const left = it->x_ ? enc->y_left_ : NULL; |
| 304 const uint8_t* top = it->y_ ? enc->y_top_ + it->x_ * 16 : NULL; | 304 const uint8_t* const top = it->y_ ? enc->y_top_ + it->x_ * 16 : NULL; |
| 305 VP8EncPredLuma16(it->yuv_p_, left, top); | 305 VP8EncPredLuma16(it->yuv_p_, left, top); |
| 306 } | 306 } |
| 307 | 307 |
| 308 void VP8MakeChroma8Preds(const VP8EncIterator* const it) { | 308 void VP8MakeChroma8Preds(const VP8EncIterator* const it) { |
| 309 VP8Encoder* const enc = it->enc_; | 309 const VP8Encoder* const enc = it->enc_; |
| 310 const uint8_t* left = it->x_ ? enc->u_left_ : NULL; | 310 const uint8_t* const left = it->x_ ? enc->u_left_ : NULL; |
| 311 const uint8_t* top = it->y_ ? enc->uv_top_ + it->x_ * 16 : NULL; | 311 const uint8_t* const top = it->y_ ? enc->uv_top_ + it->x_ * 16 : NULL; |
| 312 VP8EncPredChroma8(it->yuv_p_, left, top); | 312 VP8EncPredChroma8(it->yuv_p_, left, top); |
| 313 } | 313 } |
| 314 | 314 |
| 315 void VP8MakeIntra4Preds(const VP8EncIterator* const it) { | 315 void VP8MakeIntra4Preds(const VP8EncIterator* const it) { |
| 316 VP8EncPredLuma4(it->yuv_p_, it->i4_top_); | 316 VP8EncPredLuma4(it->yuv_p_, it->i4_top_); |
| 317 } | 317 } |
| 318 | 318 |
| 319 //------------------------------------------------------------------------------ | 319 //------------------------------------------------------------------------------ |
| 320 // Quantize | 320 // Quantize |
| 321 | 321 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 } Node; | 399 } Node; |
| 400 | 400 |
| 401 // If a coefficient was quantized to a value Q (using a neutral bias), | 401 // If a coefficient was quantized to a value Q (using a neutral bias), |
| 402 // we test all alternate possibilities between [Q-MIN_DELTA, Q+MAX_DELTA] | 402 // we test all alternate possibilities between [Q-MIN_DELTA, Q+MAX_DELTA] |
| 403 // We don't test negative values though. | 403 // We don't test negative values though. |
| 404 #define MIN_DELTA 0 // how much lower level to try | 404 #define MIN_DELTA 0 // how much lower level to try |
| 405 #define MAX_DELTA 1 // how much higher | 405 #define MAX_DELTA 1 // how much higher |
| 406 #define NUM_NODES (MIN_DELTA + 1 + MAX_DELTA) | 406 #define NUM_NODES (MIN_DELTA + 1 + MAX_DELTA) |
| 407 #define NODE(n, l) (nodes[(n) + 1][(l) + MIN_DELTA]) | 407 #define NODE(n, l) (nodes[(n) + 1][(l) + MIN_DELTA]) |
| 408 | 408 |
| 409 static inline void SetRDScore(int lambda, VP8ModeScore* const rd) { | 409 static WEBP_INLINE void SetRDScore(int lambda, VP8ModeScore* const rd) { |
| 410 // TODO: incorporate the "* 256" in the tables? | 410 // TODO: incorporate the "* 256" in the tables? |
| 411 rd->score = rd->R * lambda + 256 * (rd->D + rd->SD); | 411 rd->score = rd->R * lambda + 256 * (rd->D + rd->SD); |
| 412 } | 412 } |
| 413 | 413 |
| 414 static inline score_t RDScoreTrellis(int lambda, score_t rate, | 414 static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate, |
| 415 score_t distortion) { | 415 score_t distortion) { |
| 416 return rate * lambda + 256 * distortion; | 416 return rate * lambda + 256 * distortion; |
| 417 } | 417 } |
| 418 | 418 |
| 419 static int TrellisQuantizeBlock(const VP8EncIterator* const it, | 419 static int TrellisQuantizeBlock(const VP8EncIterator* const it, |
| 420 int16_t in[16], int16_t out[16], | 420 int16_t in[16], int16_t out[16], |
| 421 int ctx0, int coeff_type, | 421 int ctx0, int coeff_type, |
| 422 const VP8Matrix* const mtx, | 422 const VP8Matrix* const mtx, |
| 423 int lambda) { | 423 int lambda) { |
| 424 ProbaArray* const last_costs = it->enc_->proba_.coeffs_[coeff_type]; | 424 ProbaArray* const last_costs = it->enc_->proba_.coeffs_[coeff_type]; |
| 425 CostArray* const costs = it->enc_->proba_.level_cost_[coeff_type]; | 425 CostArray* const costs = it->enc_->proba_.level_cost_[coeff_type]; |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 uint8_t* const tmp = *a; | 693 uint8_t* const tmp = *a; |
| 694 *a = *b; | 694 *a = *b; |
| 695 *b = tmp; | 695 *b = tmp; |
| 696 } | 696 } |
| 697 | 697 |
| 698 static void SwapOut(VP8EncIterator* const it) { | 698 static void SwapOut(VP8EncIterator* const it) { |
| 699 SwapPtr(&it->yuv_out_, &it->yuv_out2_); | 699 SwapPtr(&it->yuv_out_, &it->yuv_out2_); |
| 700 } | 700 } |
| 701 | 701 |
| 702 static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* const rd) { | 702 static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* const rd) { |
| 703 VP8Encoder* const enc = it->enc_; | 703 const VP8Encoder* const enc = it->enc_; |
| 704 const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; | 704 const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; |
| 705 const int lambda = dqm->lambda_i16_; | 705 const int lambda = dqm->lambda_i16_; |
| 706 const int tlambda = dqm->tlambda_; | 706 const int tlambda = dqm->tlambda_; |
| 707 const uint8_t* const src = it->yuv_in_ + Y_OFF; | 707 const uint8_t* const src = it->yuv_in_ + Y_OFF; |
| 708 VP8ModeScore rd16; | 708 VP8ModeScore rd16; |
| 709 int mode; | 709 int mode; |
| 710 | 710 |
| 711 rd->mode_i16 = -1; | 711 rd->mode_i16 = -1; |
| 712 for (mode = 0; mode < 4; ++mode) { | 712 for (mode = 0; mode < 4; ++mode) { |
| 713 uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF; // scratch buffer | 713 uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF; // scratch buffer |
| (...skipping 21 matching lines...) Expand all Loading... |
| 735 } | 735 } |
| 736 } | 736 } |
| 737 SetRDScore(dqm->lambda_mode_, rd); // finalize score for mode decision. | 737 SetRDScore(dqm->lambda_mode_, rd); // finalize score for mode decision. |
| 738 VP8SetIntra16Mode(it, rd->mode_i16); | 738 VP8SetIntra16Mode(it, rd->mode_i16); |
| 739 } | 739 } |
| 740 | 740 |
| 741 //------------------------------------------------------------------------------ | 741 //------------------------------------------------------------------------------ |
| 742 | 742 |
| 743 // return the cost array corresponding to the surrounding prediction modes. | 743 // return the cost array corresponding to the surrounding prediction modes. |
| 744 static const uint16_t* GetCostModeI4(VP8EncIterator* const it, | 744 static const uint16_t* GetCostModeI4(VP8EncIterator* const it, |
| 745 const int modes[16]) { | 745 const uint8_t modes[16]) { |
| 746 const int preds_w = it->enc_->preds_w_; | 746 const int preds_w = it->enc_->preds_w_; |
| 747 const int x = (it->i4_ & 3), y = it->i4_ >> 2; | 747 const int x = (it->i4_ & 3), y = it->i4_ >> 2; |
| 748 const int left = (x == 0) ? it->preds_[y * preds_w - 1] : modes[it->i4_ - 1]; | 748 const int left = (x == 0) ? it->preds_[y * preds_w - 1] : modes[it->i4_ - 1]; |
| 749 const int top = (y == 0) ? it->preds_[-preds_w + x] : modes[it->i4_ - 4]; | 749 const int top = (y == 0) ? it->preds_[-preds_w + x] : modes[it->i4_ - 4]; |
| 750 return VP8FixedCostsI4[top][left]; | 750 return VP8FixedCostsI4[top][left]; |
| 751 } | 751 } |
| 752 | 752 |
| 753 static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) { | 753 static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) { |
| 754 VP8Encoder* const enc = it->enc_; | 754 const VP8Encoder* const enc = it->enc_; |
| 755 const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; | 755 const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; |
| 756 const int lambda = dqm->lambda_i4_; | 756 const int lambda = dqm->lambda_i4_; |
| 757 const int tlambda = dqm->tlambda_; | 757 const int tlambda = dqm->tlambda_; |
| 758 const uint8_t* const src0 = it->yuv_in_ + Y_OFF; | 758 const uint8_t* const src0 = it->yuv_in_ + Y_OFF; |
| 759 uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF; | 759 uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF; |
| 760 int total_header_bits = 0; | 760 int total_header_bits = 0; |
| 761 VP8ModeScore rd_best; | 761 VP8ModeScore rd_best; |
| 762 | 762 |
| 763 if (enc->max_i4_header_bits_ == 0) { | 763 if (enc->max_i4_header_bits_ == 0) { |
| 764 return 0; | 764 return 0; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 CopyScore(rd, &rd_best); | 820 CopyScore(rd, &rd_best); |
| 821 VP8SetIntra4Mode(it, rd->modes_i4); | 821 VP8SetIntra4Mode(it, rd->modes_i4); |
| 822 SwapOut(it); | 822 SwapOut(it); |
| 823 memcpy(rd->y_ac_levels, rd_best.y_ac_levels, sizeof(rd->y_ac_levels)); | 823 memcpy(rd->y_ac_levels, rd_best.y_ac_levels, sizeof(rd->y_ac_levels)); |
| 824 return 1; // select intra4x4 over intra16x16 | 824 return 1; // select intra4x4 over intra16x16 |
| 825 } | 825 } |
| 826 | 826 |
| 827 //------------------------------------------------------------------------------ | 827 //------------------------------------------------------------------------------ |
| 828 | 828 |
| 829 static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) { | 829 static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) { |
| 830 VP8Encoder* const enc = it->enc_; | 830 const VP8Encoder* const enc = it->enc_; |
| 831 const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; | 831 const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; |
| 832 const int lambda = dqm->lambda_uv_; | 832 const int lambda = dqm->lambda_uv_; |
| 833 const uint8_t* const src = it->yuv_in_ + U_OFF; | 833 const uint8_t* const src = it->yuv_in_ + U_OFF; |
| 834 uint8_t* const tmp_dst = it->yuv_out2_ + U_OFF; // scratch buffer | 834 uint8_t* const tmp_dst = it->yuv_out2_ + U_OFF; // scratch buffer |
| 835 uint8_t* const dst0 = it->yuv_out_ + U_OFF; | 835 uint8_t* const dst0 = it->yuv_out_ + U_OFF; |
| 836 VP8ModeScore rd_best; | 836 VP8ModeScore rd_best; |
| 837 int mode; | 837 int mode; |
| 838 | 838 |
| 839 rd->mode_uv = -1; | 839 rd->mode_uv = -1; |
| 840 InitScore(&rd_best); | 840 InitScore(&rd_best); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 921 SimpleQuantize(it, rd); | 921 SimpleQuantize(it, rd); |
| 922 } | 922 } |
| 923 is_skipped = (rd->nz == 0); | 923 is_skipped = (rd->nz == 0); |
| 924 VP8SetSkip(it, is_skipped); | 924 VP8SetSkip(it, is_skipped); |
| 925 return is_skipped; | 925 return is_skipped; |
| 926 } | 926 } |
| 927 | 927 |
| 928 #if defined(__cplusplus) || defined(c_plusplus) | 928 #if defined(__cplusplus) || defined(c_plusplus) |
| 929 } // extern "C" | 929 } // extern "C" |
| 930 #endif | 930 #endif |
| OLD | NEW |