mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
take picture->argb_stride into account for lossless coding
analysis phase was assuming flat layout... Change-Id: I96681f6d76aa3faabc51dd2ee3dffbe77ff90d36
This commit is contained in:
parent
a575b4bc15
commit
233a589ea9
144
src/enc/vp8l.c
144
src/enc/vp8l.c
@ -42,44 +42,45 @@ 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,
|
// 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.
|
// 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],
|
uint32_t palette[MAX_PALETTE_SIZE],
|
||||||
int* const palette_size) {
|
int* const palette_size) {
|
||||||
int i, key;
|
int i, x, y, key;
|
||||||
int num_colors = 0;
|
int num_colors = 0;
|
||||||
uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
|
uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
|
||||||
uint32_t colors[MAX_PALETTE_SIZE * 4];
|
uint32_t colors[MAX_PALETTE_SIZE * 4];
|
||||||
static const uint32_t kHashMul = 0x1e35a7bd;
|
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;
|
for (y = 0; y < pic->height; ++y) {
|
||||||
colors[key] = argb[0];
|
for (x = 0; x < pic->width; ++x) {
|
||||||
in_use[key] = 1;
|
if (argb[x] == last_pix) {
|
||||||
++num_colors;
|
continue;
|
||||||
|
}
|
||||||
for (i = 1; i < num_pix; ++i) {
|
last_pix = argb[x];
|
||||||
if (argb[i] == argb[i - 1]) {
|
key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT;
|
||||||
continue;
|
while (1) {
|
||||||
}
|
if (!in_use[key]) {
|
||||||
key = (kHashMul * argb[i]) >> PALETTE_KEY_RIGHT_SHIFT;
|
colors[key] = last_pix;
|
||||||
while (1) {
|
in_use[key] = 1;
|
||||||
if (!in_use[key]) {
|
++num_colors;
|
||||||
colors[key] = argb[i];
|
if (num_colors > MAX_PALETTE_SIZE) {
|
||||||
in_use[key] = 1;
|
return 0;
|
||||||
++num_colors;
|
}
|
||||||
if (num_colors > MAX_PALETTE_SIZE) {
|
break;
|
||||||
return 0;
|
} else if (colors[key] == last_pix) {
|
||||||
|
// The color is already there.
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Some other color sits there.
|
||||||
|
// Do linear conflict resolution.
|
||||||
|
++key;
|
||||||
|
key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer.
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
} else if (colors[key] == argb[i]) {
|
|
||||||
// The color is already there.
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// Some other color sits there.
|
|
||||||
// Do linear conflict resolution.
|
|
||||||
++key;
|
|
||||||
key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
argb += pic->argb_stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_colors = 0;
|
num_colors = 0;
|
||||||
@ -95,10 +96,14 @@ static int AnalyzeAndCreatePalette(const uint32_t* const argb, int num_pix,
|
|||||||
return 1;
|
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 nonpredicted_bits,
|
||||||
double* const predicted_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* nonpredicted = NULL;
|
||||||
VP8LHistogram* predicted = (VP8LHistogram*)malloc(2 * sizeof(*predicted));
|
VP8LHistogram* predicted = (VP8LHistogram*)malloc(2 * sizeof(*predicted));
|
||||||
if (predicted == NULL) return 0;
|
if (predicted == NULL) return 0;
|
||||||
@ -106,19 +111,24 @@ static int AnalyzeEntropy(const uint32_t* const argb, int xsize, int ysize,
|
|||||||
|
|
||||||
VP8LHistogramInit(predicted, 0);
|
VP8LHistogramInit(predicted, 0);
|
||||||
VP8LHistogramInit(nonpredicted, 0);
|
VP8LHistogramInit(nonpredicted, 0);
|
||||||
for (i = 1; i < xsize * ysize; ++i) {
|
for (y = 0; y < pic->height; ++y) {
|
||||||
const uint32_t pix = argb[i];
|
for (x = 0; x < pic->width; ++x) {
|
||||||
const uint32_t pix_diff = VP8LSubPixels(pix, argb[i - 1]);
|
const uint32_t pix = argb[x];
|
||||||
if (pix_diff == 0) continue;
|
const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
|
||||||
if (i >= xsize && pix == argb[i - xsize]) {
|
if (pix_diff == 0) continue;
|
||||||
continue;
|
if (last_line != NULL && pix == last_line[x]) {
|
||||||
}
|
continue;
|
||||||
{
|
}
|
||||||
const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
|
last_pix = pix;
|
||||||
const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
|
{
|
||||||
VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token);
|
const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
|
||||||
VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token);
|
const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
|
||||||
|
VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token);
|
||||||
|
VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
last_line = argb;
|
||||||
|
argb += pic->argb_stride;
|
||||||
}
|
}
|
||||||
*nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
|
*nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
|
||||||
*predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
|
*predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
|
||||||
@ -779,14 +789,17 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
|
|||||||
|
|
||||||
// Bundles multiple (2, 4 or 8) pixels into a single pixel.
|
// Bundles multiple (2, 4 or 8) pixels into a single pixel.
|
||||||
// Returns the new xsize.
|
// Returns the new xsize.
|
||||||
static void BundleColorMap(const uint32_t* const argb,
|
static void BundleColorMap(const WebPPicture* const pic,
|
||||||
int width, int height, int xbits,
|
int xbits, uint32_t* bundled_argb, int xs) {
|
||||||
uint32_t* bundled_argb, int xs) {
|
int y;
|
||||||
int x, y;
|
|
||||||
const int bit_depth = 1 << (3 - xbits);
|
const int bit_depth = 1 << (3 - xbits);
|
||||||
uint32_t code = 0;
|
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) {
|
for (y = 0; y < height; ++y) {
|
||||||
|
int x;
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
const int mask = (1 << xbits) - 1;
|
const int mask = (1 << xbits) - 1;
|
||||||
const int xsub = x & mask;
|
const int xsub = x & mask;
|
||||||
@ -794,9 +807,10 @@ static void BundleColorMap(const uint32_t* const argb,
|
|||||||
code = 0;
|
code = 0;
|
||||||
}
|
}
|
||||||
// TODO(vikasa): simplify the bundling logic.
|
// 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;
|
bundled_argb[y * xs + (x >> xbits)] = 0xff000000 | code;
|
||||||
}
|
}
|
||||||
|
argb += pic->argb_stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,21 +819,25 @@ static void BundleColorMap(const uint32_t* const argb,
|
|||||||
// later.
|
// later.
|
||||||
static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
|
static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
|
||||||
VP8LEncoder* const enc,
|
VP8LEncoder* const enc,
|
||||||
int width, int height, int quality) {
|
int quality) {
|
||||||
WebPEncodingError err = VP8_ENC_OK;
|
WebPEncodingError err = VP8_ENC_OK;
|
||||||
int i;
|
int i, x, y;
|
||||||
uint32_t* const argb = enc->pic_->argb;
|
const WebPPicture* const pic = enc->pic_;
|
||||||
|
const int width = pic->width;
|
||||||
|
const int height = pic->height;
|
||||||
uint32_t* const palette = enc->palette_;
|
uint32_t* const palette = enc->palette_;
|
||||||
const int palette_size = enc->palette_size_;
|
const int palette_size = enc->palette_size_;
|
||||||
|
|
||||||
// Replace each input pixel by corresponding palette index.
|
// Replace each input pixel by corresponding palette index.
|
||||||
for (i = 0; i < width * height; ++i) {
|
for (y = 0; y < height; ++y) {
|
||||||
int k;
|
uint32_t* const argb = pic->argb + y * pic->argb_stride;
|
||||||
for (k = 0; k < palette_size; ++k) {
|
for (x = 0; x < width; ++x) {
|
||||||
const uint32_t pix = argb[i];
|
const uint32_t pix = argb[x];
|
||||||
if (pix == palette[k]) {
|
for (i = 0; i < palette_size; ++i) {
|
||||||
argb[i] = 0xff000000u | (k << 8);
|
if (pix == palette[i]) {
|
||||||
break;
|
argb[x] = 0xff000000u | (i << 8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -847,7 +865,7 @@ static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
|
|||||||
}
|
}
|
||||||
err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
|
err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
|
||||||
if (err != VP8_ENC_OK) goto Error;
|
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:
|
Error:
|
||||||
@ -932,17 +950,21 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enc->use_palette_) {
|
if (enc->use_palette_) {
|
||||||
err = ApplyPalette(bw, enc, width, height, quality);
|
err = ApplyPalette(bw, enc, quality);
|
||||||
if (err != VP8_ENC_OK) goto Error;
|
if (err != VP8_ENC_OK) goto Error;
|
||||||
enc->cache_bits_ = 0;
|
enc->cache_bits_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case image is not packed.
|
// In case image is not packed.
|
||||||
if (enc->argb_ == NULL) {
|
if (enc->argb_ == NULL) {
|
||||||
const size_t image_size = height * width;
|
int y;
|
||||||
err = AllocateTransformBuffer(enc, width, height);
|
err = AllocateTransformBuffer(enc, width, height);
|
||||||
if (err != VP8_ENC_OK) goto Error;
|
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;
|
enc->current_width_ = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user