mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-19 20:08:28 +01:00
convert to ANSI-C
This commit is contained in:
parent
c3f41cb47e
commit
c8d15efa12
4
AUTHORS
4
AUTHORS
@ -1,3 +1,5 @@
|
||||
Main stuff:
|
||||
Initial release:
|
||||
- Pascal Massimino (pascal.massimino@gmail.com)
|
||||
|
||||
Contributors:
|
||||
- pierre.php@gmail.com (ansi-C port)
|
||||
|
@ -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
201
configure
vendored
@ -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"
|
||||
|
@ -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
|
||||
|
93
src/dsp.c
93
src/dsp.c
@ -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);
|
||||
}
|
||||
|
44
src/frame.c
44
src/frame.c
@ -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,29 +200,34 @@ 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
|
||||
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 (int y = 0; y < 16; ++y) {
|
||||
for (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) {
|
||||
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_,
|
||||
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_;
|
||||
@ -259,6 +266,7 @@ void VP8FilterRow(VP8Decoder* const dec, VP8Io* io) {
|
||||
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,11 +324,14 @@ 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;
|
||||
|
||||
if (dec->mb_y_ > 0) {
|
||||
memcpy(y_dst - BPS, top_y, 16);
|
||||
memcpy(u_dst - BPS, top_u, 8);
|
||||
@ -332,9 +345,10 @@ void VP8ReconstructBlock(VP8Decoder* const dec) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
@ -346,7 +360,7 @@ void VP8ReconstructBlock(VP8Decoder* const dec) {
|
||||
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++) {
|
||||
for (n = 0; n < 16; n++) {
|
||||
uint8_t* const dst = y_dst + kScan[n];
|
||||
VP8PredLuma4[dec->imodes_[n]](dst);
|
||||
if (dec->non_zero_ & (1 << n)) {
|
||||
@ -359,7 +373,7 @@ void VP8ReconstructBlock(VP8Decoder* const dec) {
|
||||
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++) {
|
||||
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);
|
||||
@ -369,7 +383,7 @@ void VP8ReconstructBlock(VP8Decoder* const dec) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Chroma
|
||||
const int pred_func = CheckMode(dec, dec->uvmode_);
|
||||
VP8PredChroma8[pred_func](u_dst);
|
||||
@ -399,6 +413,8 @@ void VP8ReconstructBlock(VP8Decoder* const dec) {
|
||||
memcpy(top_v, v_dst + 7 * BPS, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -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,6 +88,7 @@ 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)];
|
||||
@ -99,6 +102,7 @@ void VP8ParseQuant(VP8Decoder* const dec) {
|
||||
m->uv_mat_[1] = kAcTable[clip(q + dquv_dc, 127)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
15
src/tree.c
15
src/tree.c
@ -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);
|
||||
}
|
||||
|
94
src/vp8.c
94
src/vp8.c
@ -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,7 +221,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
}
|
||||
|
||||
// Paragraph 9.1
|
||||
VP8FrameHeader* const frm_hdr = &dec->frm_hdr_;
|
||||
{
|
||||
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;
|
||||
@ -212,8 +230,9 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
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_;
|
||||
|
||||
|
95
src/webp.c
95
src/webp.c
@ -35,12 +35,13 @@ 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
|
||||
@ -55,6 +56,8 @@ static int CheckRIFFHeader(const uint8_t** data_ptr, uint32_t *data_size_ptr) {
|
||||
}
|
||||
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, ¶ms, 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, ¶ms, 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, ¶ms, 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, ¶ms, 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,27 +354,26 @@ 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.
|
||||
}
|
||||
} 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;
|
||||
|
||||
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) {
|
||||
|
||||
if (((bits >> 1) & 7) > 3) {
|
||||
return 0; // unknown profile
|
||||
}
|
||||
if (!show_frame) {
|
||||
if (!((bits >> 4) & 1)) {
|
||||
return 0; // first frame is invisible!
|
||||
}
|
||||
if (partition_length >= chunk_size) {
|
||||
if (((bits >> 5)) >= chunk_size) { // partition_length
|
||||
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;
|
||||
}
|
||||
@ -355,6 +383,7 @@ int WebPGetInfo(const uint8_t* data, uint32_t data_size,
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} // extern "C"
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user