summaryrefslogtreecommitdiff
path: root/drivers/webp/enc/vp8l.c
diff options
context:
space:
mode:
authorbwzuk <ben.potton@gmail.com>2014-02-11 12:53:33 +0000
committerbwzuk <ben.potton@gmail.com>2014-02-11 12:53:33 +0000
commitef80fffd197e2d03b7bddd3f8da1272452357c6c (patch)
tree58bf7a95a580b6705c92cc1d35418d9aa262dfb8 /drivers/webp/enc/vp8l.c
parent5a65a6cb2b9134fbdd6e39fe3106b7a90df0cb1b (diff)
parentabb985e755ccf858149294868eff8a9a9feca67e (diff)
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'drivers/webp/enc/vp8l.c')
-rw-r--r--drivers/webp/enc/vp8l.c224
1 files changed, 103 insertions, 121 deletions
diff --git a/drivers/webp/enc/vp8l.c b/drivers/webp/enc/vp8l.c
index 15726318e2..9c202f8d36 100644
--- a/drivers/webp/enc/vp8l.c
+++ b/drivers/webp/enc/vp8l.c
@@ -1,10 +1,8 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the COPYING file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// main entry for the lossless encoder.
@@ -25,6 +23,10 @@
#include "../utils/utils.h"
#include "../webp/format_constants.h"
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
#define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024)
#define MAX_COLORS_FOR_GRAPH 64
@@ -35,8 +37,7 @@
static int CompareColors(const void* p1, const void* p2) {
const uint32_t a = *(const uint32_t*)p1;
const uint32_t b = *(const uint32_t*)p2;
- assert(a != b);
- return (a < b) ? -1 : 1;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
}
// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
@@ -84,7 +85,7 @@ static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
argb += pic->argb_stride;
}
- // TODO(skal): could we reuse in_use[] to speed up EncodePalette()?
+ // TODO(skal): could we reuse in_use[] to speed up ApplyPalette()?
num_colors = 0;
for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
if (in_use[i]) {
@@ -164,6 +165,9 @@ static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) {
}
if (pred_entropy < 0.95 * non_pred_entropy) {
enc->use_predict_ = 1;
+ // TODO(vikasa): Observed some correlation of cross_color transform with
+ // predict. Need to investigate this further and add separate heuristic
+ // for setting use_cross_color flag.
enc->use_cross_color_ = 1;
}
}
@@ -216,7 +220,7 @@ static int GetHuffBitLengthsAndCodes(
}
// Create Huffman trees.
- for (i = 0; ok && (i < histogram_image_size); ++i) {
+ for (i = 0; i < histogram_image_size; ++i) {
HuffmanTreeCode* const codes = &huffman_codes[5 * i];
VP8LHistogram* const histo = histogram_image->histograms[i];
ok = ok && VP8LCreateHuffmanTree(histo->literal_, 15, codes + 0);
@@ -227,11 +231,7 @@ static int GetHuffBitLengthsAndCodes(
}
End:
- if (!ok) {
- free(mem_buf);
- // If one VP8LCreateHuffmanTree() above fails, we need to clean up behind.
- memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
- }
+ if (!ok) free(mem_buf);
return ok;
}
@@ -406,10 +406,9 @@ static int StoreHuffmanCode(VP8LBitWriter* const bw,
}
static void WriteHuffmanCode(VP8LBitWriter* const bw,
- const HuffmanTreeCode* const code,
- int code_index) {
- const int depth = code->code_lengths[code_index];
- const int symbol = code->codes[code_index];
+ const HuffmanTreeCode* const code, int index) {
+ const int depth = code->code_lengths[index];
+ const int symbol = code->codes[index];
VP8LWriteBits(bw, depth, symbol);
}
@@ -444,12 +443,12 @@ static void StoreImageToBitMask(
int bits, n_bits;
int code, distance;
- VP8LPrefixEncode(v->len, &code, &n_bits, &bits);
+ PrefixEncode(v->len, &code, &n_bits, &bits);
WriteHuffmanCode(bw, codes, 256 + code);
VP8LWriteBits(bw, n_bits, bits);
distance = PixOrCopyDistance(v);
- VP8LPrefixEncode(distance, &code, &n_bits, &bits);
+ PrefixEncode(distance, &code, &n_bits, &bits);
WriteHuffmanCode(bw, codes + 4, code);
VP8LWriteBits(bw, n_bits, bits);
}
@@ -530,12 +529,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
sizeof(*histogram_symbols));
assert(histogram_bits >= MIN_HUFFMAN_BITS);
assert(histogram_bits <= MAX_HUFFMAN_BITS);
-
- if (histogram_image == NULL || histogram_symbols == NULL) {
- free(histogram_image);
- free(histogram_symbols);
- return 0;
- }
+ if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
// Calculate backward references from ARGB image.
if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits,
@@ -558,9 +552,6 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
goto Error;
}
- // Free combined histograms.
- free(histogram_image);
- histogram_image = NULL;
// Color Cache parameters.
VP8LWriteBits(bw, 1, use_color_cache);
@@ -580,10 +571,10 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
uint32_t i;
if (histogram_argb == NULL) goto Error;
for (i = 0; i < histogram_image_xysize; ++i) {
- const int symbol_index = histogram_symbols[i] & 0xffff;
- histogram_argb[i] = 0xff000000 | (symbol_index << 8);
- if (symbol_index >= max_index) {
- max_index = symbol_index + 1;
+ const int index = histogram_symbols[i] & 0xffff;
+ histogram_argb[i] = 0xff000000 | (index << 8);
+ if (index >= max_index) {
+ max_index = index + 1;
}
}
histogram_image_size = max_index;
@@ -607,6 +598,9 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
ClearHuffmanTreeIfOnlyOneSymbol(codes);
}
}
+ // Free combined histograms.
+ free(histogram_image);
+ histogram_image = NULL;
// Store actual literals.
StoreImageToBitMask(bw, width, histogram_bits, &refs,
@@ -614,7 +608,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
ok = 1;
Error:
- free(histogram_image);
+ if (!ok) free(histogram_image);
VP8LClearBackwardRefs(&refs);
if (huffman_codes != NULL) {
@@ -695,7 +689,7 @@ static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
const int ccolor_transform_bits = enc->transform_bits_;
const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
- const int step = (quality < 25) ? 32 : (quality > 50) ? 8 : 16;
+ const int step = (quality == 0) ? 32 : 8;
VP8LColorSpaceTransform(width, height, ccolor_transform_bits, step,
enc->argb_, enc->transform_data_);
@@ -712,6 +706,13 @@ static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
// -----------------------------------------------------------------------------
+static void PutLE32(uint8_t* const data, uint32_t val) {
+ data[0] = (val >> 0) & 0xff;
+ data[1] = (val >> 8) & 0xff;
+ data[2] = (val >> 16) & 0xff;
+ data[3] = (val >> 24) & 0xff;
+}
+
static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
size_t riff_size, size_t vp8l_size) {
uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
@@ -806,94 +807,61 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
return err;
}
-static void ApplyPalette(uint32_t* src, uint32_t* dst,
- uint32_t src_stride, uint32_t dst_stride,
- const uint32_t* palette, int palette_size,
- int width, int height, int xbits, uint8_t* row) {
- int i, x, y;
- int use_LUT = 1;
- for (i = 0; i < palette_size; ++i) {
- if ((palette[i] & 0xffff00ffu) != 0) {
- use_LUT = 0;
- break;
- }
- }
+// Bundles multiple (2, 4 or 8) pixels into a single pixel.
+// Returns the new xsize.
+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;
- if (use_LUT) {
- uint8_t inv_palette[MAX_PALETTE_SIZE] = { 0 };
- for (i = 0; i < palette_size; ++i) {
- const int color = (palette[i] >> 8) & 0xff;
- inv_palette[color] = i;
- }
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const int color = (src[x] >> 8) & 0xff;
- row[x] = inv_palette[color];
- }
- VP8LBundleColorMap(row, width, xbits, dst);
- src += src_stride;
- dst += dst_stride;
- }
- } else {
- // Use 1 pixel cache for ARGB pixels.
- uint32_t last_pix = palette[0];
- int last_idx = 0;
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const uint32_t pix = src[x];
- if (pix != last_pix) {
- for (i = 0; i < palette_size; ++i) {
- if (pix == palette[i]) {
- last_idx = i;
- last_pix = pix;
- break;
- }
- }
- }
- row[x] = last_idx;
+ 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;
+ if (xsub == 0) {
+ code = 0;
}
- VP8LBundleColorMap(row, width, xbits, dst);
- src += src_stride;
- dst += dst_stride;
+ // TODO(vikasa): simplify the bundling logic.
+ code |= (argb[x] & 0xff00) << (bit_depth * xsub);
+ bundled_argb[y * xs + (x >> xbits)] = 0xff000000 | code;
}
+ argb += pic->argb_stride;
}
}
// Note: Expects "enc->palette_" to be set properly.
// Also, "enc->palette_" will be modified after this call and should not be used
// later.
-static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
- VP8LEncoder* const enc, int quality) {
+static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
+ VP8LEncoder* const enc, int quality) {
WebPEncodingError err = VP8_ENC_OK;
- int i;
+ int i, x, y;
const WebPPicture* const pic = enc->pic_;
- uint32_t* src = pic->argb;
- uint32_t* dst;
+ uint32_t* argb = pic->argb;
const int width = pic->width;
const int height = pic->height;
uint32_t* const palette = enc->palette_;
const int palette_size = enc->palette_size_;
- uint8_t* row = NULL;
- int xbits;
// Replace each input pixel by corresponding palette index.
- // This is done line by line.
- if (palette_size <= 4) {
- xbits = (palette_size <= 2) ? 3 : 2;
- } else {
- xbits = (palette_size <= 16) ? 1 : 0;
+ for (y = 0; y < height; ++y) {
+ 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;
+ }
+ }
+ }
+ argb += pic->argb_stride;
}
- err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
- if (err != VP8_ENC_OK) goto Error;
- dst = enc->argb_;
-
- row = (uint8_t*)WebPSafeMalloc((uint64_t)width, sizeof(*row));
- if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
-
- ApplyPalette(src, dst, pic->argb_stride, enc->current_width_,
- palette, palette_size, width, height, xbits, row);
-
// Save palette to bitstream.
VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM);
@@ -907,21 +875,36 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
goto Error;
}
+ if (palette_size <= 16) {
+ // Image can be packed (multiple pixels per uint32_t).
+ int xbits = 1;
+ if (palette_size <= 2) {
+ xbits = 3;
+ } else if (palette_size <= 4) {
+ xbits = 2;
+ }
+ err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
+ if (err != VP8_ENC_OK) goto Error;
+ BundleColorMap(pic, xbits, enc->argb_, enc->current_width_);
+ }
+
Error:
- free(row);
return err;
}
// -----------------------------------------------------------------------------
-static int GetHistoBits(int method, int use_palette, int width, int height) {
- const uint64_t hist_size = sizeof(VP8LHistogram);
+static int GetHistoBits(const WebPConfig* const config,
+ const WebPPicture* const pic) {
+ const int width = pic->width;
+ const int height = pic->height;
+ const size_t hist_size = sizeof(VP8LHistogram);
// Make tile size a function of encoding method (Range: 0 to 6).
- int histo_bits = (use_palette ? 9 : 7) - method;
+ int histo_bits = 7 - config->method;
while (1) {
- const uint64_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
- VP8LSubSampleSize(height, histo_bits) *
- hist_size;
+ const size_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
+ VP8LSubSampleSize(height, histo_bits) *
+ hist_size;
if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
++histo_bits;
}
@@ -929,14 +912,13 @@ static int GetHistoBits(int method, int use_palette, int width, int height) {
(histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
}
-static void FinishEncParams(VP8LEncoder* const enc) {
+static void InitEncParams(VP8LEncoder* const enc) {
const WebPConfig* const config = enc->config_;
- const WebPPicture* const pic = enc->pic_;
+ const WebPPicture* const picture = enc->pic_;
const int method = config->method;
const float quality = config->quality;
- const int use_palette = enc->use_palette_;
enc->transform_bits_ = (method < 4) ? 5 : (method > 4) ? 3 : 4;
- enc->histo_bits_ = GetHistoBits(method, use_palette, pic->width, pic->height);
+ enc->histo_bits_ = GetHistoBits(config, picture);
enc->cache_bits_ = (quality <= 25.f) ? 0 : 7;
}
@@ -952,9 +934,6 @@ static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
}
enc->config_ = config;
enc->pic_ = picture;
-
- VP8LDspInit();
-
return enc;
}
@@ -981,6 +960,8 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
goto Error;
}
+ InitEncParams(enc);
+
// ---------------------------------------------------------------------------
// Analyze image (entropy, num_palettes etc)
@@ -989,10 +970,8 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
goto Error;
}
- FinishEncParams(enc);
-
if (enc->use_palette_) {
- err = EncodePalette(bw, enc, quality);
+ err = ApplyPalette(bw, enc, quality);
if (err != VP8_ENC_OK) goto Error;
// Color cache is disabled for palette.
enc->cache_bits_ = 0;
@@ -1166,3 +1145,6 @@ int VP8LEncodeImage(const WebPConfig* const config,
//------------------------------------------------------------------------------
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif