diff --git a/src/enc/histogram.c b/src/enc/histogram.c index 7be49a23..c38d35e5 100644 --- a/src/enc/histogram.c +++ b/src/enc/histogram.c @@ -188,59 +188,64 @@ static WEBP_INLINE double InitialHuffmanCost(void) { return kHuffmanCodeOfHuffmanCodeSize - kSmallBias; } -static WEBP_INLINE double HuffmanCostRefine(int streak, int val) { - double retval; - if (streak > 3) { - if (val == 0) { - retval = 1.5625 + 0.234375 * streak; - } else { - retval = 2.578125 + 0.703125 * streak; - } - } else { - if (val == 0) { - retval = 1.796875 * streak; - } else { - retval = 3.28125 * streak; - } - } +double VP8FinalHuffmanCost(int cnt_z, int streak_z_le3, int streak_z_gt3, + int cnt_nz, int streak_nz_le3, int streak_nz_gt3) { + double retval = InitialHuffmanCost(); + retval += cnt_z * 1.5625 + 0.234375 * streak_z_gt3; + retval += cnt_nz * 2.578125 + 0.703125 * streak_nz_gt3; + retval += 1.796875 * streak_z_le3; + retval += 3.28125 * streak_nz_le3; return retval; } // Returns the cost encode the rle-encoded entropy code. // The constants in this function are experimental. static double HuffmanCost(const int* const population, int length) { + int cnts[2] = { 0, 0 }; + int streaks[2][2] = { { 0, 0 }, { 0, 0 } }; int streak = 0; - int i = 0; - double retval = InitialHuffmanCost(); - for (; i < length - 1; ++i) { + int i; + for (i = 0; i < length - 1; ++i) { ++streak; if (population[i] == population[i + 1]) { continue; } - retval += HuffmanCostRefine(streak, population[i]); + cnts[population[i] != 0] += (streak > 3); + streaks[population[i] != 0][(streak > 3)] += streak; streak = 0; } - retval += HuffmanCostRefine(++streak, population[i]); - return retval; + ++streak; + cnts[population[i] != 0] += (streak > 3); + streaks[population[i] != 0][(streak > 3)] += streak; + return VP8FinalHuffmanCost(cnts[0], streaks[0][0], streaks[0][1], + cnts[1], streaks[1][0], streaks[1][1]); } static double HuffmanCostCombined(const int* const X, const int* const Y, int length) { + int cnts[2] = { 0, 0 }; + int streaks[2][2] = { { 0, 0 }, { 0, 0 } }; int streak = 0; - int i = 0; - double retval = InitialHuffmanCost(); - for (; i < length - 1; ++i) { + int i; + for (i = 0; i < length - 1; ++i) { const int xy = X[i] + Y[i]; const int xy_next = X[i + 1] + Y[i + 1]; ++streak; if (xy == xy_next) { continue; } - retval += HuffmanCostRefine(streak, xy); + cnts[xy != 0] += (streak > 3); + streaks[xy != 0][streak > 3] += streak; streak = 0; } - retval += HuffmanCostRefine(++streak, X[i] + Y[i]); - return retval; + { + const int xy = X[i] + Y[i]; + ++streak; + cnts[xy != 0] += (streak > 3); + streaks[xy != 0][streak > 3] += streak; + } + return VP8FinalHuffmanCost(cnts[0], streaks[0][0], streaks[0][1], + cnts[1], streaks[1][0], streaks[1][1]); } static double PopulationCost(const int* const population, int length) { diff --git a/src/enc/histogram.h b/src/enc/histogram.h index 9d13ecd5..e8c3b9d1 100644 --- a/src/enc/histogram.h +++ b/src/enc/histogram.h @@ -90,6 +90,13 @@ static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) { ((palette_code_bits > 0) ? (1 << palette_code_bits) : 0); } +// Used to finalized the Huffman cost: +// cnt_z / cnt_nz: counts the number of 0's and non-0's +// streak_{z,nz}_le3 / streak_{z,nz}_gt3: number of streaks larger than 3 +// or less-or-equal than 3. +double VP8FinalHuffmanCost(int cnt_z, int streak_z_le3, int streak_z_gt3, + int cnt_nz, int streak_nz_le3, int streak_nz_gt3); + // Builds the histogram image. int VP8LGetHistoImageSymbols(int xsize, int ysize, const VP8LBackwardRefs* const refs,