diff options
Diffstat (limited to 'third_party/libwebp/enc/syntax.c')
-rw-r--r-- | third_party/libwebp/enc/syntax.c | 103 |
1 files changed, 85 insertions, 18 deletions
diff --git a/third_party/libwebp/enc/syntax.c b/third_party/libwebp/enc/syntax.c index a788f3c..f119018 100644 --- a/third_party/libwebp/enc/syntax.c +++ b/third_party/libwebp/enc/syntax.c @@ -26,7 +26,7 @@ extern "C" { #define MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition #define MAX_PARTITION_SIZE (1 << 24) // max size for token partition -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ // Writers for header's various pieces (in order of appearance) // Main keyframe header @@ -39,26 +39,31 @@ static void PutLE32(uint8_t* const data, uint32_t val) { } static int PutHeader(int profile, size_t size0, size_t total_size, - const WebPPicture* const pic) { + WebPPicture* const pic) { uint8_t buf[KHEADER_SIZE]; uint8_t RIFF[KRIFF_SIZE] = { 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', 'V', 'P', '8', ' ' }; uint32_t bits; - if (size0 >= MAX_PARTITION0_SIZE) { - return 0; // partition #0 is too big to fit + if (size0 >= MAX_PARTITION0_SIZE) { // partition #0 is too big to fit + return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION0_OVERFLOW); } - PutLE32(RIFF + 4, total_size + KSIZE_OFFSET); - PutLE32(RIFF + 16, total_size); - if (!pic->writer(RIFF, sizeof(RIFF), pic)) - return 0; + if (total_size > 0xfffffffeU - KRIFF_SIZE) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG); + } + + PutLE32(RIFF + 4, (uint32_t)(total_size + KSIZE_OFFSET)); + PutLE32(RIFF + 16, (uint32_t)total_size); + if (!pic->writer(RIFF, sizeof(RIFF), pic)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); + } - bits = 0 // keyframe (1b) - | (profile << 1) // profile (3b) - | (1 << 4) // visible (1b) - | (size0 << 5); // partition length (19b) + bits = 0 // keyframe (1b) + | (profile << 1) // profile (3b) + | (1 << 4) // visible (1b) + | ((uint32_t)size0 << 5); // partition length (19b) buf[0] = bits & 0xff; buf[1] = (bits >> 8) & 0xff; buf[2] = (bits >> 16) & 0xff; @@ -138,13 +143,13 @@ static void PutQuant(VP8BitWriter* const bw, // Partition sizes static int EmitPartitionsSize(const VP8Encoder* const enc, - const WebPPicture* const pic) { + WebPPicture* const pic) { uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)]; int p; for (p = 0; p < enc->num_parts_ - 1; ++p) { const size_t part_size = VP8BitWriterSize(enc->parts_ + p); if (part_size >= MAX_PARTITION_SIZE) { - return 0; // partition is too big to fit + return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW); } buf[3 * p + 0] = (part_size >> 0) & 0xff; buf[3 * p + 1] = (part_size >> 8) & 0xff; @@ -153,16 +158,69 @@ static int EmitPartitionsSize(const VP8Encoder* const enc, return p ? pic->writer(buf, 3 * p, pic) : 1; } -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ + +#ifdef WEBP_EXPERIMENTAL_FEATURES + +#define KTRAILER_SIZE 8 + +static void PutLE24(uint8_t* buf, size_t value) { + buf[0] = (value >> 0) & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; +} + +static int WriteExtensions(VP8Encoder* const enc) { + uint8_t buffer[KTRAILER_SIZE]; + VP8BitWriter* const bw = &enc->bw_; + WebPPicture* const pic = enc->pic_; + + // Layer (bytes 0..3) + PutLE24(buffer + 0, enc->layer_data_size_); + buffer[3] = enc->pic_->colorspace & WEBP_CSP_UV_MASK; + if (enc->layer_data_size_ > 0) { + assert(enc->use_layer_); + // append layer data to last partition + if (!VP8BitWriterAppend(&enc->parts_[enc->num_parts_ - 1], + enc->layer_data_, enc->layer_data_size_)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY); + } + } + // Alpha (bytes 4..6) + PutLE24(buffer + 4, enc->alpha_data_size_); + if (enc->alpha_data_size_ > 0) { + assert(enc->has_alpha_); + if (!VP8BitWriterAppend(bw, enc->alpha_data_, enc->alpha_data_size_)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY); + } + } + + buffer[KTRAILER_SIZE - 1] = 0x01; // marker + if (!VP8BitWriterAppend(bw, buffer, KTRAILER_SIZE)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY); + } + return 1; +} + +#endif /* WEBP_EXPERIMENTAL_FEATURES */ + +//------------------------------------------------------------------------------ static size_t GeneratePartition0(VP8Encoder* const enc) { VP8BitWriter* const bw = &enc->bw_; const int mb_size = enc->mb_w_ * enc->mb_h_; uint64_t pos1, pos2, pos3; +#ifdef WEBP_EXPERIMENTAL_FEATURES + const int need_extensions = enc->has_alpha_ || enc->use_layer_; +#endif pos1 = VP8BitWriterPos(bw); VP8BitWriterInit(bw, mb_size * 7 / 8); // ~7 bits per macroblock +#ifdef WEBP_EXPERIMENTAL_FEATURES + VP8PutBitUniform(bw, need_extensions); // extensions +#else VP8PutBitUniform(bw, 0); // colorspace +#endif VP8PutBitUniform(bw, 0); // clamp type PutSegmentHeader(bw, enc); @@ -174,11 +232,20 @@ static size_t GeneratePartition0(VP8Encoder* const enc) { pos2 = VP8BitWriterPos(bw); VP8CodeIntraModes(enc); VP8BitWriterFinish(bw); + +#ifdef WEBP_EXPERIMENTAL_FEATURES + if (need_extensions && !WriteExtensions(enc)) { + return 0; + } +#endif + pos3 = VP8BitWriterPos(bw); if (enc->pic_->stats) { enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3); enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3); + enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_; + enc->pic_->stats->layer_data_size = (int)enc->layer_data_size_; } return !bw->error_; } @@ -191,7 +258,7 @@ int VP8EncWrite(VP8Encoder* const enc) { int p; // Partition #0 with header and partition sizes - ok = GeneratePartition0(enc); + ok = !!GeneratePartition0(enc); // Compute total size (for the RIFF header) coded_size = KHEADER_SIZE + VP8BitWriterSize(bw) + 3 * (enc->num_parts_ - 1); @@ -226,11 +293,11 @@ int VP8EncWrite(VP8Encoder* const enc) { ok = pic->writer(pad_byte, 1, pic); } - enc->coded_size_ = coded_size + KRIFF_SIZE; + enc->coded_size_ = (int)coded_size + KRIFF_SIZE; return ok; } -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ #if defined(__cplusplus) || defined(c_plusplus) } // extern "C" |