take picture->argb_stride into account for lossless coding

analysis phase was assuming flat layout...

Change-Id: I96681f6d76aa3faabc51dd2ee3dffbe77ff90d36
This commit is contained in:
Pascal Massimino 2012-06-20 10:13:04 -07:00
parent a575b4bc15
commit 233a589ea9

View File

@ -42,35 +42,34 @@ static int CompareColors(const void* p1, const void* p2) {
// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
// creates a palette and returns true, else returns false.
static int AnalyzeAndCreatePalette(const uint32_t* const argb, int num_pix,
static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
uint32_t palette[MAX_PALETTE_SIZE],
int* const palette_size) {
int i, key;
int i, x, y, key;
int num_colors = 0;
uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
uint32_t colors[MAX_PALETTE_SIZE * 4];
static const uint32_t kHashMul = 0x1e35a7bd;
const uint32_t* argb = pic->argb;
uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
key = (kHashMul * argb[0]) >> PALETTE_KEY_RIGHT_SHIFT;
colors[key] = argb[0];
in_use[key] = 1;
++num_colors;
for (i = 1; i < num_pix; ++i) {
if (argb[i] == argb[i - 1]) {
for (y = 0; y < pic->height; ++y) {
for (x = 0; x < pic->width; ++x) {
if (argb[x] == last_pix) {
continue;
}
key = (kHashMul * argb[i]) >> PALETTE_KEY_RIGHT_SHIFT;
last_pix = argb[x];
key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT;
while (1) {
if (!in_use[key]) {
colors[key] = argb[i];
colors[key] = last_pix;
in_use[key] = 1;
++num_colors;
if (num_colors > MAX_PALETTE_SIZE) {
return 0;
}
break;
} else if (colors[key] == argb[i]) {
} else if (colors[key] == last_pix) {
// The color is already there.
break;
} else {
@ -81,6 +80,8 @@ static int AnalyzeAndCreatePalette(const uint32_t* const argb, int num_pix,
}
}
}
argb += pic->argb_stride;
}
num_colors = 0;
for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
@ -95,10 +96,14 @@ static int AnalyzeAndCreatePalette(const uint32_t* const argb, int num_pix,
return 1;
}
static int AnalyzeEntropy(const uint32_t* const argb, int xsize, int ysize,
static int AnalyzeEntropy(const WebPPicture* const pic,
double* const nonpredicted_bits,
double* const predicted_bits) {
int i;
int x, y;
const uint32_t* argb = pic->argb;
const uint32_t* last_line = NULL;
uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0
VP8LHistogram* nonpredicted = NULL;
VP8LHistogram* predicted = (VP8LHistogram*)malloc(2 * sizeof(*predicted));
if (predicted == NULL) return 0;
@ -106,13 +111,15 @@ static int AnalyzeEntropy(const uint32_t* const argb, int xsize, int ysize,
VP8LHistogramInit(predicted, 0);
VP8LHistogramInit(nonpredicted, 0);
for (i = 1; i < xsize * ysize; ++i) {
const uint32_t pix = argb[i];
const uint32_t pix_diff = VP8LSubPixels(pix, argb[i - 1]);
for (y = 0; y < pic->height; ++y) {
for (x = 0; x < pic->width; ++x) {
const uint32_t pix = argb[x];
const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
if (pix_diff == 0) continue;
if (i >= xsize && pix == argb[i - xsize]) {
if (last_line != NULL && pix == last_line[x]) {
continue;
}
last_pix = pix;
{
const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
@ -120,6 +127,9 @@ static int AnalyzeEntropy(const uint32_t* const argb, int xsize, int ysize,
VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token);
}
}
last_line = argb;
argb += pic->argb_stride;
}
*nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
*predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
free(predicted);
@ -779,14 +789,17 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
// Bundles multiple (2, 4 or 8) pixels into a single pixel.
// Returns the new xsize.
static void BundleColorMap(const uint32_t* const argb,
int width, int height, int xbits,
uint32_t* bundled_argb, int xs) {
int x, y;
static void BundleColorMap(const WebPPicture* const pic,
int xbits, uint32_t* bundled_argb, int xs) {
int y;
const int bit_depth = 1 << (3 - xbits);
uint32_t code = 0;
const uint32_t* argb = pic->argb;
const int width = pic->width;
const int height = pic->height;
for (y = 0; y < height; ++y) {
int x;
for (x = 0; x < width; ++x) {
const int mask = (1 << xbits) - 1;
const int xsub = x & mask;
@ -794,9 +807,10 @@ static void BundleColorMap(const uint32_t* const argb,
code = 0;
}
// TODO(vikasa): simplify the bundling logic.
code |= (argb[y * width + x] & 0xff00) << (bit_depth * xsub);
code |= (argb[x] & 0xff00) << (bit_depth * xsub);
bundled_argb[y * xs + (x >> xbits)] = 0xff000000 | code;
}
argb += pic->argb_stride;
}
}
@ -805,24 +819,28 @@ static void BundleColorMap(const uint32_t* const argb,
// later.
static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
VP8LEncoder* const enc,
int width, int height, int quality) {
int quality) {
WebPEncodingError err = VP8_ENC_OK;
int i;
uint32_t* const argb = enc->pic_->argb;
int i, x, y;
const WebPPicture* const pic = enc->pic_;
const int width = pic->width;
const int height = pic->height;
uint32_t* const palette = enc->palette_;
const int palette_size = enc->palette_size_;
// Replace each input pixel by corresponding palette index.
for (i = 0; i < width * height; ++i) {
int k;
for (k = 0; k < palette_size; ++k) {
const uint32_t pix = argb[i];
if (pix == palette[k]) {
argb[i] = 0xff000000u | (k << 8);
for (y = 0; y < height; ++y) {
uint32_t* const argb = pic->argb + y * pic->argb_stride;
for (x = 0; x < width; ++x) {
const uint32_t pix = argb[x];
for (i = 0; i < palette_size; ++i) {
if (pix == palette[i]) {
argb[x] = 0xff000000u | (i << 8);
break;
}
}
}
}
// Save palette to bitstream.
VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
@ -847,7 +865,7 @@ static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
}
err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
if (err != VP8_ENC_OK) goto Error;
BundleColorMap(argb, width, height, xbits, enc->argb_, enc->current_width_);
BundleColorMap(pic, xbits, enc->argb_, enc->current_width_);
}
Error:
@ -932,17 +950,21 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
}
if (enc->use_palette_) {
err = ApplyPalette(bw, enc, width, height, quality);
err = ApplyPalette(bw, enc, quality);
if (err != VP8_ENC_OK) goto Error;
enc->cache_bits_ = 0;
}
// In case image is not packed.
if (enc->argb_ == NULL) {
const size_t image_size = height * width;
int y;
err = AllocateTransformBuffer(enc, width, height);
if (err != VP8_ENC_OK) goto Error;
memcpy(enc->argb_, picture->argb, image_size * sizeof(*enc->argb_));
for (y = 0; y < height; ++y) {
memcpy(enc->argb_ + y * width,
picture->argb + y * picture->argb_stride,
width * sizeof(*enc->argb_));
}
enc->current_width_ = width;
}