mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +01:00
Add VP8L prefix to backward ref & histogram methods.
Change-Id: I8c14fb219a1d7830d3244aa780c91c9964867330
This commit is contained in:
parent
fcba7be2d3
commit
32714ce3be
@ -32,7 +32,7 @@ static const uint8_t plane_to_code_lut[128] = {
|
|||||||
|
|
||||||
static const int kMinLength = 2;
|
static const int kMinLength = 2;
|
||||||
|
|
||||||
int DistanceToPlaneCode(int xsize, int dist) {
|
int VP8LDistanceToPlaneCode(int xsize, int dist) {
|
||||||
int yoffset = dist / xsize;
|
int yoffset = dist / xsize;
|
||||||
int xoffset = dist - yoffset * xsize;
|
int xoffset = dist - yoffset * xsize;
|
||||||
if (xoffset <= 8 && yoffset < 8) {
|
if (xoffset <= 8 && yoffset < 8) {
|
||||||
@ -193,8 +193,8 @@ static WEBP_INLINE void PushBackCopy(int length,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackwardReferencesRle(int xsize, int ysize, const uint32_t* argb,
|
void VP8LBackwardReferencesRle(int xsize, int ysize, const uint32_t* argb,
|
||||||
PixOrCopy* stream, int* stream_size) {
|
PixOrCopy* stream, int* stream_size) {
|
||||||
const int pix_count = xsize * ysize;
|
const int pix_count = xsize * ysize;
|
||||||
int streak = 0;
|
int streak = 0;
|
||||||
int i;
|
int i;
|
||||||
@ -213,10 +213,10 @@ void BackwardReferencesRle(int xsize, int ysize, const uint32_t* argb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns 1 when successful.
|
// Returns 1 when successful.
|
||||||
int BackwardReferencesHashChain(int xsize, int ysize, int use_palette,
|
int VP8LBackwardReferencesHashChain(int xsize, int ysize, int use_palette,
|
||||||
const uint32_t* argb, int palette_bits,
|
const uint32_t* argb, int palette_bits,
|
||||||
int quality,
|
int quality, PixOrCopy* stream,
|
||||||
PixOrCopy* stream, int* stream_size) {
|
int* stream_size) {
|
||||||
const int pix_count = xsize * ysize;
|
const int pix_count = xsize * ysize;
|
||||||
int i;
|
int i;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
@ -320,7 +320,7 @@ static int CostModel_Build(CostModel* p, int xsize, int ysize,
|
|||||||
const uint32_t* argb, int palette_bits) {
|
const uint32_t* argb, int palette_bits) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
int stream_size;
|
int stream_size;
|
||||||
Histogram histo;
|
VP8LHistogram histo;
|
||||||
int i;
|
int i;
|
||||||
PixOrCopy* stream = (PixOrCopy*)malloc(xsize * ysize * sizeof(*stream));
|
PixOrCopy* stream = (PixOrCopy*)malloc(xsize * ysize * sizeof(*stream));
|
||||||
if (stream == NULL) {
|
if (stream == NULL) {
|
||||||
@ -328,34 +328,33 @@ static int CostModel_Build(CostModel* p, int xsize, int ysize,
|
|||||||
}
|
}
|
||||||
p->palette_bits_ = palette_bits;
|
p->palette_bits_ = palette_bits;
|
||||||
if (recursion_level > 0) {
|
if (recursion_level > 0) {
|
||||||
if (!BackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1,
|
if (!VP8LBackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1,
|
||||||
use_palette, argb,
|
use_palette, argb, palette_bits,
|
||||||
palette_bits,
|
&stream[0], &stream_size)) {
|
||||||
&stream[0], &stream_size)) {
|
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const int quality = 100;
|
const int quality = 100;
|
||||||
if (!BackwardReferencesHashChain(xsize, ysize, use_palette, argb,
|
if (!VP8LBackwardReferencesHashChain(xsize, ysize, use_palette, argb,
|
||||||
palette_bits, quality,
|
palette_bits, quality,
|
||||||
&stream[0], &stream_size)) {
|
&stream[0], &stream_size)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HistogramInit(&histo, palette_bits);
|
VP8LHistogramInit(&histo, palette_bits);
|
||||||
for (i = 0; i < stream_size; ++i) {
|
for (i = 0; i < stream_size; ++i) {
|
||||||
HistogramAddSinglePixOrCopy(&histo, stream[i]);
|
VP8LHistogramAddSinglePixOrCopy(&histo, stream[i]);
|
||||||
}
|
}
|
||||||
ConvertPopulationCountTableToBitEstimates(
|
VP8LConvertPopulationCountTableToBitEstimates(
|
||||||
HistogramNumPixOrCopyCodes(&histo),
|
VP8LHistogramNumCodes(&histo),
|
||||||
&histo.literal_[0], &p->literal_[0]);
|
&histo.literal_[0], &p->literal_[0]);
|
||||||
ConvertPopulationCountTableToBitEstimates(
|
VP8LConvertPopulationCountTableToBitEstimates(
|
||||||
VALUES_IN_BYTE, &histo.red_[0], &p->red_[0]);
|
VALUES_IN_BYTE, &histo.red_[0], &p->red_[0]);
|
||||||
ConvertPopulationCountTableToBitEstimates(
|
VP8LConvertPopulationCountTableToBitEstimates(
|
||||||
VALUES_IN_BYTE, &histo.blue_[0], &p->blue_[0]);
|
VALUES_IN_BYTE, &histo.blue_[0], &p->blue_[0]);
|
||||||
ConvertPopulationCountTableToBitEstimates(
|
VP8LConvertPopulationCountTableToBitEstimates(
|
||||||
VALUES_IN_BYTE, &histo.alpha_[0], &p->alpha_[0]);
|
VALUES_IN_BYTE, &histo.alpha_[0], &p->alpha_[0]);
|
||||||
ConvertPopulationCountTableToBitEstimates(
|
VP8LConvertPopulationCountTableToBitEstimates(
|
||||||
DISTANCE_CODES_MAX, &histo.distance_[0], &p->distance_[0]);
|
DISTANCE_CODES_MAX, &histo.distance_[0], &p->distance_[0]);
|
||||||
ok = 1;
|
ok = 1;
|
||||||
Error:
|
Error:
|
||||||
@ -440,7 +439,7 @@ static int BackwardReferencesHashChainDistanceOnly(
|
|||||||
&offset, &len);
|
&offset, &len);
|
||||||
}
|
}
|
||||||
if (len >= kMinLength) {
|
if (len >= kMinLength) {
|
||||||
const int code = DistanceToPlaneCode(xsize, offset);
|
const int code = VP8LDistanceToPlaneCode(xsize, offset);
|
||||||
const double distance_cost =
|
const double distance_cost =
|
||||||
prev_cost + CostModel_DistanceCost(cost_model, code);
|
prev_cost + CostModel_DistanceCost(cost_model, code);
|
||||||
int k;
|
int k;
|
||||||
@ -601,13 +600,13 @@ Error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns 1 on success.
|
// Returns 1 on success.
|
||||||
int BackwardReferencesTraceBackwards(int xsize, int ysize,
|
int VP8LBackwardReferencesTraceBackwards(int xsize, int ysize,
|
||||||
int recursive_cost_model,
|
int recursive_cost_model,
|
||||||
int use_palette,
|
int use_palette,
|
||||||
const uint32_t* argb,
|
const uint32_t* argb,
|
||||||
int palette_bits,
|
int palette_bits,
|
||||||
PixOrCopy* stream,
|
PixOrCopy* stream,
|
||||||
int* stream_size) {
|
int* stream_size) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
const int dist_array_size = xsize * ysize;
|
const int dist_array_size = xsize * ysize;
|
||||||
uint32_t* chosen_path = NULL;
|
uint32_t* chosen_path = NULL;
|
||||||
@ -638,21 +637,22 @@ Error:
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackwardReferences2DLocality(int xsize, int data_size, PixOrCopy* data) {
|
void VP8LBackwardReferences2DLocality(int xsize, int data_size,
|
||||||
|
PixOrCopy* data) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < data_size; ++i) {
|
for (i = 0; i < data_size; ++i) {
|
||||||
if (PixOrCopyIsCopy(&data[i])) {
|
if (PixOrCopyIsCopy(&data[i])) {
|
||||||
int dist = data[i].argb_or_offset;
|
int dist = data[i].argb_or_offset;
|
||||||
int transformed_dist = DistanceToPlaneCode(xsize, dist);
|
int transformed_dist = VP8LDistanceToPlaneCode(xsize, dist);
|
||||||
data[i].argb_or_offset = transformed_dist;
|
data[i].argb_or_offset = transformed_dist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int VerifyBackwardReferences(const uint32_t* argb, int xsize, int ysize,
|
int VP8LVerifyBackwardReferences(const uint32_t* argb, int xsize, int ysize,
|
||||||
int palette_bits,
|
int palette_bits,
|
||||||
const PixOrCopy* lit,
|
const PixOrCopy* lit,
|
||||||
int lit_size) {
|
int lit_size) {
|
||||||
int num_pixels = 0;
|
int num_pixels = 0;
|
||||||
int i;
|
int i;
|
||||||
VP8LColorCache hashers;
|
VP8LColorCache hashers;
|
||||||
@ -717,7 +717,7 @@ int VerifyBackwardReferences(const uint32_t* argb, int xsize, int ysize,
|
|||||||
// Returns 1 on success.
|
// Returns 1 on success.
|
||||||
static int ComputePaletteHistogram(const uint32_t* argb, int xsize, int ysize,
|
static int ComputePaletteHistogram(const uint32_t* argb, int xsize, int ysize,
|
||||||
PixOrCopy* stream, int stream_size,
|
PixOrCopy* stream, int stream_size,
|
||||||
int palette_bits, Histogram* histo) {
|
int palette_bits, VP8LHistogram* histo) {
|
||||||
int pixel_index = 0;
|
int pixel_index = 0;
|
||||||
int i;
|
int i;
|
||||||
uint32_t k;
|
uint32_t k;
|
||||||
@ -732,12 +732,12 @@ static int ComputePaletteHistogram(const uint32_t* argb, int xsize, int ysize,
|
|||||||
VP8LColorCacheContains(&hashers, argb[pixel_index])) {
|
VP8LColorCacheContains(&hashers, argb[pixel_index])) {
|
||||||
// push pixel as a palette pixel
|
// push pixel as a palette pixel
|
||||||
const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]);
|
const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]);
|
||||||
HistogramAddSinglePixOrCopy(histo, PixOrCopyCreatePaletteIx(ix));
|
VP8LHistogramAddSinglePixOrCopy(histo, PixOrCopyCreatePaletteIx(ix));
|
||||||
} else {
|
} else {
|
||||||
HistogramAddSinglePixOrCopy(histo, v);
|
VP8LHistogramAddSinglePixOrCopy(histo, v);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
HistogramAddSinglePixOrCopy(histo, v);
|
VP8LHistogramAddSinglePixOrCopy(histo, v);
|
||||||
}
|
}
|
||||||
for (k = 0; k < PixOrCopyLength(&v); ++k) {
|
for (k = 0; k < PixOrCopyLength(&v); ++k) {
|
||||||
VP8LColorCacheInsert(&hashers, argb[pixel_index]);
|
VP8LColorCacheInsert(&hashers, argb[pixel_index]);
|
||||||
@ -752,9 +752,9 @@ static int ComputePaletteHistogram(const uint32_t* argb, int xsize, int ysize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns how many bits are to be used for a palette.
|
// Returns how many bits are to be used for a palette.
|
||||||
int CalculateEstimateForPaletteSize(const uint32_t* argb,
|
int VP8LCalculateEstimateForPaletteSize(const uint32_t* argb,
|
||||||
int xsize, int ysize,
|
int xsize, int ysize,
|
||||||
int* best_palette_bits) {
|
int* best_palette_bits) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
int palette_bits;
|
int palette_bits;
|
||||||
double lowest_entropy = 1e99;
|
double lowest_entropy = 1e99;
|
||||||
@ -763,17 +763,17 @@ int CalculateEstimateForPaletteSize(const uint32_t* argb,
|
|||||||
static const double kSmallPenaltyForLargePalette = 4.0;
|
static const double kSmallPenaltyForLargePalette = 4.0;
|
||||||
static const int quality = 30;
|
static const int quality = 30;
|
||||||
if (stream == NULL ||
|
if (stream == NULL ||
|
||||||
!BackwardReferencesHashChain(xsize, ysize,
|
!VP8LBackwardReferencesHashChain(xsize, ysize, 0, argb, 0, quality,
|
||||||
0, argb, 0, quality, stream, &stream_size)) {
|
stream, &stream_size)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
for (palette_bits = 0; palette_bits < 12; ++palette_bits) {
|
for (palette_bits = 0; palette_bits < 12; ++palette_bits) {
|
||||||
double cur_entropy;
|
double cur_entropy;
|
||||||
Histogram histo;
|
VP8LHistogram histo;
|
||||||
HistogramInit(&histo, palette_bits);
|
VP8LHistogramInit(&histo, palette_bits);
|
||||||
ComputePaletteHistogram(argb, xsize, ysize, &stream[0], stream_size,
|
ComputePaletteHistogram(argb, xsize, ysize, &stream[0], stream_size,
|
||||||
palette_bits, &histo);
|
palette_bits, &histo);
|
||||||
cur_entropy = HistogramEstimateBits(&histo) +
|
cur_entropy = VP8LHistogramEstimateBits(&histo) +
|
||||||
kSmallPenaltyForLargePalette * palette_bits;
|
kSmallPenaltyForLargePalette * palette_bits;
|
||||||
if (palette_bits == 0 || cur_entropy < lowest_entropy) {
|
if (palette_bits == 0 || cur_entropy < lowest_entropy) {
|
||||||
*best_palette_bits = palette_bits;
|
*best_palette_bits = palette_bits;
|
||||||
|
@ -173,7 +173,7 @@ static WEBP_INLINE void PixOrCopyLengthCodeAndBits(
|
|||||||
|
|
||||||
// Ridiculously simple backward references for images where it is unlikely
|
// Ridiculously simple backward references for images where it is unlikely
|
||||||
// that there are large backward references (photos).
|
// that there are large backward references (photos).
|
||||||
void BackwardReferencesRle(
|
void VP8LBackwardReferencesRle(
|
||||||
int xsize,
|
int xsize,
|
||||||
int ysize,
|
int ysize,
|
||||||
const uint32_t *argb,
|
const uint32_t *argb,
|
||||||
@ -182,7 +182,7 @@ void BackwardReferencesRle(
|
|||||||
|
|
||||||
// This is a simple fast function for obtaining backward references
|
// This is a simple fast function for obtaining backward references
|
||||||
// based on simple heuristics. Returns 1 on success.
|
// based on simple heuristics. Returns 1 on success.
|
||||||
int BackwardReferencesHashChain(
|
int VP8LBackwardReferencesHashChain(
|
||||||
int xsize,
|
int xsize,
|
||||||
int ysize,
|
int ysize,
|
||||||
int use_palette,
|
int use_palette,
|
||||||
@ -195,7 +195,7 @@ int BackwardReferencesHashChain(
|
|||||||
// This method looks for a shortest path through the backward reference
|
// This method looks for a shortest path through the backward reference
|
||||||
// network based on a cost model generated by a first round of compression.
|
// network based on a cost model generated by a first round of compression.
|
||||||
// Returns 1 on success.
|
// Returns 1 on success.
|
||||||
int BackwardReferencesTraceBackwards(
|
int VP8LBackwardReferencesTraceBackwards(
|
||||||
int xsize,
|
int xsize,
|
||||||
int ysize,
|
int ysize,
|
||||||
int recursive_cost_model,
|
int recursive_cost_model,
|
||||||
@ -208,24 +208,24 @@ int BackwardReferencesTraceBackwards(
|
|||||||
// Convert backward references that are of linear distance along
|
// Convert backward references that are of linear distance along
|
||||||
// the image scan lines to have a 2d locality indexing where
|
// the image scan lines to have a 2d locality indexing where
|
||||||
// smaller values are used for backward references that are close by.
|
// smaller values are used for backward references that are close by.
|
||||||
void BackwardReferences2DLocality(int xsize, int data_size,
|
void VP8LBackwardReferences2DLocality(int xsize, int data_size,
|
||||||
PixOrCopy *data);
|
PixOrCopy *data);
|
||||||
|
|
||||||
// Internals of locality transform exposed for testing use.
|
// Internals of locality transform exposed for testing use.
|
||||||
int DistanceToPlaneCode(int xsize, int distance);
|
int VP8LDistanceToPlaneCode(int xsize, int distance);
|
||||||
|
|
||||||
// Returns true if the given backward references actually produce
|
// Returns true if the given backward references actually produce
|
||||||
// the image given in tuple (argb, xsize, ysize).
|
// the image given in tuple (argb, xsize, ysize).
|
||||||
int VerifyBackwardReferences(const uint32_t* argb,
|
int VP8LVerifyBackwardReferences(const uint32_t* argb,
|
||||||
int xsize, int ysize,
|
int xsize, int ysize,
|
||||||
int palette_bits,
|
int palette_bits,
|
||||||
const PixOrCopy *lit,
|
const PixOrCopy *lit,
|
||||||
int lit_size);
|
int lit_size);
|
||||||
|
|
||||||
// Produce an estimate for a good emerging palette size for the image.
|
// Produce an estimate for a good emerging palette size for the image.
|
||||||
int CalculateEstimateForPaletteSize(const uint32_t *argb,
|
int VP8LCalculateEstimateForPaletteSize(const uint32_t *argb,
|
||||||
int xsize, int ysize,
|
int xsize, int ysize,
|
||||||
int *best_palette_bits);
|
int *best_palette_bits);
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ static WEBP_INLINE double FastLog(int v) {
|
|||||||
return log(v);
|
return log(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConvertPopulationCountTableToBitEstimates(
|
void VP8LConvertPopulationCountTableToBitEstimates(
|
||||||
int num_symbols,
|
int num_symbols,
|
||||||
const int* const population_counts,
|
const int* const population_counts,
|
||||||
double* const output) {
|
double* const output) {
|
||||||
@ -145,7 +145,8 @@ void ConvertPopulationCountTableToBitEstimates(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistogramAddSinglePixOrCopy(Histogram* const p, const PixOrCopy v) {
|
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const p,
|
||||||
|
const PixOrCopy v) {
|
||||||
if (PixOrCopyIsLiteral(&v)) {
|
if (PixOrCopyIsLiteral(&v)) {
|
||||||
++p->alpha_[PixOrCopyLiteral(&v, 3)];
|
++p->alpha_[PixOrCopyLiteral(&v, 3)];
|
||||||
++p->red_[PixOrCopyLiteral(&v, 2)];
|
++p->red_[PixOrCopyLiteral(&v, 2)];
|
||||||
@ -165,17 +166,17 @@ void HistogramAddSinglePixOrCopy(Histogram* const p, const PixOrCopy v) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistogramBuild(Histogram* const p,
|
void VP8LHistogramCreate(VP8LHistogram* const p,
|
||||||
const PixOrCopy* const literal_and_length,
|
const PixOrCopy* const literal_and_length,
|
||||||
int n_literal_and_length) {
|
int n_literal_and_length) {
|
||||||
int i;
|
int i;
|
||||||
HistogramClear(p);
|
VP8LHistogramClear(p);
|
||||||
for (i = 0; i < n_literal_and_length; ++i) {
|
for (i = 0; i < n_literal_and_length; ++i) {
|
||||||
HistogramAddSinglePixOrCopy(p, literal_and_length[i]);
|
VP8LHistogramAddSinglePixOrCopy(p, literal_and_length[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double ShannonEntropy(const int* const array, int n) {
|
double VP8LShannonEntropy(const int* const array, int n) {
|
||||||
int i;
|
int i;
|
||||||
double retval = 0;
|
double retval = 0;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
@ -208,7 +209,7 @@ static double BitsEntropy(const int* const array, int n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval -= sum * FastLog(sum);
|
retval -= sum * FastLog(sum);
|
||||||
retval *= -1.4426950408889634; // 1.0 / -FastLog(2);
|
retval *= -1.4426950408889634; // 1.0 / -Log(2);
|
||||||
mix = 0.627;
|
mix = 0.627;
|
||||||
if (nonzeros < 5) {
|
if (nonzeros < 5) {
|
||||||
if (nonzeros <= 1) {
|
if (nonzeros <= 1) {
|
||||||
@ -240,8 +241,8 @@ static double BitsEntropy(const int* const array, int n) {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
double HistogramEstimateBitsBulk(const Histogram* const p) {
|
double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
|
||||||
double retval = BitsEntropy(&p->literal_[0], HistogramNumPixOrCopyCodes(p)) +
|
double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p)) +
|
||||||
BitsEntropy(&p->red_[0], 256) +
|
BitsEntropy(&p->red_[0], 256) +
|
||||||
BitsEntropy(&p->blue_[0], 256) +
|
BitsEntropy(&p->blue_[0], 256) +
|
||||||
BitsEntropy(&p->alpha_[0], 256) +
|
BitsEntropy(&p->alpha_[0], 256) +
|
||||||
@ -258,8 +259,8 @@ double HistogramEstimateBitsBulk(const Histogram* const p) {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
double HistogramEstimateBits(const Histogram* const p) {
|
double VP8LHistogramEstimateBits(const VP8LHistogram* const p) {
|
||||||
return HistogramEstimateBitsHeader(p) + HistogramEstimateBitsBulk(p);
|
return VP8LHistogramEstimateBitsHeader(p) + VP8LHistogramEstimateBitsBulk(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the cost encode the rle-encoded entropy code.
|
// Returns the cost encode the rle-encoded entropy code.
|
||||||
@ -301,35 +302,33 @@ static double HuffmanCost(const int* const population, int length) {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
double HistogramEstimateBitsHeader(const Histogram* const p) {
|
double VP8LHistogramEstimateBitsHeader(const VP8LHistogram* const p) {
|
||||||
return HuffmanCost(&p->alpha_[0], 256) +
|
return HuffmanCost(&p->alpha_[0], 256) +
|
||||||
HuffmanCost(&p->red_[0], 256) +
|
HuffmanCost(&p->red_[0], 256) +
|
||||||
HuffmanCost(&p->literal_[0], HistogramNumPixOrCopyCodes(p)) +
|
HuffmanCost(&p->literal_[0], VP8LHistogramNumCodes(p)) +
|
||||||
HuffmanCost(&p->blue_[0], 256) +
|
HuffmanCost(&p->blue_[0], 256) +
|
||||||
HuffmanCost(&p->distance_[0], DISTANCE_CODES_MAX);
|
HuffmanCost(&p->distance_[0], DISTANCE_CODES_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BuildHistogramImage(int xsize, int ysize,
|
int VP8LHistogramBuildImage(int xsize, int ysize,
|
||||||
int histobits,
|
int histobits, int palettebits,
|
||||||
int palettebits,
|
const PixOrCopy* backward_refs,
|
||||||
const PixOrCopy* backward_refs,
|
int backward_refs_size,
|
||||||
int backward_refs_size,
|
VP8LHistogram*** image_arg, int* image_size) {
|
||||||
Histogram*** image_arg,
|
|
||||||
int* image_size) {
|
|
||||||
int histo_xsize = histobits ? (xsize + (1 << histobits) - 1) >> histobits : 1;
|
int histo_xsize = histobits ? (xsize + (1 << histobits) - 1) >> histobits : 1;
|
||||||
int histo_ysize = histobits ? (ysize + (1 << histobits) - 1) >> histobits : 1;
|
int histo_ysize = histobits ? (ysize + (1 << histobits) - 1) >> histobits : 1;
|
||||||
int i;
|
int i;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
Histogram** image;
|
VP8LHistogram** image;
|
||||||
*image_arg = NULL;
|
*image_arg = NULL;
|
||||||
*image_size = histo_xsize * histo_ysize;
|
*image_size = histo_xsize * histo_ysize;
|
||||||
image = (Histogram**)calloc(*image_size, sizeof(*image));
|
image = (VP8LHistogram**)calloc(*image_size, sizeof(*image));
|
||||||
if (image == NULL) {
|
if (image == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for (i = 0; i < *image_size; ++i) {
|
for (i = 0; i < *image_size; ++i) {
|
||||||
image[i] = (Histogram*)malloc(sizeof(*image[i]));
|
image[i] = (VP8LHistogram*)malloc(sizeof(*image[i]));
|
||||||
if (!image[i]) {
|
if (!image[i]) {
|
||||||
int k;
|
int k;
|
||||||
for (k = 0; k < *image_size; ++k) {
|
for (k = 0; k < *image_size; ++k) {
|
||||||
@ -338,14 +337,14 @@ int BuildHistogramImage(int xsize, int ysize,
|
|||||||
free(image);
|
free(image);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
HistogramInit(image[i], palettebits);
|
VP8LHistogramInit(image[i], palettebits);
|
||||||
}
|
}
|
||||||
// x and y trace the position in the image.
|
// x and y trace the position in the image.
|
||||||
for (i = 0; i < backward_refs_size; ++i) {
|
for (i = 0; i < backward_refs_size; ++i) {
|
||||||
const PixOrCopy v = backward_refs[i];
|
const PixOrCopy v = backward_refs[i];
|
||||||
const int ix =
|
const int ix =
|
||||||
histobits ? (y >> histobits) * histo_xsize + (x >> histobits) : 0;
|
histobits ? (y >> histobits) * histo_xsize + (x >> histobits) : 0;
|
||||||
HistogramAddSinglePixOrCopy(image[ix], v);
|
VP8LHistogramAddSinglePixOrCopy(image[ix], v);
|
||||||
x += PixOrCopyLength(&v);
|
x += PixOrCopyLength(&v);
|
||||||
while (x >= xsize) {
|
while (x >= xsize) {
|
||||||
x -= xsize;
|
x -= xsize;
|
||||||
@ -356,11 +355,8 @@ int BuildHistogramImage(int xsize, int ysize,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CombineHistogramImage(Histogram** in,
|
int VP8LHistogramCombine(VP8LHistogram** in, int in_size, int quality,
|
||||||
int in_size,
|
VP8LHistogram*** out_arg, int* out_size) {
|
||||||
int quality,
|
|
||||||
Histogram*** out_arg,
|
|
||||||
int* out_size) {
|
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
int i;
|
int i;
|
||||||
unsigned int seed = 0;
|
unsigned int seed = 0;
|
||||||
@ -368,7 +364,7 @@ int CombineHistogramImage(Histogram** in,
|
|||||||
int inner_iters = 10 + quality / 2;
|
int inner_iters = 10 + quality / 2;
|
||||||
int iter;
|
int iter;
|
||||||
double* bit_costs = (double*)malloc(in_size * sizeof(*bit_costs));
|
double* bit_costs = (double*)malloc(in_size * sizeof(*bit_costs));
|
||||||
Histogram** out = (Histogram**)calloc(in_size, sizeof(*out));
|
VP8LHistogram** out = (VP8LHistogram**)calloc(in_size, sizeof(*out));
|
||||||
*out_arg = out;
|
*out_arg = out;
|
||||||
*out_size = in_size;
|
*out_size = in_size;
|
||||||
if (bit_costs == NULL || out == NULL) {
|
if (bit_costs == NULL || out == NULL) {
|
||||||
@ -376,13 +372,13 @@ int CombineHistogramImage(Histogram** in,
|
|||||||
}
|
}
|
||||||
// Copy
|
// Copy
|
||||||
for (i = 0; i < in_size; ++i) {
|
for (i = 0; i < in_size; ++i) {
|
||||||
Histogram* new_histo = (Histogram*)malloc(sizeof(*new_histo));
|
VP8LHistogram* new_histo = (VP8LHistogram*)malloc(sizeof(*new_histo));
|
||||||
if (new_histo == NULL) {
|
if (new_histo == NULL) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
*new_histo = *(in[i]);
|
*new_histo = *(in[i]);
|
||||||
out[i] = new_histo;
|
out[i] = new_histo;
|
||||||
bit_costs[i] = HistogramEstimateBits(out[i]);
|
bit_costs[i] = VP8LHistogramEstimateBits(out[i]);
|
||||||
}
|
}
|
||||||
// Collapse similar histograms.
|
// Collapse similar histograms.
|
||||||
for (iter = 0; iter < in_size * 3 && *out_size >= 2; ++iter) {
|
for (iter = 0; iter < in_size * 3 && *out_size >= 2; ++iter) {
|
||||||
@ -394,7 +390,7 @@ int CombineHistogramImage(Histogram** in,
|
|||||||
for (k = 0; k < inner_iters; ++k) {
|
for (k = 0; k < inner_iters; ++k) {
|
||||||
// Choose two, build a combo out of them.
|
// Choose two, build a combo out of them.
|
||||||
double cost_val;
|
double cost_val;
|
||||||
Histogram* combo;
|
VP8LHistogram* combo;
|
||||||
int ix0 = rand_r(&seed) % *out_size;
|
int ix0 = rand_r(&seed) % *out_size;
|
||||||
int ix1;
|
int ix1;
|
||||||
int diff = ((k & 7) + 1) % (*out_size - 1);
|
int diff = ((k & 7) + 1) % (*out_size - 1);
|
||||||
@ -405,13 +401,14 @@ int CombineHistogramImage(Histogram** in,
|
|||||||
if (ix0 == ix1) {
|
if (ix0 == ix1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
combo = (Histogram*)malloc(sizeof(*combo));
|
combo = (VP8LHistogram*)malloc(sizeof(*combo));
|
||||||
if (combo == NULL) {
|
if (combo == NULL) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
*combo = *out[ix0];
|
*combo = *out[ix0];
|
||||||
HistogramAdd(combo, out[ix1]);
|
VP8LHistogramAdd(combo, out[ix1]);
|
||||||
cost_val = HistogramEstimateBits(combo) - bit_costs[ix0] - bit_costs[ix1];
|
cost_val =
|
||||||
|
VP8LHistogramEstimateBits(combo) - bit_costs[ix0] - bit_costs[ix1];
|
||||||
if (best_val > cost_val) {
|
if (best_val > cost_val) {
|
||||||
best_val = cost_val;
|
best_val = cost_val;
|
||||||
best_ix0 = ix0;
|
best_ix0 = ix0;
|
||||||
@ -420,7 +417,7 @@ int CombineHistogramImage(Histogram** in,
|
|||||||
free(combo);
|
free(combo);
|
||||||
}
|
}
|
||||||
if (best_val < 0.0) {
|
if (best_val < 0.0) {
|
||||||
HistogramAdd(out[best_ix0], out[best_ix1]);
|
VP8LHistogramAdd(out[best_ix0], out[best_ix1]);
|
||||||
bit_costs[best_ix0] =
|
bit_costs[best_ix0] =
|
||||||
best_val + bit_costs[best_ix0] + bit_costs[best_ix1];
|
best_val + bit_costs[best_ix0] + bit_costs[best_ix1];
|
||||||
// Erase (*out)[best_ix1]
|
// Erase (*out)[best_ix1]
|
||||||
@ -453,42 +450,39 @@ Error:
|
|||||||
|
|
||||||
// What is the bit cost of moving square_histogram from
|
// What is the bit cost of moving square_histogram from
|
||||||
// cur_symbol to candidate_symbol.
|
// cur_symbol to candidate_symbol.
|
||||||
static double HistogramDistance(const Histogram* const square_histogram,
|
static double HistogramDistance(const VP8LHistogram* const square_histogram,
|
||||||
int cur_symbol,
|
int cur_symbol,
|
||||||
int candidate_symbol,
|
int candidate_symbol,
|
||||||
Histogram** candidate_histograms) {
|
VP8LHistogram** candidate_histograms) {
|
||||||
double new_bit_cost;
|
double new_bit_cost;
|
||||||
double previous_bit_cost;
|
double previous_bit_cost;
|
||||||
Histogram modified;
|
VP8LHistogram modified;
|
||||||
if (cur_symbol == candidate_symbol) {
|
if (cur_symbol == candidate_symbol) {
|
||||||
return 0; // Going nowhere. No savings.
|
return 0; // Going nowhere. No savings.
|
||||||
}
|
}
|
||||||
previous_bit_cost =
|
previous_bit_cost =
|
||||||
HistogramEstimateBits(candidate_histograms[candidate_symbol]);
|
VP8LHistogramEstimateBits(candidate_histograms[candidate_symbol]);
|
||||||
if (cur_symbol != -1) {
|
if (cur_symbol != -1) {
|
||||||
previous_bit_cost +=
|
previous_bit_cost +=
|
||||||
HistogramEstimateBits(candidate_histograms[cur_symbol]);
|
VP8LHistogramEstimateBits(candidate_histograms[cur_symbol]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the bit cost of the histogram where the data moves to.
|
// Compute the bit cost of the histogram where the data moves to.
|
||||||
modified = *candidate_histograms[candidate_symbol];
|
modified = *candidate_histograms[candidate_symbol];
|
||||||
HistogramAdd(&modified, square_histogram);
|
VP8LHistogramAdd(&modified, square_histogram);
|
||||||
new_bit_cost = HistogramEstimateBits(&modified);
|
new_bit_cost = VP8LHistogramEstimateBits(&modified);
|
||||||
|
|
||||||
// Compute the bit cost of the histogram where the data moves away.
|
// Compute the bit cost of the histogram where the data moves away.
|
||||||
if (cur_symbol != -1) {
|
if (cur_symbol != -1) {
|
||||||
modified = *candidate_histograms[cur_symbol];
|
modified = *candidate_histograms[cur_symbol];
|
||||||
HistogramRemove(&modified, square_histogram);
|
VP8LHistogramRemove(&modified, square_histogram);
|
||||||
new_bit_cost += HistogramEstimateBits(&modified);
|
new_bit_cost += VP8LHistogramEstimateBits(&modified);
|
||||||
}
|
}
|
||||||
return new_bit_cost - previous_bit_cost;
|
return new_bit_cost - previous_bit_cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RefineHistogramImage(Histogram** raw,
|
void VP8LHistogramRefine(VP8LHistogram** raw, int raw_size,
|
||||||
int raw_size,
|
uint32_t* symbols, int out_size, VP8LHistogram** out) {
|
||||||
uint32_t* symbols,
|
|
||||||
int out_size,
|
|
||||||
Histogram** out) {
|
|
||||||
int i;
|
int i;
|
||||||
// Find the best 'out' histogram for each of the raw histograms
|
// Find the best 'out' histogram for each of the raw histograms
|
||||||
for (i = 0; i < raw_size; ++i) {
|
for (i = 0; i < raw_size; ++i) {
|
||||||
@ -507,9 +501,9 @@ void RefineHistogramImage(Histogram** raw,
|
|||||||
|
|
||||||
// Recompute each out based on raw and symbols.
|
// Recompute each out based on raw and symbols.
|
||||||
for (i = 0; i < out_size; ++i) {
|
for (i = 0; i < out_size; ++i) {
|
||||||
HistogramClear(out[i]);
|
VP8LHistogramClear(out[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < raw_size; ++i) {
|
for (i = 0; i < raw_size; ++i) {
|
||||||
HistogramAdd(out[symbols[i]], raw[i]);
|
VP8LHistogramAdd(out[symbols[i]], raw[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,9 @@ typedef struct {
|
|||||||
// Backward reference prefix-code histogram.
|
// Backward reference prefix-code histogram.
|
||||||
int distance_[DISTANCE_CODES_MAX];
|
int distance_[DISTANCE_CODES_MAX];
|
||||||
int palette_code_bits_;
|
int palette_code_bits_;
|
||||||
} Histogram;
|
} VP8LHistogram;
|
||||||
|
|
||||||
static WEBP_INLINE void HistogramClear(Histogram* const p) {
|
static WEBP_INLINE void VP8LHistogramClear(VP8LHistogram* const p) {
|
||||||
memset(&p->literal_[0], 0, sizeof(p->literal_));
|
memset(&p->literal_[0], 0, sizeof(p->literal_));
|
||||||
memset(&p->red_[0], 0, sizeof(p->red_));
|
memset(&p->red_[0], 0, sizeof(p->red_));
|
||||||
memset(&p->blue_[0], 0, sizeof(p->blue_));
|
memset(&p->blue_[0], 0, sizeof(p->blue_));
|
||||||
@ -46,36 +46,36 @@ static WEBP_INLINE void HistogramClear(Histogram* const p) {
|
|||||||
memset(&p->distance_[0], 0, sizeof(p->distance_));
|
memset(&p->distance_[0], 0, sizeof(p->distance_));
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void HistogramInit(Histogram* const p,
|
static WEBP_INLINE void VP8LHistogramInit(VP8LHistogram* const p,
|
||||||
int palette_code_bits) {
|
int palette_code_bits) {
|
||||||
p->palette_code_bits_ = palette_code_bits;
|
p->palette_code_bits_ = palette_code_bits;
|
||||||
HistogramClear(p);
|
VP8LHistogramClear(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the histogram.
|
// Create the histogram.
|
||||||
//
|
//
|
||||||
// The input data is the PixOrCopy data, which models the
|
// The input data is the PixOrCopy data, which models the
|
||||||
// literals, stop codes and backward references (both distances and lengths)
|
// literals, stop codes and backward references (both distances and lengths)
|
||||||
void HistogramBuild(Histogram* const p,
|
void VP8LHistogramCreate(VP8LHistogram* const p,
|
||||||
const PixOrCopy* const literal_and_length,
|
const PixOrCopy* const literal_and_length,
|
||||||
int n_literal_and_length);
|
int n_literal_and_length);
|
||||||
|
|
||||||
void HistogramAddSinglePixOrCopy(Histogram* const p, const PixOrCopy v);
|
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const p, const PixOrCopy v);
|
||||||
|
|
||||||
// Estimate how many bits the combined entropy of literals and distance
|
// Estimate how many bits the combined entropy of literals and distance
|
||||||
// approximately maps to.
|
// approximately maps to.
|
||||||
double HistogramEstimateBits(const Histogram* const p);
|
double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
|
||||||
|
|
||||||
// This function estimates the Huffman dictionary + other block overhead
|
// This function estimates the Huffman dictionary + other block overhead
|
||||||
// size for creating a new deflate block.
|
// size for creating a new deflate block.
|
||||||
double HistogramEstimateBitsHeader(const Histogram* const p);
|
double VP8LHistogramEstimateBitsHeader(const VP8LHistogram* const p);
|
||||||
|
|
||||||
// This function estimates the cost in bits excluding the bits needed to
|
// This function estimates the cost in bits excluding the bits needed to
|
||||||
// represent the entropy code itself.
|
// represent the entropy code itself.
|
||||||
double HistogramEstimateBitsBulk(const Histogram* const p);
|
double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p);
|
||||||
|
|
||||||
static WEBP_INLINE void HistogramAdd(Histogram* const p,
|
static WEBP_INLINE void VP8LHistogramAdd(VP8LHistogram* const p,
|
||||||
const Histogram* const a) {
|
const VP8LHistogram* const a) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
|
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
|
||||||
p->literal_[i] += a->literal_[i];
|
p->literal_[i] += a->literal_[i];
|
||||||
@ -90,8 +90,8 @@ static WEBP_INLINE void HistogramAdd(Histogram* const p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void HistogramRemove(Histogram* const p,
|
static WEBP_INLINE void VP8LHistogramRemove(VP8LHistogram* const p,
|
||||||
const Histogram* const a) {
|
const VP8LHistogram* const a) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
|
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
|
||||||
p->literal_[i] -= a->literal_[i];
|
p->literal_[i] -= a->literal_[i];
|
||||||
@ -111,39 +111,38 @@ static WEBP_INLINE void HistogramRemove(Histogram* const p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE int HistogramNumPixOrCopyCodes(const Histogram* const p) {
|
static WEBP_INLINE int VP8LHistogramNumCodes(const VP8LHistogram* const p) {
|
||||||
return 256 + kLengthCodes + (1 << p->palette_code_bits_);
|
return 256 + kLengthCodes + (1 << p->palette_code_bits_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConvertPopulationCountTableToBitEstimates(
|
void VP8LConvertPopulationCountTableToBitEstimates(
|
||||||
int n, const int* const population_counts, double* const output);
|
int n, const int* const population_counts, double* const output);
|
||||||
|
|
||||||
double ShannonEntropy(const int* const array, int n);
|
double VP8LShannonEntropy(const int* const array, int n);
|
||||||
|
|
||||||
// Build a 2d image of histograms, subresolutioned by (1 << histobits) to
|
// Build a 2d image of histograms, subresolutioned by (1 << histobits) to
|
||||||
// the original image.
|
// the original image.
|
||||||
int BuildHistogramImage(int xsize, int ysize,
|
int VP8LHistogramBuildImage(int xsize, int ysize,
|
||||||
int histobits,
|
int histobits, int palette_bits,
|
||||||
int palette_bits,
|
const PixOrCopy* backward_refs,
|
||||||
const PixOrCopy* backward_refs,
|
int backward_refs_size,
|
||||||
int backward_refs_size,
|
VP8LHistogram*** image,
|
||||||
Histogram*** image,
|
int* histogram_size);
|
||||||
int* histogram_size);
|
|
||||||
|
|
||||||
// Combines several histograms into fewer histograms.
|
// Combines several histograms into fewer histograms.
|
||||||
int CombineHistogramImage(Histogram** in,
|
int VP8LHistogramCombine(VP8LHistogram** in,
|
||||||
int in_size,
|
int in_size,
|
||||||
int quality,
|
int quality,
|
||||||
Histogram*** out,
|
VP8LHistogram*** out,
|
||||||
int* out_size);
|
int* out_size);
|
||||||
|
|
||||||
// Moves histograms from one cluster to another if smaller entropy can
|
// Moves histograms from one cluster to another if smaller entropy can
|
||||||
// be achieved by doing that.
|
// be achieved by doing that.
|
||||||
void RefineHistogramImage(Histogram** raw,
|
void VP8LHistogramRefine(VP8LHistogram** raw,
|
||||||
int raw_size,
|
int raw_size,
|
||||||
uint32_t* symbols,
|
uint32_t* symbols,
|
||||||
int out_size,
|
int out_size,
|
||||||
Histogram** out);
|
VP8LHistogram** out);
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user