summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
authorfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-07 19:03:42 +0000
committerfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-07 19:03:42 +0000
commitfd1e1a386c679717a6d0d25952dc38360fac3189 (patch)
treeecda19e7f453564eb3e34078bed74ee4ac2614f9 /third_party
parent0a27eaa85f863e30817ca438132acb4000fec4bd (diff)
downloadchromium_src-fd1e1a386c679717a6d0d25952dc38360fac3189.zip
chromium_src-fd1e1a386c679717a6d0d25952dc38360fac3189.tar.gz
chromium_src-fd1e1a386c679717a6d0d25952dc38360fac3189.tar.bz2
Add libwebp library source and gyp file.
BUG=58225 TEST=library should build Review URL: http://codereview.chromium.org/3614010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61828 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
-rw-r--r--third_party/libwebp/LICENSE52
-rw-r--r--third_party/libwebp/README.chromium8
-rw-r--r--third_party/libwebp/bits.c78
-rw-r--r--third_party/libwebp/bits.h106
-rw-r--r--third_party/libwebp/dsp.c675
-rw-r--r--third_party/libwebp/frame.c407
-rw-r--r--third_party/libwebp/libwebp.gyp72
-rw-r--r--third_party/libwebp/quant.c107
-rw-r--r--third_party/libwebp/tree.c579
-rw-r--r--third_party/libwebp/vp8.c600
-rw-r--r--third_party/libwebp/vp8i.h318
-rw-r--r--third_party/libwebp/webp.c361
-rw-r--r--third_party/libwebp/webp/decode.h111
-rw-r--r--third_party/libwebp/webp/decode_vp8.h107
-rw-r--r--third_party/libwebp/yuv.c45
-rw-r--r--third_party/libwebp/yuv.h66
16 files changed, 3692 insertions, 0 deletions
diff --git a/third_party/libwebp/LICENSE b/third_party/libwebp/LICENSE
new file mode 100644
index 0000000..73395c9
--- /dev/null
+++ b/third_party/libwebp/LICENSE
@@ -0,0 +1,52 @@
+Copyright (c) 2010, Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of Google nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the WebM Project.
+
+Google hereby grants to you a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer, and otherwise run, modify and propagate the contents of this
+implementation of VP8, where such license applies only to those patent
+claims, both currently owned by Google and acquired in the future,
+licensable by Google that are necessarily infringed by this
+implementation of VP8. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of VP8 or any code incorporated within this
+implementation of VP8 constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of VP8
+shall terminate as of the date such litigation is filed.
diff --git a/third_party/libwebp/README.chromium b/third_party/libwebp/README.chromium
new file mode 100644
index 0000000..91cf9d2
--- /dev/null
+++ b/third_party/libwebp/README.chromium
@@ -0,0 +1,8 @@
+Name: libwebpdecode
+URL: http://code.google.com/speed/webp
+
+This contains a copy of libwebp-decode-0.1
+
+The project files do not include from the distribution:
+ examples/
+
diff --git a/third_party/libwebp/bits.c b/third_party/libwebp/bits.c
new file mode 100644
index 0000000..bdc89e0
--- /dev/null
+++ b/third_party/libwebp/bits.c
@@ -0,0 +1,78 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Boolean decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "bits.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------------
+// VP8BitReader
+
+int VP8Init(VP8BitReader* const br, const uint8_t* buf, uint32_t size) {
+ if (!br || !buf || size < 2) {
+ return 0;
+ }
+ br->buf_ = buf + 2;
+ br->buf_end_ = buf + size;
+ br->left_ = -8;
+ br->value_ = (buf[0] << 8) | buf[1];
+ br->range_ = 255 - 1;
+ return 1;
+}
+
+const uint8_t kVP8Log2Range[128] = {
+ 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0
+};
+
+// range = ((range + 1) << kVP8Log2Range[range]) - 1
+const uint8_t kVP8NewRange[128] = {
+ 127, 127, 191, 127, 159, 191, 223, 127, 143, 159, 175, 191, 207, 223, 239,
+ 127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239,
+ 247, 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179,
+ 183, 187, 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239,
+ 243, 247, 251, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149,
+ 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179,
+ 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209,
+ 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239,
+ 241, 243, 245, 247, 249, 251, 253, 127
+};
+
+//-----------------------------------------------------------------------------
+// Higher-level calls
+
+uint32_t VP8GetValue(VP8BitReader* const br, int bits) {
+ uint32_t v = 0;
+ while (bits-- > 0) {
+ v |= VP8GetBit(br, 0x80) << bits;
+ }
+ return v;
+}
+
+int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
+ const int value = (bits > 0) ? VP8GetValue(br, bits) : 0;
+ return VP8Get(br) ? -value : value;
+}
+
+//-----------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/third_party/libwebp/bits.h b/third_party/libwebp/bits.h
new file mode 100644
index 0000000..e8a24e1
--- /dev/null
+++ b/third_party/libwebp/bits.h
@@ -0,0 +1,106 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Boolean decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DECODE_BITS_H_
+#define WEBP_DECODE_BITS_H_
+
+#include <assert.h>
+#include "webp/decode_vp8.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------------
+// Bitreader and code-tree reader
+
+typedef struct {
+ const uint8_t* buf_; // next byte to be read
+ const uint8_t* buf_end_; // end of read buffer
+ int eof_; // true if input is exhausted
+
+ // boolean decoder
+ uint32_t range_; // current range minus 1. In [127, 254] interval.
+ uint32_t value_; // current value
+ int left_; // how many unused bits (negated)
+} VP8BitReader;
+
+// Initialize the bit reader and the boolean decoder. Return true if ok.
+int VP8Init(VP8BitReader* const br, const uint8_t* buf, uint32_t size);
+
+// return the next value made of 'num_bits' bits
+uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
+static inline uint32_t VP8Get(VP8BitReader* const br) {
+ return VP8GetValue(br, 1);
+}
+
+// return the next value with sign-extension.
+int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits);
+
+// Read a bit with proba 'prob'. Speed-critical function!
+extern const uint8_t kVP8Log2Range[128];
+extern const uint8_t kVP8NewRange[128];
+static inline uint32_t VP8GetByte(VP8BitReader* const br) {
+ assert(br);
+ if (br->buf_ < br->buf_end_) {
+ assert(br->buf_);
+ return *br->buf_++;
+ }
+ br->eof_ = 1;
+ return 0x80;
+}
+
+static inline void VP8Shift(VP8BitReader* const br) {
+ // range_ is in [0..127] interval here.
+ const int shift = kVP8Log2Range[br->range_];
+ br->range_ = kVP8NewRange[br->range_];
+ br->value_ <<= shift;
+ br->left_ += shift;
+ if (br->left_ > 0) {
+ br->value_ |= VP8GetByte(br) << br->left_;
+ br->left_ -= 8;
+ }
+}
+
+static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) {
+ const uint32_t split = (br->range_ * prob) >> 8;
+ const uint32_t bit = ((br->value_ >> 8) > split);
+ if (bit) {
+ br->range_ -= split + 1;
+ br->value_ -= (split + 1) << 8;
+ } else {
+ br->range_ = split;
+ }
+ if (br->range_ < 0x7f) {
+ VP8Shift(br);
+ }
+ return bit;
+}
+
+static inline int VP8GetSigned(VP8BitReader* const br, int v) {
+ const uint32_t split = br->range_ >> 1;
+ const uint32_t bit = ((br->value_ >> 8) > split);
+ if (bit) {
+ br->range_ -= split + 1;
+ br->value_ -= (split + 1) << 8;
+ v = -v;
+ } else {
+ br->range_ = split;
+ }
+ VP8Shift(br);
+ return v;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_DECODE_BITS_H_
diff --git a/third_party/libwebp/dsp.c b/third_party/libwebp/dsp.c
new file mode 100644
index 0000000..2730b78
--- /dev/null
+++ b/third_party/libwebp/dsp.c
@@ -0,0 +1,675 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// speed-critical functions.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "vp8i.h"
+
+#if defined(__SSE2__)
+#include <emmintrin.h>
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------------
+// run-time tables (~4k)
+
+static uint8_t abs0[255 + 255 + 1]; // abs(i)
+static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1
+static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127]
+static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15]
+static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
+
+static int tables_ok = 0;
+
+void VP8DspInitTables() {
+ if (!tables_ok) {
+ for (int i = -255; i <= 255; ++i) {
+ abs0[255 + i] = (i < 0) ? -i : i;
+ abs1[255 + i] = abs0[255 + i] >> 1;
+ }
+ for (int i = -1020; i <= 1020; ++i) {
+ sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
+ }
+ for (int i = -112; i <= 112; ++i) {
+ sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
+ }
+ for (int i = -255; i <= 255 + 255; ++i) {
+ clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
+ }
+ tables_ok = 1;
+ }
+}
+
+static inline uint8_t clip_8b(int v) {
+ assert(v >= -255 && v <= 255 + 255);
+ return clip1[255 + v];
+}
+
+//-----------------------------------------------------------------------------
+// Transforms (Paragraph 14.4)
+
+#define STORE(x, y, v) \
+ dst[x + y * BPS] = clip_8b(dst[x + y * BPS] + ((v) >> 3))
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+#define MUL(a, b) (((a) * (b)) >> 16)
+
+static void Transform(const int16_t* in, uint8_t* dst) {
+ int C[4 * 4], *tmp;
+ tmp = C;
+ for (int i = 0; i < 4; ++i) { // vertical pass
+ const int a = in[0] + in[8];
+ const int b = in[0] - in[8];
+ const int c = MUL(in[4], kC2) - MUL(in[12], kC1);
+ const int d = MUL(in[4], kC1) + MUL(in[12], kC2);
+ tmp[0] = a + d;
+ tmp[1] = b + c;
+ tmp[2] = b - c;
+ tmp[3] = a - d;
+ tmp += 4;
+ in++;
+ }
+
+ tmp = C;
+ for (int i = 0; i < 4; ++i) { // horizontal pass
+ const int dc = tmp[0] + 4;
+ const int a = dc + tmp[8];
+ const int b = dc - tmp[8];
+ const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1);
+ const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2);
+ STORE(0, 0, a + d);
+ STORE(1, 0, b + c);
+ STORE(2, 0, b - c);
+ STORE(3, 0, a - d);
+ tmp++;
+ dst += BPS;
+ }
+}
+#undef MUL
+
+static void TransformUV(const int16_t* in, uint8_t* dst) {
+ Transform(in + 0 * 16, dst);
+ Transform(in + 1 * 16, dst + 4);
+ Transform(in + 2 * 16, dst + 4 * BPS);
+ Transform(in + 3 * 16, dst + 4 * BPS + 4);
+}
+
+static void TransformDC(const int16_t *in, uint8_t* dst) {
+ const int DC = in[0] + 4;
+ for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; ++i) {
+ STORE(i, j, DC);
+ }
+ }
+}
+
+static void TransformDCUV(const int16_t* in, uint8_t* dst) {
+ if (in[0 * 16]) TransformDC(in + 0 * 16, dst);
+ if (in[1 * 16]) TransformDC(in + 1 * 16, dst + 4);
+ if (in[2 * 16]) TransformDC(in + 2 * 16, dst + 4 * BPS);
+ if (in[3 * 16]) TransformDC(in + 3 * 16, dst + 4 * BPS + 4);
+}
+
+#undef STORE
+
+// default C implementations:
+VP8Idct VP8Transform = Transform;
+VP8Idct VP8TransformUV = TransformUV;
+VP8Idct VP8TransformDC = TransformDC;
+VP8Idct VP8TransformDCUV = TransformDCUV;
+
+//-----------------------------------------------------------------------------
+// Paragraph 14.3
+
+static void TransformWHT(const int16_t* in, int16_t* out) {
+ int tmp[16];
+ for (int i = 0; i < 4; ++i) {
+ const int a0 = in[0 + i] + in[12 + i];
+ const int a1 = in[4 + i] + in[ 8 + i];
+ const int a2 = in[4 + i] - in[ 8 + i];
+ const int a3 = in[0 + i] - in[12 + i];
+ tmp[0 + i] = a0 + a1;
+ tmp[8 + i] = a0 - a1;
+ tmp[4 + i] = a3 + a2;
+ tmp[12 + i] = a3 - a2;
+ }
+ for (int i = 0; i < 4; ++i) {
+ const int dc = tmp[0 + i * 4] + 3; // w/ rounder
+ const int a0 = dc + tmp[3 + i * 4];
+ const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4];
+ const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4];
+ const int a3 = dc - tmp[3 + i * 4];
+ out[ 0] = (a0 + a1) >> 3;
+ out[16] = (a3 + a2) >> 3;
+ out[32] = (a0 - a1) >> 3;
+ out[48] = (a3 - a2) >> 3;
+ out += 64;
+ }
+}
+
+void (*VP8TransformWHT)(const int16_t* in, int16_t* out) = TransformWHT;
+
+//-----------------------------------------------------------------------------
+// Intra predictions
+
+#define OUT(x, y) dst[(x) + (y) * BPS]
+
+static inline void TrueMotion(uint8_t *dst, int size) {
+ const uint8_t* top = dst - BPS;
+ const int tl = top[-1];
+ for (int y = 0; y < size; ++y) {
+ const uint8_t* const clip = clip1 + 255 + dst[-1] - tl;
+ for (int x = 0; x < size; ++x) {
+ dst[x] = clip[top[x]];
+ }
+ dst += BPS;
+ }
+}
+static void TM4(uint8_t *dst) { TrueMotion(dst, 4); }
+static void TM8uv(uint8_t *dst) { TrueMotion(dst, 8); }
+static void TM16(uint8_t *dst) { TrueMotion(dst, 16); }
+
+//-----------------------------------------------------------------------------
+// 16x16
+
+static void V16(uint8_t *dst) { // vertical
+ for (int j = 0; j < 16; ++j) {
+ memcpy(dst + j * BPS, dst - BPS, 16);
+ }
+}
+
+static void H16(uint8_t *dst) { // horizontal
+ for (int j = 16; j > 0; --j) {
+ memset(dst, dst[-1], 16);
+ dst += BPS;
+ }
+}
+
+static inline void Put16(int v, uint8_t* dst) {
+ for (int j = 0; j < 16; ++j) {
+ memset(dst + j * BPS, v, 16);
+ }
+}
+
+static void DC16(uint8_t *dst) { // DC
+ int DC = 16;
+ for (int j = 0; j < 16; ++j) {
+ DC += dst[-1 + j * BPS] + dst[j - BPS];
+ }
+ Put16(DC >> 5, dst);
+}
+
+static void DC16NoTop(uint8_t *dst) { // DC with top samples not available
+ int DC = 8;
+ int j;
+ for (j = 0; j < 16; ++j) {
+ DC += dst[-1 + j * BPS];
+ }
+ Put16(DC >> 4, dst);
+}
+
+static void DC16NoLeft(uint8_t *dst) { // DC with left samples not available
+ int DC = 8;
+ int i;
+ for (i = 0; i < 16; ++i) {
+ DC += dst[i - BPS];
+ }
+ Put16(DC >> 4, dst);
+}
+
+static void DC16NoTopLeft(uint8_t *dst) { // DC with no top and left samples
+ Put16(0x80, dst);
+}
+
+//-----------------------------------------------------------------------------
+// 4x4
+
+static inline void Put4(uint32_t v, uint8_t* dst) {
+ for (int i = 4; i > 0; --i) {
+ *(uint32_t*)dst = v;
+ dst += BPS;
+ }
+}
+
+#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
+#define AVG2(a, b) (((a) + (b) + 1) >> 1)
+
+static void V4(uint8_t *dst) { // vertical
+ const uint8_t* top = dst - BPS;
+ const uint8_t vals[4] = {
+ AVG3(top[-1], top[0], top[1]),
+ AVG3(top[0], top[1], top[2]),
+ AVG3(top[1], top[2], top[3]),
+ AVG3(top[2], top[3], top[4])
+ };
+ const uint32_t v = *(uint32_t*)vals;
+ Put4(v, dst);
+}
+
+static void H4(uint8_t *dst) { // horizontal
+ const int A = dst[-1 - BPS];
+ const int B = dst[-1];
+ const int C = dst[-1 + BPS];
+ const int D = dst[-1 + 2 * BPS];
+ const int E = dst[-1 + 3 * BPS];
+ *(uint32_t*)(dst + 0 * BPS) = 0x01010101U * AVG3(A, B, C);
+ *(uint32_t*)(dst + 1 * BPS) = 0x01010101U * AVG3(B, C, D);
+ *(uint32_t*)(dst + 2 * BPS) = 0x01010101U * AVG3(C, D, E);
+ *(uint32_t*)(dst + 3 * BPS) = 0x01010101U * AVG3(D, E, E);
+}
+
+static void DC4(uint8_t *dst) { // DC
+ uint32_t dc = 4;
+ for (int i = 0; i < 4; ++i) {
+ dc += dst[i - BPS] + dst[-1 + i * BPS];
+ }
+ Put4((dc >> 3) * 0x01010101U, dst);
+}
+
+static void RD4(uint8_t *dst) { // Down-right
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int L = dst[-1 + 3 * BPS];
+ const int X = dst[-1 - BPS];
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+ const int D = dst[3 - BPS];
+ OUT(0, 3) = AVG3(J, K, L);
+ OUT(0, 2) = OUT(1, 3) = AVG3(I, J, K);
+ OUT(0, 1) = OUT(1, 2) = OUT(2, 3) = AVG3(X, I, J);
+ OUT(0, 0) = OUT(1, 1) = OUT(2, 2) = OUT(3, 3) = AVG3(A, X, I);
+ OUT(1, 0) = OUT(2, 1) = OUT(3, 2) = AVG3(B, A, X);
+ OUT(2, 0) = OUT(3, 1) = AVG3(C, B, A);
+ OUT(3, 0) = AVG3(D, C, B);
+}
+
+static void LD4(uint8_t *dst) { // Down-Left
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+ const int D = dst[3 - BPS];
+ const int E = dst[4 - BPS];
+ const int F = dst[5 - BPS];
+ const int G = dst[6 - BPS];
+ const int H = dst[7 - BPS];
+ OUT(0, 0) = AVG3(A, B, C);
+ OUT(1, 0) = OUT(0, 1) = AVG3(B, C, D);
+ OUT(2, 0) = OUT(1, 1) = OUT(0, 2) = AVG3(C, D, E);
+ OUT(3, 0) = OUT(2, 1) = OUT(1, 2) = OUT(0, 3) = AVG3(D, E, F);
+ OUT(3, 1) = OUT(2, 2) = OUT(1, 3) = AVG3(E, F, G);
+ OUT(3, 2) = OUT(2, 3) = AVG3(F, G, H);
+ OUT(3, 3) = AVG3(G, H, H);
+}
+
+static void VR4(uint8_t *dst) { // Vertical-Right
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int X = dst[-1 - BPS];
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+ const int D = dst[3 - BPS];
+ OUT(0, 0) = OUT(1, 2) = AVG2(X, A);
+ OUT(1, 0) = OUT(2, 2) = AVG2(A, B);
+ OUT(2, 0) = OUT(3, 2) = AVG2(B, C);
+ OUT(3, 0) = AVG2(C, D);
+
+ OUT(0, 3) = AVG3(K, J, I);
+ OUT(0, 2) = AVG3(J, I, X);
+ OUT(0, 1) = OUT(1, 3) = AVG3(I, X, A);
+ OUT(1, 1) = OUT(2, 3) = AVG3(X, A, B);
+ OUT(2, 1) = OUT(3, 3) = AVG3(A, B, C);
+ OUT(3, 1) = AVG3(B, C, D);
+}
+
+static void VL4(uint8_t *dst) { // Vertical-Left
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+ const int D = dst[3 - BPS];
+ const int E = dst[4 - BPS];
+ const int F = dst[5 - BPS];
+ const int G = dst[6 - BPS];
+ const int H = dst[7 - BPS];
+ OUT(0, 0) = AVG2(A, B);
+ OUT(1, 0) = OUT(0, 2) = AVG2(B, C);
+ OUT(2, 0) = OUT(1, 2) = AVG2(C, D);
+ OUT(3, 0) = OUT(2, 2) = AVG2(D, E);
+
+ OUT(0, 1) = AVG3(A, B, C);
+ OUT(1, 1) = OUT(0, 3) = AVG3(B, C, D);
+ OUT(2, 1) = OUT(1, 3) = AVG3(C, D, E);
+ OUT(3, 1) = OUT(2, 3) = AVG3(D, E, F);
+ OUT(3, 2) = AVG3(E, F, G);
+ OUT(3, 3) = AVG3(F, G, H);
+}
+
+static void HU4(uint8_t *dst) { // Horizontal-Up
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int L = dst[-1 + 3 * BPS];
+ OUT(0, 0) = AVG2(I, J);
+ OUT(2, 0) = OUT(0, 1) = AVG2(J, K);
+ OUT(2, 1) = OUT(0, 2) = AVG2(K, L);
+ OUT(1, 0) = AVG3(I, J, K);
+ OUT(3, 0) = OUT(1, 1) = AVG3(J, K, L);
+ OUT(3, 1) = OUT(1, 2) = AVG3(K, L, L);
+ OUT(3, 2) = OUT(2, 2) =
+ OUT(0, 3) = OUT(1, 3) = OUT(2, 3) = OUT(3, 3) = L;
+}
+
+static void HD4(uint8_t *dst) { // Horizontal-Down
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int L = dst[-1 + 3 * BPS];
+ const int X = dst[-1 - BPS];
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+
+ OUT(0, 0) = OUT(2, 1) = AVG2(I, X);
+ OUT(0, 1) = OUT(2, 2) = AVG2(J, I);
+ OUT(0, 2) = OUT(2, 3) = AVG2(K, J);
+ OUT(0, 3) = AVG2(L, K);
+
+ OUT(3, 0) = AVG3(A, B, C);
+ OUT(2, 0) = AVG3(X, A, B);
+ OUT(1, 0) = OUT(3, 1) = AVG3(I, X, A);
+ OUT(1, 1) = OUT(3, 2) = AVG3(J, I, X);
+ OUT(1, 2) = OUT(3, 3) = AVG3(K, J, I);
+ OUT(1, 3) = AVG3(L, K, J);
+}
+
+#undef AVG3
+#undef AVG2
+
+//-----------------------------------------------------------------------------
+// Chroma
+
+static void V8uv(uint8_t *dst) { // vertical
+ for (int j = 0; j < 8; ++j) {
+ memcpy(dst + j * BPS, dst - BPS, 8);
+ }
+}
+
+static void H8uv(uint8_t *dst) { // horizontal
+ for (int j = 0; j < 8; ++j) {
+ memset(dst, dst[-1], 8);
+ dst += BPS;
+ }
+}
+
+// helper for chroma-DC predictions
+static inline void Put8x8uv(uint64_t v, uint8_t* dst) {
+ for (int j = 0; j < 8; ++j) {
+ *(uint64_t*)(dst + j * BPS) = v;
+ }
+}
+
+static void DC8uv(uint8_t *dst) { // DC
+ int dc0 = 8;
+ for (int i = 0; i < 8; ++i) {
+ dc0 += dst[i - BPS] + dst[-1 + i * BPS];
+ }
+ const uint64_t t = (dc0 >> 4) * 0x0101010101010101ULL;
+ Put8x8uv(t, dst);
+}
+
+static void DC8uvNoLeft(uint8_t *dst) { // DC with no left samples
+ int dc0 = 4;
+ for (int i = 0; i < 8; ++i) {
+ dc0 += dst[i - BPS];
+ }
+ const uint64_t v = (dc0 >> 3) * 0x0101010101010101ULL;
+ Put8x8uv(v, dst);
+}
+
+static void DC8uvNoTop(uint8_t *dst) { // DC with no top samples
+ int dc0 = 4;
+ for (int i = 0; i < 8; ++i) {
+ dc0 += dst[-1 + i * BPS];
+ }
+ const uint64_t v = (dc0 >> 3) * 0x0101010101010101ULL;
+ Put8x8uv(v, dst);
+}
+
+static void DC8uvNoTopLeft(uint8_t *dst) { // DC with nothing
+ Put8x8uv(0x8080808080808080ULL, dst);
+}
+
+//-----------------------------------------------------------------------------
+// default C implementations
+
+VP8PredFunc VP8PredLuma4[11] = {
+ DC4, TM4, V4, H4, LD4, RD4, VR4, VL4, HD4, HU4
+};
+
+VP8PredFunc VP8PredLuma16[7] = {
+ DC16, TM16, V16, H16,
+ DC16NoTop, DC16NoLeft, DC16NoTopLeft
+};
+
+VP8PredFunc VP8PredChroma8[7] = {
+ DC8uv, TM8uv, V8uv, H8uv,
+ DC8uvNoTop, DC8uvNoLeft, DC8uvNoTopLeft
+};
+
+//-----------------------------------------------------------------------------
+// Edge filtering functions
+
+// 4 pixels in, 2 pixels out
+static inline void do_filter2(uint8_t* p, int step) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1];
+ const int a1 = sclip2[112 + ((a + 4) >> 3)];
+ const int a2 = sclip2[112 + ((a + 3) >> 3)];
+ p[-step] = clip1[255 + p0 + a2];
+ p[ 0] = clip1[255 + q0 - a1];
+}
+
+// 4 pixels in, 4 pixels out
+static inline void do_filter4(uint8_t* p, int step) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0);
+ const int a1 = sclip2[112 + ((a + 4) >> 3)];
+ const int a2 = sclip2[112 + ((a + 3) >> 3)];
+ const int a3 = (a1 + 1) >> 1;
+ p[-2*step] = clip1[255 + p1 + a3];
+ p[- step] = clip1[255 + p0 + a2];
+ p[ 0] = clip1[255 + q0 - a1];
+ p[ step] = clip1[255 + q1 - a3];
+}
+
+// 6 pixels in, 6 pixels out
+static inline void do_filter6(uint8_t* p, int step) {
+ const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2*step];
+ const int a = sclip1[1020 + 3 * (q0 - p0) + sclip1[1020 + p1 - q1]];
+ const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
+ const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
+ const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
+ p[-3*step] = clip1[255 + p2 + a3];
+ p[-2*step] = clip1[255 + p1 + a2];
+ p[- step] = clip1[255 + p0 + a1];
+ p[ 0] = clip1[255 + q0 - a1];
+ p[ step] = clip1[255 + q1 - a2];
+ p[ 2*step] = clip1[255 + q2 - a3];
+}
+
+static inline int hev(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh);
+}
+
+static inline int needs_filter(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh;
+}
+
+static inline int needs_filter2(const uint8_t* p, int step, int t, int it) {
+ const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step];
+ if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t)
+ return 0;
+ return abs0[255 + p3 - p2] <= it && abs0[255 + p2 - p1] <= it &&
+ abs0[255 + p1 - p0] <= it && abs0[255 + q3 - q2] <= it &&
+ abs0[255 + q2 - q1] <= it && abs0[255 + q1 - q0] <= it;
+}
+
+//-----------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+ for (int i = 0; i < 16; ++i) {
+ if (needs_filter(p + i, stride, thresh)) {
+ do_filter2(p + i, stride);
+ }
+ }
+}
+
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+ for (int i = 0; i < 16; ++i) {
+ if (needs_filter(p + i * stride, 1, thresh)) {
+ do_filter2(p + i * stride, 1);
+ }
+ }
+}
+
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+ for (int k = 3; k > 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+ for (int k = 3; k > 0; --k) {
+ p += 4;
+ SimpleHFilter16(p, stride, thresh);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Complex In-loop filtering (Paragraph 15.3)
+
+static inline void FilterLoop26(uint8_t* p, int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter6(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+static inline void FilterLoop24(uint8_t* p, int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter4(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+// on macroblock edges
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+}
+
+// on three inner edges
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ for (int k = 3; k > 0; --k) {
+ p += 4 * stride;
+ FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ for (int k = 3; k > 0; --k) {
+ p += 4;
+ FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+// 8-pixels wide variant, for chroma filtering
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+//-----------------------------------------------------------------------------
+
+void (*VP8VFilter16)(uint8_t*, int, int, int, int) = VFilter16;
+void (*VP8HFilter16)(uint8_t*, int, int, int, int) = HFilter16;
+void (*VP8VFilter8)(uint8_t*, uint8_t*, int, int, int, int) = VFilter8;
+void (*VP8HFilter8)(uint8_t*, uint8_t*, int, int, int, int) = HFilter8;
+void (*VP8VFilter16i)(uint8_t*, int, int, int, int) = VFilter16i;
+void (*VP8HFilter16i)(uint8_t*, int, int, int, int) = HFilter16i;
+void (*VP8VFilter8i)(uint8_t*, uint8_t*, int, int, int, int) = VFilter8i;
+void (*VP8HFilter8i)(uint8_t*, uint8_t*, int, int, int, int) = HFilter8i;
+
+void (*VP8SimpleVFilter16)(uint8_t*, int, int) = SimpleVFilter16;
+void (*VP8SimpleHFilter16)(uint8_t*, int, int) = SimpleHFilter16;
+void (*VP8SimpleVFilter16i)(uint8_t*, int, int) = SimpleVFilter16i;
+void (*VP8SimpleHFilter16i)(uint8_t*, int, int) = SimpleHFilter16i;
+
+//-----------------------------------------------------------------------------
+
+void VP8DspInit() {
+ // later we'll plug some SSE2 variant here
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/third_party/libwebp/frame.c b/third_party/libwebp/frame.c
new file mode 100644
index 0000000..ef8eab5
--- /dev/null
+++ b/third_party/libwebp/frame.c
@@ -0,0 +1,407 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Frame-reconstruction function. Memory allocation.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+#include "vp8i.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define ALIGN_MASK (32 - 1)
+
+//-----------------------------------------------------------------------------
+// Memory setup
+
+// how many extra luma lines are needed for caching, given a filtering level
+static const uint8_t kFilterExtraRows[3] = { 0, 4, 8 };
+
+int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
+ const int mb_w = dec->mb_w_;
+ const int intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t);
+ const int top_size = (16 + 8 + 8) * mb_w;
+ const int info_size = (mb_w + 1) * sizeof(VP8MB);
+ const int yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_);
+ const int coeffs_size = 384 * sizeof(*dec->coeffs_);
+ const int cache_height = (dec->filter_type_ == 0) ? 0 :
+ (16 + kFilterExtraRows[dec->filter_type_]) * 3 / 2;
+ const int cache_size = top_size * cache_height;
+ const int needed = intra_pred_mode_size
+ + top_size + info_size
+ + yuv_size + coeffs_size
+ + cache_size + ALIGN_MASK;
+ if (needed > dec->mem_size_) {
+ free(dec->mem_);
+ dec->mem_size_ = 0;
+ dec->mem_ = (uint8_t*)malloc(needed);
+ if (dec->mem_ == NULL) {
+ return VP8SetError(dec, 1, "no memory during frame initialization.");
+ }
+ dec->mem_size_ = needed;
+ }
+
+ uint8_t* mem = (uint8_t*)dec->mem_;
+ dec->intra_t_ = (uint8_t*)mem;
+ mem += intra_pred_mode_size;
+
+ dec->y_t_ = (uint8_t*)mem;
+ mem += 16 * mb_w;
+ dec->u_t_ = (uint8_t*)mem;
+ mem += 8 * mb_w;
+ dec->v_t_ = (uint8_t*)mem;
+ mem += 8 * mb_w;
+
+ dec->mb_info_ = ((VP8MB*)mem) + 1;
+ mem += info_size;
+
+ mem = (uint8_t*)((uint64_t)(mem + ALIGN_MASK) & ~ALIGN_MASK);
+ assert((yuv_size & ALIGN_MASK) == 0);
+ dec->yuv_b_ = (uint8_t*)mem;
+ mem += yuv_size;
+
+ dec->coeffs_ = (int16_t*)mem;
+ mem += coeffs_size;
+
+ dec->cache_y_stride_ = 16 * mb_w;
+ dec->cache_uv_stride_ = 8 * mb_w;
+ if (dec->filter_type_ == 0) {
+ dec->cache_y_ = NULL;
+ dec->cache_u_ = NULL;
+ dec->cache_v_ = NULL;
+ } else {
+ const int extra_rows = kFilterExtraRows[dec->filter_type_];
+ const int extra_y = extra_rows * dec->cache_y_stride_;
+ const int extra_uv =(extra_rows / 2) * dec->cache_uv_stride_;
+ dec->cache_y_ = ((uint8_t*)mem) + extra_y;
+ dec->cache_u_ = dec->cache_y_ + 16 * dec->cache_y_stride_ + extra_uv;
+ dec->cache_v_ = dec->cache_u_ + 8 * dec->cache_uv_stride_ + extra_uv;
+ }
+ mem += cache_size;
+
+ // note: left-info is initialized once for all.
+ memset(dec->mb_info_ - 1, 0, (mb_w + 1) * sizeof(*dec->mb_info_));
+
+ // initialize top
+ memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
+
+ // prepare 'io'
+ io->width = dec->pic_hdr_.width_;
+ io->height = dec->pic_hdr_.height_;
+ io->mb_x = 0;
+ io->mb_y = 0;
+ if (dec->filter_type_ == 0) {
+ io->y = dec->yuv_b_ + Y_OFF;
+ io->u = dec->yuv_b_ + U_OFF;
+ io->v = dec->yuv_b_ + V_OFF;
+ io->y_stride = BPS;
+ io->uv_stride = BPS;
+ } else {
+ io->y = dec->cache_y_;
+ io->u = dec->cache_u_;
+ io->v = dec->cache_v_;
+ io->y_stride = dec->cache_y_stride_;
+ io->uv_stride = dec->cache_uv_stride_;
+ io->mb_w = io->width;
+ }
+
+ // Init critical function pointers and look-up tables.
+ VP8DspInitTables();
+ VP8DspInit();
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Filtering
+
+static inline int hev_thresh_from_level(int level, int keyframe) {
+ if (keyframe) {
+ return (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
+ } else {
+ return (level >= 40) ? 3 : (level >= 20) ? 2 : (level >= 15) ? 1 : 0;
+ }
+}
+
+static void DoFilter(VP8Decoder* const dec, int mb_x, int mb_y) {
+ VP8MB* const mb = dec->mb_info_ + mb_x;
+ uint8_t* const y_dst = dec->cache_y_ + mb_x * 16;
+ const int y_bps = dec->cache_y_stride_;
+ const int level = mb->f_level_;
+ const int ilevel = mb->f_ilevel_;
+ const int limit = 2 * level + ilevel;
+ if (dec->filter_type_ == 1) { // simple
+ if (mb_x > 0) {
+ VP8SimpleHFilter16(y_dst, y_bps, limit + 4);
+ }
+ if (mb->f_inner_) {
+ VP8SimpleHFilter16i(y_dst, y_bps, limit);
+ }
+ if (mb_y > 0) {
+ VP8SimpleVFilter16(y_dst, y_bps, limit + 4);
+ }
+ if (mb->f_inner_) {
+ VP8SimpleVFilter16i(y_dst, y_bps, limit);
+ }
+ } else { // complex
+ uint8_t* const u_dst = dec->cache_u_ + mb_x * 8;
+ uint8_t* const v_dst = dec->cache_v_ + mb_x * 8;
+ const int uv_bps = dec->cache_uv_stride_;
+ const int hev_thresh =
+ hev_thresh_from_level(level, dec->frm_hdr_.key_frame_);
+ if (mb_x > 0) {
+ VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
+ VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
+ }
+ if (mb->f_inner_) {
+ VP8HFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh);
+ VP8HFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
+ }
+ if (mb_y > 0) {
+ VP8VFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
+ VP8VFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
+ }
+ if (mb->f_inner_) {
+ VP8VFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh);
+ VP8VFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
+ }
+ }
+}
+
+void VP8StoreBlock(VP8Decoder* const dec) {
+ VP8MB* const info = dec->mb_info_ + dec->mb_x_;
+ int level = dec->filter_levels_[dec->segment_];
+ if (dec->filter_hdr_.use_lf_delta_) {
+ // TODO(skal): only CURRENT is handled for now.
+ level += dec->filter_hdr_.ref_lf_delta_[0];
+ if (dec->is_i4x4_) {
+ level += dec->filter_hdr_.mode_lf_delta_[0];
+ }
+ }
+ level = (level < 0) ? 0 : (level > 63) ? 63 : level;
+ info->f_level_ = level;
+
+ if (dec->filter_hdr_.sharpness_ > 0) {
+ if (dec->filter_hdr_.sharpness_ > 4) {
+ level >>= 2;
+ } else {
+ level >>= 1;
+ }
+ if (level > 9 - dec->filter_hdr_.sharpness_) {
+ level = 9 - dec->filter_hdr_.sharpness_;
+ }
+ }
+ info->f_ilevel_ = (level < 1) ? 1 : level;
+ info->f_inner_ = (!info->skip_ || dec->is_i4x4_);
+
+ // Transfer samples to row cache
+ uint8_t* const ydst = dec->cache_y_ + dec->mb_x_ * 16;
+ uint8_t* const udst = dec->cache_u_ + dec->mb_x_ * 8;
+ uint8_t* const vdst = dec->cache_v_ + dec->mb_x_ * 8;
+ for (int y = 0; y < 16; ++y) {
+ memcpy(ydst + y * dec->cache_y_stride_,
+ dec->yuv_b_ + Y_OFF + y * BPS, 16);
+ }
+ for (int y = 0; y < 8; ++y) {
+ memcpy(udst + y * dec->cache_uv_stride_,
+ dec->yuv_b_ + U_OFF + y * BPS, 8);
+ memcpy(vdst + y * dec->cache_uv_stride_,
+ dec->yuv_b_ + V_OFF + y * BPS, 8);
+ }
+}
+
+void VP8FilterRow(VP8Decoder* const dec, VP8Io* io) {
+ for (int mb_x = 0; mb_x < dec->mb_w_; ++mb_x) {
+ DoFilter(dec, mb_x, dec->mb_y_);
+ }
+ const int extra_y_rows = kFilterExtraRows[dec->filter_type_];
+ const int ysize = extra_y_rows * dec->cache_y_stride_;
+ const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_;
+ uint8_t* const ydst = dec->cache_y_ - ysize;
+ uint8_t* const udst = dec->cache_u_ - uvsize;
+ uint8_t* const vdst = dec->cache_v_ - uvsize;
+ if (io->put) {
+ int y_end;
+ if (dec->mb_y_ > 0) {
+ io->mb_y = dec->mb_y_ * 16 - extra_y_rows;
+ io->y = ydst;
+ io->u = udst;
+ io->v = vdst;
+ if (dec->mb_y_ < dec->mb_h_ - 1) {
+ y_end = io->mb_y + 16;
+ } else {
+ y_end = io->height; // last macroblock row.
+ }
+ } else { // first macroblock row.
+ io->mb_y = 0;
+ y_end = 16 - extra_y_rows;
+ io->y = dec->cache_y_;
+ io->u = dec->cache_u_;
+ io->v = dec->cache_v_;
+ }
+ if (y_end > io->height) {
+ y_end = io->height;
+ }
+ io->mb_h = y_end - io->mb_y;
+ io->put(io);
+ }
+ // rotate top samples
+ if (dec->mb_y_ < dec->mb_h_ - 1) {
+ memcpy(ydst, ydst + 16 * dec->cache_y_stride_, ysize);
+ memcpy(udst, udst + 8 * dec->cache_uv_stride_, uvsize);
+ memcpy(vdst, vdst + 8 * dec->cache_uv_stride_, uvsize);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Main reconstruction function.
+
+static const int kScan[16] = {
+ 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
+ 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
+ 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
+ 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS
+};
+
+static inline int CheckMode(VP8Decoder* const dec, int mode) {
+ if (mode == B_DC_PRED) {
+ if (dec->mb_x_ == 0) {
+ return (dec->mb_y_ == 0) ? B_DC_PRED_NOTOPLEFT : B_DC_PRED_NOLEFT;
+ } else {
+ return (dec->mb_y_ == 0) ? B_DC_PRED_NOTOP : B_DC_PRED;
+ }
+ }
+ return mode;
+}
+
+static inline void Copy32b(uint8_t* dst, uint8_t* src) {
+ *(uint32_t*)dst = *(uint32_t*)src;
+}
+
+void VP8ReconstructBlock(VP8Decoder* const dec) {
+ uint8_t* const y_dst = dec->yuv_b_ + Y_OFF;
+ uint8_t* const u_dst = dec->yuv_b_ + U_OFF;
+ uint8_t* const v_dst = dec->yuv_b_ + V_OFF;
+
+ // Rotate in the left samples from previously decoded block. We move four
+ // pixels at a time for alignment reason, and because of in-loop filter.
+ if (dec->mb_x_ > 0) {
+ for (int j = -1; j < 16; ++j) {
+ Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]);
+ }
+ for (int j = -1; j < 8; ++j) {
+ Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]);
+ Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]);
+ }
+ } else {
+ for (int j = 0; j < 16; ++j) {
+ y_dst[j * BPS - 1] = 129;
+ }
+ for (int j = 0; j < 8; ++j) {
+ u_dst[j * BPS - 1] = 129;
+ v_dst[j * BPS - 1] = 129;
+ }
+ // Init top-left sample on left column too
+ if (dec->mb_y_ > 0) {
+ y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129;
+ }
+ }
+
+ // bring top samples into the cache
+ uint8_t* const top_y = dec->y_t_ + dec->mb_x_ * 16;
+ uint8_t* const top_u = dec->u_t_ + dec->mb_x_ * 8;
+ uint8_t* const top_v = dec->v_t_ + dec->mb_x_ * 8;
+ if (dec->mb_y_ > 0) {
+ memcpy(y_dst - BPS, top_y, 16);
+ memcpy(u_dst - BPS, top_u, 8);
+ memcpy(v_dst - BPS, top_v, 8);
+ } else if (dec->mb_x_ == 0) {
+ // we only need to do this init once at block (0,0).
+ // Afterward, it remains valid for the whole topmost row.
+ memset(y_dst - BPS - 1, 127, 16 + 4 + 1);
+ memset(u_dst - BPS - 1, 127, 8 + 1);
+ memset(v_dst - BPS - 1, 127, 8 + 1);
+ }
+
+ // predict and add residuals
+ const int16_t* coeffs = dec->coeffs_;
+ if (dec->is_i4x4_) { // 4x4
+ uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16);
+ if (dec->mb_y_ > 0) {
+ if (dec->mb_x_ >= dec->mb_w_ - 1) { // on rightmost border
+ top_right[0] = top_y[15] * 0x01010101u;
+ } else {
+ memcpy(top_right, top_y + 16, sizeof(*top_right));
+ }
+ }
+ // replicate the top-right pixels below
+ top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0];
+
+ // predict and add residues for all 4x4 blocks in turn.
+ for (int n = 0; n < 16; n++) {
+ uint8_t* const dst = y_dst + kScan[n];
+ VP8PredLuma4[dec->imodes_[n]](dst);
+ if (dec->non_zero_ & (1 << n)) {
+ VP8Transform(coeffs + n * 16, dst);
+ } else if (dec->non_zero_ & (1 << n)) { // only DC is present
+ VP8TransformDC(coeffs + n * 16, dst);
+ }
+ }
+ } else { // 16x16
+ const int pred_func = CheckMode(dec, dec->imodes_[0]);
+ VP8PredLuma16[pred_func](y_dst);
+ if (dec->non_zero_) {
+ for (int n = 0; n < 16; n++) {
+ uint8_t* const dst = y_dst + kScan[n];
+ if (dec->non_zero_ac_ & (1 << n)) {
+ VP8Transform(coeffs + n * 16, dst);
+ } else if (dec->non_zero_ & (1 << n)) { // only DC is present
+ VP8TransformDC(coeffs + n * 16, dst);
+ }
+ }
+ }
+ }
+
+ // Chroma
+ const int pred_func = CheckMode(dec, dec->uvmode_);
+ VP8PredChroma8[pred_func](u_dst);
+ VP8PredChroma8[pred_func](v_dst);
+
+ if (dec->non_zero_ & 0x0f0000) { // chroma-U
+ const int16_t* const u_coeffs = dec->coeffs_ + 16 * 16;
+ if (dec->non_zero_ac_ & 0x0f0000) {
+ VP8TransformUV(u_coeffs, u_dst);
+ } else {
+ VP8TransformDCUV(u_coeffs, u_dst);
+ }
+ }
+ if (dec->non_zero_ & 0xf00000) { // chroma-V
+ const int16_t* const v_coeffs = dec->coeffs_ + 20 * 16;
+ if (dec->non_zero_ac_ & 0xf00000) {
+ VP8TransformUV(v_coeffs, v_dst);
+ } else {
+ VP8TransformDCUV(v_coeffs, v_dst);
+ }
+ }
+
+ // stash away top samples for next block
+ if (dec->mb_y_ < dec->mb_h_ - 1) {
+ memcpy(top_y, y_dst + 15 * BPS, 16);
+ memcpy(top_u, u_dst + 7 * BPS, 8);
+ memcpy(top_v, v_dst + 7 * BPS, 8);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/third_party/libwebp/libwebp.gyp b/third_party/libwebp/libwebp.gyp
new file mode 100644
index 0000000..42510a5
--- /dev/null
+++ b/third_party/libwebp/libwebp.gyp
@@ -0,0 +1,72 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'use_system_libwebp%': 0,
+ },
+ 'conditions': [
+ ['use_system_libwebp==0', {
+ 'targets': [
+ {
+ 'target_name': 'libwebp',
+ 'type': '<(library)',
+ 'sources': [
+ 'bits.c',
+ 'frame.c',
+ 'dsp.c',
+ 'quant.c',
+ 'tree.c',
+ 'vp8.c',
+ 'webp.c',
+ 'yuv.c',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '.', './webp',
+ ],
+ },
+ 'conditions': [
+ ['OS!="win"', {
+ 'product_name': 'webp',
+ 'cflags': [
+ '-std=c99',
+ ],},
+ ],
+ ['OS=="win"', {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'AdditionalOptions': ['/TP'], # compile as C++ to get C99
+ },
+ },
+ }],
+ ],
+ },
+ ],
+ }, {
+ 'targets': [
+ {
+ 'target_name': 'libwebp',
+ 'type': 'settings',
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'ENABLE_WEBP',
+ ],
+ },
+ 'link_settings': {
+ 'libraries': [
+ '-lwebp',
+ ],
+ },
+ }
+ ],
+ }],
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/third_party/libwebp/quant.c b/third_party/libwebp/quant.c
new file mode 100644
index 0000000..557467e
--- /dev/null
+++ b/third_party/libwebp/quant.c
@@ -0,0 +1,107 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Quantizer initialization
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "vp8i.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static inline int clip(int v, int M) {
+ return v < 0 ? 0 : v > M ? M : v;
+}
+
+// Paragraph 14.1
+static const uint8_t kDcTable[128] = {
+ 4, 5, 6, 7, 8, 9, 10, 10,
+ 11, 12, 13, 14, 15, 16, 17, 17,
+ 18, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 25, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89,
+ 91, 93, 95, 96, 98, 100, 101, 102,
+ 104, 106, 108, 110, 112, 114, 116, 118,
+ 122, 124, 126, 128, 130, 132, 134, 136,
+ 138, 140, 143, 145, 148, 151, 154, 157
+};
+
+static const uint16_t kAcTable[128] = {
+ 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 60,
+ 62, 64, 66, 68, 70, 72, 74, 76,
+ 78, 80, 82, 84, 86, 88, 90, 92,
+ 94, 96, 98, 100, 102, 104, 106, 108,
+ 110, 112, 14, 116, 119, 122, 125, 128,
+ 131, 134, 37, 140, 143, 146, 149, 152,
+ 155, 158, 161, 164, 167, 170, 173, 177,
+ 181, 185, 189, 193, 197, 201, 205, 209,
+ 213, 217, 221, 225, 229, 234, 239, 245,
+ 249, 254, 259, 264, 269, 274, 279, 284
+};
+
+//-----------------------------------------------------------------------------
+// Paragraph 9.6
+
+void VP8ParseQuant(VP8Decoder* const dec) {
+ VP8BitReader* const br = &dec->br_;
+ const int base_q0 = VP8GetValue(br, 7);
+ const int dqy1_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+ const int dqy2_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+ const int dqy2_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+ const int dquv_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+ const int dquv_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+
+ const VP8SegmentHeader* const hdr = &dec->segment_hdr_;
+ for (int i = 0; i < NUM_MB_SEGMENTS; ++i) {
+ int q;
+ if (hdr->use_segment_) {
+ q = hdr->quantizer_[i];
+ if (!hdr->absolute_delta_) {
+ q += base_q0;
+ }
+ } else {
+ if (i > 0) {
+ dec->dqm_[i] = dec->dqm_[0];
+ continue;
+ } else {
+ q = base_q0;
+ }
+ }
+ VP8QuantMatrix* const m = &dec->dqm_[i];
+ m->y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)];
+ m->y1_mat_[1] = kAcTable[clip(q + 0, 127)];
+
+ m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2;
+ // TODO(skal): make it another table?
+ m->y2_mat_[1] = kAcTable[clip(q + dqy2_ac, 127)] * 155 / 100;
+ if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8;
+
+ m->uv_mat_[0] = kDcTable[clip(q + dquv_ac, 117)];
+ m->uv_mat_[1] = kAcTable[clip(q + dquv_dc, 127)];
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/third_party/libwebp/tree.c b/third_party/libwebp/tree.c
new file mode 100644
index 0000000..be9951d
--- /dev/null
+++ b/third_party/libwebp/tree.c
@@ -0,0 +1,579 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Coding trees and probas
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdio.h>
+#include "vp8i.h"
+#define USE_GENERIC_TREE
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#ifdef USE_GENERIC_TREE
+static const int8_t kYModesIntra4[18] = {
+ -B_DC_PRED, 1,
+ -B_TM_PRED, 2,
+ -B_VE_PRED, 3,
+ 4, 6,
+ -B_HE_PRED, 5,
+ -B_RD_PRED, -B_VR_PRED,
+ -B_LD_PRED, 7,
+ -B_VL_PRED, 8,
+ -B_HD_PRED, -B_HU_PRED
+};
+#endif
+
+#ifndef ONLY_KEYFRAME_CODE
+static const int8_t kYModesInter[8] = {
+ -DC_PRED, 1,
+ 2, 3,
+ -V_PRED, -H_PRED,
+ -TM_PRED, -B_PRED
+};
+
+static const int8_t kMBSplit[6] = {
+ -3, 1,
+ -2, 2,
+ -0, -1
+};
+
+static const int8_t kMVRef[8] = {
+ -ZEROMV, 1,
+ -NEARESTMV, 2,
+ -NEARMV, 3,
+ -NEWMV, -SPLITMV
+};
+
+static const int8_t kMVRef4[6] = {
+ -LEFT4, 1
+ -ABOVE4, 2
+ -ZERO4, -NEW4
+};
+#endif
+
+//-----------------------------------------------------------------------------
+// Default probabilities
+
+// Inter
+#ifndef ONLY_KEYFRAME_CODE
+static const uint8_t kYModeProbaInter0[4] = { 112, 86, 140, 37 };
+static const uint8_t kUVModeProbaInter0[3] = { 162, 101, 204 };
+static const uint8_t kMVProba0[2][NUM_MV_PROBAS] = {
+ { 162, 128, 225, 146, 172, 147, 214, 39,
+ 156, 128, 129, 132, 75, 145, 178, 206,
+ 239, 254, 254 },
+ { 164, 128, 204, 170, 119, 235, 140, 230,
+ 228, 128, 130, 130, 74, 148, 180, 203,
+ 236, 254, 254 }
+};
+#endif
+
+// Paragraph 13.5
+static const uint8_t
+ CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
+ // genereated using vp8_default_coef_probs() in entropy.c:129
+ { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 },
+ { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 },
+ { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 },
+ { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 },
+ { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 },
+ },
+ { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 },
+ { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 },
+ { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 },
+ },
+ { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 },
+ { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 },
+ { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 },
+ { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 },
+ { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 },
+ { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 },
+ { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 },
+ { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 },
+ { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 }
+ },
+ { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 },
+ { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 },
+ { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 }
+ },
+ { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 },
+ { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 },
+ { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 }
+ },
+ { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 },
+ { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 },
+ { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 },
+ { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 },
+ { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 }
+ },
+ { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 },
+ { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 },
+ { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 }
+ },
+ { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 },
+ { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 },
+ { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 }
+ },
+ { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 },
+ { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 },
+ { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 },
+ { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 }
+ },
+ { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 },
+ { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 },
+ { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 },
+ { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 },
+ { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 }
+ },
+ { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 },
+ { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 },
+ { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 },
+ { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 },
+ { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 }
+ },
+ { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 },
+ { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 },
+ { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 }
+ },
+ { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 },
+ { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 },
+ { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 }
+ },
+ { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 },
+ { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 },
+ { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 }
+ },
+ { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 },
+ { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 },
+ { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 }
+ },
+ { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 },
+ { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 },
+ { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 },
+ { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 },
+ { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 }
+ },
+ { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ }
+};
+
+// Paragraph 11.5
+static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
+ // genereated using vp8_kf_default_bmode_probs()
+ { { 231, 120, 48, 89, 115, 113, 120, 152, 112 },
+ { 152, 179, 64, 126, 170, 118, 46, 70, 95 },
+ { 175, 69, 143, 80, 85, 82, 72, 155, 103 },
+ { 56, 58, 10, 171, 218, 189, 17, 13, 152 },
+ { 144, 71, 10, 38, 171, 213, 144, 34, 26 },
+ { 114, 26, 17, 163, 44, 195, 21, 10, 173 },
+ { 121, 24, 80, 195, 26, 62, 44, 64, 85 },
+ { 170, 46, 55, 19, 136, 160, 33, 206, 71 },
+ { 63, 20, 8, 114, 114, 208, 12, 9, 226 },
+ { 81, 40, 11, 96, 182, 84, 29, 16, 36 } },
+ { { 134, 183, 89, 137, 98, 101, 106, 165, 148 },
+ { 72, 187, 100, 130, 157, 111, 32, 75, 80 },
+ { 66, 102, 167, 99, 74, 62, 40, 234, 128 },
+ { 41, 53, 9, 178, 241, 141, 26, 8, 107 },
+ { 104, 79, 12, 27, 217, 255, 87, 17, 7 },
+ { 74, 43, 26, 146, 73, 166, 49, 23, 157 },
+ { 65, 38, 105, 160, 51, 52, 31, 115, 128 },
+ { 87, 68, 71, 44, 114, 51, 15, 186, 23 },
+ { 47, 41, 14, 110, 182, 183, 21, 17, 194 },
+ { 66, 45, 25, 102, 197, 189, 23, 18, 22 } },
+ { { 88, 88, 147, 150, 42, 46, 45, 196, 205 },
+ { 43, 97, 183, 117, 85, 38, 35, 179, 61 },
+ { 39, 53, 200, 87, 26, 21, 43, 232, 171 },
+ { 56, 34, 51, 104, 114, 102, 29, 93, 77 },
+ { 107, 54, 32, 26, 51, 1, 81, 43, 31 },
+ { 39, 28, 85, 171, 58, 165, 90, 98, 64 },
+ { 34, 22, 116, 206, 23, 34, 43, 166, 73 },
+ { 68, 25, 106, 22, 64, 171, 36, 225, 114 },
+ { 34, 19, 21, 102, 132, 188, 16, 76, 124 },
+ { 62, 18, 78, 95, 85, 57, 50, 48, 51 } },
+ { { 193, 101, 35, 159, 215, 111, 89, 46, 111 },
+ { 60, 148, 31, 172, 219, 228, 21, 18, 111 },
+ { 112, 113, 77, 85, 179, 255, 38, 120, 114 },
+ { 40, 42, 1, 196, 245, 209, 10, 25, 109 },
+ { 100, 80, 8, 43, 154, 1, 51, 26, 71 },
+ { 88, 43, 29, 140, 166, 213, 37, 43, 154 },
+ { 61, 63, 30, 155, 67, 45, 68, 1, 209 },
+ { 142, 78, 78, 16, 255, 128, 34, 197, 171 },
+ { 41, 40, 5, 102, 211, 183, 4, 1, 221 },
+ { 51, 50, 17, 168, 209, 192, 23, 25, 82 } },
+ { { 125, 98, 42, 88, 104, 85, 117, 175, 82 },
+ { 95, 84, 53, 89, 128, 100, 113, 101, 45 },
+ { 75, 79, 123, 47, 51, 128, 81, 171, 1 },
+ { 57, 17, 5, 71, 102, 57, 53, 41, 49 },
+ { 115, 21, 2, 10, 102, 255, 166, 23, 6 },
+ { 38, 33, 13, 121, 57, 73, 26, 1, 85 },
+ { 41, 10, 67, 138, 77, 110, 90, 47, 114 },
+ { 101, 29, 16, 10, 85, 128, 101, 196, 26 },
+ { 57, 18, 10, 102, 102, 213, 34, 20, 43 },
+ { 117, 20, 15, 36, 163, 128, 68, 1, 26 } },
+ { { 138, 31, 36, 171, 27, 166, 38, 44, 229 },
+ { 67, 87, 58, 169, 82, 115, 26, 59, 179 },
+ { 63, 59, 90, 180, 59, 166, 93, 73, 154 },
+ { 40, 40, 21, 116, 143, 209, 34, 39, 175 },
+ { 57, 46, 22, 24, 128, 1, 54, 17, 37 },
+ { 47, 15, 16, 183, 34, 223, 49, 45, 183 },
+ { 46, 17, 33, 183, 6, 98, 15, 32, 183 },
+ { 65, 32, 73, 115, 28, 128, 23, 128, 205 },
+ { 40, 3, 9, 115, 51, 192, 18, 6, 223 },
+ { 87, 37, 9, 115, 59, 77, 64, 21, 47 } },
+ { { 104, 55, 44, 218, 9, 54, 53, 130, 226 },
+ { 64, 90, 70, 205, 40, 41, 23, 26, 57 },
+ { 54, 57, 112, 184, 5, 41, 38, 166, 213 },
+ { 30, 34, 26, 133, 152, 116, 10, 32, 134 },
+ { 75, 32, 12, 51, 192, 255, 160, 43, 51 },
+ { 39, 19, 53, 221, 26, 114, 32, 73, 255 },
+ { 31, 9, 65, 234, 2, 15, 1, 118, 73 },
+ { 88, 31, 35, 67, 102, 85, 55, 186, 85 },
+ { 56, 21, 23, 111, 59, 205, 45, 37, 192 },
+ { 55, 38, 70, 124, 73, 102, 1, 34, 98 } },
+ { { 102, 61, 71, 37, 34, 53, 31, 243, 192 },
+ { 69, 60, 71, 38, 73, 119, 28, 222, 37 },
+ { 68, 45, 128, 34, 1, 47, 11, 245, 171 },
+ { 62, 17, 19, 70, 146, 85, 55, 62, 70 },
+ { 75, 15, 9, 9, 64, 255, 184, 119, 16 },
+ { 37, 43, 37, 154, 100, 163, 85, 160, 1 },
+ { 63, 9, 92, 136, 28, 64, 32, 201, 85 },
+ { 86, 6, 28, 5, 64, 255, 25, 248, 1 },
+ { 56, 8, 17, 132, 137, 255, 55, 116, 128 },
+ { 58, 15, 20, 82, 135, 57, 26, 121, 40 } },
+ { { 164, 50, 31, 137, 154, 133, 25, 35, 218 },
+ { 51, 103, 44, 131, 131, 123, 31, 6, 158 },
+ { 86, 40, 64, 135, 148, 224, 45, 183, 128 },
+ { 22, 26, 17, 131, 240, 154, 14, 1, 209 },
+ { 83, 12, 13, 54, 192, 255, 68, 47, 28 },
+ { 45, 16, 21, 91, 64, 222, 7, 1, 197 },
+ { 56, 21, 39, 155, 60, 138, 23, 102, 213 },
+ { 85, 26, 85, 85, 128, 128, 32, 146, 171 },
+ { 18, 11, 7, 63, 144, 171, 4, 4, 246 },
+ { 35, 27, 10, 146, 174, 171, 12, 26, 128 } },
+ { { 190, 80, 35, 99, 180, 80, 126, 54, 45 },
+ { 85, 126, 47, 87, 176, 51, 41, 20, 32 },
+ { 101, 75, 128, 139, 118, 146, 116, 128, 85 },
+ { 56, 41, 15, 176, 236, 85, 37, 9, 62 },
+ { 146, 36, 19, 30, 171, 255, 97, 27, 20 },
+ { 71, 30, 17, 119, 118, 255, 17, 18, 138 },
+ { 101, 38, 60, 138, 55, 70, 43, 26, 142 },
+ { 138, 45, 61, 62, 219, 1, 81, 188, 64 },
+ { 32, 41, 20, 117, 151, 142, 20, 21, 163 },
+ { 112, 19, 12, 61, 195, 128, 48, 4, 24 } }
+};
+
+void VP8ResetProba(VP8Proba* const proba) {
+ memset(proba->segments_, 255u, sizeof(proba->segments_));
+ memcpy(proba->coeffs_, CoeffsProba0, sizeof(CoeffsProba0));
+#ifndef ONLY_KEYFRAME_CODE
+ memcpy(proba->mv_, kMVProba0, sizeof(kMVProba0));
+ memcpy(proba->ymode_, kYModeProbaInter0, sizeof(kYModeProbaInter0));
+ memcpy(proba->uvmode_, kUVModeProbaInter0, sizeof(kYModeProbaInter0));
+#endif
+}
+
+void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
+ uint8_t* const top = dec->intra_t_ + 4 * dec->mb_x_;
+ uint8_t* const left = dec->intra_l_;
+ // Hardcoded 16x16 intra-mode decision tree.
+ dec->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
+ if (!dec->is_i4x4_) {
+ const int ymode =
+ VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED)
+ : (VP8GetBit(br, 163) ? V_PRED : DC_PRED);
+ dec->imodes_[0] = ymode;
+ memset(top, ymode, 4 * sizeof(top[0]));
+ memset(left, ymode, 4 * sizeof(left[0]));
+ } else {
+ uint8_t* modes = dec->imodes_;
+ for (int y = 0; y < 4; ++y) {
+ int ymode = left[y];
+ for (int x = 0; x < 4; ++x) {
+ const uint8_t* const prob = kBModesProba[top[x]][ymode];
+#ifdef USE_GENERIC_TREE
+ // Generic tree-parsing
+ int i = 0;
+ do {
+ i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])];
+ } while (i > 0);
+ ymode = -i;
+#else
+ // Hardcoded tree parsing
+ ymode = !VP8GetBit(br, prob[0]) ? B_DC_PRED :
+ !VP8GetBit(br, prob[1]) ? B_TM_PRED :
+ !VP8GetBit(br, prob[2]) ? B_VE_PRED :
+ !VP8GetBit(br, prob[3]) ?
+ (!VP8GetBit(br, prob[4]) ? B_HE_PRED :
+ (!VP8GetBit(br, prob[5]) ? B_RD_PRED : B_VR_PRED)) :
+ (!VP8GetBit(br, prob[6]) ? B_LD_PRED :
+ (!VP8GetBit(br, prob[7]) ? B_VL_PRED :
+ (!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
+#endif // USE_GENERIC_TREE
+ top[x] = ymode;
+ *modes++ = ymode;
+ }
+ left[y] = ymode;
+ }
+ }
+ // Hardcoded UVMode decision tree
+ dec->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
+ : !VP8GetBit(br, 114) ? V_PRED
+ : VP8GetBit(br, 183) ? TM_PRED : H_PRED;
+}
+
+//-----------------------------------------------------------------------------
+// Paragraph 13
+
+static const uint8_t
+ CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
+ { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 },
+ { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 }
+ },
+ { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 },
+ { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ }
+};
+
+#ifndef ONLY_KEYFRAME_CODE
+static const uint8_t MVUpdateProba[2][NUM_MV_PROBAS] = {
+ { 237, 246, 253, 253, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 254, 250, 250,
+ 252, 254, 254 },
+ { 231, 243, 245, 253, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 254, 251, 251,
+ 254, 254, 254 }
+};
+#endif
+
+// Paragraph 9.9
+void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
+ VP8Proba* const proba = &dec->proba_;
+ for (int t = 0; t < NUM_TYPES; ++t) {
+ for (int b = 0; b < NUM_BANDS; ++b) {
+ for (int c = 0; c < NUM_CTX; ++c) {
+ for (int p = 0; p < NUM_PROBAS; ++p) {
+ if (VP8GetBit(br, CoeffsUpdateProba[t][b][c][p])) {
+ proba->coeffs_[t][b][c][p] = VP8GetValue(br, 8);
+ }
+ }
+ }
+ }
+ }
+ dec->use_skip_proba_ = VP8Get(br);
+ if (dec->use_skip_proba_) {
+ dec->skip_p_ = VP8GetValue(br, 8);
+ }
+#ifndef ONLY_KEYFRAME_CODE
+ if (!dec->frm_hdr_.key_frame_) {
+ dec->intra_p_ = VP8GetValue(br, 8);
+ dec->last_p_ = VP8GetValue(br, 8);
+ dec->golden_p_ = VP8GetValue(br, 8);
+ if (VP8Get(br)) { // update y-mode
+ for (int i = 0; i < 4; ++i) {
+ proba->ymode_[i] = VP8GetValue(br, 8);
+ }
+ }
+ if (VP8Get(br)) { // update uv-mode
+ for (int i = 0; i < 3; ++i) {
+ proba->uvmode_[i] = VP8GetValue(br, 8);
+ }
+ }
+ // update MV
+ for (int d = 0; d < 2; ++d) {
+ for (int k = 0; k < NUM_MV_PROBAS; ++k) {
+ if (VP8GetBit(br, MVUpdateProba[d][k])) {
+ const int v = VP8GetValue(br, 7);
+ proba->mv_[d][k] = v ? v << 1 : 1;
+ }
+ }
+ }
+ }
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/third_party/libwebp/vp8.c b/third_party/libwebp/vp8.c
new file mode 100644
index 0000000..ddfe189
--- /dev/null
+++ b/third_party/libwebp/vp8.c
@@ -0,0 +1,600 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// main entry for the decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+#include "vp8i.h"
+
+//-----------------------------------------------------------------------------
+// VP8Decoder
+
+static void SetOk(VP8Decoder* const dec) {
+ dec->status_ = 0;
+ dec->error_msg_ = "OK";
+}
+
+void VP8InitIo(VP8Io* const io) {
+ if (io) {
+ memset(io, 0, sizeof(*io));
+ }
+}
+
+VP8Decoder* VP8New() {
+ VP8Decoder* dec = (VP8Decoder*)calloc(1, sizeof(VP8Decoder));
+ if (dec) {
+ SetOk(dec);
+ dec->ready_ = 0;
+ }
+ return dec;
+}
+
+int VP8Status(VP8Decoder* const dec) {
+ if (!dec) return 2;
+ return dec->status_;
+}
+
+const char* VP8StatusMessage(VP8Decoder* const dec) {
+ if (!dec) return "no object";
+ if (!dec->error_msg_) return "OK";
+ return dec->error_msg_;
+}
+
+void VP8Delete(VP8Decoder* const dec) {
+ if (dec) {
+ VP8Clear(dec);
+ free(dec);
+ }
+}
+
+int VP8SetError(VP8Decoder* const dec, int error, const char *msg) {
+ dec->status_ = error;
+ dec->error_msg_ = msg;
+ dec->ready_ = 0;
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Header parsing
+
+static void ResetSegmentHeader(VP8SegmentHeader* const hdr) {
+ assert(hdr);
+ hdr->use_segment_ = 0;
+ hdr->update_map_ = 0;
+ hdr->absolute_delta_ = 1;
+ memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_));
+ memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_));
+}
+
+// Paragraph 9.3
+static int ParseSegmentHeader(VP8BitReader* br,
+ VP8SegmentHeader* hdr, VP8Proba* proba) {
+ assert(br);
+ assert(hdr);
+ hdr->use_segment_ = VP8Get(br);
+ if (hdr->use_segment_) {
+ hdr->update_map_ = VP8Get(br);
+ const int update_data = VP8Get(br);
+ if (update_data) {
+ hdr->absolute_delta_ = VP8Get(br);
+ for (int s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ hdr->quantizer_[s] = VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
+ }
+ for (int s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ hdr->filter_strength_[s] = VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
+ }
+ }
+ if (hdr->update_map_) {
+ for (int s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
+ proba->segments_[s] = VP8Get(br) ? VP8GetValue(br, 8) : 255u;
+ }
+ }
+ } else {
+ hdr->update_map_ = 0;
+ }
+ return 1;
+}
+
+// Paragraph 9.5
+static int ParsePartitions(VP8Decoder* const dec,
+ const uint8_t* buf, uint32_t size) {
+ VP8BitReader* const br = &dec->br_;
+ dec->num_parts_ = 1 << VP8GetValue(br, 2);
+ const uint8_t* sz = buf;
+ const int last_part = dec->num_parts_ - 1;
+ uint32_t offset = last_part * 3;
+ if (size <= offset) {
+ return 0;
+ }
+ for (int p = 0; p < last_part; ++p) {
+ const uint32_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
+ if (offset + psize > size) {
+ return 0;
+ }
+ VP8Init(dec->parts_ + p, buf + offset, psize);
+ offset += psize;
+ sz += 3;
+ }
+ size -= offset;
+ VP8Init(dec->parts_ + last_part, buf + offset, size);
+ return 1;
+}
+
+// Paragraph 9.4
+static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
+ VP8FilterHeader* const hdr = &dec->filter_hdr_;
+ hdr->simple_ = VP8Get(br);
+ hdr->level_ = VP8GetValue(br, 6);
+ hdr->sharpness_ = VP8GetValue(br, 3);
+ hdr->use_lf_delta_ = VP8Get(br);
+ if (hdr->use_lf_delta_) {
+ if (VP8Get(br)) { // update lf-delta?
+ for (int i = 0; i < NUM_REF_LF_DELTAS; ++i) {
+ if (VP8Get(br)) {
+ hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6);
+ }
+ }
+ for (int i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
+ if (VP8Get(br)) {
+ hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6);
+ }
+ }
+ }
+ }
+ dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2;
+ if (dec->filter_type_ > 0) { // precompute filter levels per segment
+ if (dec->segment_hdr_.use_segment_) {
+ for (int s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ int strength = dec->segment_hdr_.filter_strength_[s];
+ if (!dec->segment_hdr_.absolute_delta_) {
+ strength += hdr->level_;
+ }
+ dec->filter_levels_[s] = strength;
+ }
+ } else {
+ dec->filter_levels_[0] = hdr->level_;
+ }
+ }
+ return 1;
+}
+
+static inline uint32_t get_le32(const uint8_t* const data) {
+ return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+}
+
+// Topmost call
+int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
+ if (dec == NULL) {
+ return 0;
+ }
+ SetOk(dec);
+ if (io == NULL || io->data == NULL || io->data_size <= 4) {
+ return VP8SetError(dec, 2, "null VP8Io passed to VP8GetHeaders()");
+ }
+ const uint8_t* buf = io->data;
+ uint32_t buf_size = io->data_size;
+ if (buf_size < 4) {
+ return VP8SetError(dec, 2, "Not enough data to parse frame header");
+ }
+
+ // Skip over valid RIFF headers
+ if (!memcmp(buf, "RIFF", 4)) {
+ if (buf_size < 20 + 4) {
+ return VP8SetError(dec, 2, "RIFF: Truncated header.");
+ }
+ if (memcmp(buf + 8, "WEBP", 4)) { // wrong image file signature
+ return VP8SetError(dec, 2, "RIFF: WEBP signature not found.");
+ }
+ const uint32_t riff_size = get_le32(buf + 4);
+ if (memcmp(buf + 12, "VP8 ", 4)) {
+ return VP8SetError(dec, 2, "RIFF: Invalid compression format.");
+ }
+ const uint32_t chunk_size = get_le32(buf + 16);
+ if ((chunk_size > riff_size + 8) || (chunk_size & 1)) {
+ return VP8SetError(dec, 2, "RIFF: Inconsistent size information.");
+ }
+ buf += 20;
+ buf_size -= 20;
+ }
+
+ // Paragraph 9.1
+ VP8FrameHeader* const frm_hdr = &dec->frm_hdr_;
+ const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
+ frm_hdr->key_frame_ = !(bits & 1);
+ frm_hdr->profile_ = (bits >> 1) & 7;
+ frm_hdr->show_ = (bits >> 4) & 1;
+ frm_hdr->partition_length_ = (bits >> 5);
+ buf += 3;
+ buf_size -= 3;
+
+ VP8PictureHeader* const pic_hdr = &dec->pic_hdr_;
+ if (frm_hdr->key_frame_) {
+ // Paragraph 9.2
+ if (buf_size < 7) {
+ return VP8SetError(dec, 2, "cannot parse picture header");
+ }
+ if (buf[0] != 0x9d || buf[1] != 0x01 || buf[2] != 0x2a) {
+ return VP8SetError(dec, 2, "Bad code word");
+ }
+ pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff;
+ pic_hdr->xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2
+ pic_hdr->height_ = ((buf[6] << 8) | buf[5]) & 0x3fff;
+ pic_hdr->yscale_ = buf[6] >> 6;
+ buf += 7;
+ buf_size -= 7;
+
+ dec->mb_w_ = (pic_hdr->width_ + 15) >> 4;
+ dec->mb_h_ = (pic_hdr->height_ + 15) >> 4;
+ io->width = pic_hdr->width_;
+ io->height = pic_hdr->height_;
+
+ VP8ResetProba(&dec->proba_);
+ ResetSegmentHeader(&dec->segment_hdr_);
+ dec->segment_ = 0; // default for intra
+ }
+
+ VP8BitReader* const br = &dec->br_;
+ VP8Init(br, buf, buf_size);
+ buf += frm_hdr->partition_length_;
+ buf_size -= frm_hdr->partition_length_;
+ if (frm_hdr->key_frame_) {
+ pic_hdr->colorspace_ = VP8Get(br);
+ pic_hdr->clamp_type_ = VP8Get(br);
+ }
+ if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) {
+ return VP8SetError(dec, 2, "cannot parse segment header");
+ }
+ // Filter specs
+ if (!ParseFilterHeader(br, dec)) {
+ return VP8SetError(dec, 2, "cannot parse filter header");
+ }
+ if (!ParsePartitions(dec, buf, buf_size)) {
+ return VP8SetError(dec, 2, "cannot parse partitions");
+ }
+
+ // quantizer change
+ VP8ParseQuant(dec);
+
+ // Frame buffer marking
+ if (!frm_hdr->key_frame_) {
+ // Paragraph 9.7
+#ifndef ONLY_KEYFRAME_CODE
+ dec->buffer_flags_ = VP8Get(br) << 0; // update golden
+ dec->buffer_flags_ |= VP8Get(br) << 1; // update alt ref
+ if (!(dec->buffer_flags_ & 1)) {
+ dec->buffer_flags_ |= VP8GetValue(br, 2) << 2;
+ }
+ if (!(dec->buffer_flags_ & 2)) {
+ dec->buffer_flags_ |= VP8GetValue(br, 2) << 4;
+ }
+ dec->buffer_flags_ |= VP8Get(br) << 6; // sign bias golden
+ dec->buffer_flags_ |= VP8Get(br) << 7; // sign bias alt ref
+#else
+ return VP8SetError(dec, 2, "Not a key frame.");
+#endif
+ } else {
+ dec->buffer_flags_ = 0x003 | 0x100;
+ }
+
+ // Paragraph 9.8
+ dec->update_proba_ = VP8Get(br);
+ if (!dec->update_proba_) { // save for later restore
+ dec->proba_saved_ = dec->proba_;
+ }
+
+#ifndef ONLY_KEYFRAME_CODE
+ dec->buffer_flags_ &= 1 << 8;
+ dec->buffer_flags_ |=
+ (frm_hdr->key_frame_ || VP8Get(br)) << 8; // refresh last frame
+#endif
+
+ VP8ParseProba(br, dec);
+
+ // sanitized state
+ dec->ready_ = 1;
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Residual decoding (Paragraph 13.2 / 13.3)
+
+static const uint8_t kBands[16 + 1] = {
+ 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 0 // extra entry as sentinel
+};
+
+static const uint8_t kCat3[] = {173, 148, 140, 0};
+static const uint8_t kCat4[] = {176, 155, 140, 135, 0};
+static const uint8_t kCat5[] = {180, 157, 141, 134, 130, 0};
+static const uint8_t kCat6[] =
+ {254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0};
+static const uint8_t * const kCat3456[] = { kCat3, kCat4, kCat5, kCat6 };
+static const uint8_t kZigzag[16] = {
+ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
+};
+
+typedef const uint8_t PROBA_ARRAY[NUM_CTX][NUM_PROBAS];
+
+static int GetCoeffs(VP8BitReader* const br,
+ const uint8_t (*prob)[NUM_CTX][NUM_PROBAS],
+ int ctx, const uint16_t dq[2], int n, int16_t* out) {
+ const uint8_t* p = prob[kBands[n]][ctx];
+ if (!VP8GetBit(br, p[0])) { // first EOB is more a 'CBP' bit.
+ return -1;
+ }
+ while (1) {
+ ++n;
+ if (!VP8GetBit(br, p[1])) {
+ p = prob[kBands[n]][0];
+ } else { // non zero coeff
+ int v;
+ if (!VP8GetBit(br, p[2])) {
+ p = prob[kBands[n]][1];
+ v = 1;
+ } else {
+ if (!VP8GetBit(br, p[3])) {
+ if (!VP8GetBit(br, p[4])) {
+ v = 2;
+ } else {
+ v = 3 + VP8GetBit(br, p[5]);
+ }
+ } else {
+ if (!VP8GetBit(br, p[6])) {
+ if (!VP8GetBit(br, p[7])) {
+ v = 5 + VP8GetBit(br, 159);
+ } else {
+ v = 7 + 2 * VP8GetBit(br, 165) + VP8GetBit(br, 145);
+ }
+ } else {
+ const int bit1 = VP8GetBit(br, p[8]);
+ const int bit0 = VP8GetBit(br, p[9 + bit1]);
+ const int cat = 2 * bit1 + bit0;
+ v = 0;
+ for (const uint8_t* tab = kCat3456[cat]; *tab; ++tab) {
+ v += v + VP8GetBit(br, *tab);
+ }
+ v += 3 + (8 << cat);
+ }
+ }
+ p = prob[kBands[n]][2];
+ }
+ const int j = kZigzag[n - 1];
+ out[j] = VP8GetSigned(br, v) * dq[j > 0];
+ if (n == 16) break;
+ if (!VP8GetBit(br, p[0])) { // EOB
+ return n;
+ }
+ }
+ }
+ return 15;
+}
+
+// Table to unpack four bits into four bytes
+static const uint8_t kUnpackTab[16][4] = {
+ {0, 0, 0, 0}, {1, 0, 0, 0}, {0, 1, 0, 0}, {1, 1, 0, 0},
+ {0, 0, 1, 0}, {1, 0, 1, 0}, {0, 1, 1, 0}, {1, 1, 1, 0},
+ {0, 0, 0, 1}, {1, 0, 0, 1}, {0, 1, 0, 1}, {1, 1, 0, 1},
+ {0, 0, 1, 1}, {1, 0, 1, 1}, {0, 1, 1, 1}, {1, 1, 1, 1} };
+
+// Macro to pack four LSB of four bytes into four bits.
+#define PACK(X, S) \
+ ((((*(uint32_t*)(X)) * 0x01020408U) & 0xff000000) >> (S))
+
+typedef const uint8_t (*Proba_t)[NUM_CTX][NUM_PROBAS]; // for const-casting
+static int ParseResiduals(VP8Decoder* const dec,
+ VP8MB* const mb, VP8BitReader* const token_br) {
+ int out_t_nz, out_l_nz, first;
+ Proba_t ac_prob;
+ const VP8QuantMatrix* q = &dec->dqm_[dec->segment_];
+ int16_t* dst = dec->coeffs_;
+ VP8MB* const left_mb = dec->mb_info_ - 1;
+ memset(dst, 0, 384 * sizeof(*dst));
+ if (!dec->is_i4x4_) { // parse DC
+ int16_t dc[16] = { 0 };
+ const int ctx = mb->dc_nz_ + left_mb->dc_nz_;
+ const int last = GetCoeffs(token_br, (Proba_t)dec->proba_.coeffs_[1],
+ ctx, q->y2_mat_, 0, dc);
+ mb->dc_nz_ = left_mb->dc_nz_ = (last >= 0);
+ first = 1;
+ ac_prob = (Proba_t)dec->proba_.coeffs_[0];
+ VP8TransformWHT(dc, dst);
+ } else {
+ first = 0;
+ ac_prob = (Proba_t)dec->proba_.coeffs_[3];
+ }
+
+ uint8_t nz_ac[4], nz_dc[4];
+ uint32_t non_zero_ac = 0;
+ uint32_t non_zero_dc = 0;
+
+ uint8_t tnz[4], lnz[4];
+ memcpy(tnz, kUnpackTab[mb->nz_ & 0xf], sizeof(tnz));
+ memcpy(lnz, kUnpackTab[left_mb->nz_ & 0xf], sizeof(lnz));
+ for (int y = 0; y < 4; ++y) {
+ int l = lnz[y];
+ for (int x = 0; x < 4; ++x) {
+ const int ctx = l + tnz[x];
+ const int last = GetCoeffs(token_br, ac_prob, ctx,
+ q->y1_mat_, first, dst);
+ nz_dc[x] = (dst[0] != 0);
+ nz_ac[x] = (last > 0);
+ tnz[x] = l = (last >= 0);
+ dst += 16;
+ }
+ lnz[y] = l;
+ non_zero_dc |= PACK(nz_dc, 24 - y * 4);
+ non_zero_ac |= PACK(nz_ac, 24 - y * 4);
+ }
+ out_t_nz = PACK(tnz, 24);
+ out_l_nz = PACK(lnz, 24);
+
+ memcpy(tnz, kUnpackTab[mb->nz_ >> 4], sizeof(tnz));
+ memcpy(lnz, kUnpackTab[left_mb->nz_ >> 4], sizeof(lnz));
+ for (int ch = 0; ch < 4; ch += 2) {
+ for (int y = 0; y < 2; ++y) {
+ int l = lnz[ch + y];
+ for (int x = 0; x < 2; ++x) {
+ const int ctx = l + tnz[ch + x];
+ const int last =
+ GetCoeffs(token_br, (Proba_t)dec->proba_.coeffs_[2],
+ ctx, q->uv_mat_, 0, dst);
+ nz_dc[y * 2 + x] = (dst[0] != 0);
+ nz_ac[y * 2 + x] = (last > 0);
+ tnz[ch + x] = l = (last >= 0);
+ dst += 16;
+ }
+ lnz[ch + y] = l;
+ }
+ non_zero_dc |= PACK(nz_dc, 8 - ch * 2);
+ non_zero_ac |= PACK(nz_ac, 8 - ch * 2);
+ }
+ out_t_nz |= PACK(tnz, 20);
+ out_l_nz |= PACK(lnz, 20);
+ mb->nz_ = out_t_nz;
+ left_mb->nz_ = out_l_nz;
+
+ dec->non_zero_ac_ = non_zero_ac;
+ dec->non_zero_ = non_zero_ac | non_zero_dc;
+ mb->skip_ = !dec->non_zero_;
+
+ return 1;
+}
+#undef PACK
+
+//-----------------------------------------------------------------------------
+// Main loop
+
+static void SendBlock(VP8Decoder* const dec, VP8Io* io) {
+ if (io->put) {
+ io->mb_x = dec->mb_x_ * 16;
+ io->mb_y = dec->mb_y_ * 16;
+ io->mb_w = io->width - io->mb_x;
+ io->mb_h = io->height - io->mb_y;
+ if (io->mb_w > 16) io->mb_w = 16;
+ if (io->mb_h > 16) io->mb_h = 16;
+ io->put(io);
+ }
+}
+
+static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
+ int ok = 1;
+ VP8BitReader* const br = &dec->br_;
+
+ for (dec->mb_y_ = 0; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
+ memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
+ VP8MB* const left = dec->mb_info_ - 1;
+ left->nz_ = 0;
+ left->dc_nz_ = 0;
+ VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
+ for (dec->mb_x_ = 0; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
+ VP8MB* const info = dec->mb_info_ + dec->mb_x_;
+
+ // Note: we don't save segment map (yet), as we don't expect
+ // to decode more than 1 keyframe.
+ if (dec->segment_hdr_.update_map_) {
+ // Hardcoded tree parsing
+ dec->segment_ = !VP8GetBit(br, dec->proba_.segments_[0]) ?
+ VP8GetBit(br, dec->proba_.segments_[1]) :
+ 2 + VP8GetBit(br, dec->proba_.segments_[2]);
+ }
+ info->skip_ = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0;
+
+ VP8ParseIntraMode(br, dec);
+
+ if (!info->skip_) {
+ if (!ParseResiduals(dec, info, token_br)) {
+ ok = 0;
+ break;
+ }
+ } else {
+ left->nz_ = info->nz_ = 0;
+ if (!dec->is_i4x4_) {
+ left->dc_nz_ = info->dc_nz_ = 0;
+ }
+ dec->non_zero_ = 0;
+ dec->non_zero_ac_ = 0;
+ }
+ VP8ReconstructBlock(dec);
+
+ // Store filter params
+ if (dec->filter_type_ > 0) {
+ VP8StoreBlock(dec);
+ } else { // We're done. Send block to user at once.
+ SendBlock(dec, io);
+ }
+ }
+ if (!ok) {
+ break;
+ }
+ if (dec->filter_type_ > 0) { // filter a row
+ VP8FilterRow(dec, io);
+ }
+ if (dec->br_.eof_ || token_br->eof_) {
+ ok = 0;
+ break;
+ }
+ }
+
+ // Finish
+ if (!dec->update_proba_) {
+ dec->proba_ = dec->proba_saved_;
+ }
+ return ok;
+}
+
+// Main entry point
+int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
+ if (dec == NULL) {
+ return 0;
+ }
+ if (io == NULL) {
+ return VP8SetError(dec, 2, "NULL VP8Io parameter in VP8Decode().");
+ }
+
+ if (!dec->ready_) {
+ if (!VP8GetHeaders(dec, io)) {
+ return 0;
+ }
+ }
+ assert(dec->ready_);
+
+ // will allocate memory and prepare everything.
+ if (!VP8InitFrame(dec, io)) {
+ VP8Clear(dec);
+ return VP8SetError(dec, 3, "Allocation failed");
+ }
+
+ // set-up
+ if (io->setup) io->setup(io);
+
+ // Main decoding loop
+ if (!ParseFrame(dec, io)) {
+ VP8Clear(dec);
+ return VP8SetError(dec, 3, "Frame decoding failed");
+ }
+
+ // tear-down
+ if (io->teardown) io->teardown(io);
+
+ dec->ready_ = 0;
+ return 1;
+}
+
+void VP8Clear(VP8Decoder* const dec) {
+ if (dec == NULL) {
+ return;
+ }
+ if (dec->mem_) {
+ free(dec->mem_);
+ }
+ dec->mem_ = NULL;
+ dec->mem_size_ = 0;
+ memset(&dec->br_, 0, sizeof(dec->br_));
+ dec->ready_ = 0;
+}
diff --git a/third_party/libwebp/vp8i.h b/third_party/libwebp/vp8i.h
new file mode 100644
index 0000000..d3869c9
--- /dev/null
+++ b/third_party/libwebp/vp8i.h
@@ -0,0 +1,318 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// VP8 decoder: internal header.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DECODE_VP8I_H_
+#define WEBP_DECODE_VP8I_H_
+
+#include <string.h> // for memcpy()
+#include "bits.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------------
+// Various defines and enums
+
+#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames
+
+// intra prediction modes
+enum { B_DC_PRED = 0, // 4x4 modes
+ B_TM_PRED,
+ B_VE_PRED,
+ B_HE_PRED,
+ B_LD_PRED,
+ B_RD_PRED,
+ B_VR_PRED,
+ B_VL_PRED,
+ B_HD_PRED,
+ B_HU_PRED,
+ NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10
+
+ // Luma16 or UV modes
+ DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED,
+ H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED,
+ B_PRED = NUM_BMODES, // refined I4x4 mode
+
+ // special modes
+ B_DC_PRED_NOTOP = 4,
+ B_DC_PRED_NOLEFT = 5,
+ B_DC_PRED_NOTOPLEFT = 6 };
+
+#ifndef ONLY_KEYFRAME_CODE
+// inter prediction modes
+enum {
+ LEFT4 = 0, ABOVE4 = 1, ZERO4 = 2, NEW4 = 3,
+ NEARESTMV, NEARMV, ZEROMV, NEWMV, SPLITMV };
+#endif
+
+enum { MB_FEATURE_TREE_PROBS = 3,
+ NUM_MB_SEGMENTS = 4,
+ NUM_REF_LF_DELTAS = 4,
+ NUM_MODE_LF_DELTAS = 4, // I4x4, ZERO, *, SPLIT
+ MAX_NUM_PARTITIONS = 8,
+ // Probabilities
+ NUM_TYPES = 4,
+ NUM_BANDS = 8,
+ NUM_CTX = 3,
+ NUM_PROBAS = 11,
+ NUM_MV_PROBAS = 19 };
+
+// YUV-cache parameters.
+// Constraints are: We need to store one 16x16 block of luma samples (y),
+// and two 8x8 chroma blocks (u/v). These are better be 16-bytes aligned,
+// in order to be SIMD-friendly. We also need to store the top, left and
+// top-left samples (from previously decoded blocks), along with four
+// extra top-right samples for luma (intra4x4 prediction only).
+// One possible layout is, using 32 * (17 + 9) bytes:
+//
+// .+------ <- only 1 pixel high
+// .|yyyyt.
+// .|yyyyt.
+// .|yyyyt.
+// .|yyyy..
+// .+--.+-- <- only 1 pixel high
+// .|uu.|vv
+// .|uu.|vv
+//
+// Every character is a 4x4 block, with legend:
+// '.' = unused
+// 'y' = y-samples 'u' = u-samples 'v' = u-samples
+// '|' = left sample, '-' = top sample, '+' = top-left sample
+// 't' = extra top-right sample for 4x4 modes
+// With this layout, BPS (=Bytes Per Scan-line) is one cacheline size.
+#define BPS 32 // this is the common stride used by yuv[]
+#define YUV_SIZE (BPS * 17 + BPS * 9)
+#define Y_SIZE (BPS * 17)
+#define Y_OFF (BPS * 1 + 8)
+#define U_OFF (Y_OFF + BPS * 16 + BPS)
+#define V_OFF (U_OFF + 16)
+
+//-----------------------------------------------------------------------------
+// Headers
+
+typedef struct {
+ uint8_t key_frame_;
+ uint8_t profile_;
+ uint8_t show_;
+ uint32_t partition_length_;
+} VP8FrameHeader;
+
+typedef struct {
+ uint16_t width_;
+ uint16_t height_;
+ uint8_t xscale_;
+ uint8_t yscale_;
+ uint8_t colorspace_; // 0 = YCbCr
+ uint8_t clamp_type_;
+} VP8PictureHeader;
+
+// segment features
+typedef struct {
+ int use_segment_;
+ int update_map_; // whether to update the segment map or not
+ int absolute_delta_; // absolute or delta values for quantizer and filter
+ int8_t quantizer_[NUM_MB_SEGMENTS]; // quantization changes
+ int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments
+} VP8SegmentHeader;
+
+// Struct collecting all frame-persistent probabilities.
+typedef struct {
+ uint8_t segments_[MB_FEATURE_TREE_PROBS];
+ // Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4
+ uint8_t coeffs_[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS];
+#ifndef ONLY_KEYFRAME_CODE
+ uint8_t ymode_[4], uvmode_[3];
+ uint8_t mv_[2][NUM_MV_PROBAS];
+#endif
+} VP8Proba;
+
+// Filter parameters
+typedef struct {
+ int simple_; // 0=complex, 1=simple
+ int level_; // [0..63]
+ int sharpness_; // [0..7]
+ int use_lf_delta_;
+ int ref_lf_delta_[NUM_REF_LF_DELTAS];
+ int mode_lf_delta_[NUM_MODE_LF_DELTAS];
+} VP8FilterHeader;
+
+//-----------------------------------------------------------------------------
+// Informations about the macroblocks.
+
+typedef struct {
+ // block type
+ uint8_t skip_:1;
+ // filter specs
+ uint8_t f_level_:6; // filter strength: 0..63
+ uint8_t f_ilevel_:6; // inner limit: 1..63
+ uint8_t f_inner_:1; // do inner filtering?
+ // cbp
+ uint8_t nz_; // non-zero AC/DC coeffs
+ uint8_t dc_nz_; // non-zero DC coeffs
+} VP8MB;
+
+// Dequantization matrices
+typedef struct {
+ uint16_t y1_mat_[2], y2_mat_[2], uv_mat_[2]; // [DC / AC]
+} VP8QuantMatrix;
+
+//-----------------------------------------------------------------------------
+// VP8Decoder: the main opaque structure handed over to user
+
+struct VP8Decoder {
+ int status_; // 0 = OK
+ int ready_; // true if ready to decode a picture with VP8Decode()
+ const char* error_msg_; // set when status_ is not OK.
+
+ // Main data source
+ VP8BitReader br_;
+
+ // headers
+ VP8FrameHeader frm_hdr_;
+ VP8PictureHeader pic_hdr_;
+ VP8FilterHeader filter_hdr_;
+ VP8SegmentHeader segment_hdr_;
+
+ // dimension, in macroblock units.
+ int mb_w_, mb_h_;
+
+ // number of partitions.
+ int num_parts_;
+ // per-partition boolean decoders.
+ VP8BitReader parts_[MAX_NUM_PARTITIONS];
+
+ // buffer refresh flags
+ // bit 0: refresh Gold, bit 1: refresh Alt
+ // bit 2-3: copy to Gold, bit 4-5: copy to Alt
+ // bit 6: Gold sign bias, bit 7: Alt sign bias
+ // bit 8: refresh last frame
+ uint32_t buffer_flags_;
+
+ // dequantization (one set of DC/AC dequant factor per segment)
+ VP8QuantMatrix dqm_[NUM_MB_SEGMENTS];
+
+ // probabilities
+ VP8Proba proba_, proba_saved_;
+ int update_proba_;
+ int use_skip_proba_;
+ uint8_t skip_p_, intra_p_, last_p_, golden_p_;
+
+ // Boundary data cache and persistent buffers.
+ uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
+ uint8_t intra_l_[4]; // left intra modes values
+ uint8_t *y_t_; // top luma samples: 16 * mb_w_
+ uint8_t *u_t_, *v_t_; // top u/v samples: 8 * mb_w_ each
+
+ VP8MB* mb_info_; // contextual macroblock infos (mb_w_ + 1)
+ uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE)
+ int16_t* coeffs_; // 384 coeffs = (16+8+8) * 4*4
+
+ uint8_t* cache_y_; // macroblock row for storing unfiltered samples
+ uint8_t* cache_u_;
+ uint8_t* cache_v_;
+ int cache_y_stride_;
+ int cache_uv_stride_;
+
+ // main memory chunk for the above data. Persistent.
+ void* mem_;
+ int mem_size_;
+
+ // Per macroblock non-persistent infos.
+ int mb_x_, mb_y_; // current position, in macroblock units
+ uint8_t is_i4x4_; // true if intra4x4
+ uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
+ uint8_t uvmode_; // chroma prediction mode
+ uint8_t segment_; // block's segment
+
+ // bit-wise info about the content of each sub-4x4 blocks: there are 16 bits
+ // for luma (bits #0->#15), then 4 bits for chroma-u (#16->#19) and 4 bits for
+ // chroma-v (#20->#23), each corresponding to one 4x4 block in decoding order.
+ // If the bit is set, the 4x4 block contains some non-zero coefficients.
+ uint32_t non_zero_;
+ uint32_t non_zero_ac_;
+
+ // Filtering side-info
+ int filter_type_; // 0=off, 1=simple, 2=complex
+ uint8_t filter_levels_[NUM_MB_SEGMENTS]; // precalculated per-segment
+};
+
+//-----------------------------------------------------------------------------
+// internal functions. Not public.
+
+// in vp8.c
+int VP8SetError(VP8Decoder* const dec, int error, const char *msg);
+
+// in tree.c
+void VP8ResetProba(VP8Proba* const proba);
+void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec);
+void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec);
+
+// in quant.c
+void VP8ParseQuant(VP8Decoder* const dec);
+
+// in frame.c
+int VP8InitFrame(VP8Decoder* const dec, VP8Io* io);
+// Predict a block and add residual
+void VP8ReconstructBlock(VP8Decoder* const dec);
+// Filtering
+void VP8StoreBlock(VP8Decoder* const dec);
+void VP8FilterRow(VP8Decoder* const dec, VP8Io* io);
+
+// in dsp.c
+typedef void (*VP8Idct)(const int16_t* coeffs, uint8_t* dst);
+extern VP8Idct VP8Transform;
+extern VP8Idct VP8TransformUV;
+extern VP8Idct VP8TransformDC;
+extern VP8Idct VP8TransformDCUV;
+extern void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
+
+// *dst is the destination block, with stride BPS. Boundary samples are
+// assumed accessible when needed.
+typedef void (*VP8PredFunc)(uint8_t *dst);
+extern VP8PredFunc VP8PredLuma16[7];
+extern VP8PredFunc VP8PredChroma8[7];
+extern VP8PredFunc VP8PredLuma4[11];
+
+void VP8DspInit(); // must be called before anything using the above
+void VP8DspInitTables(); // needs to be called no matter what.
+
+// simple filter (only for luma)
+typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh);
+extern VP8SimpleFilterFunc VP8SimpleVFilter16;
+extern VP8SimpleFilterFunc VP8SimpleHFilter16;
+extern VP8SimpleFilterFunc VP8SimpleVFilter16i; // filter 3 inner edges
+extern VP8SimpleFilterFunc VP8SimpleHFilter16i;
+
+// regular filter (on both macroblock edges and inner edges)
+typedef void (*VP8LumaFilterFunc)(uint8_t* luma, int stride,
+ int thresh, int ithresh, int hev_t);
+typedef void (*VP8ChromaFilterFunc)(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_t);
+// on outter edge
+extern VP8LumaFilterFunc VP8VFilter16;
+extern VP8LumaFilterFunc VP8HFilter16;
+extern VP8ChromaFilterFunc VP8VFilter8;
+extern VP8ChromaFilterFunc VP8HFilter8;
+
+// on inner edge
+extern VP8LumaFilterFunc VP8VFilter16i; // filtering 3 inner edges altogether
+extern VP8LumaFilterFunc VP8HFilter16i;
+extern VP8ChromaFilterFunc VP8VFilter8i; // filtering u and v altogether
+extern VP8ChromaFilterFunc VP8HFilter8i;
+
+//-----------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_DECODE_VP8I_H_
diff --git a/third_party/libwebp/webp.c b/third_party/libwebp/webp.c
new file mode 100644
index 0000000..4c13fd2
--- /dev/null
+++ b/third_party/libwebp/webp.c
@@ -0,0 +1,361 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Main decoding functions for WEBP images.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+#include "vp8i.h"
+#include "yuv.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------------
+// RIFF layout is:
+// 0ffset tag
+// 0...3 "RIFF" 4-byte tag
+// 4...7 size of image data (including metadata) starting at offset 8
+// 8...11 "WEBP" our form-type signature
+// 12..15 "VP8 ": 4-bytes tags, describing the raw video format used
+// 16..19 size of the raw VP8 image data, starting at offset 20
+// 20.... the VP8 bytes
+// There can be extra chunks after the "VP8 " chunk (ICMT, ICOP, ...)
+// All 32-bits sizes are in little-endian order.
+// Note: chunk data must be padded to multiple of 2 in size
+
+static inline uint32_t get_le32(const uint8_t* const data) {
+ return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+}
+
+// If a RIFF container is detected, validate it and skip over it.
+static int CheckRIFFHeader(const uint8_t** data_ptr, uint32_t *data_size_ptr) {
+ uint32_t chunk_size = 0xffffffffu;
+ if (*data_size_ptr >= 10 + 20 && !memcmp(*data_ptr, "RIFF", 4)) {
+ if (memcmp(*data_ptr + 8, "WEBP", 4)) {
+ return 0; // wrong image file signature
+ }
+ const uint32_t riff_size = get_le32(*data_ptr + 4);
+ if (memcmp(*data_ptr + 12, "VP8 ", 4)) {
+ return 0; // invalid compression format
+ }
+ chunk_size = get_le32(*data_ptr + 16);
+ if ((chunk_size > riff_size + 8) || (chunk_size & 1)) {
+ return 0; // inconsistent size information.
+ }
+ // We have a IFF container. Skip it.
+ *data_ptr += 20;
+ *data_size_ptr -= 20;
+ }
+ return chunk_size;
+}
+
+//-----------------------------------------------------------------------------
+
+typedef enum { MODE_RGB = 0, MODE_RGBA = 1,
+ MODE_BGR = 2, MODE_BGRA = 3,
+ MODE_YUV = 4 } CSP_MODE;
+
+typedef struct {
+ uint8_t* output; // rgb(a) or luma
+ uint8_t *u, *v;
+ int stride; // rgb(a) stride or luma stride
+ int u_stride;
+ int v_stride;
+ CSP_MODE mode;
+} Params;
+
+static void CustomPut(const VP8Io* io) {
+ Params *p = (Params*)io->opaque;
+ const int mb_w = io->mb_w;
+ const int mb_h = io->mb_h;
+ if (p->mode == MODE_YUV) {
+ uint8_t* const y_dst = p->output + io->mb_x + io->mb_y * p->stride;
+ for (int j = 0; j < mb_h; ++j) {
+ memcpy(y_dst + j * p->stride, io->y + j * io->y_stride, mb_w);
+ }
+ uint8_t* const u_dst = p->u + (io->mb_x / 2) + (io->mb_y / 2) * p->u_stride;
+ uint8_t* const v_dst = p->v + (io->mb_x / 2) + (io->mb_y / 2) * p->v_stride;
+ const int uv_w = (mb_w + 1) / 2;
+ for (int j = 0; j < (mb_h + 1) / 2; ++j) {
+ memcpy(u_dst + j * p->u_stride, io->u + j * io->uv_stride, uv_w);
+ memcpy(v_dst + j * p->v_stride, io->v + j * io->uv_stride, uv_w);
+ }
+ } else {
+ const int psize = (p->mode == MODE_RGB || p->mode == MODE_BGR) ? 3 : 4;
+ uint8_t* dst = p->output + psize * io->mb_x + io->mb_y * p->stride;
+ for (int j = 0; j < mb_h; ++j) {
+ const uint8_t* y_src = io->y + j * io->y_stride;
+ for (int i = 0; i < mb_w; ++i) {
+ const int y = y_src[i];
+ const int u = io->u[(j / 2) * io->uv_stride + (i / 2)];
+ const int v = io->v[(j / 2) * io->uv_stride + (i / 2)];
+ if (p->mode == MODE_RGB) {
+ VP8YuvToRgb(y, u, v, dst + i * 3);
+ } else if (p->mode == MODE_BGR) {
+ VP8YuvToBgr(y, u, v, dst + i * 3);
+ } else if (p->mode == MODE_RGBA) {
+ VP8YuvToRgba(y, u, v, dst + i * 4);
+ } else {
+ VP8YuvToBgra(y, u, v, dst + i * 4);
+ }
+ }
+ dst += p->stride;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// "Into" variants
+
+static uint8_t* DecodeInto(CSP_MODE mode,
+ const uint8_t* data, uint32_t data_size,
+ Params* params, int output_size,
+ int output_u_size, int output_v_size) {
+ VP8Decoder* dec = VP8New();
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ VP8Io io;
+ VP8InitIo(&io);
+ io.data = data;
+ io.data_size = data_size;
+
+ params->mode = mode;
+ io.opaque = params;
+ io.put = CustomPut;
+
+ if (!VP8GetHeaders(dec, &io)) {
+ VP8Delete(dec);
+ return NULL;
+ }
+ // check output buffers
+ int ok = 1;
+ ok &= (params->stride * io.height <= output_size);
+ if (mode == MODE_RGB || mode == MODE_BGR) {
+ ok &= (params->stride >= io.width * 3);
+ } else if (mode == MODE_RGBA || mode == MODE_BGRA) {
+ ok &= (params->stride >= io.width * 4);
+ } else {
+ ok &= (params->stride >= io.width);
+ // some extra checks for U/V
+ const int u_size = params->u_stride * ((io.height + 1) / 2);
+ const int v_size = params->v_stride * ((io.height + 1) / 2);
+ ok &= (params->u_stride >= (io.width + 1) / 2) &&
+ (params->v_stride >= (io.width + 1) / 2);
+ ok &= (u_size <= output_u_size && v_size <= output_v_size);
+ }
+ if (!ok) {
+ VP8Delete(dec);
+ return NULL;
+ }
+
+ if (mode != MODE_YUV) {
+ VP8YUVInit();
+ }
+
+ ok = VP8Decode(dec, &io);
+ VP8Delete(dec);
+ return ok ? params->output : NULL;
+}
+
+uint8_t* WebPDecodeRGBInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* output, int output_size,
+ int output_stride) {
+ if (output == NULL) {
+ return NULL;
+ }
+ Params params;
+ params.output = output;
+ params.stride = output_stride;
+ return DecodeInto(MODE_RGB, data, data_size, &params, output_size, 0, 0);
+}
+
+uint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* output, int output_size,
+ int output_stride) {
+ if (output == NULL) {
+ return NULL;
+ }
+ Params params;
+ params.output = output;
+ params.stride = output_stride;
+ return DecodeInto(MODE_RGBA, data, data_size, &params, output_size, 0, 0);
+}
+
+uint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* output, int output_size,
+ int output_stride) {
+ if (output == NULL) {
+ return NULL;
+ }
+ Params params;
+ params.output = output;
+ params.stride = output_stride;
+ return DecodeInto(MODE_BGR, data, data_size, &params, output_size, 0, 0);
+}
+
+uint8_t* WebPDecodeBGRAInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* output, int output_size,
+ int output_stride) {
+ if (output == NULL) {
+ return NULL;
+ }
+ Params params;
+ params.output = output;
+ params.stride = output_stride;
+ return DecodeInto(MODE_BGRA, data, data_size, &params, output_size, 0, 0);
+}
+
+uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* luma, int luma_size, int luma_stride,
+ uint8_t* u, int u_size, int u_stride,
+ uint8_t* v, int v_size, int v_stride) {
+ if (luma == NULL) {
+ return NULL;
+ }
+ Params params;
+ params.output = luma;
+ params.stride = luma_stride;
+ params.u = u;
+ params.u_stride = u_stride;
+ params.v = v;
+ params.v_stride = v_stride;
+ return DecodeInto(MODE_YUV, data, data_size, &params,
+ luma_size, u_size, v_size);
+}
+
+//-----------------------------------------------------------------------------
+
+static uint8_t* Decode(CSP_MODE mode, const uint8_t* data, uint32_t data_size,
+ int* width, int* height, Params* params_out) {
+ int w, h;
+ if (!WebPGetInfo(data, data_size, &w, &h)) {
+ return NULL;
+ }
+ if (width) *width = w;
+ if (height) *height = h;
+
+ // initialize output buffer, now that dimensions are known.
+ int stride = (mode == MODE_RGB || mode == MODE_BGR) ? 3 * w
+ : (mode == MODE_RGBA || mode == MODE_BGRA) ? 4 * w
+ : w;
+ const int size = stride * h;
+ int uv_size = 0;
+ int uv_stride = 0;
+ if (mode == MODE_YUV) {
+ uv_stride = (w + 1) / 2;
+ uv_size = uv_stride * ((h + 1) / 2);
+ }
+ uint8_t* const output = (uint8_t*)malloc(size + 2 * uv_size);
+ if (!output) {
+ return NULL;
+ }
+ Params params = { 0 };
+ params.output = output;
+ params.stride = stride;
+ if (mode == MODE_YUV) {
+ params.u = output + size;
+ params.u_stride = uv_stride;
+ params.v = output + size + uv_size;
+ params.v_stride = uv_stride;
+ }
+ if (params_out) *params_out = params;
+ return DecodeInto(mode, data, data_size, &params, size, uv_size, uv_size);
+}
+
+uint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size,
+ int *width, int *height) {
+ return Decode(MODE_RGB, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size,
+ int *width, int *height) {
+ return Decode(MODE_RGBA, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size,
+ int *width, int *height) {
+ return Decode(MODE_BGR, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeBGRA(const uint8_t* data, uint32_t data_size,
+ int *width, int *height) {
+ return Decode(MODE_BGRA, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeYUV(const uint8_t* data, uint32_t data_size,
+ int *width, int *height, uint8_t** u, uint8_t** v,
+ int *stride, int* uv_stride) {
+ Params params;
+ uint8_t* const out = Decode(MODE_YUV, data, data_size,
+ width, height, &params);
+
+ if (out) {
+ *u = params.u;
+ *v = params.v;
+ *stride = params.stride;
+ *uv_stride = params.u_stride;
+ assert(params.u_stride == params.v_stride);
+ }
+ return out;
+}
+
+//-----------------------------------------------------------------------------
+// WebPGetInfo()
+
+int WebPGetInfo(const uint8_t* data, uint32_t data_size,
+ int *width, int *height) {
+ const uint32_t chunk_size = CheckRIFFHeader(&data, &data_size);
+ if (!chunk_size) {
+ return 0; // unsupported RIFF header
+ }
+ // Validate raw video data
+ if (data_size < 10) {
+ return 0; // not enough data
+ }
+ // check signature
+ if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a) {
+ return 0; // Wrong signature.
+ }
+ const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16);
+ const int key_frame = !(bits & 1);
+ if (!key_frame) { // Not a keyframe.
+ return 0;
+ }
+ const int profile = (bits >> 1) & 7;
+ const int show_frame = (bits >> 4) & 1;
+ const uint32_t partition_length = (bits >> 5);
+ if (profile > 3) {
+ return 0; // unknown profile
+ }
+ if (!show_frame) {
+ return 0; // first frame is invisible!
+ }
+ if (partition_length >= chunk_size) {
+ return 0; // inconsistent size information.
+ }
+
+ const int w = ((data[7] << 8) | data[6]) & 0x3fff;
+ const int h = ((data[9] << 8) | data[8]) & 0x3fff;
+ if (width) {
+ *width = w;
+ }
+ if (height) {
+ *height = h;
+ }
+
+ return 1;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/third_party/libwebp/webp/decode.h b/third_party/libwebp/webp/decode.h
new file mode 100644
index 0000000..6ecaa00
--- /dev/null
+++ b/third_party/libwebp/webp/decode.h
@@ -0,0 +1,111 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Main decoding functions for WEBP images.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DECODE_WEBP_DECODE_H_
+#define WEBP_DECODE_WEBP_DECODE_H_
+
+#ifndef _MSC_VER
+#include <inttypes.h>
+#else
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long int uint64_t;
+#define inline __forceinline
+#endif
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// Retrieve basic header information: width, height.
+// This function will also validate the header and return 0 in
+// case of formatting error.
+// Pointers *width/*height can be passed NULL if deemed irrelevant.
+int WebPGetInfo(const uint8_t* data, uint32_t data_size,
+ int *width, int *height);
+
+// Decodes WEBP images pointed to by *data and returns RGB samples, along
+// with the dimensions in *width and *height.
+// The returned pointer should be deleted calling free().
+// Returns NULL in case of error.
+uint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size,
+ int *width, int *height);
+
+// Same as WebPDecodeRGB, but returning RGBA data.
+uint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size,
+ int *width, int *height);
+
+// This variant decode to BGR instead of RGB.
+uint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size,
+ int *width, int *height);
+// This variant decodes to BGRA instead of RGBA.
+uint8_t* WebPDecodeBGRA(const uint8_t* data, uint32_t data_size,
+ int *width, int *height);
+
+// Decode WEBP images stored in *data in Y'UV format(*). The pointer returned is
+// the Y samples buffer. Upon return, *u and *v will point to the U and V
+// chroma data. These U and V buffers need NOT be free()'d, unlike the returned
+// Y luma one. The dimension of the U and V planes are both (*width + 1) / 2
+// and (*height + 1)/ 2.
+// Upon return, the Y buffer has a stride returned as '*stride', while U and V
+// have a common stride returned as '*uv_stride'.
+// Return NULL in case of error.
+// (*) Also named Y'CbCr. See: http://en.wikipedia.org/wiki/YCbCr
+uint8_t* WebPDecodeYUV(const uint8_t* data, uint32_t data_size,
+ int *width, int *height, uint8_t** u, uint8_t** v,
+ int *stride, int* uv_stride);
+
+// These three functions are variants of the above ones, that decode the image
+// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
+// available in this buffer is indicated by 'output_buffer_size'. If this
+// storage is not sufficient (or an error occurred), NULL is returned.
+// Otherwise, output_buffer is returned, for convenience.
+// The parameter 'output_stride' specifies the distance (in bytes)
+// between scanlines. Hence, output_buffer_size is expected to be at least
+// output_stride x picture-height.
+uint8_t* WebPDecodeRGBInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* output_buffer, int output_buffer_size,
+ int output_stride);
+uint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* output_buffer, int output_buffer_size,
+ int output_stride);
+// BGR variants
+uint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* output_buffer, int output_buffer_size,
+ int output_stride);
+uint8_t* WebPDecodeBGRAInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* output_buffer, int output_buffer_size,
+ int output_stride);
+
+// WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly
+// into pre-allocated luma/chroma plane buffers. This function requires the
+// strides to be passed: one for the luma plane and one for each of the
+// chroma ones. The size of each plane buffer is passed as 'luma_size',
+// 'u_size' and 'v_size' respectively.
+// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
+// during decoding (or because some buffers were found to be too small).
+uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
+ uint8_t* luma, int luma_size, int luma_stride,
+ uint8_t* u, int u_size, int u_stride,
+ uint8_t* v, int v_size, int v_stride);
+
+//-----------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_DECODE_WEBP_DECODE_H_
diff --git a/third_party/libwebp/webp/decode_vp8.h b/third_party/libwebp/webp/decode_vp8.h
new file mode 100644
index 0000000..6ac9fc5
--- /dev/null
+++ b/third_party/libwebp/webp/decode_vp8.h
@@ -0,0 +1,107 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Low-level API for VP8 decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DECODE_WEBP_DECODE_VP8_H_
+#define WEBP_DECODE_WEBP_DECODE_VP8_H_
+
+#include "decode.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------------
+// Lower-level API
+//
+// Thes functions provide fine-grained control of the decoding process.
+// The call flow should resemble:
+//
+// VP8Io io;
+// VP8InitIo(&io);
+// io.data = data;
+// io.data_size = size;
+// /* customize io's functions (setup()/put()/teardown()) if needed. */
+//
+// VP8Decoder* dec = VP8New();
+// bool ok = VP8Decode(dec);
+// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec));
+// VP8Delete(dec);
+// return ok;
+
+// Input / Output
+typedef struct VP8Io VP8Io;
+struct VP8Io {
+ // set by VP8GetHeaders()
+ int width, height; // picture dimensions, in pixels
+
+ // set before calling put()
+ int mb_x, mb_y; // position of the current sample (in pixels)
+ int mb_w, mb_h; // size of the current sample (usually 16x16)
+ const uint8_t *y, *u, *v; // samples to copy
+ int y_stride; // stride for luma
+ int uv_stride; // stride for chroma
+
+ void* opaque; // user data
+
+ // called when fresh samples are available (1 block of 16x16 pixels)
+ void (*put)(const VP8Io* io);
+
+ // called just before starting to decode the blocks
+ void (*setup)(const VP8Io* io);
+
+ // called just after block decoding is finished
+ void (*teardown)(const VP8Io* io);
+
+ // Input buffer.
+ uint32_t data_size;
+ const uint8_t* data;
+};
+
+// Main decoding object. This is an opaque structure.
+typedef struct VP8Decoder VP8Decoder;
+
+// Create a new decoder object.
+VP8Decoder* VP8New();
+
+// Can be called to make sure 'io' is initialized properly.
+void VP8InitIo(VP8Io* const io);
+
+// Start decoding a new picture. Returns true if ok.
+int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
+
+// Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
+int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
+
+// Return current status of the decoder:
+// 0 = OK
+// 1 = OUT_OF_MEMORY
+// 2 = INVALID_PARAM
+// 3 = BITSTREAM_ERROR
+// 4 = UNSUPPORTED_FEATURE
+int VP8Status(VP8Decoder* const dec);
+
+// return readable string corresponding to the last status.
+const char* VP8StatusMessage(VP8Decoder* const dec);
+
+// Resets the decoder in its initial state, reclaiming memory.
+// Not a mandatory call between calls to VP8Decode().
+void VP8Clear(VP8Decoder* const dec);
+
+// Destroy the decoder object.
+void VP8Delete(VP8Decoder* const dec);
+
+//-----------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_DECODE_WEBP_DECODE_VP8_H_
diff --git a/third_party/libwebp/yuv.c b/third_party/libwebp/yuv.c
new file mode 100644
index 0000000..32927fb
--- /dev/null
+++ b/third_party/libwebp/yuv.c
@@ -0,0 +1,45 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// YUV->RGB conversion function
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "yuv.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+enum { YUV_HALF = 1 << (YUV_FIX - 1) };
+
+int16_t VP8kVToR[256], VP8kUToB[256];
+int32_t VP8kVToG[256], VP8kUToG[256];
+uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
+
+static int done = 0;
+
+void VP8YUVInit() {
+ if (done) {
+ return;
+ }
+ for (int i = 0; i < 256; ++i) {
+ VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
+ VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
+ VP8kVToG[i] = -45773 * (i - 128);
+ VP8kUToB[i] = (113618 * (i - 128) + YUV_HALF) >> YUV_FIX;
+ }
+ for (int i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
+ const int j = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
+ VP8kClip[i - YUV_RANGE_MIN] = (j < 0) ? 0 : (j > 255) ? 255 : j;
+ }
+ done = 1;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/third_party/libwebp/yuv.h b/third_party/libwebp/yuv.h
new file mode 100644
index 0000000..5a9fce2
--- /dev/null
+++ b/third_party/libwebp/yuv.h
@@ -0,0 +1,66 @@
+// Copyright 2010 Google Inc.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// inline YUV->RGB conversion function
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DECODE_YUV_H_
+#define WEBP_DECODE_YUV_H_
+
+#include "webp/decode_vp8.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+enum { YUV_FIX = 16, // fixed-point precision
+ YUV_RANGE_MIN = -227, // min value of r/g/b output
+ YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output
+};
+extern int16_t VP8kVToR[256], VP8kUToB[256];
+extern int32_t VP8kVToG[256], VP8kUToG[256];
+extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
+
+inline static void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const rgb) {
+ const int r_off = VP8kVToR[v];
+ const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
+ const int b_off = VP8kUToB[u];
+ rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN];
+ rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
+ rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
+}
+
+inline static void VP8YuvToRgba(int y, int u, int v, uint8_t* const rgba) {
+ VP8YuvToRgb(y, u, v, rgba);
+ rgba[3] = 0xff;
+}
+
+inline static void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const bgr) {
+ const int r_off = VP8kVToR[v];
+ const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
+ const int b_off = VP8kUToB[u];
+ bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
+ bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
+ bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
+}
+
+inline static void VP8YuvToBgra(int y, int u, int v, uint8_t* const bgra) {
+ VP8YuvToBgr(y, u, v, bgra);
+ bgra[3] = 0xff;
+}
+
+// Must be called before everything, to initialize the tables.
+void VP8YUVInit();
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_DECODE_YUV_H_