diff options
Diffstat (limited to 'drivers/webp/enc/vp8l.c')
-rw-r--r-- | drivers/webp/enc/vp8l.c | 224 |
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 |