Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Unified Diff: third_party/libwebp/enc/syntax.c

Issue 10832153: libwebp: update snapshot to v0.2.0-rc1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/libwebp/enc/syntax.c
diff --git a/third_party/libwebp/enc/syntax.c b/third_party/libwebp/enc/syntax.c
index f119018135742930ff90e1a244bdcedd69ef3245..7c8c7b1a848123443938e8417cd884861d6454c8 100644
--- a/third_party/libwebp/enc/syntax.c
+++ b/third_party/libwebp/enc/syntax.c
@@ -1,4 +1,4 @@
-// Copyright 2011 Google Inc.
+// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
@@ -10,74 +10,190 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
-#include <math.h>
-#include "vp8enci.h"
+#include "../webp/format_constants.h"
+#include "./vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
-#define KSIGNATURE 0x9d012a
-#define KHEADER_SIZE 10
-#define KRIFF_SIZE 20
-#define KSIZE_OFFSET (KRIFF_SIZE - 8)
-
-#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)
+// Helper functions
-// Main keyframe header
-
-static void PutLE32(uint8_t* const data, uint32_t val) {
+// TODO(later): Move to webp/format_constants.h?
+static void PutLE24(uint8_t* const data, uint32_t val) {
data[0] = (val >> 0) & 0xff;
data[1] = (val >> 8) & 0xff;
data[2] = (val >> 16) & 0xff;
+}
+
+static void PutLE32(uint8_t* const data, uint32_t val) {
+ PutLE24(data, val);
data[3] = (val >> 24) & 0xff;
}
-static int PutHeader(int profile, size_t size0, size_t total_size,
- 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', ' '
+static int IsVP8XNeeded(const VP8Encoder* const enc) {
+ return !!enc->has_alpha_; // Currently the only case when VP8X is needed.
+ // This could change in the future.
+}
+
+static int PutPaddingByte(const WebPPicture* const pic) {
+
+ const uint8_t pad_byte[1] = { 0 };
+ return !!pic->writer(pad_byte, 1, pic);
+}
+
+//------------------------------------------------------------------------------
+// Writers for header's various pieces (in order of appearance)
+
+static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc,
+ size_t riff_size) {
+ const WebPPicture* const pic = enc->pic_;
+ uint8_t riff[RIFF_HEADER_SIZE] = {
+ 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P'
};
- uint32_t bits;
+ assert(riff_size == (uint32_t)riff_size);
+ PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
+ if (!pic->writer(riff, sizeof(riff), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
+ const WebPPicture* const pic = enc->pic_;
+ uint8_t vp8x[CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE] = {
+ 'V', 'P', '8', 'X'
+ };
+ uint32_t flags = 0;
+
+ assert(IsVP8XNeeded(enc));
+ assert(pic->width >= 1 && pic->height >= 1);
+ assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE);
- if (size0 >= MAX_PARTITION0_SIZE) { // partition #0 is too big to fit
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION0_OVERFLOW);
+ if (enc->has_alpha_) {
+ flags |= ALPHA_FLAG_BIT;
}
- if (total_size > 0xfffffffeU - KRIFF_SIZE) {
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG);
+ PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE);
+ PutLE32(vp8x + CHUNK_HEADER_SIZE, flags);
+ PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1);
+ PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1);
+ if(!pic->writer(vp8x, sizeof(vp8x), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+static WebPEncodingError PutAlphaChunk(const VP8Encoder* const enc) {
+ const WebPPicture* const pic = enc->pic_;
+ uint8_t alpha_chunk_hdr[CHUNK_HEADER_SIZE] = {
+ 'A', 'L', 'P', 'H'
+ };
+
+ assert(enc->has_alpha_);
+
+ // Alpha chunk header.
+ PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size_);
+ if (!pic->writer(alpha_chunk_hdr, sizeof(alpha_chunk_hdr), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+
+ // Alpha chunk data.
+ if (!pic->writer(enc->alpha_data_, enc->alpha_data_size_, pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+
+ // Padding.
+ if ((enc->alpha_data_size_ & 1) && !PutPaddingByte(pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+static WebPEncodingError PutVP8Header(const WebPPicture* const pic,
+ size_t vp8_size) {
+ uint8_t vp8_chunk_hdr[CHUNK_HEADER_SIZE] = {
+ 'V', 'P', '8', ' '
+ };
+ assert(vp8_size == (uint32_t)vp8_size);
+ PutLE32(vp8_chunk_hdr + TAG_SIZE, (uint32_t)vp8_size);
+ if (!pic->writer(vp8_chunk_hdr, sizeof(vp8_chunk_hdr), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
}
+ return VP8_ENC_OK;
+}
- 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);
+static WebPEncodingError PutVP8FrameHeader(const WebPPicture* const pic,
+ int profile, size_t size0) {
+ uint8_t vp8_frm_hdr[VP8_FRAME_HEADER_SIZE];
+ uint32_t bits;
+
+ if (size0 >= VP8_MAX_PARTITION0_SIZE) { // partition #0 is too big to fit
+ return VP8_ENC_ERROR_PARTITION0_OVERFLOW;
}
+ // Paragraph 9.1.
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;
+ vp8_frm_hdr[0] = (bits >> 0) & 0xff;
+ vp8_frm_hdr[1] = (bits >> 8) & 0xff;
+ vp8_frm_hdr[2] = (bits >> 16) & 0xff;
// signature
- buf[3] = (KSIGNATURE >> 16) & 0xff;
- buf[4] = (KSIGNATURE >> 8) & 0xff;
- buf[5] = (KSIGNATURE >> 0) & 0xff;
+ vp8_frm_hdr[3] = (VP8_SIGNATURE >> 16) & 0xff;
+ vp8_frm_hdr[4] = (VP8_SIGNATURE >> 8) & 0xff;
+ vp8_frm_hdr[5] = (VP8_SIGNATURE >> 0) & 0xff;
// dimensions
- buf[6] = pic->width & 0xff;
- buf[7] = pic->width >> 8;
- buf[8] = pic->height & 0xff;
- buf[9] = pic->height >> 8;
+ vp8_frm_hdr[6] = pic->width & 0xff;
+ vp8_frm_hdr[7] = pic->width >> 8;
+ vp8_frm_hdr[8] = pic->height & 0xff;
+ vp8_frm_hdr[9] = pic->height >> 8;
+
+ if (!pic->writer(vp8_frm_hdr, sizeof(vp8_frm_hdr), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+// WebP Headers.
+static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0,
+ size_t vp8_size, size_t riff_size) {
+ WebPPicture* const pic = enc->pic_;
+ WebPEncodingError err = VP8_ENC_OK;
+
+ // RIFF header.
+ err = PutRIFFHeader(enc, riff_size);
+ if (err != VP8_ENC_OK) goto Error;
+
+ // VP8X.
+ if (IsVP8XNeeded(enc)) {
+ err = PutVP8XHeader(enc);
+ if (err != VP8_ENC_OK) goto Error;
+ }
+
+ // Alpha.
+ if (enc->has_alpha_) {
+ err = PutAlphaChunk(enc);
+ if (err != VP8_ENC_OK) goto Error;
+ }
+
+ // VP8 header.
+ err = PutVP8Header(pic, vp8_size);
+ if (err != VP8_ENC_OK) goto Error;
- return pic->writer(buf, sizeof(buf), pic);
+ // VP8 frame header.
+ err = PutVP8FrameHeader(pic, enc->profile_, size0);
+ if (err != VP8_ENC_OK) goto Error;
+
+ // All OK.
+ return 1;
+
+ // Error.
+ Error:
+ return WebPEncodingSetError(pic, err);
}
// Segmentation header
@@ -148,7 +264,7 @@ static int EmitPartitionsSize(const VP8Encoder* const enc,
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) {
+ if (part_size >= VP8_MAX_PARTITION_SIZE) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW);
}
buf[3 * p + 0] = (part_size >> 0) & 0xff;
@@ -164,12 +280,6 @@ static int EmitPartitionsSize(const VP8Encoder* const enc,
#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_;
@@ -186,14 +296,6 @@ static int WriteExtensions(VP8Encoder* const enc) {
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)) {
@@ -211,7 +313,7 @@ static size_t GeneratePartition0(VP8Encoder* const enc) {
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_;
+ const int need_extensions = enc->use_layer_;
#endif
pos1 = VP8BitWriterPos(bw);
@@ -250,32 +352,61 @@ static size_t GeneratePartition0(VP8Encoder* const enc) {
return !bw->error_;
}
+void VP8EncFreeBitWriters(VP8Encoder* const enc) {
+ int p;
+ VP8BitWriterWipeOut(&enc->bw_);
+ for (p = 0; p < enc->num_parts_; ++p) {
+ VP8BitWriterWipeOut(enc->parts_ + p);
+ }
+}
+
int VP8EncWrite(VP8Encoder* const enc) {
WebPPicture* const pic = enc->pic_;
VP8BitWriter* const bw = &enc->bw_;
+ const int task_percent = 19;
+ const int percent_per_part = task_percent / enc->num_parts_;
+ const int final_percent = enc->percent_ + task_percent;
int ok = 0;
- size_t coded_size, pad;
+ size_t vp8_size, pad, riff_size;
int p;
// Partition #0 with header and partition sizes
ok = !!GeneratePartition0(enc);
- // Compute total size (for the RIFF header)
- coded_size = KHEADER_SIZE + VP8BitWriterSize(bw) + 3 * (enc->num_parts_ - 1);
+ // Compute VP8 size
+ vp8_size = VP8_FRAME_HEADER_SIZE +
+ VP8BitWriterSize(bw) +
+ 3 * (enc->num_parts_ - 1);
for (p = 0; p < enc->num_parts_; ++p) {
- coded_size += VP8BitWriterSize(enc->parts_ + p);
+ vp8_size += VP8BitWriterSize(enc->parts_ + p);
+ }
+ pad = vp8_size & 1;
+ vp8_size += pad;
+
+ // Compute RIFF size
+ // At the minimum it is: "WEBPVP8 nnnn" + VP8 data size.
+ riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8_size;
+ if (IsVP8XNeeded(enc)) { // Add size for: VP8X header + data.
+ riff_size += CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
+ }
+ if (enc->has_alpha_) { // Add size for: ALPH header + data.
+ const uint32_t padded_alpha_size = enc->alpha_data_size_ +
+ (enc->alpha_data_size_ & 1);
+ riff_size += CHUNK_HEADER_SIZE + padded_alpha_size;
+ }
+ // Sanity check.
+ if (riff_size > 0xfffffffeU) {
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG);
}
- pad = coded_size & 1;
- coded_size += pad;
// Emit headers and partition #0
{
const uint8_t* const part0 = VP8BitWriterBuf(bw);
const size_t size0 = VP8BitWriterSize(bw);
- ok = ok && PutHeader(enc->profile_, size0, coded_size, pic)
+ ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size)
&& pic->writer(part0, size0, pic)
&& EmitPartitionsSize(enc, pic);
- free((void*)part0);
+ VP8BitWriterWipeOut(bw); // will free the internal buffer.
}
// Token partitions
@@ -284,16 +415,18 @@ int VP8EncWrite(VP8Encoder* const enc) {
const size_t size = VP8BitWriterSize(enc->parts_ + p);
if (size)
ok = ok && pic->writer(buf, size, pic);
- free((void*)buf);
+ VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer.
+ ok = ok && WebPReportProgress(pic, enc->percent_ + percent_per_part,
+ &enc->percent_);
}
// Padding byte
if (ok && pad) {
- const uint8_t pad_byte[1] = { 0 };
- ok = pic->writer(pad_byte, 1, pic);
+ ok = PutPaddingByte(pic);
}
- enc->coded_size_ = (int)coded_size + KRIFF_SIZE;
+ enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size);
+ ok = ok && WebPReportProgress(pic, final_percent, &enc->percent_);
return ok;
}

Powered by Google App Engine
This is Rietveld 408576698