mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +01:00
move the quantization function to dsp.c
and add a function pointer for it Change-Id: Ic7012e35c74a474bf140bb23cdaf9d6950026bc6
This commit is contained in:
parent
b2c3575c8f
commit
8b77c63262
@ -581,6 +581,38 @@ static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
|
|||||||
VP8WMetric VP8TDisto4x4 = Disto4x4;
|
VP8WMetric VP8TDisto4x4 = Disto4x4;
|
||||||
VP8WMetric VP8TDisto16x16 = Disto16x16;
|
VP8WMetric VP8TDisto16x16 = Disto16x16;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Quantization
|
||||||
|
//
|
||||||
|
|
||||||
|
// Simple quantization
|
||||||
|
static int QuantizeBlock(int16_t in[16], int16_t out[16],
|
||||||
|
int n, const VP8Matrix* const mtx) {
|
||||||
|
int last = -1;
|
||||||
|
for (; n < 16; ++n) {
|
||||||
|
const int j = VP8Zigzag[n];
|
||||||
|
const int sign = (in[j] < 0);
|
||||||
|
int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
|
||||||
|
if (coeff > 2047) coeff = 2047;
|
||||||
|
if (coeff > mtx->zthresh_[j]) {
|
||||||
|
const int Q = mtx->q_[j];
|
||||||
|
const int iQ = mtx->iq_[j];
|
||||||
|
const int B = mtx->bias_[j];
|
||||||
|
out[n] = QUANTDIV(coeff, iQ, B);
|
||||||
|
if (sign) out[n] = -out[n];
|
||||||
|
in[j] = out[n] * Q;
|
||||||
|
if (out[n]) last = n;
|
||||||
|
} else {
|
||||||
|
out[n] = 0;
|
||||||
|
in[j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (last >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// default C implementation
|
||||||
|
VP8QuantizeBlock VP8EncQuantizeBlock = QuantizeBlock;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Block copy
|
// Block copy
|
||||||
|
|
||||||
@ -606,7 +638,6 @@ VP8BlockCopy VP8Copy16x16 = Copy16x16;
|
|||||||
|
|
||||||
void VP8EncDspInit() {
|
void VP8EncDspInit() {
|
||||||
InitTables();
|
InitTables();
|
||||||
// later we'll plug some SSE2 variant here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -39,7 +39,7 @@ static inline int clip(int v, int m, int M) {
|
|||||||
return v < m ? m : v > M ? M : v;
|
return v < m ? m : v > M ? M : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t kZigzag[16] = {
|
const uint8_t VP8Zigzag[16] = {
|
||||||
0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
|
0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,8 +100,6 @@ static const uint16_t kAcTable2[128] = {
|
|||||||
385, 393, 401, 409, 416, 424, 432, 440
|
385, 393, 401, 409, 416, 424, 432, 440
|
||||||
};
|
};
|
||||||
|
|
||||||
#define QFIX 17
|
|
||||||
#define BIAS(b) ((b) << (QFIX - 8))
|
|
||||||
static const uint16_t kCoeffThresh[16] = {
|
static const uint16_t kCoeffThresh[16] = {
|
||||||
0, 10, 20, 30,
|
0, 10, 20, 30,
|
||||||
10, 20, 30, 30,
|
10, 20, 30, 30,
|
||||||
@ -145,7 +143,7 @@ static int ExpandMatrix(VP8Matrix* const m, int type) {
|
|||||||
m->q_[i] = m->q_[1];
|
m->q_[i] = m->q_[1];
|
||||||
}
|
}
|
||||||
for (i = 0; i < 16; ++i) {
|
for (i = 0; i < 16; ++i) {
|
||||||
const int j = kZigzag[i];
|
const int j = VP8Zigzag[i];
|
||||||
const int bias = kBiasMatrices[type][j];
|
const int bias = kBiasMatrices[type][j];
|
||||||
m->iq_[j] = (1 << QFIX) / m->q_[j];
|
m->iq_[j] = (1 << QFIX) / m->q_[j];
|
||||||
m->bias_[j] = BIAS(bias);
|
m->bias_[j] = BIAS(bias);
|
||||||
@ -387,38 +385,7 @@ static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Performs simple and trellis-optimized quantization.
|
// Performs trellis-optimized quantization.
|
||||||
|
|
||||||
// Fun fact: this is the _only_ line where we're actually being lossy and
|
|
||||||
// discarding bits.
|
|
||||||
static int DIV(int n, int iQ, int B) {
|
|
||||||
return (n * iQ + B) >> QFIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple quantization
|
|
||||||
static int QuantizeBlock(int16_t in[16], int16_t out[16],
|
|
||||||
int n, const VP8Matrix* const mtx) {
|
|
||||||
int last = -1;
|
|
||||||
for (; n < 16; ++n) {
|
|
||||||
const int j = kZigzag[n];
|
|
||||||
const int sign = (in[j] < 0);
|
|
||||||
int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
|
|
||||||
if (coeff > 2047) coeff = 2047;
|
|
||||||
if (coeff > mtx->zthresh_[j]) {
|
|
||||||
const int Q = mtx->q_[j];
|
|
||||||
const int iQ = mtx->iq_[j];
|
|
||||||
const int B = mtx->bias_[j];
|
|
||||||
out[n] = DIV(coeff, iQ, B);
|
|
||||||
if (sign) out[n] = -out[n];
|
|
||||||
in[j] = out[n] * Q;
|
|
||||||
if (out[n]) last = n;
|
|
||||||
} else {
|
|
||||||
out[n] = 0;
|
|
||||||
in[j] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (last >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trellis
|
// Trellis
|
||||||
|
|
||||||
@ -473,7 +440,7 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
|
|||||||
// compute maximal distortion.
|
// compute maximal distortion.
|
||||||
max_error = 0;
|
max_error = 0;
|
||||||
for (n = first; n < 16; ++n) {
|
for (n = first; n < 16; ++n) {
|
||||||
const int j = kZigzag[n];
|
const int j = VP8Zigzag[n];
|
||||||
const int err = in[j] * in[j];
|
const int err = in[j] * in[j];
|
||||||
max_error += kWeightTrellis[j] * err;
|
max_error += kWeightTrellis[j] * err;
|
||||||
if (err > thresh) last = n;
|
if (err > thresh) last = n;
|
||||||
@ -497,7 +464,7 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
|
|||||||
|
|
||||||
// traverse trellis.
|
// traverse trellis.
|
||||||
for (n = first; n <= last; ++n) {
|
for (n = first; n <= last; ++n) {
|
||||||
const int j = kZigzag[n];
|
const int j = VP8Zigzag[n];
|
||||||
const int Q = mtx->q_[j];
|
const int Q = mtx->q_[j];
|
||||||
const int iQ = mtx->iq_[j];
|
const int iQ = mtx->iq_[j];
|
||||||
const int B = BIAS(0x00); // neutral bias
|
const int B = BIAS(0x00); // neutral bias
|
||||||
@ -508,7 +475,7 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
|
|||||||
int level0;
|
int level0;
|
||||||
if (coeff0 > 2047) coeff0 = 2047;
|
if (coeff0 > 2047) coeff0 = 2047;
|
||||||
|
|
||||||
level0 = DIV(coeff0, iQ, B);
|
level0 = QUANTDIV(coeff0, iQ, B);
|
||||||
// test all alternate level values around level0.
|
// test all alternate level values around level0.
|
||||||
for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) {
|
for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) {
|
||||||
Node* const cur = &NODE(n, m);
|
Node* const cur = &NODE(n, m);
|
||||||
@ -593,7 +560,7 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
|
|||||||
|
|
||||||
for (; n >= first; --n) {
|
for (; n >= first; --n) {
|
||||||
const Node* const node = &NODE(n, best_node);
|
const Node* const node = &NODE(n, best_node);
|
||||||
const int j = kZigzag[n];
|
const int j = VP8Zigzag[n];
|
||||||
out[n] = node->sign ? -node->level : node->level;
|
out[n] = node->sign ? -node->level : node->level;
|
||||||
nz |= (node->level != 0);
|
nz |= (node->level != 0);
|
||||||
in[j] = out[n] * mtx->q_[j];
|
in[j] = out[n] * mtx->q_[j];
|
||||||
@ -625,7 +592,7 @@ static int ReconstructIntra16(VP8EncIterator* const it,
|
|||||||
VP8FTransform(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]);
|
VP8FTransform(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]);
|
||||||
}
|
}
|
||||||
VP8FTransformWHT(tmp[0], dc_tmp);
|
VP8FTransformWHT(tmp[0], dc_tmp);
|
||||||
nz |= QuantizeBlock(dc_tmp, rd->y_dc_levels, 0, &dqm->y2_) << 24;
|
nz |= VP8EncQuantizeBlock(dc_tmp, rd->y_dc_levels, 0, &dqm->y2_) << 24;
|
||||||
|
|
||||||
if (DO_TRELLIS_I16 && it->do_trellis_) {
|
if (DO_TRELLIS_I16 && it->do_trellis_) {
|
||||||
int x, y;
|
int x, y;
|
||||||
@ -642,7 +609,7 @@ static int ReconstructIntra16(VP8EncIterator* const it,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (n = 0; n < 16; ++n) {
|
for (n = 0; n < 16; ++n) {
|
||||||
nz |= QuantizeBlock(tmp[n], rd->y_ac_levels[n], 1, &dqm->y1_) << n;
|
nz |= VP8EncQuantizeBlock(tmp[n], rd->y_ac_levels[n], 1, &dqm->y1_) << n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,7 +640,7 @@ static int ReconstructIntra4(VP8EncIterator* const it,
|
|||||||
nz = TrellisQuantizeBlock(it, tmp, levels, ctx, 3, &dqm->y1_,
|
nz = TrellisQuantizeBlock(it, tmp, levels, ctx, 3, &dqm->y1_,
|
||||||
dqm->lambda_trellis_i4_);
|
dqm->lambda_trellis_i4_);
|
||||||
} else {
|
} else {
|
||||||
nz = QuantizeBlock(tmp, levels, 0, &dqm->y1_);
|
nz = VP8EncQuantizeBlock(tmp, levels, 0, &dqm->y1_);
|
||||||
}
|
}
|
||||||
VP8ITransform(ref, tmp, yuv_out);
|
VP8ITransform(ref, tmp, yuv_out);
|
||||||
return nz;
|
return nz;
|
||||||
@ -708,7 +675,7 @@ static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (n = 0; n < 8; ++n) {
|
for (n = 0; n < 8; ++n) {
|
||||||
nz |= QuantizeBlock(tmp[n], rd->uv_levels[n], 0, &dqm->uv_) << n;
|
nz |= VP8EncQuantizeBlock(tmp[n], rd->uv_levels[n], 0, &dqm->uv_) << n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +144,15 @@ extern const int VP8I4ModeOffsets[NUM_BMODES];
|
|||||||
typedef int64_t score_t; // type used for scores, rate, distortion
|
typedef int64_t score_t; // type used for scores, rate, distortion
|
||||||
#define MAX_COST ((score_t)0x7fffffffffffffLL)
|
#define MAX_COST ((score_t)0x7fffffffffffffLL)
|
||||||
|
|
||||||
|
#define QFIX 17
|
||||||
|
#define BIAS(b) ((b) << (QFIX - 8))
|
||||||
|
// Fun fact: this is the _only_ line where we're actually being lossy and
|
||||||
|
// discarding bits.
|
||||||
|
static inline int QUANTDIV(int n, int iQ, int B) {
|
||||||
|
return (n * iQ + B) >> QFIX;
|
||||||
|
}
|
||||||
|
extern const uint8_t VP8Zigzag[16];
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Headers
|
// Headers
|
||||||
|
|
||||||
@ -428,6 +437,18 @@ typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst);
|
|||||||
extern VP8BlockCopy VP8Copy4x4;
|
extern VP8BlockCopy VP8Copy4x4;
|
||||||
extern VP8BlockCopy VP8Copy8x8;
|
extern VP8BlockCopy VP8Copy8x8;
|
||||||
extern VP8BlockCopy VP8Copy16x16;
|
extern VP8BlockCopy VP8Copy16x16;
|
||||||
|
// Quantization
|
||||||
|
typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16],
|
||||||
|
int n, const VP8Matrix* const mtx);
|
||||||
|
extern VP8QuantizeBlock VP8EncQuantizeBlock;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kSSE2,
|
||||||
|
kSSE3
|
||||||
|
} CPUFeature;
|
||||||
|
// returns true if the CPU supports the feature.
|
||||||
|
typedef int (*VP8CPUInfo)(CPUFeature feature);
|
||||||
|
extern VP8CPUInfo CPUInfo;
|
||||||
|
|
||||||
void VP8EncDspInit(); // must be called before using anything from the above.
|
void VP8EncDspInit(); // must be called before using anything from the above.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user