15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2012 Google Inc. All Rights Reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// that can be found in the COPYING file in the root of the source 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// tree. An additional intellectual property rights grant can be found 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// in the file PATENTS. All contributing project authors may 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// be found in the AUTHORS file in the root of the source tree. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// main entry for the lossless encoder. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Vikas Arora (vikaas.arora@gmail.com) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "./backward_references.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "./vp8enci.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "./vp8li.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../dsp/lossless.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../utils/bit_writer.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../utils/huffman_encode.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../utils/utils.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../webp/format_constants.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define MAX_COLORS_FOR_GRAPH 64 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Palette 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int CompareColors(const void* p1, const void* p2) { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t a = *(const uint32_t*)p1; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t b = *(const uint32_t*)p2; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) assert(a != b); 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return (a < b) ? -1 : 1; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE, 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// creates a palette and returns true, else returns false. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int AnalyzeAndCreatePalette(const WebPPicture* const pic, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t palette[MAX_PALETTE_SIZE], 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* const palette_size) { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i, x, y, key; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_colors = 0; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 }; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t colors[MAX_PALETTE_SIZE * 4]; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint32_t kHashMul = 0x1e35a7bd; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t* argb = pic->argb; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int width = pic->width; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int height = pic->height; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0] 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (y = 0; y < height; ++y) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (x = 0; x < width; ++x) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (argb[x] == last_pix) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_pix = argb[x]; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (1) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!in_use[key]) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) colors[key] = last_pix; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_use[key] = 1; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_colors; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_colors > MAX_PALETTE_SIZE) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (colors[key] == last_pix) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The color is already there. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some other color sits there. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do linear conflict resolution. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++key; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) argb += pic->argb_stride; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // TODO(skal): could we reuse in_use[] to speed up EncodePalette()? 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_colors = 0; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_use[i]) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) palette[num_colors] = colors[i]; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_colors; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qsort(palette, num_colors, sizeof(*palette), CompareColors); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *palette_size = num_colors; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static int AnalyzeEntropy(const uint32_t* argb, 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int width, int height, int argb_stride, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double* const nonpredicted_bits, 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double* const predicted_bits) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x, y; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t* last_line = NULL; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LHistogramSet* const histo_set = VP8LAllocateHistogramSet(2, 0); 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (histo_set == NULL) return 0; 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (y = 0; y < height; ++y) { 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (x = 0; x < width; ++x) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t pix = argb[x]; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t pix_diff = VP8LSubPixels(pix, last_pix); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pix_diff == 0) continue; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_line != NULL && pix == last_line[x]) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_pix = pix; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff); 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LHistogramAddSinglePixOrCopy(histo_set->histograms[0], &pix_token); 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LHistogramAddSinglePixOrCopy(histo_set->histograms[1], 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &pix_diff_token); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_line = argb; 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) argb += argb_stride; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(histo_set->histograms[0]); 1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *predicted_bits = VP8LHistogramEstimateBitsBulk(histo_set->histograms[1]); 1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LFreeHistogramSet(histo_set); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static int AnalyzeAndInit(VP8LEncoder* const enc, WebPImageHint image_hint) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebPPicture* const pic = enc->pic_; 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int width = pic->width; 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int height = pic->height; 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int pix_cnt = width * height; 1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // we round the block size up, so we're guaranteed to have 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // at max MAX_REFS_BLOCK_PER_IMAGE blocks used: 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(pic != NULL && pic->argb != NULL); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enc->use_palette_ = 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (image_hint == WEBP_HINT_GRAPH) { 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (enc->use_palette_ && enc->palette_size_ < MAX_COLORS_FOR_GRAPH) { 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enc->use_palette_ = 0; 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enc->use_palette_) { 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (image_hint == WEBP_HINT_PHOTO) { 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enc->use_predict_ = 1; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enc->use_cross_color_ = 1; 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double non_pred_entropy, pred_entropy; 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &non_pred_entropy, &pred_entropy)) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pred_entropy < 0.95 * non_pred_entropy) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->use_predict_ = 1; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->use_cross_color_ = 1; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0; 1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // palette-friendly input typically uses less literals 1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // -> reduce block size a bit 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (enc->use_palette_) refs_block_size /= 2; 1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefsInit(&enc->refs_[0], refs_block_size); 1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefsInit(&enc->refs_[1], refs_block_size); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Returns false in case of memory error. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int GetHuffBitLengthsAndCodes( 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const VP8LHistogramSet* const histogram_image, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode* const huffman_codes) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i, k; 1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int ok = 0; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64_t total_length_size = 0; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t* mem_buf = NULL; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int histogram_image_size = histogram_image->size; 1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int max_num_symbols = 0; 1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) uint8_t* buf_rle = NULL; 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTree* huff_tree = NULL; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over all histograms and get the aggregate number of codes used. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < histogram_image_size; ++i) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const VP8LHistogram* const histo = histogram_image->histograms[i]; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode* const codes = &huffman_codes[5 * i]; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (k = 0; k < 5; ++k) { 2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int num_symbols = 2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) : 2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (k == 4) ? NUM_DISTANCE_CODES : 256; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes[k].num_symbols = num_symbols; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_length_size += num_symbols; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allocate and Set Huffman codes. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t* codes; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t* lengths; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size, 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(*lengths) + sizeof(*codes)); 2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (mem_buf == NULL) goto End; 2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes = (uint16_t*)mem_buf; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lengths = (uint8_t*)&codes[total_length_size]; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < 5 * histogram_image_size; ++i) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int bit_length = huffman_codes[i].num_symbols; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) huffman_codes[i].codes = codes; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) huffman_codes[i].code_lengths = lengths; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes += bit_length; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lengths += bit_length; 2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (max_num_symbols < bit_length) { 2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) max_num_symbols = bit_length; 2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buf_rle = (uint8_t*)WebPSafeMalloc(1ULL, max_num_symbols); 2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * max_num_symbols, 2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sizeof(*huff_tree)); 2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (buf_rle == NULL || huff_tree == NULL) goto End; 2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create Huffman trees. 2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (i = 0; i < histogram_image_size; ++i) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode* const codes = &huffman_codes[5 * i]; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LHistogram* const histo = histogram_image->histograms[i]; 2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LCreateHuffmanTree(histo->literal_, 15, buf_rle, huff_tree, codes + 0); 2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LCreateHuffmanTree(histo->red_, 15, buf_rle, huff_tree, codes + 1); 2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LCreateHuffmanTree(histo->blue_, 15, buf_rle, huff_tree, codes + 2); 2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LCreateHuffmanTree(histo->alpha_, 15, buf_rle, huff_tree, codes + 3); 2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LCreateHuffmanTree(histo->distance_, 15, buf_rle, huff_tree, codes + 4); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ok = 1; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) End: 2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(huff_tree); 2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(buf_rle); 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!ok) { 2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(mem_buf); 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes)); 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ok; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void StoreHuffmanTreeOfHuffmanTreeToBitMask( 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RFC 1951 will calm you down if you are worried about this funny sequence. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This sequence is tuned from that, but more weighted for lower symbol count, 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and more spiking histograms. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Throw away trailing zeros: 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int codes_to_store = CODE_LENGTH_CODES; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; codes_to_store > 4; --codes_to_store) { 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 4, codes_to_store - 4); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < codes_to_store; ++i) { 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 3, code_length_bitdepth[kStorageOrder[i]]); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ClearHuffmanTreeIfOnlyOneSymbol( 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode* const huffman_code) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int k; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = 0; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (k = 0; k < huffman_code->num_symbols; ++k) { 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (huffman_code->code_lengths[k] != 0) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++count; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count > 1) return; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (k = 0; k < huffman_code->num_symbols; ++k) { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) huffman_code->code_lengths[k] = 0; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) huffman_code->codes[k] = 0; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void StoreHuffmanTreeToBitMask( 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBitWriter* const bw, 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HuffmanTreeToken* const tokens, const int num_tokens, 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HuffmanTreeCode* const huffman_code) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < num_tokens; ++i) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int ix = tokens[i].code; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int extra_bits = tokens[i].extra_bits; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, huffman_code->code_lengths[ix], huffman_code->codes[ix]); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ix) { 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 16: 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 2, extra_bits); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 17: 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 3, extra_bits); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 18: 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 7, extra_bits); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// 'huff_tree' and 'tokens' are pre-alloacted buffers. 3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static void StoreFullHuffmanCode(VP8LBitWriter* const bw, 3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTree* const huff_tree, 3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTreeToken* const tokens, 3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const HuffmanTreeCode* const tree) { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 }; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 }; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int max_tokens = tree->num_symbols; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_tokens; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode huffman_code; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) huffman_code.num_symbols = CODE_LENGTH_CODES; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) huffman_code.code_lengths = code_length_bitdepth; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) huffman_code.codes = code_length_bitdepth_symbols; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, 0); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) uint32_t histogram[CODE_LENGTH_CODES] = { 0 }; 3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 }; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < num_tokens; ++i) { 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++histogram[tokens[i].code]; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int trailing_zero_bits = 0; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int trimmed_length = num_tokens; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int write_trimmed_length; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int length; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i = num_tokens; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (i-- > 0) { 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int ix = tokens[i].code; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ix == 0 || ix == 17 || ix == 18) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --trimmed_length; // discount trailing zeros 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trailing_zero_bits += code_length_bitdepth[ix]; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ix == 17) { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trailing_zero_bits += 3; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (ix == 18) { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trailing_zero_bits += 7; 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = write_trimmed_length ? trimmed_length : num_tokens; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, write_trimmed_length); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_trimmed_length) { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 3, nbitpairs - 1); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(trimmed_length >= 2); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// 'huff_tree' and 'tokens' are pre-alloacted buffers. 3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static void StoreHuffmanCode(VP8LBitWriter* const bw, 3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTree* const huff_tree, 3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTreeToken* const tokens, 3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const HuffmanTreeCode* const huffman_code) { 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = 0; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int symbols[2] = { 0, 0 }; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kMaxBits = 8; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kMaxSymbol = 1 << kMaxBits; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check whether it's a small tree. 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) { 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (huffman_code->code_lengths[i] != 0) { 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count < 2) symbols[count] = i; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++count; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count == 0) { // emit minimal tree for empty cases 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 4, 0x01); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols. 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, count - 1); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (symbols[0] <= 1) { 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, 0); // Code bit for small (1 bit) symbol value. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, symbols[0]); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, 1); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 8, symbols[0]); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count == 2) { 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 8, symbols[1]); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void WriteHuffmanCode(VP8LBitWriter* const bw, 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const HuffmanTreeCode* const code, 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int code_index) { 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int depth = code->code_lengths[code_index]; 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int symbol = code->codes[code_index]; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, depth, symbol); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static WebPEncodingError StoreImageToBitMask( 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBitWriter* const bw, int width, int histo_bits, 4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefs* const refs, 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint16_t* histogram_symbols, 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HuffmanTreeCode* const huffman_codes) { 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // x and y trace the position in the image. 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = 0; 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = 0; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1; 4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LRefsCursor c = VP8LRefsCursorInit(refs); 4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while (VP8LRefsCursorOk(&c)) { 4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const PixOrCopy* const v = c.cur_pos; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int histogram_ix = histogram_symbols[histo_bits ? 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (y >> histo_bits) * histo_xsize + 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (x >> histo_bits) : 0]; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HuffmanTreeCode* const codes = huffman_codes + 5 * histogram_ix; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (PixOrCopyIsCacheIdx(v)) { 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int code = PixOrCopyCacheIdx(v); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int literal_ix = 256 + NUM_LENGTH_CODES + code; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteHuffmanCode(bw, codes, literal_ix); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (PixOrCopyIsLiteral(v)) { 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int order[] = { 1, 2, 0, 3 }; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int k; 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (k = 0; k < 4; ++k) { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int code = PixOrCopyLiteral(v, order[k]); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteHuffmanCode(bw, codes + k, code); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bits, n_bits; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int code, distance; 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VP8LPrefixEncode(v->len, &code, &n_bits, &bits); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteHuffmanCode(bw, codes, 256 + code); 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, n_bits, bits); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) distance = PixOrCopyDistance(v); 4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VP8LPrefixEncode(distance, &code, &n_bits, &bits); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteHuffmanCode(bw, codes + 4, code); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, n_bits, bits); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x += PixOrCopyLength(v); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (x >= width) { 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x -= width; 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++y; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LRefsCursorNext(&c); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK; 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31 4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, 4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const uint32_t* const argb, 4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LHashChain* const hash_chain, 4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefs refs_array[2], 4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int width, int height, 4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int quality) { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int max_tokens = 0; 4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPEncodingError err = VP8_ENC_OK; 4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefs* refs; 4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTreeToken* tokens = NULL; 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } }; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0); 4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( 4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); 4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (histogram_image == NULL || huff_tree == NULL) { 4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) goto Error; 5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate backward references from ARGB image. 5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, 1, 5045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hash_chain, refs_array); 5055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (refs == NULL) { 5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Build histogram image and symbols from backward references. 5105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create Huffman bit lengths and codes for each histogram image. 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(histogram_image->size == 1); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { 5155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No color cache, no Huffman image. 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, 0); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Find maximum number of symbols for the huffman tree-set. 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < 5; ++i) { 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode* const codes = &huffman_codes[i]; 5255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (max_tokens < codes->num_symbols) { 5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) max_tokens = codes->num_symbols; 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens)); 5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (tokens == NULL) { 5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) goto Error; 5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Store Huffman codes. 5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (i = 0; i < 5; ++i) { 5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTreeCode* const codes = &huffman_codes[i]; 5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) StoreHuffmanCode(bw, huff_tree, tokens, codes); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClearHuffmanTreeIfOnlyOneSymbol(codes); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Store actual literals. 5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, 5455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) huffman_codes); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error: 5485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(tokens); 5495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(huff_tree); 5505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LFreeHistogramSet(histogram_image); 5515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(huffman_codes[0].codes); 5525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return err; 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw, 5565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const uint32_t* const argb, 5575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LHashChain* const hash_chain, 5585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefs refs_array[2], 5595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int width, int height, int quality, 5605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int cache_bits, 5615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int histogram_bits) { 5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPEncodingError err = VP8_ENC_OK; 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int use_2d_locality = 1; 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int use_color_cache = (cache_bits > 0); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t histogram_image_xysize = 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LSubSampleSize(width, histogram_bits) * 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LSubSampleSize(height, histogram_bits); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LHistogramSet* histogram_image = 5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int histogram_image_size = 0; 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t bit_array_size = 0; 5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTree* huff_tree = NULL; 5735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTreeToken* tokens = NULL; 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode* huffman_codes = NULL; 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBackwardRefs refs; 5765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefs* best_refs; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t* const histogram_symbols = 5785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (uint16_t*)WebPSafeMalloc(histogram_image_xysize, 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(*histogram_symbols)); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(histogram_bits >= MIN_HUFFMAN_BITS); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(histogram_bits <= MAX_HUFFMAN_BITS); 5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefsInit(&refs, refs_array[0].block_size_); 5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (histogram_image == NULL || histogram_symbols == NULL) { 5855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LFreeHistogramSet(histogram_image); 5865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(histogram_symbols); 5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 'best_refs' is the reference to the best backward refs and points to one 5915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // of refs_array[0] or refs_array[1]. 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate backward references from ARGB image. 5935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) best_refs = VP8LGetBackwardReferences(width, height, argb, quality, 5945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cache_bits, use_2d_locality, 5955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hash_chain, refs_array); 5965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) { 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Build histogram image and symbols from backward references. 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!VP8LGetHistoImageSymbols(width, height, &refs, 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quality, histogram_bits, cache_bits, 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histogram_image, 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histogram_symbols)) { 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create Huffman bit lengths and codes for each histogram image. 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histogram_image_size = histogram_image->size; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bit_array_size = 5 * histogram_image_size; 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size, 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(*huffman_codes)); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (huffman_codes == NULL || 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Free combined histograms. 6165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LFreeHistogramSet(histogram_image); 6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) histogram_image = NULL; 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Color Cache parameters. 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, use_color_cache); 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (use_color_cache) { 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 4, cache_bits); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Huffman image + meta huffman. 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int write_histogram_image = (histogram_image_size > 1); 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, write_histogram_image); 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_histogram_image) { 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t* const histogram_argb = 6315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (uint32_t*)WebPSafeMalloc(histogram_image_xysize, 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(*histogram_argb)); 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_index = 0; 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t i; 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (histogram_argb == NULL) goto Error; 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < histogram_image_xysize; ++i) { 6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int symbol_index = histogram_symbols[i] & 0xffff; 6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) histogram_argb[i] = 0xff000000 | (symbol_index << 8); 6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (symbol_index >= max_index) { 6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) max_index = symbol_index + 1; 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histogram_image_size = max_index; 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 3, histogram_bits - 2); 6465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array, 6475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LSubSampleSize(width, histogram_bits), 6485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LSubSampleSize(height, histogram_bits), 6495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) quality); 6505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(histogram_argb); 6515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Store Huffman codes. 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 6585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int max_tokens = 0; 6595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * CODE_LENGTH_CODES, 6605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sizeof(*huff_tree)); 6615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (huff_tree == NULL) goto Error; 6625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Find maximum number of symbols for the huffman tree-set. 6635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (i = 0; i < 5 * histogram_image_size; ++i) { 6645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HuffmanTreeCode* const codes = &huffman_codes[i]; 6655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (max_tokens < codes->num_symbols) { 6665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) max_tokens = codes->num_symbols; 6675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, 6705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sizeof(*tokens)); 6715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (tokens == NULL) goto Error; 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < 5 * histogram_image_size; ++i) { 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HuffmanTreeCode* const codes = &huffman_codes[i]; 6745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) StoreHuffmanCode(bw, huff_tree, tokens, codes); 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClearHuffmanTreeIfOnlyOneSymbol(codes); 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Store actual literals. 6805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = StoreImageToBitMask(bw, width, histogram_bits, &refs, 6815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) histogram_symbols, huffman_codes); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error: 6845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(tokens); 6855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(huff_tree); 6865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LFreeHistogramSet(histogram_image); 6875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefsClear(&refs); 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (huffman_codes != NULL) { 6895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(huffman_codes->codes); 6905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(huffman_codes); 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(histogram_symbols); 6935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return err; 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Transforms 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check if it would be a good idea to subtract green from red and blue. We 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// only impact entropy in red/blue components, don't bother to look at others. 7015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static WebPEncodingError EvalAndApplySubtractGreen(VP8LEncoder* const enc, 7025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int width, int height, 7035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBitWriter* const bw) { 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enc->use_palette_) { 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t* const argb = enc->argb_; 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double bit_cost_before, bit_cost_after; 7085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Allocate histogram with cache_bits = 1. 7095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LHistogram* const histo = VP8LAllocateHistogram(1); 7105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (histo == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < width * height; ++i) { 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t c = argb[i]; 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++histo->red_[(c >> 16) & 0xff]; 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++histo->blue_[(c >> 0) & 0xff]; 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bit_cost_before = VP8LHistogramEstimateBits(histo); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LHistogramInit(histo, 1); 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < width * height; ++i) { 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32_t c = argb[i]; 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int green = (c >> 8) & 0xff; 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++histo->red_[((c >> 16) - green) & 0xff]; 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++histo->blue_[((c >> 0) - green) & 0xff]; 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bit_cost_after = VP8LHistogramEstimateBits(histo); 7265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LFreeHistogram(histo); 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if subtracting green yields low entropy. 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->use_subtract_green_ = (bit_cost_after < bit_cost_before); 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->use_subtract_green_) { 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 2, SUBTRACT_GREEN); 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height); 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return VP8_ENC_OK; 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc, 7405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int width, int height, int quality, 7415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBitWriter* const bw) { 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int pred_bits = enc->transform_bits_; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int transform_width = VP8LSubSampleSize(width, pred_bits); 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int transform_height = VP8LSubSampleSize(height, pred_bits); 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->argb_scratch_, 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->transform_data_); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM); 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(pred_bits >= 2); 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 3, pred_bits - 2); 7525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return EncodeImageNoHuffman(bw, enc->transform_data_, 7535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (VP8LHashChain*)&enc->hash_chain_, 7545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (VP8LBackwardRefs*)enc->refs_, // cast const away 7555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) transform_width, transform_height, 7565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) quality); 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, 7605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int width, int height, 7615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int quality, 7625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBitWriter* const bw) { 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int ccolor_transform_bits = enc->transform_bits_; 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality, 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->argb_, enc->transform_data_); 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM); 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(ccolor_transform_bits >= 2); 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 3, ccolor_transform_bits - 2); 7735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return EncodeImageNoHuffman(bw, enc->transform_data_, 7745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (VP8LHashChain*)&enc->hash_chain_, 7755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (VP8LBackwardRefs*)enc->refs_, // cast const away 7765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) transform_width, transform_height, 7775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) quality); 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic, 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t riff_size, size_t vp8l_size) { 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size); 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!pic->writer(riff, sizeof(riff), pic)) { 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return VP8_ENC_ERROR_BAD_WRITE; 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return VP8_ENC_OK; 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int WriteImageSize(const WebPPicture* const pic, 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBitWriter* const bw) { 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int width = pic->width - 1; 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int height = pic->height - 1; 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION); 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, width); 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, height); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !bw->error_; 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) { 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, has_alpha); 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, VP8L_VERSION_BITS, VP8L_VERSION); 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !bw->error_; 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static WebPEncodingError WriteImage(const WebPPicture* const pic, 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBitWriter* const bw, 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t* const coded_size) { 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPEncodingError err = VP8_ENC_OK; 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint8_t* const webpll_data = VP8LBitWriterFinish(bw); 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t webpll_size = VP8LBitWriterNumBytes(bw); 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size; 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t pad = vp8l_size & 1; 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad; 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = WriteRiffHeader(pic, riff_size, vp8l_size); 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!pic->writer(webpll_data, webpll_size, pic)) { 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_BAD_WRITE; 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pad) { 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint8_t pad_byte[1] = { 0 }; 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!pic->writer(pad_byte, 1, pic)) { 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_BAD_WRITE; 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *coded_size = CHUNK_HEADER_SIZE + riff_size; 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return VP8_ENC_OK; 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error: 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return err; 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Allocates the memory for argb (W x H) buffer, 2 rows of context for 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// prediction and transform data. 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width, int height) { 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPEncodingError err = VP8_ENC_OK; 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int tile_size = 1 << enc->transform_bits_; 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint64_t image_size = width * height; 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint64_t argb_scratch_size = tile_size * width + width; 8555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int transform_data_size = 8565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LSubSampleSize(width, enc->transform_bits_) * 8575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LSubSampleSize(height, enc->transform_bits_); 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint64_t total_size = 8595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) image_size + argb_scratch_size + (uint64_t)transform_data_size; 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem)); 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mem == NULL) { 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->argb_ = mem; 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mem += image_size; 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->argb_scratch_ = mem; 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mem += argb_scratch_size; 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->transform_data_ = mem; 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->current_width_ = width; 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error: 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return err; 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 876eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void ApplyPalette(uint32_t* src, uint32_t* dst, 877eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t src_stride, uint32_t dst_stride, 878eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const uint32_t* palette, int palette_size, 879eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int width, int height, int xbits, uint8_t* row) { 880eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int i, x, y; 881eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int use_LUT = 1; 882eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (i = 0; i < palette_size; ++i) { 883eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if ((palette[i] & 0xffff00ffu) != 0) { 884eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch use_LUT = 0; 885eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 886eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 887eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 888eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 889eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (use_LUT) { 8905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint8_t inv_palette[MAX_PALETTE_SIZE] = { 0 }; 891eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (i = 0; i < palette_size; ++i) { 892eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int color = (palette[i] >> 8) & 0xff; 893eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch inv_palette[color] = i; 894eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 895eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (y = 0; y < height; ++y) { 896eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (x = 0; x < width; ++x) { 897eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int color = (src[x] >> 8) & 0xff; 898eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch row[x] = inv_palette[color]; 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 900eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch VP8LBundleColorMap(row, width, xbits, dst); 901eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch src += src_stride; 902eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch dst += dst_stride; 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 905eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Use 1 pixel cache for ARGB pixels. 906eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t last_pix = palette[0]; 907eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int last_idx = 0; 908eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (y = 0; y < height; ++y) { 909eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (x = 0; x < width; ++x) { 910eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const uint32_t pix = src[x]; 911eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pix != last_pix) { 912eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (i = 0; i < palette_size; ++i) { 913eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pix == palette[i]) { 914eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_idx = i; 915eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_pix = pix; 916eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 917eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 918eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 919eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 920eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch row[x] = last_idx; 921eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 922eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch VP8LBundleColorMap(row, width, xbits, dst); 923eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch src += src_stride; 924eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch dst += dst_stride; 925eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: Expects "enc->palette_" to be set properly. 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Also, "enc->palette_" will be modified after this call and should not be used 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// later. 932eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic WebPEncodingError EncodePalette(VP8LBitWriter* const bw, 933eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch VP8LEncoder* const enc, int quality) { 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPEncodingError err = VP8_ENC_OK; 935eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int i; 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebPPicture* const pic = enc->pic_; 9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint32_t* src = pic->argb; 9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint32_t* dst; 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int width = pic->width; 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int height = pic->height; 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t* const palette = enc->palette_; 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int palette_size = enc->palette_size_; 9432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint8_t* row = NULL; 9442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int xbits; 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Replace each input pixel by corresponding palette index. 9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This is done line by line. 9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (palette_size <= 4) { 9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) xbits = (palette_size <= 2) ? 3 : 2; 9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) xbits = (palette_size <= 16) ? 1 : 0; 9522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height); 9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dst = enc->argb_; 9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) row = (uint8_t*)WebPSafeMalloc(width, sizeof(*row)); 9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; 9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 961eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ApplyPalette(src, dst, pic->argb_stride, enc->current_width_, 962eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch palette, palette_size, width, height, xbits, row); 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save palette to bitstream. 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM); 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(palette_size >= 1); 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 8, palette_size - 1); 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = palette_size - 1; i >= 1; --i) { 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) palette[i] = VP8LSubPixels(palette[i], palette[i - 1]); 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = EncodeImageNoHuffman(bw, palette, &enc->hash_chain_, enc->refs_, 9735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) palette_size, 1, quality); 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error: 9765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(row); 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return err; 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 982eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int GetHistoBits(int method, int use_palette, int width, int height) { 9835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int hist_size = VP8LGetHistogramSize(MAX_COLOR_CACHE_BITS); 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make tile size a function of encoding method (Range: 0 to 6). 985eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int histo_bits = (use_palette ? 9 : 7) - method; 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (1) { 9875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int huff_image_size = VP8LSubSampleSize(width, histo_bits) * 9885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LSubSampleSize(height, histo_bits); 9895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if ((uint64_t)huff_image_size * hist_size <= MAX_HUFF_IMAGE_SIZE) break; 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++histo_bits; 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS : 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits; 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static int GetTransformBits(int method, int histo_bits) { 9975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5; 9985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits; 9995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 10005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 10015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static int GetCacheBits(float quality) { 10025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return (quality <= 25.f) ? 0 : 7; 10035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 10045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1005eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void FinishEncParams(VP8LEncoder* const enc) { 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebPConfig* const config = enc->config_; 1007eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const WebPPicture* const pic = enc->pic_; 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int method = config->method; 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const float quality = config->quality; 1010eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int use_palette = enc->use_palette_; 1011eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch enc->histo_bits_ = GetHistoBits(method, use_palette, pic->width, pic->height); 10125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_); 10135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) enc->cache_bits_ = GetCacheBits(quality); 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// VP8LEncoder 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebPPicture* const picture) { 10215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc)); 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc == NULL) { 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->config_ = config; 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->pic_ = picture; 10285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 10295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VP8LDspInit(); 10305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return enc; 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void VP8LEncoderDelete(VP8LEncoder* enc) { 10355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (enc != NULL) { 10365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LHashChainClear(&enc->hash_chain_); 10375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefsClear(&enc->refs_[0]); 10385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VP8LBackwardRefsClear(&enc->refs_[1]); 10395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(enc->argb_); 10405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(enc); 10415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Main call 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebPPicture* const picture, 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBitWriter* const bw) { 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPEncodingError err = VP8_ENC_OK; 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int quality = (int)config->quality; 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int width = picture->width; 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int height = picture->height; 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LEncoder* const enc = VP8LEncoderNew(config, picture); 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t byte_position = VP8LBitWriterNumBytes(bw); 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc == NULL) { 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // --------------------------------------------------------------------------- 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Analyze image (entropy, num_palettes etc) 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!AnalyzeAndInit(enc, config->image_hint)) { 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1070eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch FinishEncParams(enc); 1071eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->use_palette_) { 1073eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch err = EncodePalette(bw, enc, quality); 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 10752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Color cache is disabled for palette. 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->cache_bits_ = 0; 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In case image is not packed. 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->argb_ == NULL) { 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y; 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = AllocateTransformBuffer(enc, width, height); 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (y = 0; y < height; ++y) { 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(enc->argb_ + y * width, 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) picture->argb + y * picture->argb_stride, 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width * sizeof(*enc->argb_)); 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc->current_width_ = width; 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // --------------------------------------------------------------------------- 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Apply transforms and write transform data. 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw); 10965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->use_predict_) { 10995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = ApplyPredictFilter(enc, enc->current_width_, height, quality, bw); 11005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->use_cross_color_) { 11045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw); 11055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms. 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // --------------------------------------------------------------------------- 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Estimate the color cache size. 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->cache_bits_ > 0) { 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_, 11155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) height, quality, &enc->hash_chain_, 11165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &enc->refs_[0], &enc->cache_bits_)) { 11175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // --------------------------------------------------------------------------- 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Encode and write the transformed image. 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_, 11265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) enc->current_width_, height, quality, 11275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) enc->cache_bits_, enc->histo_bits_); 11285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (picture->stats != NULL) { 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPAuxStats* const stats = picture->stats; 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->lossless_features = 0; 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->use_predict_) stats->lossless_features |= 1; 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->use_cross_color_) stats->lossless_features |= 2; 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->use_subtract_green_) stats->lossless_features |= 4; 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enc->use_palette_) stats->lossless_features |= 8; 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->histogram_bits = enc->histo_bits_; 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->transform_bits = enc->transform_bits_; 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->cache_bits = enc->cache_bits_; 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->palette_size = enc->palette_size_; 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position); 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error: 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LEncoderDelete(enc); 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return err; 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int VP8LEncodeImage(const WebPConfig* const config, 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebPPicture* const picture) { 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width, height; 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int has_alpha; 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t coded_size; 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int percent = 0; 11555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int initial_size; 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPEncodingError err = VP8_ENC_OK; 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBitWriter bw; 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (picture == NULL) return 0; 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (config == NULL || picture->argb == NULL) { 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_NULL_PARAMETER; 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPEncodingSetError(picture, err); 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width = picture->width; 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) height = picture->height; 11695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Initialize BitWriter with size corresponding to 16 bpp to photo images and 11705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 8 bpp for graphical images. 11715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) initial_size = (config->image_hint == WEBP_HINT_GRAPH) ? 11725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) width * height : width * height * 2; 11735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!VP8LBitWriterInit(&bw, initial_size)) { 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WebPReportProgress(picture, 1, &percent)) { 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UserAbort: 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_USER_ABORT; 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset stats (for pure lossless coding) 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (picture->stats != NULL) { 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPAuxStats* const stats = picture->stats; 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(stats, 0, sizeof(*stats)); 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->PSNR[0] = 99.f; 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->PSNR[1] = 99.f; 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->PSNR[2] = 99.f; 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->PSNR[3] = 99.f; 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats->PSNR[4] = 99.f; 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write image size. 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WriteImageSize(picture, &bw)) { 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) has_alpha = WebPPictureHasTransparency(picture); 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write the non-trivial Alpha flag and lossless version. 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WriteRealAlphaAndVersion(&bw, has_alpha)) { 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto Error; 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort; 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Encode main image stream. 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = VP8LEncodeStream(config, picture, &bw); 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(skal): have a fine-grained progress report in VP8LEncodeStream(). 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort; 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Finish the RIFF chunk. 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = WriteImage(picture, &bw, &coded_size); 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != VP8_ENC_OK) goto Error; 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort; 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save size. 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (picture->stats != NULL) { 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) picture->stats->coded_size += (int)coded_size; 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) picture->stats->lossless_size = (int)coded_size; 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (picture->extra_info != NULL) { 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int mb_w = (width + 15) >> 4; 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int mb_h = (height + 15) >> 4; 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info)); 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error: 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VP8LBitWriterDestroy(&bw); 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != VP8_ENC_OK) { 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPEncodingSetError(picture, err); 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------ 1245