convert to ANSI-C

This commit is contained in:
Pierre Joye 2010-10-05 16:58:47 -07:00 committed by Pascal Massimino
parent c3f41cb47e
commit c8d15efa12
11 changed files with 382 additions and 482 deletions

View File

@ -1,3 +1,5 @@
Main stuff:
Initial release:
- Pascal Massimino (pascal.massimino@gmail.com)
Contributors:
- pierre.php@gmail.com (ansi-C port)

View File

@ -13,7 +13,7 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD \
-finline-functions -frename-registers -ffast-math \
-s -fomit-frame-pointer -std=gnu99
-s -fomit-frame-pointer
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src

201
configure vendored
View File

@ -19742,207 +19742,6 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool'
{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C99" >&5
echo $ECHO_N "checking for $CC option to accept ISO C99... $ECHO_C" >&6; }
if test "${ac_cv_prog_cc_c99+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_cv_prog_cc_c99=no
ac_save_CC=$CC
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <wchar.h>
#include <stdio.h>
// Check varargs macros. These examples are taken from C99 6.10.3.5.
#define debug(...) fprintf (stderr, __VA_ARGS__)
#define showlist(...) puts (#__VA_ARGS__)
#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
static void
test_varargs_macros (void)
{
int x = 1234;
int y = 5678;
debug ("Flag");
debug ("X = %d\n", x);
showlist (The first, second, and third items.);
report (x>y, "x is %d but y is %d", x, y);
}
// Check long long types.
#define BIG64 18446744073709551615ull
#define BIG32 4294967295ul
#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
#if !BIG_OK
your preprocessor is broken;
#endif
#if BIG_OK
#else
your preprocessor is broken;
#endif
static long long int bignum = -9223372036854775807LL;
static unsigned long long int ubignum = BIG64;
struct incomplete_array
{
int datasize;
double data[];
};
struct named_init {
int number;
const wchar_t *name;
double average;
};
typedef const char *ccp;
static inline int
test_restrict (ccp restrict text)
{
// See if C++-style comments work.
// Iterate through items via the restricted pointer.
// Also check for declarations in for loops.
for (unsigned int i = 0; *(text+i) != '\0'; ++i)
continue;
return 0;
}
// Check varargs and va_copy.
static void
test_varargs (const char *format, ...)
{
va_list args;
va_start (args, format);
va_list args_copy;
va_copy (args_copy, args);
const char *str;
int number;
float fnumber;
while (*format)
{
switch (*format++)
{
case 's': // string
str = va_arg (args_copy, const char *);
break;
case 'd': // int
number = va_arg (args_copy, int);
break;
case 'f': // float
fnumber = va_arg (args_copy, double);
break;
default:
break;
}
}
va_end (args_copy);
va_end (args);
}
int
main ()
{
// Check bool.
_Bool success = false;
// Check restrict.
if (test_restrict ("String literal") == 0)
success = true;
char *restrict newvar = "Another string";
// Check varargs.
test_varargs ("s, d' f .", "string", 65, 34.234);
test_varargs_macros ();
// Check flexible array members.
struct incomplete_array *ia =
malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
ia->datasize = 10;
for (int i = 0; i < ia->datasize; ++i)
ia->data[i] = i * 1.234;
// Check named initializers.
struct named_init ni = {
.number = 34,
.name = L"Test wide string",
.average = 543.34343,
};
ni.number = 58;
int dynamic_array[ni.number];
dynamic_array[ni.number - 1] = 543;
// work around unused variable warnings
return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
|| dynamic_array[ni.number - 1] != 543);
;
return 0;
}
_ACEOF
for ac_arg in '' -std=gnu99 -c99 -qlanglvl=extc99
do
CC="$ac_save_CC $ac_arg"
rm -f conftest.$ac_objext
if { (ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_compile") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
} && test -s conftest.$ac_objext; then
ac_cv_prog_cc_c99=$ac_arg
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -f core conftest.err conftest.$ac_objext
test "x$ac_cv_prog_cc_c99" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
fi
# AC_CACHE_VAL
case "x$ac_cv_prog_cc_c99" in
x)
{ echo "$as_me:$LINENO: result: none needed" >&5
echo "${ECHO_T}none needed" >&6; } ;;
xno)
{ echo "$as_me:$LINENO: result: unsupported" >&5
echo "${ECHO_T}unsupported" >&6; } ;;
*)
CC="$CC $ac_cv_prog_cc_c99"
{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c99" >&5
echo "${ECHO_T}$ac_cv_prog_cc_c99" >&6; } ;;
esac
ac_config_headers="$ac_config_headers config.h"
ac_config_files="$ac_config_files Makefile examples/Makefile src/Makefile"

View File

@ -1,7 +1,6 @@
AC_INIT([webpdecode], [0.1])
AM_INIT_AUTOMAKE
AC_PROG_LIBTOOL
AC_PROG_CC_C99
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile examples/Makefile src/Makefile])
AC_OUTPUT

View File

@ -32,17 +32,18 @@ static int tables_ok = 0;
void VP8DspInitTables() {
if (!tables_ok) {
for (int i = -255; i <= 255; ++i) {
int i;
for (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) {
for (i = -1020; i <= 1020; ++i) {
sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
}
for (int i = -112; i <= 112; ++i) {
for (i = -112; i <= 112; ++i) {
sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
}
for (int i = -255; i <= 255 + 255; ++i) {
for (i = -255; i <= 255 + 255; ++i) {
clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
}
tables_ok = 1;
@ -66,8 +67,9 @@ static const int kC2 = 35468;
static void Transform(const int16_t* in, uint8_t* dst) {
int C[4 * 4], *tmp;
int i;
tmp = C;
for (int i = 0; i < 4; ++i) { // vertical pass
for (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);
@ -81,7 +83,7 @@ static void Transform(const int16_t* in, uint8_t* dst) {
}
tmp = C;
for (int i = 0; i < 4; ++i) { // horizontal pass
for (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];
@ -106,8 +108,9 @@ static void TransformUV(const int16_t* in, uint8_t* dst) {
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) {
int i, j;
for (j = 0; j < 4; ++j) {
for (i = 0; i < 4; ++i) {
STORE(i, j, DC);
}
}
@ -133,7 +136,8 @@ VP8Idct VP8TransformDCUV = TransformDCUV;
static void TransformWHT(const int16_t* in, int16_t* out) {
int tmp[16];
for (int i = 0; i < 4; ++i) {
int i;
for (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];
@ -143,7 +147,7 @@ static void TransformWHT(const int16_t* in, int16_t* out) {
tmp[4 + i] = a3 + a2;
tmp[12 + i] = a3 - a2;
}
for (int i = 0; i < 4; ++i) {
for (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];
@ -167,9 +171,11 @@ void (*VP8TransformWHT)(const int16_t* in, int16_t* out) = TransformWHT;
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) {
int x, y;
for (y = 0; y < size; ++y) {
const uint8_t* const clip = clip1 + 255 + dst[-1] - tl;
for (int x = 0; x < size; ++x) {
for (x = 0; x < size; ++x) {
dst[x] = clip[top[x]];
}
dst += BPS;
@ -183,27 +189,31 @@ static void TM16(uint8_t *dst) { TrueMotion(dst, 16); }
// 16x16
static void V16(uint8_t *dst) { // vertical
for (int j = 0; j < 16; ++j) {
int j;
for (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) {
int j;
for (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) {
int j;
for (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) {
int j;
for (j = 0; j < 16; ++j) {
DC += dst[-1 + j * BPS] + dst[j - BPS];
}
Put16(DC >> 5, dst);
@ -235,7 +245,8 @@ static void DC16NoTopLeft(uint8_t *dst) { // DC with no top and left samples
// 4x4
static inline void Put4(uint32_t v, uint8_t* dst) {
for (int i = 4; i > 0; --i) {
int i;
for (i = 4; i > 0; --i) {
*(uint32_t*)dst = v;
dst += BPS;
}
@ -270,7 +281,8 @@ static void H4(uint8_t *dst) { // horizontal
static void DC4(uint8_t *dst) { // DC
uint32_t dc = 4;
for (int i = 0; i < 4; ++i) {
int i;
for (i = 0; i < 4; ++i) {
dc += dst[i - BPS] + dst[-1 + i * BPS];
}
Put4((dc >> 3) * 0x01010101U, dst);
@ -402,13 +414,15 @@ static void HD4(uint8_t *dst) { // Horizontal-Down
// Chroma
static void V8uv(uint8_t *dst) { // vertical
for (int j = 0; j < 8; ++j) {
int j;
for (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) {
int j;
for (j = 0; j < 8; ++j) {
memset(dst, dst[-1], 8);
dst += BPS;
}
@ -416,36 +430,37 @@ static void H8uv(uint8_t *dst) { // horizontal
// helper for chroma-DC predictions
static inline void Put8x8uv(uint64_t v, uint8_t* dst) {
for (int j = 0; j < 8; ++j) {
int j;
for (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) {
int i;
for (i = 0; i < 8; ++i) {
dc0 += dst[i - BPS] + dst[-1 + i * BPS];
}
const uint64_t t = (dc0 >> 4) * 0x0101010101010101ULL;
Put8x8uv(t, dst);
Put8x8uv((uint64_t)((dc0 >> 4) * 0x0101010101010101ULL), dst);
}
static void DC8uvNoLeft(uint8_t *dst) { // DC with no left samples
int dc0 = 4;
for (int i = 0; i < 8; ++i) {
int i;
for (i = 0; i < 8; ++i) {
dc0 += dst[i - BPS];
}
const uint64_t v = (dc0 >> 3) * 0x0101010101010101ULL;
Put8x8uv(v, dst);
Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst);
}
static void DC8uvNoTop(uint8_t *dst) { // DC with no top samples
int dc0 = 4;
for (int i = 0; i < 8; ++i) {
int i;
for (i = 0; i < 8; ++i) {
dc0 += dst[-1 + i * BPS];
}
const uint64_t v = (dc0 >> 3) * 0x0101010101010101ULL;
Put8x8uv(v, dst);
Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst);
}
static void DC8uvNoTopLeft(uint8_t *dst) { // DC with nothing
@ -535,7 +550,8 @@ static inline int needs_filter2(const uint8_t* p, int step, int t, int 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) {
int i;
for (i = 0; i < 16; ++i) {
if (needs_filter(p + i, stride, thresh)) {
do_filter2(p + i, stride);
}
@ -543,7 +559,8 @@ static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
}
static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
for (int i = 0; i < 16; ++i) {
int i;
for (i = 0; i < 16; ++i) {
if (needs_filter(p + i * stride, 1, thresh)) {
do_filter2(p + i * stride, 1);
}
@ -551,14 +568,16 @@ static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
}
static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
for (int k = 3; k > 0; --k) {
int k;
for (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) {
int k;
for (k = 3; k > 0; --k) {
p += 4;
SimpleHFilter16(p, stride, thresh);
}
@ -609,7 +628,8 @@ static void HFilter16(uint8_t* p, int stride,
// 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) {
int k;
for (k = 3; k > 0; --k) {
p += 4 * stride;
FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
}
@ -617,7 +637,8 @@ static void VFilter16i(uint8_t* p, int stride,
static void HFilter16i(uint8_t* p, int stride,
int thresh, int ithresh, int hev_thresh) {
for (int k = 3; k > 0; --k) {
int k;
for (k = 3; k > 0; --k) {
p += 4;
FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
}

View File

@ -38,6 +38,8 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
+ top_size + info_size
+ yuv_size + coeffs_size
+ cache_size + ALIGN_MASK;
uint8_t* mem;
if (needed > dec->mem_size_) {
free(dec->mem_);
dec->mem_size_ = 0;
@ -48,7 +50,7 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
dec->mem_size_ = needed;
}
uint8_t* mem = (uint8_t*)dec->mem_;
mem = (uint8_t*)dec->mem_;
dec->intra_t_ = (uint8_t*)mem;
mem += intra_pred_mode_size;
@ -198,65 +200,71 @@ void VP8StoreBlock(VP8Decoder* const dec) {
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_,
{
// Transfer samples to row cache
int y;
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 (y = 0; y < 16; ++y) {
memcpy(ydst + y * dec->cache_y_stride_,
dec->yuv_b_ + Y_OFF + y * BPS, 16);
}
for (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_,
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) {
int mb_x;
for (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.
{
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_;
}
} 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);
}
if (y_end > io->height) {
y_end = io->height;
// 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);
}
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);
}
}
@ -294,18 +302,20 @@ void VP8ReconstructBlock(VP8Decoder* const dec) {
// 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) {
int j;
for (j = -1; j < 16; ++j) {
Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]);
}
for (int j = -1; j < 8; ++j) {
for (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) {
int j;
for (j = 0; j < 16; ++j) {
y_dst[j * BPS - 1] = 129;
}
for (int j = 0; j < 8; ++j) {
for (j = 0; j < 8; ++j) {
u_dst[j * BPS - 1] = 129;
v_dst[j * BPS - 1] = 129;
}
@ -314,90 +324,96 @@ void VP8ReconstructBlock(VP8Decoder* const dec) {
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;
const int16_t* coeffs = dec->coeffs_;
int n;
// 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));
}
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);
}
// 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);
// predict and add residuals
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));
}
}
}
} 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++) {
// 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 (n = 0; n < 16; n++) {
uint8_t* const dst = y_dst + kScan[n];
if (dec->non_zero_ac_ & (1 << 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 (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);
// 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);
}
}
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);
// 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 (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);
}
}
//-----------------------------------------------------------------------------

View File

@ -71,7 +71,9 @@ void VP8ParseQuant(VP8Decoder* const dec) {
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 i;
for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
int q;
if (hdr->use_segment_) {
q = hdr->quantizer_[i];
@ -86,17 +88,19 @@ void VP8ParseQuant(VP8Decoder* const dec) {
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)];
{
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->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)];
m->uv_mat_[0] = kDcTable[clip(q + dquv_ac, 117)];
m->uv_mat_[1] = kAcTable[clip(q + dquv_dc, 127)];
}
}
}

View File

@ -343,9 +343,11 @@ void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
memset(left, ymode, 4 * sizeof(left[0]));
} else {
uint8_t* modes = dec->imodes_;
for (int y = 0; y < 4; ++y) {
int y;
for (y = 0; y < 4; ++y) {
int ymode = left[y];
for (int x = 0; x < 4; ++x) {
int x;
for (x = 0; x < 4; ++x) {
const uint8_t* const prob = kBModesProba[top[x]][ymode];
#ifdef USE_GENERIC_TREE
// Generic tree-parsing
@ -531,10 +533,11 @@ static const uint8_t MVUpdateProba[2][NUM_MV_PROBAS] = {
// 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) {
int t, b, c, p;
for (t = 0; t < NUM_TYPES; ++t) {
for (b = 0; b < NUM_BANDS; ++b) {
for (c = 0; c < NUM_CTX; ++c) {
for (p = 0; p < NUM_PROBAS; ++p) {
if (VP8GetBit(br, CoeffsUpdateProba[t][b][c][p])) {
proba->coeffs_[t][b][c][p] = VP8GetValue(br, 8);
}

108
src/vp8.c
View File

@ -80,18 +80,19 @@ static int ParseSegmentHeader(VP8BitReader* br,
hdr->use_segment_ = VP8Get(br);
if (hdr->use_segment_) {
hdr->update_map_ = VP8Get(br);
const int update_data = VP8Get(br);
if (update_data) {
if (VP8Get(br)) { // update data
int s;
hdr->absolute_delta_ = VP8Get(br);
for (int s = 0; s < NUM_MB_SEGMENTS; ++s) {
for (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) {
for (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) {
int s;
for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
proba->segments_[s] = VP8Get(br) ? VP8GetValue(br, 8) : 255u;
}
}
@ -105,14 +106,19 @@ static int ParseSegmentHeader(VP8BitReader* br,
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;
int last_part;
uint32_t offset;
int p;
dec->num_parts_ = 1 << VP8GetValue(br, 2);
last_part = dec->num_parts_ - 1;
offset = last_part * 3;
if (size <= offset) {
return 0;
}
for (int p = 0; p < last_part; ++p) {
for (p = 0; p < last_part; ++p) {
const uint32_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
if (offset + psize > size) {
return 0;
@ -135,12 +141,13 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
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) {
int i;
for (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) {
for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
if (VP8Get(br)) {
hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6);
}
@ -150,7 +157,8 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
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 s;
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
int strength = dec->segment_hdr_.filter_strength_[s];
if (!dec->segment_hdr_.absolute_delta_) {
strength += hdr->level_;
@ -170,6 +178,12 @@ static inline uint32_t get_le32(const uint8_t* const data) {
// Topmost call
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
uint8_t* buf;
uint32_t buf_size;
VP8FrameHeader* frm_hdr;
VP8PictureHeader* pic_hdr;
VP8BitReader* br;
if (dec == NULL) {
return 0;
}
@ -177,25 +191,28 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
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;
buf = (uint8_t *)io->data;
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)) {
uint32_t riff_size;
uint32_t chunk_size;
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);
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);
chunk_size = get_le32(buf + 16);
if ((chunk_size > riff_size + 8) || (chunk_size & 1)) {
return VP8SetError(dec, 2, "RIFF: Inconsistent size information.");
}
@ -204,16 +221,18 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
}
// 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;
{
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_;
pic_hdr = &dec->pic_hdr_;
if (frm_hdr->key_frame_) {
// Paragraph 9.2
if (buf_size < 7) {
@ -239,7 +258,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
dec->segment_ = 0; // default for intra
}
VP8BitReader* const br = &dec->br_;
br = &dec->br_;
VP8Init(br, buf, buf_size);
buf += frm_hdr->partition_length_;
buf_size -= frm_hdr->partition_length_;
@ -333,7 +352,7 @@ static int GetCoeffs(VP8BitReader* const br,
if (!VP8GetBit(br, p[1])) {
p = prob[kBands[n]][0];
} else { // non zero coeff
int v;
int v, j;
if (!VP8GetBit(br, p[2])) {
p = prob[kBands[n]][1];
v = 1;
@ -352,11 +371,12 @@ static int GetCoeffs(VP8BitReader* const br,
v = 7 + 2 * VP8GetBit(br, 165) + VP8GetBit(br, 145);
}
} else {
uint8_t* tab;
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) {
for (tab = (uint8_t*)kCat3456[cat]; *tab; ++tab) {
v += v + VP8GetBit(br, *tab);
}
v += 3 + (8 << cat);
@ -364,7 +384,7 @@ static int GetCoeffs(VP8BitReader* const br,
}
p = prob[kBands[n]][2];
}
const int j = kZigzag[n - 1];
j = kZigzag[n - 1];
out[j] = VP8GetSigned(br, v) * dq[j > 0];
if (n == 16) break;
if (!VP8GetBit(br, p[0])) { // EOB
@ -394,6 +414,12 @@ static int ParseResiduals(VP8Decoder* const dec,
const VP8QuantMatrix* q = &dec->dqm_[dec->segment_];
int16_t* dst = dec->coeffs_;
VP8MB* const left_mb = dec->mb_info_ - 1;
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];
int x, y, ch;
memset(dst, 0, 384 * sizeof(*dst));
if (!dec->is_i4x4_) { // parse DC
int16_t dc[16] = { 0 };
@ -409,16 +435,12 @@ static int ParseResiduals(VP8Decoder* const dec,
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) {
for (y = 0; y < 4; ++y) {
int l = lnz[y];
for (int x = 0; x < 4; ++x) {
for (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);
@ -436,10 +458,10 @@ static int ParseResiduals(VP8Decoder* const dec,
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) {
for (ch = 0; ch < 4; ch += 2) {
for (y = 0; y < 2; ++y) {
int l = lnz[ch + y];
for (int x = 0; x < 2; ++x) {
for (x = 0; x < 2; ++x) {
const int ctx = l + tnz[ch + x];
const int last =
GetCoeffs(token_br, (Proba_t)dec->proba_.coeffs_[2],
@ -485,13 +507,17 @@ static void SendBlock(VP8Decoder* const dec, VP8Io* io) {
static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
int ok = 1;
VP8BitReader* const br = &dec->br_;
VP8BitReader* token_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;
memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
left->nz_ = 0;
left->dc_nz_ = 0;
VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
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_;

View File

@ -35,25 +35,28 @@ static inline uint32_t get_le32(const uint8_t* const data) {
}
// 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) {
static uint32_t 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
} else {
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;
}
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;
}
return chunk_size;
return *data_size_ptr;
}
//-----------------------------------------------------------------------------
@ -75,24 +78,32 @@ 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;
int j;
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) {
uint8_t* u_dst;
uint8_t* v_dst;
int uv_w;
for (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) {
u_dst = p->u + (io->mb_x / 2) + (io->mb_y / 2) * p->u_stride;
v_dst = p->v + (io->mb_x / 2) + (io->mb_y / 2) * p->v_stride;
uv_w = (mb_w + 1) / 2;
for (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) {
int i;
for (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) {
for (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)];
@ -120,11 +131,13 @@ static uint8_t* DecodeInto(CSP_MODE mode,
Params* params, int output_size,
int output_u_size, int output_v_size) {
VP8Decoder* dec = VP8New();
VP8Io io;
int ok = 1;
if (dec == NULL) {
return NULL;
}
VP8Io io;
VP8InitIo(&io);
io.data = data;
io.data_size = data_size;
@ -138,17 +151,17 @@ static uint8_t* DecodeInto(CSP_MODE mode,
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->stride >= io.width);
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);
@ -170,10 +183,12 @@ static uint8_t* DecodeInto(CSP_MODE mode,
uint8_t* WebPDecodeRGBInto(const uint8_t* data, uint32_t data_size,
uint8_t* output, int output_size,
int output_stride) {
Params params;
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);
@ -182,10 +197,12 @@ uint8_t* WebPDecodeRGBInto(const uint8_t* data, uint32_t data_size,
uint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size,
uint8_t* output, int output_size,
int output_stride) {
Params params;
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);
@ -194,10 +211,12 @@ uint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size,
uint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size,
uint8_t* output, int output_size,
int output_stride) {
Params params;
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);
@ -206,10 +225,12 @@ uint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size,
uint8_t* WebPDecodeBGRAInto(const uint8_t* data, uint32_t data_size,
uint8_t* output, int output_size,
int output_stride) {
Params params;
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);
@ -219,10 +240,12 @@ 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) {
Params params;
if (luma == NULL) {
return NULL;
}
Params params;
params.output = luma;
params.stride = luma_stride;
params.u = u;
@ -237,7 +260,13 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_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;
int w, h, stride;
int uv_size = 0;
int uv_stride = 0;
int size;
uint8_t* output;
Params params = { 0 };
if (!WebPGetInfo(data, data_size, &w, &h)) {
return NULL;
}
@ -245,21 +274,21 @@ static uint8_t* Decode(CSP_MODE mode, const uint8_t* data, uint32_t data_size,
if (height) *height = h;
// initialize output buffer, now that dimensions are known.
int stride = (mode == MODE_RGB || mode == MODE_BGR) ? 3 * w
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;
size = stride * h;
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);
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) {
@ -325,35 +354,35 @@ int WebPGetInfo(const uint8_t* data, uint32_t data_size,
// 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.
}
} else {
const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16);
const int key_frame = !(bits & 1);
const int w = ((data[7] << 8) | data[6]) & 0x3fff;
const int h = ((data[9] << 8) | data[8]) & 0x3fff;
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;
}
if (!key_frame) { // Not a keyframe.
return 0;
}
return 1;
if (((bits >> 1) & 7) > 3) {
return 0; // unknown profile
}
if (!((bits >> 4) & 1)) {
return 0; // first frame is invisible!
}
if (((bits >> 5)) >= chunk_size) { // partition_length
return 0; // inconsistent size information.
}
if (width) {
*width = w;
}
if (height) {
*height = h;
}
return 1;
}
}
#if defined(__cplusplus) || defined(c_plusplus)

View File

@ -24,18 +24,19 @@ uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
static int done = 0;
void VP8YUVInit() {
int i;
if (done) {
return;
}
for (int i = 0; i < 256; ++i) {
for (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;
for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
VP8kClip[i - YUV_RANGE_MIN] = (k < 0) ? 0 : (k > 255) ? 255 : k;
}
done = 1;
}