Built SDL2_image and _mixer static
This commit is contained in:
42
libsdl2_image/external/libwebp-1.0.2/src/enc/Makefile.am
vendored
Normal file
42
libsdl2_image/external/libwebp-1.0.2/src/enc/Makefile.am
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
|
||||
noinst_LTLIBRARIES = libwebpencode.la
|
||||
|
||||
libwebpencode_la_SOURCES =
|
||||
libwebpencode_la_SOURCES += alpha_enc.c
|
||||
libwebpencode_la_SOURCES += analysis_enc.c
|
||||
libwebpencode_la_SOURCES += backward_references_cost_enc.c
|
||||
libwebpencode_la_SOURCES += backward_references_enc.c
|
||||
libwebpencode_la_SOURCES += backward_references_enc.h
|
||||
libwebpencode_la_SOURCES += config_enc.c
|
||||
libwebpencode_la_SOURCES += cost_enc.c
|
||||
libwebpencode_la_SOURCES += cost_enc.h
|
||||
libwebpencode_la_SOURCES += filter_enc.c
|
||||
libwebpencode_la_SOURCES += frame_enc.c
|
||||
libwebpencode_la_SOURCES += histogram_enc.c
|
||||
libwebpencode_la_SOURCES += histogram_enc.h
|
||||
libwebpencode_la_SOURCES += iterator_enc.c
|
||||
libwebpencode_la_SOURCES += near_lossless_enc.c
|
||||
libwebpencode_la_SOURCES += picture_enc.c
|
||||
libwebpencode_la_SOURCES += picture_csp_enc.c
|
||||
libwebpencode_la_SOURCES += picture_psnr_enc.c
|
||||
libwebpencode_la_SOURCES += picture_rescale_enc.c
|
||||
libwebpencode_la_SOURCES += picture_tools_enc.c
|
||||
libwebpencode_la_SOURCES += predictor_enc.c
|
||||
libwebpencode_la_SOURCES += quant_enc.c
|
||||
libwebpencode_la_SOURCES += syntax_enc.c
|
||||
libwebpencode_la_SOURCES += token_enc.c
|
||||
libwebpencode_la_SOURCES += tree_enc.c
|
||||
libwebpencode_la_SOURCES += vp8i_enc.h
|
||||
libwebpencode_la_SOURCES += vp8l_enc.c
|
||||
libwebpencode_la_SOURCES += vp8li_enc.h
|
||||
libwebpencode_la_SOURCES += webp_enc.c
|
||||
|
||||
libwebpencodeinclude_HEADERS =
|
||||
libwebpencodeinclude_HEADERS += ../webp/encode.h
|
||||
libwebpencodeinclude_HEADERS += ../webp/types.h
|
||||
noinst_HEADERS =
|
||||
noinst_HEADERS += ../webp/format_constants.h
|
||||
|
||||
libwebpencode_la_LDFLAGS = -lm
|
||||
libwebpencode_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libwebpencodeincludedir = $(includedir)/webp
|
||||
960
libsdl2_image/external/libwebp-1.0.2/src/enc/Makefile.in
vendored
Normal file
960
libsdl2_image/external/libwebp-1.0.2/src/enc/Makefile.in
vendored
Normal file
@ -0,0 +1,960 @@
|
||||
# Makefile.in generated by automake 1.16 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2018 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = src/enc
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(libwebpencodeinclude_HEADERS) \
|
||||
$(noinst_HEADERS) $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/src/webp/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||
libwebpencode_la_LIBADD =
|
||||
am_libwebpencode_la_OBJECTS = libwebpencode_la-alpha_enc.lo \
|
||||
libwebpencode_la-analysis_enc.lo \
|
||||
libwebpencode_la-backward_references_cost_enc.lo \
|
||||
libwebpencode_la-backward_references_enc.lo \
|
||||
libwebpencode_la-config_enc.lo libwebpencode_la-cost_enc.lo \
|
||||
libwebpencode_la-filter_enc.lo libwebpencode_la-frame_enc.lo \
|
||||
libwebpencode_la-histogram_enc.lo \
|
||||
libwebpencode_la-iterator_enc.lo \
|
||||
libwebpencode_la-near_lossless_enc.lo \
|
||||
libwebpencode_la-picture_enc.lo \
|
||||
libwebpencode_la-picture_csp_enc.lo \
|
||||
libwebpencode_la-picture_psnr_enc.lo \
|
||||
libwebpencode_la-picture_rescale_enc.lo \
|
||||
libwebpencode_la-picture_tools_enc.lo \
|
||||
libwebpencode_la-predictor_enc.lo \
|
||||
libwebpencode_la-quant_enc.lo libwebpencode_la-syntax_enc.lo \
|
||||
libwebpencode_la-token_enc.lo libwebpencode_la-tree_enc.lo \
|
||||
libwebpencode_la-vp8l_enc.lo libwebpencode_la-webp_enc.lo
|
||||
libwebpencode_la_OBJECTS = $(am_libwebpencode_la_OBJECTS)
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am__v_lt_1 =
|
||||
libwebpencode_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
|
||||
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
|
||||
$(AM_CFLAGS) $(CFLAGS) $(libwebpencode_la_LDFLAGS) $(LDFLAGS) \
|
||||
-o $@
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src/webp
|
||||
depcomp = $(SHELL) $(top_srcdir)/../../depcomp
|
||||
am__maybe_remake_depfiles = depfiles
|
||||
am__depfiles_remade = ./$(DEPDIR)/libwebpencode_la-alpha_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-analysis_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-backward_references_cost_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-backward_references_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-config_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-cost_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-filter_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-frame_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-histogram_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-iterator_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-near_lossless_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-picture_csp_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-picture_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-picture_psnr_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-picture_rescale_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-picture_tools_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-predictor_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-quant_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-syntax_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-token_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-tree_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-vp8l_enc.Plo \
|
||||
./$(DEPDIR)/libwebpencode_la-webp_enc.Plo
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(libwebpencode_la_SOURCES)
|
||||
DIST_SOURCES = $(libwebpencode_la_SOURCES)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(libwebpencodeincludedir)"
|
||||
HEADERS = $(libwebpencodeinclude_HEADERS) $(noinst_HEADERS)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../../depcomp
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_CFLAGS = @AM_CFLAGS@
|
||||
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GIF_INCLUDES = @GIF_INCLUDES@
|
||||
GIF_LIBS = @GIF_LIBS@
|
||||
GL_INCLUDES = @GL_INCLUDES@
|
||||
GL_LIBS = @GL_LIBS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
JPEG_INCLUDES = @JPEG_INCLUDES@
|
||||
JPEG_LIBS = @JPEG_LIBS@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBPNG_CONFIG = @LIBPNG_CONFIG@
|
||||
LIBS = @LIBS@
|
||||
LIBSDL_CONFIG = @LIBSDL_CONFIG@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NEON_FLAGS = @NEON_FLAGS@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PNG_INCLUDES = @PNG_INCLUDES@
|
||||
PNG_LIBS = @PNG_LIBS@
|
||||
PTHREAD_CC = @PTHREAD_CC@
|
||||
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
|
||||
PTHREAD_LIBS = @PTHREAD_LIBS@
|
||||
RANLIB = @RANLIB@
|
||||
SDL_INCLUDES = @SDL_INCLUDES@
|
||||
SDL_LIBS = @SDL_LIBS@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SSE2_FLAGS = @SSE2_FLAGS@
|
||||
SSE41_FLAGS = @SSE41_FLAGS@
|
||||
STRIP = @STRIP@
|
||||
TIFF_INCLUDES = @TIFF_INCLUDES@
|
||||
TIFF_LIBS = @TIFF_LIBS@
|
||||
USE_SWAP_16BIT_CSP = @USE_SWAP_16BIT_CSP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
ax_pthread_config = @ax_pthread_config@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
pkgconfigdir = @pkgconfigdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
noinst_LTLIBRARIES = libwebpencode.la
|
||||
libwebpencode_la_SOURCES = alpha_enc.c analysis_enc.c \
|
||||
backward_references_cost_enc.c backward_references_enc.c \
|
||||
backward_references_enc.h config_enc.c cost_enc.c cost_enc.h \
|
||||
filter_enc.c frame_enc.c histogram_enc.c histogram_enc.h \
|
||||
iterator_enc.c near_lossless_enc.c picture_enc.c \
|
||||
picture_csp_enc.c picture_psnr_enc.c picture_rescale_enc.c \
|
||||
picture_tools_enc.c predictor_enc.c quant_enc.c syntax_enc.c \
|
||||
token_enc.c tree_enc.c vp8i_enc.h vp8l_enc.c vp8li_enc.h \
|
||||
webp_enc.c
|
||||
libwebpencodeinclude_HEADERS = ../webp/encode.h ../webp/types.h
|
||||
noinst_HEADERS = ../webp/format_constants.h
|
||||
libwebpencode_la_LDFLAGS = -lm
|
||||
libwebpencode_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libwebpencodeincludedir = $(includedir)/webp
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/enc/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign src/enc/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstLTLIBRARIES:
|
||||
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
|
||||
@list='$(noinst_LTLIBRARIES)'; \
|
||||
locs=`for p in $$list; do echo $$p; done | \
|
||||
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
|
||||
sort -u`; \
|
||||
test -z "$$locs" || { \
|
||||
echo rm -f $${locs}; \
|
||||
rm -f $${locs}; \
|
||||
}
|
||||
|
||||
libwebpencode.la: $(libwebpencode_la_OBJECTS) $(libwebpencode_la_DEPENDENCIES) $(EXTRA_libwebpencode_la_DEPENDENCIES)
|
||||
$(AM_V_CCLD)$(libwebpencode_la_LINK) $(libwebpencode_la_OBJECTS) $(libwebpencode_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-alpha_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-analysis_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-backward_references_cost_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-backward_references_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-config_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-cost_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-filter_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-frame_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-histogram_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-iterator_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-near_lossless_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-picture_csp_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-picture_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-picture_psnr_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-picture_rescale_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-picture_tools_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-predictor_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-quant_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-syntax_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-token_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-tree_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-vp8l_enc.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebpencode_la-webp_enc.Plo@am__quote@ # am--include-marker
|
||||
|
||||
$(am__depfiles_remade):
|
||||
@$(MKDIR_P) $(@D)
|
||||
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
|
||||
|
||||
am--depfiles: $(am__depfiles_remade)
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
libwebpencode_la-alpha_enc.lo: alpha_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-alpha_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-alpha_enc.Tpo -c -o libwebpencode_la-alpha_enc.lo `test -f 'alpha_enc.c' || echo '$(srcdir)/'`alpha_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-alpha_enc.Tpo $(DEPDIR)/libwebpencode_la-alpha_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='alpha_enc.c' object='libwebpencode_la-alpha_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-alpha_enc.lo `test -f 'alpha_enc.c' || echo '$(srcdir)/'`alpha_enc.c
|
||||
|
||||
libwebpencode_la-analysis_enc.lo: analysis_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-analysis_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-analysis_enc.Tpo -c -o libwebpencode_la-analysis_enc.lo `test -f 'analysis_enc.c' || echo '$(srcdir)/'`analysis_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-analysis_enc.Tpo $(DEPDIR)/libwebpencode_la-analysis_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='analysis_enc.c' object='libwebpencode_la-analysis_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-analysis_enc.lo `test -f 'analysis_enc.c' || echo '$(srcdir)/'`analysis_enc.c
|
||||
|
||||
libwebpencode_la-backward_references_cost_enc.lo: backward_references_cost_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-backward_references_cost_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-backward_references_cost_enc.Tpo -c -o libwebpencode_la-backward_references_cost_enc.lo `test -f 'backward_references_cost_enc.c' || echo '$(srcdir)/'`backward_references_cost_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-backward_references_cost_enc.Tpo $(DEPDIR)/libwebpencode_la-backward_references_cost_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backward_references_cost_enc.c' object='libwebpencode_la-backward_references_cost_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-backward_references_cost_enc.lo `test -f 'backward_references_cost_enc.c' || echo '$(srcdir)/'`backward_references_cost_enc.c
|
||||
|
||||
libwebpencode_la-backward_references_enc.lo: backward_references_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-backward_references_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-backward_references_enc.Tpo -c -o libwebpencode_la-backward_references_enc.lo `test -f 'backward_references_enc.c' || echo '$(srcdir)/'`backward_references_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-backward_references_enc.Tpo $(DEPDIR)/libwebpencode_la-backward_references_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backward_references_enc.c' object='libwebpencode_la-backward_references_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-backward_references_enc.lo `test -f 'backward_references_enc.c' || echo '$(srcdir)/'`backward_references_enc.c
|
||||
|
||||
libwebpencode_la-config_enc.lo: config_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-config_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-config_enc.Tpo -c -o libwebpencode_la-config_enc.lo `test -f 'config_enc.c' || echo '$(srcdir)/'`config_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-config_enc.Tpo $(DEPDIR)/libwebpencode_la-config_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='config_enc.c' object='libwebpencode_la-config_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-config_enc.lo `test -f 'config_enc.c' || echo '$(srcdir)/'`config_enc.c
|
||||
|
||||
libwebpencode_la-cost_enc.lo: cost_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-cost_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-cost_enc.Tpo -c -o libwebpencode_la-cost_enc.lo `test -f 'cost_enc.c' || echo '$(srcdir)/'`cost_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-cost_enc.Tpo $(DEPDIR)/libwebpencode_la-cost_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cost_enc.c' object='libwebpencode_la-cost_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-cost_enc.lo `test -f 'cost_enc.c' || echo '$(srcdir)/'`cost_enc.c
|
||||
|
||||
libwebpencode_la-filter_enc.lo: filter_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-filter_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-filter_enc.Tpo -c -o libwebpencode_la-filter_enc.lo `test -f 'filter_enc.c' || echo '$(srcdir)/'`filter_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-filter_enc.Tpo $(DEPDIR)/libwebpencode_la-filter_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='filter_enc.c' object='libwebpencode_la-filter_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-filter_enc.lo `test -f 'filter_enc.c' || echo '$(srcdir)/'`filter_enc.c
|
||||
|
||||
libwebpencode_la-frame_enc.lo: frame_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-frame_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-frame_enc.Tpo -c -o libwebpencode_la-frame_enc.lo `test -f 'frame_enc.c' || echo '$(srcdir)/'`frame_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-frame_enc.Tpo $(DEPDIR)/libwebpencode_la-frame_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='frame_enc.c' object='libwebpencode_la-frame_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-frame_enc.lo `test -f 'frame_enc.c' || echo '$(srcdir)/'`frame_enc.c
|
||||
|
||||
libwebpencode_la-histogram_enc.lo: histogram_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-histogram_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-histogram_enc.Tpo -c -o libwebpencode_la-histogram_enc.lo `test -f 'histogram_enc.c' || echo '$(srcdir)/'`histogram_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-histogram_enc.Tpo $(DEPDIR)/libwebpencode_la-histogram_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='histogram_enc.c' object='libwebpencode_la-histogram_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-histogram_enc.lo `test -f 'histogram_enc.c' || echo '$(srcdir)/'`histogram_enc.c
|
||||
|
||||
libwebpencode_la-iterator_enc.lo: iterator_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-iterator_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-iterator_enc.Tpo -c -o libwebpencode_la-iterator_enc.lo `test -f 'iterator_enc.c' || echo '$(srcdir)/'`iterator_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-iterator_enc.Tpo $(DEPDIR)/libwebpencode_la-iterator_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iterator_enc.c' object='libwebpencode_la-iterator_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-iterator_enc.lo `test -f 'iterator_enc.c' || echo '$(srcdir)/'`iterator_enc.c
|
||||
|
||||
libwebpencode_la-near_lossless_enc.lo: near_lossless_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-near_lossless_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-near_lossless_enc.Tpo -c -o libwebpencode_la-near_lossless_enc.lo `test -f 'near_lossless_enc.c' || echo '$(srcdir)/'`near_lossless_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-near_lossless_enc.Tpo $(DEPDIR)/libwebpencode_la-near_lossless_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='near_lossless_enc.c' object='libwebpencode_la-near_lossless_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-near_lossless_enc.lo `test -f 'near_lossless_enc.c' || echo '$(srcdir)/'`near_lossless_enc.c
|
||||
|
||||
libwebpencode_la-picture_enc.lo: picture_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-picture_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-picture_enc.Tpo -c -o libwebpencode_la-picture_enc.lo `test -f 'picture_enc.c' || echo '$(srcdir)/'`picture_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-picture_enc.Tpo $(DEPDIR)/libwebpencode_la-picture_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='picture_enc.c' object='libwebpencode_la-picture_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-picture_enc.lo `test -f 'picture_enc.c' || echo '$(srcdir)/'`picture_enc.c
|
||||
|
||||
libwebpencode_la-picture_csp_enc.lo: picture_csp_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-picture_csp_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-picture_csp_enc.Tpo -c -o libwebpencode_la-picture_csp_enc.lo `test -f 'picture_csp_enc.c' || echo '$(srcdir)/'`picture_csp_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-picture_csp_enc.Tpo $(DEPDIR)/libwebpencode_la-picture_csp_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='picture_csp_enc.c' object='libwebpencode_la-picture_csp_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-picture_csp_enc.lo `test -f 'picture_csp_enc.c' || echo '$(srcdir)/'`picture_csp_enc.c
|
||||
|
||||
libwebpencode_la-picture_psnr_enc.lo: picture_psnr_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-picture_psnr_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-picture_psnr_enc.Tpo -c -o libwebpencode_la-picture_psnr_enc.lo `test -f 'picture_psnr_enc.c' || echo '$(srcdir)/'`picture_psnr_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-picture_psnr_enc.Tpo $(DEPDIR)/libwebpencode_la-picture_psnr_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='picture_psnr_enc.c' object='libwebpencode_la-picture_psnr_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-picture_psnr_enc.lo `test -f 'picture_psnr_enc.c' || echo '$(srcdir)/'`picture_psnr_enc.c
|
||||
|
||||
libwebpencode_la-picture_rescale_enc.lo: picture_rescale_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-picture_rescale_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-picture_rescale_enc.Tpo -c -o libwebpencode_la-picture_rescale_enc.lo `test -f 'picture_rescale_enc.c' || echo '$(srcdir)/'`picture_rescale_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-picture_rescale_enc.Tpo $(DEPDIR)/libwebpencode_la-picture_rescale_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='picture_rescale_enc.c' object='libwebpencode_la-picture_rescale_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-picture_rescale_enc.lo `test -f 'picture_rescale_enc.c' || echo '$(srcdir)/'`picture_rescale_enc.c
|
||||
|
||||
libwebpencode_la-picture_tools_enc.lo: picture_tools_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-picture_tools_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-picture_tools_enc.Tpo -c -o libwebpencode_la-picture_tools_enc.lo `test -f 'picture_tools_enc.c' || echo '$(srcdir)/'`picture_tools_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-picture_tools_enc.Tpo $(DEPDIR)/libwebpencode_la-picture_tools_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='picture_tools_enc.c' object='libwebpencode_la-picture_tools_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-picture_tools_enc.lo `test -f 'picture_tools_enc.c' || echo '$(srcdir)/'`picture_tools_enc.c
|
||||
|
||||
libwebpencode_la-predictor_enc.lo: predictor_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-predictor_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-predictor_enc.Tpo -c -o libwebpencode_la-predictor_enc.lo `test -f 'predictor_enc.c' || echo '$(srcdir)/'`predictor_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-predictor_enc.Tpo $(DEPDIR)/libwebpencode_la-predictor_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='predictor_enc.c' object='libwebpencode_la-predictor_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-predictor_enc.lo `test -f 'predictor_enc.c' || echo '$(srcdir)/'`predictor_enc.c
|
||||
|
||||
libwebpencode_la-quant_enc.lo: quant_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-quant_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-quant_enc.Tpo -c -o libwebpencode_la-quant_enc.lo `test -f 'quant_enc.c' || echo '$(srcdir)/'`quant_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-quant_enc.Tpo $(DEPDIR)/libwebpencode_la-quant_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='quant_enc.c' object='libwebpencode_la-quant_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-quant_enc.lo `test -f 'quant_enc.c' || echo '$(srcdir)/'`quant_enc.c
|
||||
|
||||
libwebpencode_la-syntax_enc.lo: syntax_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-syntax_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-syntax_enc.Tpo -c -o libwebpencode_la-syntax_enc.lo `test -f 'syntax_enc.c' || echo '$(srcdir)/'`syntax_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-syntax_enc.Tpo $(DEPDIR)/libwebpencode_la-syntax_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='syntax_enc.c' object='libwebpencode_la-syntax_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-syntax_enc.lo `test -f 'syntax_enc.c' || echo '$(srcdir)/'`syntax_enc.c
|
||||
|
||||
libwebpencode_la-token_enc.lo: token_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-token_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-token_enc.Tpo -c -o libwebpencode_la-token_enc.lo `test -f 'token_enc.c' || echo '$(srcdir)/'`token_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-token_enc.Tpo $(DEPDIR)/libwebpencode_la-token_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='token_enc.c' object='libwebpencode_la-token_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-token_enc.lo `test -f 'token_enc.c' || echo '$(srcdir)/'`token_enc.c
|
||||
|
||||
libwebpencode_la-tree_enc.lo: tree_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-tree_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-tree_enc.Tpo -c -o libwebpencode_la-tree_enc.lo `test -f 'tree_enc.c' || echo '$(srcdir)/'`tree_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-tree_enc.Tpo $(DEPDIR)/libwebpencode_la-tree_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tree_enc.c' object='libwebpencode_la-tree_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-tree_enc.lo `test -f 'tree_enc.c' || echo '$(srcdir)/'`tree_enc.c
|
||||
|
||||
libwebpencode_la-vp8l_enc.lo: vp8l_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-vp8l_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-vp8l_enc.Tpo -c -o libwebpencode_la-vp8l_enc.lo `test -f 'vp8l_enc.c' || echo '$(srcdir)/'`vp8l_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-vp8l_enc.Tpo $(DEPDIR)/libwebpencode_la-vp8l_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vp8l_enc.c' object='libwebpencode_la-vp8l_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-vp8l_enc.lo `test -f 'vp8l_enc.c' || echo '$(srcdir)/'`vp8l_enc.c
|
||||
|
||||
libwebpencode_la-webp_enc.lo: webp_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwebpencode_la-webp_enc.lo -MD -MP -MF $(DEPDIR)/libwebpencode_la-webp_enc.Tpo -c -o libwebpencode_la-webp_enc.lo `test -f 'webp_enc.c' || echo '$(srcdir)/'`webp_enc.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libwebpencode_la-webp_enc.Tpo $(DEPDIR)/libwebpencode_la-webp_enc.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='webp_enc.c' object='libwebpencode_la-webp_enc.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwebpencode_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwebpencode_la-webp_enc.lo `test -f 'webp_enc.c' || echo '$(srcdir)/'`webp_enc.c
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
install-libwebpencodeincludeHEADERS: $(libwebpencodeinclude_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(libwebpencodeinclude_HEADERS)'; test -n "$(libwebpencodeincludedir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(libwebpencodeincludedir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(libwebpencodeincludedir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libwebpencodeincludedir)'"; \
|
||||
$(INSTALL_HEADER) $$files "$(DESTDIR)$(libwebpencodeincludedir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-libwebpencodeincludeHEADERS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(libwebpencodeinclude_HEADERS)'; test -n "$(libwebpencodeincludedir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(libwebpencodeincludedir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES) $(HEADERS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libwebpencodeincludedir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-alpha_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-analysis_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-backward_references_cost_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-backward_references_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-config_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-cost_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-filter_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-frame_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-histogram_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-iterator_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-near_lossless_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_csp_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_psnr_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_rescale_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_tools_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-predictor_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-quant_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-syntax_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-token_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-tree_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-vp8l_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-webp_enc.Plo
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-libwebpencodeincludeHEADERS
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-alpha_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-analysis_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-backward_references_cost_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-backward_references_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-config_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-cost_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-filter_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-frame_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-histogram_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-iterator_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-near_lossless_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_csp_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_psnr_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_rescale_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-picture_tools_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-predictor_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-quant_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-syntax_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-token_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-tree_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-vp8l_enc.Plo
|
||||
-rm -f ./$(DEPDIR)/libwebpencode_la-webp_enc.Plo
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-libwebpencodeincludeHEADERS
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
|
||||
clean-generic clean-libtool clean-noinstLTLIBRARIES \
|
||||
cscopelist-am ctags ctags-am distclean distclean-compile \
|
||||
distclean-generic distclean-libtool distclean-tags distdir dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-info install-info-am \
|
||||
install-libwebpencodeincludeHEADERS install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am \
|
||||
uninstall-libwebpencodeincludeHEADERS
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
443
libsdl2_image/external/libwebp-1.0.2/src/enc/alpha_enc.c
vendored
Normal file
443
libsdl2_image/external/libwebp-1.0.2/src/enc/alpha_enc.c
vendored
Normal file
@ -0,0 +1,443 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Alpha-plane compression.
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/utils/filters_utils.h"
|
||||
#include "src/utils/quant_levels_utils.h"
|
||||
#include "src/utils/utils.h"
|
||||
#include "src/webp/format_constants.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Encodes the given alpha data via specified compression method 'method'.
|
||||
// The pre-processing (quantization) is performed if 'quality' is less than 100.
|
||||
// For such cases, the encoding is lossy. The valid range is [0, 100] for
|
||||
// 'quality' and [0, 1] for 'method':
|
||||
// 'method = 0' - No compression;
|
||||
// 'method = 1' - Use lossless coder on the alpha plane only
|
||||
// 'filter' values [0, 4] correspond to prediction modes none, horizontal,
|
||||
// vertical & gradient filters. The prediction mode 4 will try all the
|
||||
// prediction modes 0 to 3 and pick the best one.
|
||||
// 'effort_level': specifies how much effort must be spent to try and reduce
|
||||
// the compressed output size. In range 0 (quick) to 6 (slow).
|
||||
//
|
||||
// 'output' corresponds to the buffer containing compressed alpha data.
|
||||
// This buffer is allocated by this method and caller should call
|
||||
// WebPSafeFree(*output) when done.
|
||||
// 'output_size' corresponds to size of this compressed alpha buffer.
|
||||
//
|
||||
// Returns 1 on successfully encoding the alpha and
|
||||
// 0 if either:
|
||||
// invalid quality or method, or
|
||||
// memory allocation for the compressed data fails.
|
||||
|
||||
#include "src/enc/vp8li_enc.h"
|
||||
|
||||
static int EncodeLossless(const uint8_t* const data, int width, int height,
|
||||
int effort_level, // in [0..6] range
|
||||
int use_quality_100, VP8LBitWriter* const bw,
|
||||
WebPAuxStats* const stats) {
|
||||
int ok = 0;
|
||||
WebPConfig config;
|
||||
WebPPicture picture;
|
||||
|
||||
WebPPictureInit(&picture);
|
||||
picture.width = width;
|
||||
picture.height = height;
|
||||
picture.use_argb = 1;
|
||||
picture.stats = stats;
|
||||
if (!WebPPictureAlloc(&picture)) return 0;
|
||||
|
||||
// Transfer the alpha values to the green channel.
|
||||
WebPDispatchAlphaToGreen(data, width, picture.width, picture.height,
|
||||
picture.argb, picture.argb_stride);
|
||||
|
||||
WebPConfigInit(&config);
|
||||
config.lossless = 1;
|
||||
// Enable exact, or it would alter RGB values of transparent alpha, which is
|
||||
// normally OK but not here since we are not encoding the input image but an
|
||||
// internal encoding-related image containing necessary exact information in
|
||||
// RGB channels.
|
||||
config.exact = 1;
|
||||
config.method = effort_level; // impact is very small
|
||||
// Set a low default quality for encoding alpha. Ensure that Alpha quality at
|
||||
// lower methods (3 and below) is less than the threshold for triggering
|
||||
// costly 'BackwardReferencesTraceBackwards'.
|
||||
// If the alpha quality is set to 100 and the method to 6, allow for a high
|
||||
// lossless quality to trigger the cruncher.
|
||||
config.quality =
|
||||
(use_quality_100 && effort_level == 6) ? 100 : 8.f * effort_level;
|
||||
assert(config.quality >= 0 && config.quality <= 100.f);
|
||||
|
||||
// TODO(urvang): Temporary fix to avoid generating images that trigger
|
||||
// a decoder bug related to alpha with color cache.
|
||||
// See: https://code.google.com/p/webp/issues/detail?id=239
|
||||
// Need to re-enable this later.
|
||||
ok = (VP8LEncodeStream(&config, &picture, bw, 0 /*use_cache*/) == VP8_ENC_OK);
|
||||
WebPPictureFree(&picture);
|
||||
ok = ok && !bw->error_;
|
||||
if (!ok) {
|
||||
VP8LBitWriterWipeOut(bw);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Small struct to hold the result of a filter mode compression attempt.
|
||||
typedef struct {
|
||||
size_t score;
|
||||
VP8BitWriter bw;
|
||||
WebPAuxStats stats;
|
||||
} FilterTrial;
|
||||
|
||||
// This function always returns an initialized 'bw' object, even upon error.
|
||||
static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
|
||||
int method, int filter, int reduce_levels,
|
||||
int effort_level, // in [0..6] range
|
||||
uint8_t* const tmp_alpha,
|
||||
FilterTrial* result) {
|
||||
int ok = 0;
|
||||
const uint8_t* alpha_src;
|
||||
WebPFilterFunc filter_func;
|
||||
uint8_t header;
|
||||
const size_t data_size = width * height;
|
||||
const uint8_t* output = NULL;
|
||||
size_t output_size = 0;
|
||||
VP8LBitWriter tmp_bw;
|
||||
|
||||
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
|
||||
assert(filter >= 0 && filter < WEBP_FILTER_LAST);
|
||||
assert(method >= ALPHA_NO_COMPRESSION);
|
||||
assert(method <= ALPHA_LOSSLESS_COMPRESSION);
|
||||
assert(sizeof(header) == ALPHA_HEADER_LEN);
|
||||
|
||||
filter_func = WebPFilters[filter];
|
||||
if (filter_func != NULL) {
|
||||
filter_func(data, width, height, width, tmp_alpha);
|
||||
alpha_src = tmp_alpha;
|
||||
} else {
|
||||
alpha_src = data;
|
||||
}
|
||||
|
||||
if (method != ALPHA_NO_COMPRESSION) {
|
||||
ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3);
|
||||
ok = ok && EncodeLossless(alpha_src, width, height, effort_level,
|
||||
!reduce_levels, &tmp_bw, &result->stats);
|
||||
if (ok) {
|
||||
output = VP8LBitWriterFinish(&tmp_bw);
|
||||
output_size = VP8LBitWriterNumBytes(&tmp_bw);
|
||||
if (output_size > data_size) {
|
||||
// compressed size is larger than source! Revert to uncompressed mode.
|
||||
method = ALPHA_NO_COMPRESSION;
|
||||
VP8LBitWriterWipeOut(&tmp_bw);
|
||||
}
|
||||
} else {
|
||||
VP8LBitWriterWipeOut(&tmp_bw);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (method == ALPHA_NO_COMPRESSION) {
|
||||
output = alpha_src;
|
||||
output_size = data_size;
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
// Emit final result.
|
||||
header = method | (filter << 2);
|
||||
if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
|
||||
|
||||
VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size);
|
||||
ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
|
||||
ok = ok && VP8BitWriterAppend(&result->bw, output, output_size);
|
||||
|
||||
if (method != ALPHA_NO_COMPRESSION) {
|
||||
VP8LBitWriterWipeOut(&tmp_bw);
|
||||
}
|
||||
ok = ok && !result->bw.error_;
|
||||
result->score = VP8BitWriterSize(&result->bw);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static int GetNumColors(const uint8_t* data, int width, int height,
|
||||
int stride) {
|
||||
int j;
|
||||
int colors = 0;
|
||||
uint8_t color[256] = { 0 };
|
||||
|
||||
for (j = 0; j < height; ++j) {
|
||||
int i;
|
||||
const uint8_t* const p = data + j * stride;
|
||||
for (i = 0; i < width; ++i) {
|
||||
color[p[i]] = 1;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 256; ++j) {
|
||||
if (color[j] > 0) ++colors;
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
#define FILTER_TRY_NONE (1 << WEBP_FILTER_NONE)
|
||||
#define FILTER_TRY_ALL ((1 << WEBP_FILTER_LAST) - 1)
|
||||
|
||||
// Given the input 'filter' option, return an OR'd bit-set of filters to try.
|
||||
static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height,
|
||||
int filter, int effort_level) {
|
||||
uint32_t bit_map = 0U;
|
||||
if (filter == WEBP_FILTER_FAST) {
|
||||
// Quick estimate of the best candidate.
|
||||
int try_filter_none = (effort_level > 3);
|
||||
const int kMinColorsForFilterNone = 16;
|
||||
const int kMaxColorsForFilterNone = 192;
|
||||
const int num_colors = GetNumColors(alpha, width, height, width);
|
||||
// For low number of colors, NONE yields better compression.
|
||||
filter = (num_colors <= kMinColorsForFilterNone)
|
||||
? WEBP_FILTER_NONE
|
||||
: WebPEstimateBestFilter(alpha, width, height, width);
|
||||
bit_map |= 1 << filter;
|
||||
// For large number of colors, try FILTER_NONE in addition to the best
|
||||
// filter as well.
|
||||
if (try_filter_none || num_colors > kMaxColorsForFilterNone) {
|
||||
bit_map |= FILTER_TRY_NONE;
|
||||
}
|
||||
} else if (filter == WEBP_FILTER_NONE) {
|
||||
bit_map = FILTER_TRY_NONE;
|
||||
} else { // WEBP_FILTER_BEST -> try all
|
||||
bit_map = FILTER_TRY_ALL;
|
||||
}
|
||||
return bit_map;
|
||||
}
|
||||
|
||||
static void InitFilterTrial(FilterTrial* const score) {
|
||||
score->score = (size_t)~0U;
|
||||
VP8BitWriterInit(&score->bw, 0);
|
||||
}
|
||||
|
||||
static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height,
|
||||
size_t data_size, int method, int filter,
|
||||
int reduce_levels, int effort_level,
|
||||
uint8_t** const output,
|
||||
size_t* const output_size,
|
||||
WebPAuxStats* const stats) {
|
||||
int ok = 1;
|
||||
FilterTrial best;
|
||||
uint32_t try_map =
|
||||
GetFilterMap(alpha, width, height, filter, effort_level);
|
||||
InitFilterTrial(&best);
|
||||
|
||||
if (try_map != FILTER_TRY_NONE) {
|
||||
uint8_t* filtered_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
|
||||
if (filtered_alpha == NULL) return 0;
|
||||
|
||||
for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) {
|
||||
if (try_map & 1) {
|
||||
FilterTrial trial;
|
||||
ok = EncodeAlphaInternal(alpha, width, height, method, filter,
|
||||
reduce_levels, effort_level, filtered_alpha,
|
||||
&trial);
|
||||
if (ok && trial.score < best.score) {
|
||||
VP8BitWriterWipeOut(&best.bw);
|
||||
best = trial;
|
||||
} else {
|
||||
VP8BitWriterWipeOut(&trial.bw);
|
||||
}
|
||||
}
|
||||
}
|
||||
WebPSafeFree(filtered_alpha);
|
||||
} else {
|
||||
ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE,
|
||||
reduce_levels, effort_level, NULL, &best);
|
||||
}
|
||||
if (ok) {
|
||||
#if !defined(WEBP_DISABLE_STATS)
|
||||
if (stats != NULL) {
|
||||
stats->lossless_features = best.stats.lossless_features;
|
||||
stats->histogram_bits = best.stats.histogram_bits;
|
||||
stats->transform_bits = best.stats.transform_bits;
|
||||
stats->cache_bits = best.stats.cache_bits;
|
||||
stats->palette_size = best.stats.palette_size;
|
||||
stats->lossless_size = best.stats.lossless_size;
|
||||
stats->lossless_hdr_size = best.stats.lossless_hdr_size;
|
||||
stats->lossless_data_size = best.stats.lossless_data_size;
|
||||
}
|
||||
#else
|
||||
(void)stats;
|
||||
#endif
|
||||
*output_size = VP8BitWriterSize(&best.bw);
|
||||
*output = VP8BitWriterBuf(&best.bw);
|
||||
} else {
|
||||
VP8BitWriterWipeOut(&best.bw);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int EncodeAlpha(VP8Encoder* const enc,
|
||||
int quality, int method, int filter,
|
||||
int effort_level,
|
||||
uint8_t** const output, size_t* const output_size) {
|
||||
const WebPPicture* const pic = enc->pic_;
|
||||
const int width = pic->width;
|
||||
const int height = pic->height;
|
||||
|
||||
uint8_t* quant_alpha = NULL;
|
||||
const size_t data_size = width * height;
|
||||
uint64_t sse = 0;
|
||||
int ok = 1;
|
||||
const int reduce_levels = (quality < 100);
|
||||
|
||||
// quick sanity checks
|
||||
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
|
||||
assert(enc != NULL && pic != NULL && pic->a != NULL);
|
||||
assert(output != NULL && output_size != NULL);
|
||||
assert(width > 0 && height > 0);
|
||||
assert(pic->a_stride >= width);
|
||||
assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST);
|
||||
|
||||
if (quality < 0 || quality > 100) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (method < ALPHA_NO_COMPRESSION || method > ALPHA_LOSSLESS_COMPRESSION) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (method == ALPHA_NO_COMPRESSION) {
|
||||
// Don't filter, as filtering will make no impact on compressed size.
|
||||
filter = WEBP_FILTER_NONE;
|
||||
}
|
||||
|
||||
quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
|
||||
if (quant_alpha == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract alpha data (width x height) from raw_data (stride x height).
|
||||
WebPCopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height);
|
||||
|
||||
if (reduce_levels) { // No Quantization required for 'quality = 100'.
|
||||
// 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence
|
||||
// mapped to moderate quality 70. Hence Quality:[0, 70] -> Levels:[2, 16]
|
||||
// and Quality:]70, 100] -> Levels:]16, 256].
|
||||
const int alpha_levels = (quality <= 70) ? (2 + quality / 5)
|
||||
: (16 + (quality - 70) * 8);
|
||||
ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
VP8FiltersInit();
|
||||
ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method,
|
||||
filter, reduce_levels, effort_level, output,
|
||||
output_size, pic->stats);
|
||||
#if !defined(WEBP_DISABLE_STATS)
|
||||
if (pic->stats != NULL) { // need stats?
|
||||
pic->stats->coded_size += (int)(*output_size);
|
||||
enc->sse_[3] = sse;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
WebPSafeFree(quant_alpha);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Main calls
|
||||
|
||||
static int CompressAlphaJob(void* arg1, void* dummy) {
|
||||
VP8Encoder* const enc = (VP8Encoder*)arg1;
|
||||
const WebPConfig* config = enc->config_;
|
||||
uint8_t* alpha_data = NULL;
|
||||
size_t alpha_size = 0;
|
||||
const int effort_level = config->method; // maps to [0..6]
|
||||
const WEBP_FILTER_TYPE filter =
|
||||
(config->alpha_filtering == 0) ? WEBP_FILTER_NONE :
|
||||
(config->alpha_filtering == 1) ? WEBP_FILTER_FAST :
|
||||
WEBP_FILTER_BEST;
|
||||
if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression,
|
||||
filter, effort_level, &alpha_data, &alpha_size)) {
|
||||
return 0;
|
||||
}
|
||||
if (alpha_size != (uint32_t)alpha_size) { // Sanity check.
|
||||
WebPSafeFree(alpha_data);
|
||||
return 0;
|
||||
}
|
||||
enc->alpha_data_size_ = (uint32_t)alpha_size;
|
||||
enc->alpha_data_ = alpha_data;
|
||||
(void)dummy;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VP8EncInitAlpha(VP8Encoder* const enc) {
|
||||
WebPInitAlphaProcessing();
|
||||
enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_);
|
||||
enc->alpha_data_ = NULL;
|
||||
enc->alpha_data_size_ = 0;
|
||||
if (enc->thread_level_ > 0) {
|
||||
WebPWorker* const worker = &enc->alpha_worker_;
|
||||
WebPGetWorkerInterface()->Init(worker);
|
||||
worker->data1 = enc;
|
||||
worker->data2 = NULL;
|
||||
worker->hook = CompressAlphaJob;
|
||||
}
|
||||
}
|
||||
|
||||
int VP8EncStartAlpha(VP8Encoder* const enc) {
|
||||
if (enc->has_alpha_) {
|
||||
if (enc->thread_level_ > 0) {
|
||||
WebPWorker* const worker = &enc->alpha_worker_;
|
||||
// Makes sure worker is good to go.
|
||||
if (!WebPGetWorkerInterface()->Reset(worker)) {
|
||||
return 0;
|
||||
}
|
||||
WebPGetWorkerInterface()->Launch(worker);
|
||||
return 1;
|
||||
} else {
|
||||
return CompressAlphaJob(enc, NULL); // just do the job right away
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int VP8EncFinishAlpha(VP8Encoder* const enc) {
|
||||
if (enc->has_alpha_) {
|
||||
if (enc->thread_level_ > 0) {
|
||||
WebPWorker* const worker = &enc->alpha_worker_;
|
||||
if (!WebPGetWorkerInterface()->Sync(worker)) return 0; // error
|
||||
}
|
||||
}
|
||||
return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
|
||||
}
|
||||
|
||||
int VP8EncDeleteAlpha(VP8Encoder* const enc) {
|
||||
int ok = 1;
|
||||
if (enc->thread_level_ > 0) {
|
||||
WebPWorker* const worker = &enc->alpha_worker_;
|
||||
// finish anything left in flight
|
||||
ok = WebPGetWorkerInterface()->Sync(worker);
|
||||
// still need to end the worker, even if !ok
|
||||
WebPGetWorkerInterface()->End(worker);
|
||||
}
|
||||
WebPSafeFree(enc->alpha_data_);
|
||||
enc->alpha_data_ = NULL;
|
||||
enc->alpha_data_size_ = 0;
|
||||
enc->has_alpha_ = 0;
|
||||
return ok;
|
||||
}
|
||||
535
libsdl2_image/external/libwebp-1.0.2/src/enc/analysis_enc.c
vendored
Normal file
535
libsdl2_image/external/libwebp-1.0.2/src/enc/analysis_enc.c
vendored
Normal file
@ -0,0 +1,535 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Macroblock analysis
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/enc/cost_enc.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
#define MAX_ITERS_K_MEANS 6
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Smooth the segment map by replacing isolated block by the majority of its
|
||||
// neighbours.
|
||||
|
||||
static void SmoothSegmentMap(VP8Encoder* const enc) {
|
||||
int n, x, y;
|
||||
const int w = enc->mb_w_;
|
||||
const int h = enc->mb_h_;
|
||||
const int majority_cnt_3_x_3_grid = 5;
|
||||
uint8_t* const tmp = (uint8_t*)WebPSafeMalloc(w * h, sizeof(*tmp));
|
||||
assert((uint64_t)(w * h) == (uint64_t)w * h); // no overflow, as per spec
|
||||
|
||||
if (tmp == NULL) return;
|
||||
for (y = 1; y < h - 1; ++y) {
|
||||
for (x = 1; x < w - 1; ++x) {
|
||||
int cnt[NUM_MB_SEGMENTS] = { 0 };
|
||||
const VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
|
||||
int majority_seg = mb->segment_;
|
||||
// Check the 8 neighbouring segment values.
|
||||
cnt[mb[-w - 1].segment_]++; // top-left
|
||||
cnt[mb[-w + 0].segment_]++; // top
|
||||
cnt[mb[-w + 1].segment_]++; // top-right
|
||||
cnt[mb[ - 1].segment_]++; // left
|
||||
cnt[mb[ + 1].segment_]++; // right
|
||||
cnt[mb[ w - 1].segment_]++; // bottom-left
|
||||
cnt[mb[ w + 0].segment_]++; // bottom
|
||||
cnt[mb[ w + 1].segment_]++; // bottom-right
|
||||
for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
|
||||
if (cnt[n] >= majority_cnt_3_x_3_grid) {
|
||||
majority_seg = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmp[x + y * w] = majority_seg;
|
||||
}
|
||||
}
|
||||
for (y = 1; y < h - 1; ++y) {
|
||||
for (x = 1; x < w - 1; ++x) {
|
||||
VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
|
||||
mb->segment_ = tmp[x + y * w];
|
||||
}
|
||||
}
|
||||
WebPSafeFree(tmp);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// set segment susceptibility alpha_ / beta_
|
||||
|
||||
static WEBP_INLINE int clip(int v, int m, int M) {
|
||||
return (v < m) ? m : (v > M) ? M : v;
|
||||
}
|
||||
|
||||
static void SetSegmentAlphas(VP8Encoder* const enc,
|
||||
const int centers[NUM_MB_SEGMENTS],
|
||||
int mid) {
|
||||
const int nb = enc->segment_hdr_.num_segments_;
|
||||
int min = centers[0], max = centers[0];
|
||||
int n;
|
||||
|
||||
if (nb > 1) {
|
||||
for (n = 0; n < nb; ++n) {
|
||||
if (min > centers[n]) min = centers[n];
|
||||
if (max < centers[n]) max = centers[n];
|
||||
}
|
||||
}
|
||||
if (max == min) max = min + 1;
|
||||
assert(mid <= max && mid >= min);
|
||||
for (n = 0; n < nb; ++n) {
|
||||
const int alpha = 255 * (centers[n] - mid) / (max - min);
|
||||
const int beta = 255 * (centers[n] - min) / (max - min);
|
||||
enc->dqm_[n].alpha_ = clip(alpha, -127, 127);
|
||||
enc->dqm_[n].beta_ = clip(beta, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Compute susceptibility based on DCT-coeff histograms:
|
||||
// the higher, the "easier" the macroblock is to compress.
|
||||
|
||||
#define MAX_ALPHA 255 // 8b of precision for susceptibilities.
|
||||
#define ALPHA_SCALE (2 * MAX_ALPHA) // scaling factor for alpha.
|
||||
#define DEFAULT_ALPHA (-1)
|
||||
#define IS_BETTER_ALPHA(alpha, best_alpha) ((alpha) > (best_alpha))
|
||||
|
||||
static int FinalAlphaValue(int alpha) {
|
||||
alpha = MAX_ALPHA - alpha;
|
||||
return clip(alpha, 0, MAX_ALPHA);
|
||||
}
|
||||
|
||||
static int GetAlpha(const VP8Histogram* const histo) {
|
||||
// 'alpha' will later be clipped to [0..MAX_ALPHA] range, clamping outer
|
||||
// values which happen to be mostly noise. This leaves the maximum precision
|
||||
// for handling the useful small values which contribute most.
|
||||
const int max_value = histo->max_value;
|
||||
const int last_non_zero = histo->last_non_zero;
|
||||
const int alpha =
|
||||
(max_value > 1) ? ALPHA_SCALE * last_non_zero / max_value : 0;
|
||||
return alpha;
|
||||
}
|
||||
|
||||
static void InitHistogram(VP8Histogram* const histo) {
|
||||
histo->max_value = 0;
|
||||
histo->last_non_zero = 1;
|
||||
}
|
||||
|
||||
static void MergeHistograms(const VP8Histogram* const in,
|
||||
VP8Histogram* const out) {
|
||||
if (in->max_value > out->max_value) {
|
||||
out->max_value = in->max_value;
|
||||
}
|
||||
if (in->last_non_zero > out->last_non_zero) {
|
||||
out->last_non_zero = in->last_non_zero;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Simplified k-Means, to assign Nb segments based on alpha-histogram
|
||||
|
||||
static void AssignSegments(VP8Encoder* const enc,
|
||||
const int alphas[MAX_ALPHA + 1]) {
|
||||
// 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an
|
||||
// explicit check is needed to avoid spurious warning about 'n + 1' exceeding
|
||||
// array bounds of 'centers' with some compilers (noticed with gcc-4.9).
|
||||
const int nb = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) ?
|
||||
enc->segment_hdr_.num_segments_ : NUM_MB_SEGMENTS;
|
||||
int centers[NUM_MB_SEGMENTS];
|
||||
int weighted_average = 0;
|
||||
int map[MAX_ALPHA + 1];
|
||||
int a, n, k;
|
||||
int min_a = 0, max_a = MAX_ALPHA, range_a;
|
||||
// 'int' type is ok for histo, and won't overflow
|
||||
int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS];
|
||||
|
||||
assert(nb >= 1);
|
||||
assert(nb <= NUM_MB_SEGMENTS);
|
||||
|
||||
// bracket the input
|
||||
for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {}
|
||||
min_a = n;
|
||||
for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {}
|
||||
max_a = n;
|
||||
range_a = max_a - min_a;
|
||||
|
||||
// Spread initial centers evenly
|
||||
for (k = 0, n = 1; k < nb; ++k, n += 2) {
|
||||
assert(n < 2 * nb);
|
||||
centers[k] = min_a + (n * range_a) / (2 * nb);
|
||||
}
|
||||
|
||||
for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough
|
||||
int total_weight;
|
||||
int displaced;
|
||||
// Reset stats
|
||||
for (n = 0; n < nb; ++n) {
|
||||
accum[n] = 0;
|
||||
dist_accum[n] = 0;
|
||||
}
|
||||
// Assign nearest center for each 'a'
|
||||
n = 0; // track the nearest center for current 'a'
|
||||
for (a = min_a; a <= max_a; ++a) {
|
||||
if (alphas[a]) {
|
||||
while (n + 1 < nb && abs(a - centers[n + 1]) < abs(a - centers[n])) {
|
||||
n++;
|
||||
}
|
||||
map[a] = n;
|
||||
// accumulate contribution into best centroid
|
||||
dist_accum[n] += a * alphas[a];
|
||||
accum[n] += alphas[a];
|
||||
}
|
||||
}
|
||||
// All point are classified. Move the centroids to the
|
||||
// center of their respective cloud.
|
||||
displaced = 0;
|
||||
weighted_average = 0;
|
||||
total_weight = 0;
|
||||
for (n = 0; n < nb; ++n) {
|
||||
if (accum[n]) {
|
||||
const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n];
|
||||
displaced += abs(centers[n] - new_center);
|
||||
centers[n] = new_center;
|
||||
weighted_average += new_center * accum[n];
|
||||
total_weight += accum[n];
|
||||
}
|
||||
}
|
||||
weighted_average = (weighted_average + total_weight / 2) / total_weight;
|
||||
if (displaced < 5) break; // no need to keep on looping...
|
||||
}
|
||||
|
||||
// Map each original value to the closest centroid
|
||||
for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
|
||||
VP8MBInfo* const mb = &enc->mb_info_[n];
|
||||
const int alpha = mb->alpha_;
|
||||
mb->segment_ = map[alpha];
|
||||
mb->alpha_ = centers[map[alpha]]; // for the record.
|
||||
}
|
||||
|
||||
if (nb > 1) {
|
||||
const int smooth = (enc->config_->preprocessing & 1);
|
||||
if (smooth) SmoothSegmentMap(enc);
|
||||
}
|
||||
|
||||
SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Macroblock analysis: collect histogram for each mode, deduce the maximal
|
||||
// susceptibility and set best modes for this macroblock.
|
||||
// Segment assignment is done later.
|
||||
|
||||
// Number of modes to inspect for alpha_ evaluation. We don't need to test all
|
||||
// the possible modes during the analysis phase: we risk falling into a local
|
||||
// optimum, or be subject to boundary effect
|
||||
#define MAX_INTRA16_MODE 2
|
||||
#define MAX_INTRA4_MODE 2
|
||||
#define MAX_UV_MODE 2
|
||||
|
||||
static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
|
||||
const int max_mode = MAX_INTRA16_MODE;
|
||||
int mode;
|
||||
int best_alpha = DEFAULT_ALPHA;
|
||||
int best_mode = 0;
|
||||
|
||||
VP8MakeLuma16Preds(it);
|
||||
for (mode = 0; mode < max_mode; ++mode) {
|
||||
VP8Histogram histo;
|
||||
int alpha;
|
||||
|
||||
InitHistogram(&histo);
|
||||
VP8CollectHistogram(it->yuv_in_ + Y_OFF_ENC,
|
||||
it->yuv_p_ + VP8I16ModeOffsets[mode],
|
||||
0, 16, &histo);
|
||||
alpha = GetAlpha(&histo);
|
||||
if (IS_BETTER_ALPHA(alpha, best_alpha)) {
|
||||
best_alpha = alpha;
|
||||
best_mode = mode;
|
||||
}
|
||||
}
|
||||
VP8SetIntra16Mode(it, best_mode);
|
||||
return best_alpha;
|
||||
}
|
||||
|
||||
static int FastMBAnalyze(VP8EncIterator* const it) {
|
||||
// Empirical cut-off value, should be around 16 (~=block size). We use the
|
||||
// [8-17] range and favor intra4 at high quality, intra16 for low quality.
|
||||
const int q = (int)it->enc_->config_->quality;
|
||||
const uint32_t kThreshold = 8 + (17 - 8) * q / 100;
|
||||
int k;
|
||||
uint32_t dc[16], m, m2;
|
||||
for (k = 0; k < 16; k += 4) {
|
||||
VP8Mean16x4(it->yuv_in_ + Y_OFF_ENC + k * BPS, &dc[k]);
|
||||
}
|
||||
for (m = 0, m2 = 0, k = 0; k < 16; ++k) {
|
||||
m += dc[k];
|
||||
m2 += dc[k] * dc[k];
|
||||
}
|
||||
if (kThreshold * m2 < m * m) {
|
||||
VP8SetIntra16Mode(it, 0); // DC16
|
||||
} else {
|
||||
const uint8_t modes[16] = { 0 }; // DC4
|
||||
VP8SetIntra4Mode(it, modes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it,
|
||||
int best_alpha) {
|
||||
uint8_t modes[16];
|
||||
const int max_mode = MAX_INTRA4_MODE;
|
||||
int i4_alpha;
|
||||
VP8Histogram total_histo;
|
||||
int cur_histo = 0;
|
||||
InitHistogram(&total_histo);
|
||||
|
||||
VP8IteratorStartI4(it);
|
||||
do {
|
||||
int mode;
|
||||
int best_mode_alpha = DEFAULT_ALPHA;
|
||||
VP8Histogram histos[2];
|
||||
const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_];
|
||||
|
||||
VP8MakeIntra4Preds(it);
|
||||
for (mode = 0; mode < max_mode; ++mode) {
|
||||
int alpha;
|
||||
|
||||
InitHistogram(&histos[cur_histo]);
|
||||
VP8CollectHistogram(src, it->yuv_p_ + VP8I4ModeOffsets[mode],
|
||||
0, 1, &histos[cur_histo]);
|
||||
alpha = GetAlpha(&histos[cur_histo]);
|
||||
if (IS_BETTER_ALPHA(alpha, best_mode_alpha)) {
|
||||
best_mode_alpha = alpha;
|
||||
modes[it->i4_] = mode;
|
||||
cur_histo ^= 1; // keep track of best histo so far.
|
||||
}
|
||||
}
|
||||
// accumulate best histogram
|
||||
MergeHistograms(&histos[cur_histo ^ 1], &total_histo);
|
||||
// Note: we reuse the original samples for predictors
|
||||
} while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF_ENC));
|
||||
|
||||
i4_alpha = GetAlpha(&total_histo);
|
||||
if (IS_BETTER_ALPHA(i4_alpha, best_alpha)) {
|
||||
VP8SetIntra4Mode(it, modes);
|
||||
best_alpha = i4_alpha;
|
||||
}
|
||||
return best_alpha;
|
||||
}
|
||||
|
||||
static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
|
||||
int best_alpha = DEFAULT_ALPHA;
|
||||
int smallest_alpha = 0;
|
||||
int best_mode = 0;
|
||||
const int max_mode = MAX_UV_MODE;
|
||||
int mode;
|
||||
|
||||
VP8MakeChroma8Preds(it);
|
||||
for (mode = 0; mode < max_mode; ++mode) {
|
||||
VP8Histogram histo;
|
||||
int alpha;
|
||||
InitHistogram(&histo);
|
||||
VP8CollectHistogram(it->yuv_in_ + U_OFF_ENC,
|
||||
it->yuv_p_ + VP8UVModeOffsets[mode],
|
||||
16, 16 + 4 + 4, &histo);
|
||||
alpha = GetAlpha(&histo);
|
||||
if (IS_BETTER_ALPHA(alpha, best_alpha)) {
|
||||
best_alpha = alpha;
|
||||
}
|
||||
// The best prediction mode tends to be the one with the smallest alpha.
|
||||
if (mode == 0 || alpha < smallest_alpha) {
|
||||
smallest_alpha = alpha;
|
||||
best_mode = mode;
|
||||
}
|
||||
}
|
||||
VP8SetIntraUVMode(it, best_mode);
|
||||
return best_alpha;
|
||||
}
|
||||
|
||||
static void MBAnalyze(VP8EncIterator* const it,
|
||||
int alphas[MAX_ALPHA + 1],
|
||||
int* const alpha, int* const uv_alpha) {
|
||||
const VP8Encoder* const enc = it->enc_;
|
||||
int best_alpha, best_uv_alpha;
|
||||
|
||||
VP8SetIntra16Mode(it, 0); // default: Intra16, DC_PRED
|
||||
VP8SetSkip(it, 0); // not skipped
|
||||
VP8SetSegment(it, 0); // default segment, spec-wise.
|
||||
|
||||
if (enc->method_ <= 1) {
|
||||
best_alpha = FastMBAnalyze(it);
|
||||
} else {
|
||||
best_alpha = MBAnalyzeBestIntra16Mode(it);
|
||||
if (enc->method_ >= 5) {
|
||||
// We go and make a fast decision for intra4/intra16.
|
||||
// It's usually not a good and definitive pick, but helps seeding the
|
||||
// stats about level bit-cost.
|
||||
// TODO(skal): improve criterion.
|
||||
best_alpha = MBAnalyzeBestIntra4Mode(it, best_alpha);
|
||||
}
|
||||
}
|
||||
best_uv_alpha = MBAnalyzeBestUVMode(it);
|
||||
|
||||
// Final susceptibility mix
|
||||
best_alpha = (3 * best_alpha + best_uv_alpha + 2) >> 2;
|
||||
best_alpha = FinalAlphaValue(best_alpha);
|
||||
alphas[best_alpha]++;
|
||||
it->mb_->alpha_ = best_alpha; // for later remapping.
|
||||
|
||||
// Accumulate for later complexity analysis.
|
||||
*alpha += best_alpha; // mixed susceptibility (not just luma)
|
||||
*uv_alpha += best_uv_alpha;
|
||||
}
|
||||
|
||||
static void DefaultMBInfo(VP8MBInfo* const mb) {
|
||||
mb->type_ = 1; // I16x16
|
||||
mb->uv_mode_ = 0;
|
||||
mb->skip_ = 0; // not skipped
|
||||
mb->segment_ = 0; // default segment
|
||||
mb->alpha_ = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Main analysis loop:
|
||||
// Collect all susceptibilities for each macroblock and record their
|
||||
// distribution in alphas[]. Segments is assigned a-posteriori, based on
|
||||
// this histogram.
|
||||
// We also pick an intra16 prediction mode, which shouldn't be considered
|
||||
// final except for fast-encode settings. We can also pick some intra4 modes
|
||||
// and decide intra4/intra16, but that's usually almost always a bad choice at
|
||||
// this stage.
|
||||
|
||||
static void ResetAllMBInfo(VP8Encoder* const enc) {
|
||||
int n;
|
||||
for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
|
||||
DefaultMBInfo(&enc->mb_info_[n]);
|
||||
}
|
||||
// Default susceptibilities.
|
||||
enc->dqm_[0].alpha_ = 0;
|
||||
enc->dqm_[0].beta_ = 0;
|
||||
// Note: we can't compute this alpha_ / uv_alpha_ -> set to default value.
|
||||
enc->alpha_ = 0;
|
||||
enc->uv_alpha_ = 0;
|
||||
WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
|
||||
}
|
||||
|
||||
// struct used to collect job result
|
||||
typedef struct {
|
||||
WebPWorker worker;
|
||||
int alphas[MAX_ALPHA + 1];
|
||||
int alpha, uv_alpha;
|
||||
VP8EncIterator it;
|
||||
int delta_progress;
|
||||
} SegmentJob;
|
||||
|
||||
// main work call
|
||||
static int DoSegmentsJob(void* arg1, void* arg2) {
|
||||
SegmentJob* const job = (SegmentJob*)arg1;
|
||||
VP8EncIterator* const it = (VP8EncIterator*)arg2;
|
||||
int ok = 1;
|
||||
if (!VP8IteratorIsDone(it)) {
|
||||
uint8_t tmp[32 + WEBP_ALIGN_CST];
|
||||
uint8_t* const scratch = (uint8_t*)WEBP_ALIGN(tmp);
|
||||
do {
|
||||
// Let's pretend we have perfect lossless reconstruction.
|
||||
VP8IteratorImport(it, scratch);
|
||||
MBAnalyze(it, job->alphas, &job->alpha, &job->uv_alpha);
|
||||
ok = VP8IteratorProgress(it, job->delta_progress);
|
||||
} while (ok && VP8IteratorNext(it));
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
|
||||
int i;
|
||||
for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i];
|
||||
dst->alpha += src->alpha;
|
||||
dst->uv_alpha += src->uv_alpha;
|
||||
}
|
||||
|
||||
// initialize the job struct with some tasks to perform
|
||||
static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
|
||||
int start_row, int end_row) {
|
||||
WebPGetWorkerInterface()->Init(&job->worker);
|
||||
job->worker.data1 = job;
|
||||
job->worker.data2 = &job->it;
|
||||
job->worker.hook = DoSegmentsJob;
|
||||
VP8IteratorInit(enc, &job->it);
|
||||
VP8IteratorSetRow(&job->it, start_row);
|
||||
VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_);
|
||||
memset(job->alphas, 0, sizeof(job->alphas));
|
||||
job->alpha = 0;
|
||||
job->uv_alpha = 0;
|
||||
// only one of both jobs can record the progress, since we don't
|
||||
// expect the user's hook to be multi-thread safe
|
||||
job->delta_progress = (start_row == 0) ? 20 : 0;
|
||||
}
|
||||
|
||||
// main entry point
|
||||
int VP8EncAnalyze(VP8Encoder* const enc) {
|
||||
int ok = 1;
|
||||
const int do_segments =
|
||||
enc->config_->emulate_jpeg_size || // We need the complexity evaluation.
|
||||
(enc->segment_hdr_.num_segments_ > 1) ||
|
||||
(enc->method_ <= 1); // for method 0 - 1, we need preds_[] to be filled.
|
||||
if (do_segments) {
|
||||
const int last_row = enc->mb_h_;
|
||||
// We give a little more than a half work to the main thread.
|
||||
const int split_row = (9 * last_row + 15) >> 4;
|
||||
const int total_mb = last_row * enc->mb_w_;
|
||||
#ifdef WEBP_USE_THREAD
|
||||
const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it
|
||||
const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow);
|
||||
#else
|
||||
const int do_mt = 0;
|
||||
#endif
|
||||
const WebPWorkerInterface* const worker_interface =
|
||||
WebPGetWorkerInterface();
|
||||
SegmentJob main_job;
|
||||
if (do_mt) {
|
||||
SegmentJob side_job;
|
||||
// Note the use of '&' instead of '&&' because we must call the functions
|
||||
// no matter what.
|
||||
InitSegmentJob(enc, &main_job, 0, split_row);
|
||||
InitSegmentJob(enc, &side_job, split_row, last_row);
|
||||
// we don't need to call Reset() on main_job.worker, since we're calling
|
||||
// WebPWorkerExecute() on it
|
||||
ok &= worker_interface->Reset(&side_job.worker);
|
||||
// launch the two jobs in parallel
|
||||
if (ok) {
|
||||
worker_interface->Launch(&side_job.worker);
|
||||
worker_interface->Execute(&main_job.worker);
|
||||
ok &= worker_interface->Sync(&side_job.worker);
|
||||
ok &= worker_interface->Sync(&main_job.worker);
|
||||
}
|
||||
worker_interface->End(&side_job.worker);
|
||||
if (ok) MergeJobs(&side_job, &main_job); // merge results together
|
||||
} else {
|
||||
// Even for single-thread case, we use the generic Worker tools.
|
||||
InitSegmentJob(enc, &main_job, 0, last_row);
|
||||
worker_interface->Execute(&main_job.worker);
|
||||
ok &= worker_interface->Sync(&main_job.worker);
|
||||
}
|
||||
worker_interface->End(&main_job.worker);
|
||||
if (ok) {
|
||||
enc->alpha_ = main_job.alpha / total_mb;
|
||||
enc->uv_alpha_ = main_job.uv_alpha / total_mb;
|
||||
AssignSegments(enc, main_job.alphas);
|
||||
}
|
||||
} else { // Use only one default segment.
|
||||
ResetAllMBInfo(enc);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
790
libsdl2_image/external/libwebp-1.0.2/src/enc/backward_references_cost_enc.c
vendored
Normal file
790
libsdl2_image/external/libwebp-1.0.2/src/enc/backward_references_cost_enc.c
vendored
Normal file
@ -0,0 +1,790 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Improves a given set of backward references by analyzing its bit cost.
|
||||
// The algorithm is similar to the Zopfli compression algorithm but tailored to
|
||||
// images.
|
||||
//
|
||||
// Author: Vincent Rabaud (vrabaud@google.com)
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "src/enc/backward_references_enc.h"
|
||||
#include "src/enc/histogram_enc.h"
|
||||
#include "src/dsp/lossless_common.h"
|
||||
#include "src/utils/color_cache_utils.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
#define VALUES_IN_BYTE 256
|
||||
|
||||
extern void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs);
|
||||
extern int VP8LDistanceToPlaneCode(int xsize, int dist);
|
||||
extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
|
||||
const PixOrCopy v);
|
||||
|
||||
typedef struct {
|
||||
double alpha_[VALUES_IN_BYTE];
|
||||
double red_[VALUES_IN_BYTE];
|
||||
double blue_[VALUES_IN_BYTE];
|
||||
double distance_[NUM_DISTANCE_CODES];
|
||||
double* literal_;
|
||||
} CostModel;
|
||||
|
||||
static void ConvertPopulationCountTableToBitEstimates(
|
||||
int num_symbols, const uint32_t population_counts[], double output[]) {
|
||||
uint32_t sum = 0;
|
||||
int nonzeros = 0;
|
||||
int i;
|
||||
for (i = 0; i < num_symbols; ++i) {
|
||||
sum += population_counts[i];
|
||||
if (population_counts[i] > 0) {
|
||||
++nonzeros;
|
||||
}
|
||||
}
|
||||
if (nonzeros <= 1) {
|
||||
memset(output, 0, num_symbols * sizeof(*output));
|
||||
} else {
|
||||
const double logsum = VP8LFastLog2(sum);
|
||||
for (i = 0; i < num_symbols; ++i) {
|
||||
output[i] = logsum - VP8LFastLog2(population_counts[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
|
||||
const VP8LBackwardRefs* const refs) {
|
||||
int ok = 0;
|
||||
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
|
||||
VP8LHistogram* const histo = VP8LAllocateHistogram(cache_bits);
|
||||
if (histo == NULL) goto Error;
|
||||
|
||||
// The following code is similar to VP8LHistogramCreate but converts the
|
||||
// distance to plane code.
|
||||
VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 1);
|
||||
while (VP8LRefsCursorOk(&c)) {
|
||||
VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode,
|
||||
xsize);
|
||||
VP8LRefsCursorNext(&c);
|
||||
}
|
||||
|
||||
ConvertPopulationCountTableToBitEstimates(
|
||||
VP8LHistogramNumCodes(histo->palette_code_bits_),
|
||||
histo->literal_, m->literal_);
|
||||
ConvertPopulationCountTableToBitEstimates(
|
||||
VALUES_IN_BYTE, histo->red_, m->red_);
|
||||
ConvertPopulationCountTableToBitEstimates(
|
||||
VALUES_IN_BYTE, histo->blue_, m->blue_);
|
||||
ConvertPopulationCountTableToBitEstimates(
|
||||
VALUES_IN_BYTE, histo->alpha_, m->alpha_);
|
||||
ConvertPopulationCountTableToBitEstimates(
|
||||
NUM_DISTANCE_CODES, histo->distance_, m->distance_);
|
||||
ok = 1;
|
||||
|
||||
Error:
|
||||
VP8LFreeHistogram(histo);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) {
|
||||
return m->alpha_[v >> 24] +
|
||||
m->red_[(v >> 16) & 0xff] +
|
||||
m->literal_[(v >> 8) & 0xff] +
|
||||
m->blue_[v & 0xff];
|
||||
}
|
||||
|
||||
static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
|
||||
const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx;
|
||||
return m->literal_[literal_idx];
|
||||
}
|
||||
|
||||
static WEBP_INLINE double GetLengthCost(const CostModel* const m,
|
||||
uint32_t length) {
|
||||
int code, extra_bits;
|
||||
VP8LPrefixEncodeBits(length, &code, &extra_bits);
|
||||
return m->literal_[VALUES_IN_BYTE + code] + extra_bits;
|
||||
}
|
||||
|
||||
static WEBP_INLINE double GetDistanceCost(const CostModel* const m,
|
||||
uint32_t distance) {
|
||||
int code, extra_bits;
|
||||
VP8LPrefixEncodeBits(distance, &code, &extra_bits);
|
||||
return m->distance_[code] + extra_bits;
|
||||
}
|
||||
|
||||
static WEBP_INLINE void AddSingleLiteralWithCostModel(
|
||||
const uint32_t* const argb, VP8LColorCache* const hashers,
|
||||
const CostModel* const cost_model, int idx, int use_color_cache,
|
||||
float prev_cost, float* const cost, uint16_t* const dist_array) {
|
||||
double cost_val = prev_cost;
|
||||
const uint32_t color = argb[idx];
|
||||
const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1;
|
||||
if (ix >= 0) {
|
||||
// use_color_cache is true and hashers contains color
|
||||
const double mul0 = 0.68;
|
||||
cost_val += GetCacheCost(cost_model, ix) * mul0;
|
||||
} else {
|
||||
const double mul1 = 0.82;
|
||||
if (use_color_cache) VP8LColorCacheInsert(hashers, color);
|
||||
cost_val += GetLiteralCost(cost_model, color) * mul1;
|
||||
}
|
||||
if (cost[idx] > cost_val) {
|
||||
cost[idx] = (float)cost_val;
|
||||
dist_array[idx] = 1; // only one is inserted.
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CostManager and interval handling
|
||||
|
||||
// Empirical value to avoid high memory consumption but good for performance.
|
||||
#define COST_CACHE_INTERVAL_SIZE_MAX 500
|
||||
|
||||
// To perform backward reference every pixel at index index_ is considered and
|
||||
// the cost for the MAX_LENGTH following pixels computed. Those following pixels
|
||||
// at index index_ + k (k from 0 to MAX_LENGTH) have a cost of:
|
||||
// cost_ = distance cost at index + GetLengthCost(cost_model, k)
|
||||
// and the minimum value is kept. GetLengthCost(cost_model, k) is cached in an
|
||||
// array of size MAX_LENGTH.
|
||||
// Instead of performing MAX_LENGTH comparisons per pixel, we keep track of the
|
||||
// minimal values using intervals of constant cost.
|
||||
// An interval is defined by the index_ of the pixel that generated it and
|
||||
// is only useful in a range of indices from start_ to end_ (exclusive), i.e.
|
||||
// it contains the minimum value for pixels between start_ and end_.
|
||||
// Intervals are stored in a linked list and ordered by start_. When a new
|
||||
// interval has a better value, old intervals are split or removed. There are
|
||||
// therefore no overlapping intervals.
|
||||
typedef struct CostInterval CostInterval;
|
||||
struct CostInterval {
|
||||
float cost_;
|
||||
int start_;
|
||||
int end_;
|
||||
int index_;
|
||||
CostInterval* previous_;
|
||||
CostInterval* next_;
|
||||
};
|
||||
|
||||
// The GetLengthCost(cost_model, k) are cached in a CostCacheInterval.
|
||||
typedef struct {
|
||||
double cost_;
|
||||
int start_;
|
||||
int end_; // Exclusive.
|
||||
} CostCacheInterval;
|
||||
|
||||
// This structure is in charge of managing intervals and costs.
|
||||
// It caches the different CostCacheInterval, caches the different
|
||||
// GetLengthCost(cost_model, k) in cost_cache_ and the CostInterval's (whose
|
||||
// count_ is limited by COST_CACHE_INTERVAL_SIZE_MAX).
|
||||
#define COST_MANAGER_MAX_FREE_LIST 10
|
||||
typedef struct {
|
||||
CostInterval* head_;
|
||||
int count_; // The number of stored intervals.
|
||||
CostCacheInterval* cache_intervals_;
|
||||
size_t cache_intervals_size_;
|
||||
double cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k).
|
||||
float* costs_;
|
||||
uint16_t* dist_array_;
|
||||
// Most of the time, we only need few intervals -> use a free-list, to avoid
|
||||
// fragmentation with small allocs in most common cases.
|
||||
CostInterval intervals_[COST_MANAGER_MAX_FREE_LIST];
|
||||
CostInterval* free_intervals_;
|
||||
// These are regularly malloc'd remains. This list can't grow larger than than
|
||||
// size COST_CACHE_INTERVAL_SIZE_MAX - COST_MANAGER_MAX_FREE_LIST, note.
|
||||
CostInterval* recycled_intervals_;
|
||||
} CostManager;
|
||||
|
||||
static void CostIntervalAddToFreeList(CostManager* const manager,
|
||||
CostInterval* const interval) {
|
||||
interval->next_ = manager->free_intervals_;
|
||||
manager->free_intervals_ = interval;
|
||||
}
|
||||
|
||||
static int CostIntervalIsInFreeList(const CostManager* const manager,
|
||||
const CostInterval* const interval) {
|
||||
return (interval >= &manager->intervals_[0] &&
|
||||
interval <= &manager->intervals_[COST_MANAGER_MAX_FREE_LIST - 1]);
|
||||
}
|
||||
|
||||
static void CostManagerInitFreeList(CostManager* const manager) {
|
||||
int i;
|
||||
manager->free_intervals_ = NULL;
|
||||
for (i = 0; i < COST_MANAGER_MAX_FREE_LIST; ++i) {
|
||||
CostIntervalAddToFreeList(manager, &manager->intervals_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void DeleteIntervalList(CostManager* const manager,
|
||||
const CostInterval* interval) {
|
||||
while (interval != NULL) {
|
||||
const CostInterval* const next = interval->next_;
|
||||
if (!CostIntervalIsInFreeList(manager, interval)) {
|
||||
WebPSafeFree((void*)interval);
|
||||
} // else: do nothing
|
||||
interval = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void CostManagerClear(CostManager* const manager) {
|
||||
if (manager == NULL) return;
|
||||
|
||||
WebPSafeFree(manager->costs_);
|
||||
WebPSafeFree(manager->cache_intervals_);
|
||||
|
||||
// Clear the interval lists.
|
||||
DeleteIntervalList(manager, manager->head_);
|
||||
manager->head_ = NULL;
|
||||
DeleteIntervalList(manager, manager->recycled_intervals_);
|
||||
manager->recycled_intervals_ = NULL;
|
||||
|
||||
// Reset pointers, count_ and cache_intervals_size_.
|
||||
memset(manager, 0, sizeof(*manager));
|
||||
CostManagerInitFreeList(manager);
|
||||
}
|
||||
|
||||
static int CostManagerInit(CostManager* const manager,
|
||||
uint16_t* const dist_array, int pix_count,
|
||||
const CostModel* const cost_model) {
|
||||
int i;
|
||||
const int cost_cache_size = (pix_count > MAX_LENGTH) ? MAX_LENGTH : pix_count;
|
||||
|
||||
manager->costs_ = NULL;
|
||||
manager->cache_intervals_ = NULL;
|
||||
manager->head_ = NULL;
|
||||
manager->recycled_intervals_ = NULL;
|
||||
manager->count_ = 0;
|
||||
manager->dist_array_ = dist_array;
|
||||
CostManagerInitFreeList(manager);
|
||||
|
||||
// Fill in the cost_cache_.
|
||||
manager->cache_intervals_size_ = 1;
|
||||
manager->cost_cache_[0] = GetLengthCost(cost_model, 0);
|
||||
for (i = 1; i < cost_cache_size; ++i) {
|
||||
manager->cost_cache_[i] = GetLengthCost(cost_model, i);
|
||||
// Get the number of bound intervals.
|
||||
if (manager->cost_cache_[i] != manager->cost_cache_[i - 1]) {
|
||||
++manager->cache_intervals_size_;
|
||||
}
|
||||
}
|
||||
|
||||
// With the current cost model, we usually have below 20 intervals.
|
||||
// The worst case scenario with a cost model would be if every length has a
|
||||
// different cost, hence MAX_LENGTH but that is impossible with the current
|
||||
// implementation that spirals around a pixel.
|
||||
assert(manager->cache_intervals_size_ <= MAX_LENGTH);
|
||||
manager->cache_intervals_ = (CostCacheInterval*)WebPSafeMalloc(
|
||||
manager->cache_intervals_size_, sizeof(*manager->cache_intervals_));
|
||||
if (manager->cache_intervals_ == NULL) {
|
||||
CostManagerClear(manager);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fill in the cache_intervals_.
|
||||
{
|
||||
CostCacheInterval* cur = manager->cache_intervals_;
|
||||
|
||||
// Consecutive values in cost_cache_ are compared and if a big enough
|
||||
// difference is found, a new interval is created and bounded.
|
||||
cur->start_ = 0;
|
||||
cur->end_ = 1;
|
||||
cur->cost_ = manager->cost_cache_[0];
|
||||
for (i = 1; i < cost_cache_size; ++i) {
|
||||
const double cost_val = manager->cost_cache_[i];
|
||||
if (cost_val != cur->cost_) {
|
||||
++cur;
|
||||
// Initialize an interval.
|
||||
cur->start_ = i;
|
||||
cur->cost_ = cost_val;
|
||||
}
|
||||
cur->end_ = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
manager->costs_ = (float*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_));
|
||||
if (manager->costs_ == NULL) {
|
||||
CostManagerClear(manager);
|
||||
return 0;
|
||||
}
|
||||
// Set the initial costs_ high for every pixel as we will keep the minimum.
|
||||
for (i = 0; i < pix_count; ++i) manager->costs_[i] = 1e38f;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Given the cost and the position that define an interval, update the cost at
|
||||
// pixel 'i' if it is smaller than the previously computed value.
|
||||
static WEBP_INLINE void UpdateCost(CostManager* const manager, int i,
|
||||
int position, float cost) {
|
||||
const int k = i - position;
|
||||
assert(k >= 0 && k < MAX_LENGTH);
|
||||
|
||||
if (manager->costs_[i] > cost) {
|
||||
manager->costs_[i] = cost;
|
||||
manager->dist_array_[i] = k + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Given the cost and the position that define an interval, update the cost for
|
||||
// all the pixels between 'start' and 'end' excluded.
|
||||
static WEBP_INLINE void UpdateCostPerInterval(CostManager* const manager,
|
||||
int start, int end, int position,
|
||||
float cost) {
|
||||
int i;
|
||||
for (i = start; i < end; ++i) UpdateCost(manager, i, position, cost);
|
||||
}
|
||||
|
||||
// Given two intervals, make 'prev' be the previous one of 'next' in 'manager'.
|
||||
static WEBP_INLINE void ConnectIntervals(CostManager* const manager,
|
||||
CostInterval* const prev,
|
||||
CostInterval* const next) {
|
||||
if (prev != NULL) {
|
||||
prev->next_ = next;
|
||||
} else {
|
||||
manager->head_ = next;
|
||||
}
|
||||
|
||||
if (next != NULL) next->previous_ = prev;
|
||||
}
|
||||
|
||||
// Pop an interval in the manager.
|
||||
static WEBP_INLINE void PopInterval(CostManager* const manager,
|
||||
CostInterval* const interval) {
|
||||
if (interval == NULL) return;
|
||||
|
||||
ConnectIntervals(manager, interval->previous_, interval->next_);
|
||||
if (CostIntervalIsInFreeList(manager, interval)) {
|
||||
CostIntervalAddToFreeList(manager, interval);
|
||||
} else { // recycle regularly malloc'd intervals too
|
||||
interval->next_ = manager->recycled_intervals_;
|
||||
manager->recycled_intervals_ = interval;
|
||||
}
|
||||
--manager->count_;
|
||||
assert(manager->count_ >= 0);
|
||||
}
|
||||
|
||||
// Update the cost at index i by going over all the stored intervals that
|
||||
// overlap with i.
|
||||
// If 'do_clean_intervals' is set to something different than 0, intervals that
|
||||
// end before 'i' will be popped.
|
||||
static WEBP_INLINE void UpdateCostAtIndex(CostManager* const manager, int i,
|
||||
int do_clean_intervals) {
|
||||
CostInterval* current = manager->head_;
|
||||
|
||||
while (current != NULL && current->start_ <= i) {
|
||||
CostInterval* const next = current->next_;
|
||||
if (current->end_ <= i) {
|
||||
if (do_clean_intervals) {
|
||||
// We have an outdated interval, remove it.
|
||||
PopInterval(manager, current);
|
||||
}
|
||||
} else {
|
||||
UpdateCost(manager, i, current->index_, current->cost_);
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
// Given a current orphan interval and its previous interval, before
|
||||
// it was orphaned (which can be NULL), set it at the right place in the list
|
||||
// of intervals using the start_ ordering and the previous interval as a hint.
|
||||
static WEBP_INLINE void PositionOrphanInterval(CostManager* const manager,
|
||||
CostInterval* const current,
|
||||
CostInterval* previous) {
|
||||
assert(current != NULL);
|
||||
|
||||
if (previous == NULL) previous = manager->head_;
|
||||
while (previous != NULL && current->start_ < previous->start_) {
|
||||
previous = previous->previous_;
|
||||
}
|
||||
while (previous != NULL && previous->next_ != NULL &&
|
||||
previous->next_->start_ < current->start_) {
|
||||
previous = previous->next_;
|
||||
}
|
||||
|
||||
if (previous != NULL) {
|
||||
ConnectIntervals(manager, current, previous->next_);
|
||||
} else {
|
||||
ConnectIntervals(manager, current, manager->head_);
|
||||
}
|
||||
ConnectIntervals(manager, previous, current);
|
||||
}
|
||||
|
||||
// Insert an interval in the list contained in the manager by starting at
|
||||
// interval_in as a hint. The intervals are sorted by start_ value.
|
||||
static WEBP_INLINE void InsertInterval(CostManager* const manager,
|
||||
CostInterval* const interval_in,
|
||||
float cost, int position, int start,
|
||||
int end) {
|
||||
CostInterval* interval_new;
|
||||
|
||||
if (start >= end) return;
|
||||
if (manager->count_ >= COST_CACHE_INTERVAL_SIZE_MAX) {
|
||||
// Serialize the interval if we cannot store it.
|
||||
UpdateCostPerInterval(manager, start, end, position, cost);
|
||||
return;
|
||||
}
|
||||
if (manager->free_intervals_ != NULL) {
|
||||
interval_new = manager->free_intervals_;
|
||||
manager->free_intervals_ = interval_new->next_;
|
||||
} else if (manager->recycled_intervals_ != NULL) {
|
||||
interval_new = manager->recycled_intervals_;
|
||||
manager->recycled_intervals_ = interval_new->next_;
|
||||
} else { // malloc for good
|
||||
interval_new = (CostInterval*)WebPSafeMalloc(1, sizeof(*interval_new));
|
||||
if (interval_new == NULL) {
|
||||
// Write down the interval if we cannot create it.
|
||||
UpdateCostPerInterval(manager, start, end, position, cost);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
interval_new->cost_ = cost;
|
||||
interval_new->index_ = position;
|
||||
interval_new->start_ = start;
|
||||
interval_new->end_ = end;
|
||||
PositionOrphanInterval(manager, interval_new, interval_in);
|
||||
|
||||
++manager->count_;
|
||||
}
|
||||
|
||||
// Given a new cost interval defined by its start at position, its length value
|
||||
// and distance_cost, add its contributions to the previous intervals and costs.
|
||||
// If handling the interval or one of its subintervals becomes to heavy, its
|
||||
// contribution is added to the costs right away.
|
||||
static WEBP_INLINE void PushInterval(CostManager* const manager,
|
||||
double distance_cost, int position,
|
||||
int len) {
|
||||
size_t i;
|
||||
CostInterval* interval = manager->head_;
|
||||
CostInterval* interval_next;
|
||||
const CostCacheInterval* const cost_cache_intervals =
|
||||
manager->cache_intervals_;
|
||||
// If the interval is small enough, no need to deal with the heavy
|
||||
// interval logic, just serialize it right away. This constant is empirical.
|
||||
const int kSkipDistance = 10;
|
||||
|
||||
if (len < kSkipDistance) {
|
||||
int j;
|
||||
for (j = position; j < position + len; ++j) {
|
||||
const int k = j - position;
|
||||
float cost_tmp;
|
||||
assert(k >= 0 && k < MAX_LENGTH);
|
||||
cost_tmp = (float)(distance_cost + manager->cost_cache_[k]);
|
||||
|
||||
if (manager->costs_[j] > cost_tmp) {
|
||||
manager->costs_[j] = cost_tmp;
|
||||
manager->dist_array_[j] = k + 1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < manager->cache_intervals_size_ &&
|
||||
cost_cache_intervals[i].start_ < len;
|
||||
++i) {
|
||||
// Define the intersection of the ith interval with the new one.
|
||||
int start = position + cost_cache_intervals[i].start_;
|
||||
const int end = position + (cost_cache_intervals[i].end_ > len
|
||||
? len
|
||||
: cost_cache_intervals[i].end_);
|
||||
const float cost = (float)(distance_cost + cost_cache_intervals[i].cost_);
|
||||
|
||||
for (; interval != NULL && interval->start_ < end;
|
||||
interval = interval_next) {
|
||||
interval_next = interval->next_;
|
||||
|
||||
// Make sure we have some overlap
|
||||
if (start >= interval->end_) continue;
|
||||
|
||||
if (cost >= interval->cost_) {
|
||||
// When intervals are represented, the lower, the better.
|
||||
// [**********************************************************[
|
||||
// start end
|
||||
// [----------------------------------[
|
||||
// interval->start_ interval->end_
|
||||
// If we are worse than what we already have, add whatever we have so
|
||||
// far up to interval.
|
||||
const int start_new = interval->end_;
|
||||
InsertInterval(manager, interval, cost, position, start,
|
||||
interval->start_);
|
||||
start = start_new;
|
||||
if (start >= end) break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start <= interval->start_) {
|
||||
if (interval->end_ <= end) {
|
||||
// [----------------------------------[
|
||||
// interval->start_ interval->end_
|
||||
// [**************************************************************[
|
||||
// start end
|
||||
// We can safely remove the old interval as it is fully included.
|
||||
PopInterval(manager, interval);
|
||||
} else {
|
||||
// [------------------------------------[
|
||||
// interval->start_ interval->end_
|
||||
// [*****************************[
|
||||
// start end
|
||||
interval->start_ = end;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (end < interval->end_) {
|
||||
// [--------------------------------------------------------------[
|
||||
// interval->start_ interval->end_
|
||||
// [*****************************[
|
||||
// start end
|
||||
// We have to split the old interval as it fully contains the new one.
|
||||
const int end_original = interval->end_;
|
||||
interval->end_ = start;
|
||||
InsertInterval(manager, interval, interval->cost_, interval->index_,
|
||||
end, end_original);
|
||||
interval = interval->next_;
|
||||
break;
|
||||
} else {
|
||||
// [------------------------------------[
|
||||
// interval->start_ interval->end_
|
||||
// [*****************************[
|
||||
// start end
|
||||
interval->end_ = start;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Insert the remaining interval from start to end.
|
||||
InsertInterval(manager, interval, cost, position, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
static int BackwardReferencesHashChainDistanceOnly(
|
||||
int xsize, int ysize, const uint32_t* const argb, int cache_bits,
|
||||
const VP8LHashChain* const hash_chain, const VP8LBackwardRefs* const refs,
|
||||
uint16_t* const dist_array) {
|
||||
int i;
|
||||
int ok = 0;
|
||||
int cc_init = 0;
|
||||
const int pix_count = xsize * ysize;
|
||||
const int use_color_cache = (cache_bits > 0);
|
||||
const size_t literal_array_size =
|
||||
sizeof(double) * (NUM_LITERAL_CODES + NUM_LENGTH_CODES +
|
||||
((cache_bits > 0) ? (1 << cache_bits) : 0));
|
||||
const size_t cost_model_size = sizeof(CostModel) + literal_array_size;
|
||||
CostModel* const cost_model =
|
||||
(CostModel*)WebPSafeCalloc(1ULL, cost_model_size);
|
||||
VP8LColorCache hashers;
|
||||
CostManager* cost_manager =
|
||||
(CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager));
|
||||
int offset_prev = -1, len_prev = -1;
|
||||
double offset_cost = -1;
|
||||
int first_offset_is_constant = -1; // initialized with 'impossible' value
|
||||
int reach = 0;
|
||||
|
||||
if (cost_model == NULL || cost_manager == NULL) goto Error;
|
||||
|
||||
cost_model->literal_ = (double*)(cost_model + 1);
|
||||
if (use_color_cache) {
|
||||
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
|
||||
if (!cc_init) goto Error;
|
||||
}
|
||||
|
||||
if (!CostModelBuild(cost_model, xsize, cache_bits, refs)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
if (!CostManagerInit(cost_manager, dist_array, pix_count, cost_model)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// We loop one pixel at a time, but store all currently best points to
|
||||
// non-processed locations from this point.
|
||||
dist_array[0] = 0;
|
||||
// Add first pixel as literal.
|
||||
AddSingleLiteralWithCostModel(argb, &hashers, cost_model, 0, use_color_cache,
|
||||
0.f, cost_manager->costs_, dist_array);
|
||||
|
||||
for (i = 1; i < pix_count; ++i) {
|
||||
const float prev_cost = cost_manager->costs_[i - 1];
|
||||
int offset, len;
|
||||
VP8LHashChainFindCopy(hash_chain, i, &offset, &len);
|
||||
|
||||
// Try adding the pixel as a literal.
|
||||
AddSingleLiteralWithCostModel(argb, &hashers, cost_model, i,
|
||||
use_color_cache, prev_cost,
|
||||
cost_manager->costs_, dist_array);
|
||||
|
||||
// If we are dealing with a non-literal.
|
||||
if (len >= 2) {
|
||||
if (offset != offset_prev) {
|
||||
const int code = VP8LDistanceToPlaneCode(xsize, offset);
|
||||
offset_cost = GetDistanceCost(cost_model, code);
|
||||
first_offset_is_constant = 1;
|
||||
PushInterval(cost_manager, prev_cost + offset_cost, i, len);
|
||||
} else {
|
||||
assert(offset_cost >= 0);
|
||||
assert(len_prev >= 0);
|
||||
assert(first_offset_is_constant == 0 || first_offset_is_constant == 1);
|
||||
// Instead of considering all contributions from a pixel i by calling:
|
||||
// PushInterval(cost_manager, prev_cost + offset_cost, i, len);
|
||||
// we optimize these contributions in case offset_cost stays the same
|
||||
// for consecutive pixels. This describes a set of pixels similar to a
|
||||
// previous set (e.g. constant color regions).
|
||||
if (first_offset_is_constant) {
|
||||
reach = i - 1 + len_prev - 1;
|
||||
first_offset_is_constant = 0;
|
||||
}
|
||||
|
||||
if (i + len - 1 > reach) {
|
||||
// We can only be go further with the same offset if the previous
|
||||
// length was maxed, hence len_prev == len == MAX_LENGTH.
|
||||
// TODO(vrabaud), bump i to the end right away (insert cache and
|
||||
// update cost).
|
||||
// TODO(vrabaud), check if one of the points in between does not have
|
||||
// a lower cost.
|
||||
// Already consider the pixel at "reach" to add intervals that are
|
||||
// better than whatever we add.
|
||||
int offset_j, len_j = 0;
|
||||
int j;
|
||||
assert(len == MAX_LENGTH || len == pix_count - i);
|
||||
// Figure out the last consecutive pixel within [i, reach + 1] with
|
||||
// the same offset.
|
||||
for (j = i; j <= reach; ++j) {
|
||||
VP8LHashChainFindCopy(hash_chain, j + 1, &offset_j, &len_j);
|
||||
if (offset_j != offset) {
|
||||
VP8LHashChainFindCopy(hash_chain, j, &offset_j, &len_j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Update the cost at j - 1 and j.
|
||||
UpdateCostAtIndex(cost_manager, j - 1, 0);
|
||||
UpdateCostAtIndex(cost_manager, j, 0);
|
||||
|
||||
PushInterval(cost_manager, cost_manager->costs_[j - 1] + offset_cost,
|
||||
j, len_j);
|
||||
reach = j + len_j - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateCostAtIndex(cost_manager, i, 1);
|
||||
offset_prev = offset;
|
||||
len_prev = len;
|
||||
}
|
||||
|
||||
ok = !refs->error_;
|
||||
Error:
|
||||
if (cc_init) VP8LColorCacheClear(&hashers);
|
||||
CostManagerClear(cost_manager);
|
||||
WebPSafeFree(cost_model);
|
||||
WebPSafeFree(cost_manager);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// We pack the path at the end of *dist_array and return
|
||||
// a pointer to this part of the array. Example:
|
||||
// dist_array = [1x2xx3x2] => packed [1x2x1232], chosen_path = [1232]
|
||||
static void TraceBackwards(uint16_t* const dist_array,
|
||||
int dist_array_size,
|
||||
uint16_t** const chosen_path,
|
||||
int* const chosen_path_size) {
|
||||
uint16_t* path = dist_array + dist_array_size;
|
||||
uint16_t* cur = dist_array + dist_array_size - 1;
|
||||
while (cur >= dist_array) {
|
||||
const int k = *cur;
|
||||
--path;
|
||||
*path = k;
|
||||
cur -= k;
|
||||
}
|
||||
*chosen_path = path;
|
||||
*chosen_path_size = (int)(dist_array + dist_array_size - path);
|
||||
}
|
||||
|
||||
static int BackwardReferencesHashChainFollowChosenPath(
|
||||
const uint32_t* const argb, int cache_bits,
|
||||
const uint16_t* const chosen_path, int chosen_path_size,
|
||||
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs) {
|
||||
const int use_color_cache = (cache_bits > 0);
|
||||
int ix;
|
||||
int i = 0;
|
||||
int ok = 0;
|
||||
int cc_init = 0;
|
||||
VP8LColorCache hashers;
|
||||
|
||||
if (use_color_cache) {
|
||||
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
|
||||
if (!cc_init) goto Error;
|
||||
}
|
||||
|
||||
VP8LClearBackwardRefs(refs);
|
||||
for (ix = 0; ix < chosen_path_size; ++ix) {
|
||||
const int len = chosen_path[ix];
|
||||
if (len != 1) {
|
||||
int k;
|
||||
const int offset = VP8LHashChainFindOffset(hash_chain, i);
|
||||
VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len));
|
||||
if (use_color_cache) {
|
||||
for (k = 0; k < len; ++k) {
|
||||
VP8LColorCacheInsert(&hashers, argb[i + k]);
|
||||
}
|
||||
}
|
||||
i += len;
|
||||
} else {
|
||||
PixOrCopy v;
|
||||
const int idx =
|
||||
use_color_cache ? VP8LColorCacheContains(&hashers, argb[i]) : -1;
|
||||
if (idx >= 0) {
|
||||
// use_color_cache is true and hashers contains argb[i]
|
||||
// push pixel as a color cache index
|
||||
v = PixOrCopyCreateCacheIdx(idx);
|
||||
} else {
|
||||
if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
|
||||
v = PixOrCopyCreateLiteral(argb[i]);
|
||||
}
|
||||
VP8LBackwardRefsCursorAdd(refs, v);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
ok = !refs->error_;
|
||||
Error:
|
||||
if (cc_init) VP8LColorCacheClear(&hashers);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Returns 1 on success.
|
||||
extern int VP8LBackwardReferencesTraceBackwards(
|
||||
int xsize, int ysize, const uint32_t* const argb, int cache_bits,
|
||||
const VP8LHashChain* const hash_chain,
|
||||
const VP8LBackwardRefs* const refs_src, VP8LBackwardRefs* const refs_dst);
|
||||
int VP8LBackwardReferencesTraceBackwards(int xsize, int ysize,
|
||||
const uint32_t* const argb,
|
||||
int cache_bits,
|
||||
const VP8LHashChain* const hash_chain,
|
||||
const VP8LBackwardRefs* const refs_src,
|
||||
VP8LBackwardRefs* const refs_dst) {
|
||||
int ok = 0;
|
||||
const int dist_array_size = xsize * ysize;
|
||||
uint16_t* chosen_path = NULL;
|
||||
int chosen_path_size = 0;
|
||||
uint16_t* dist_array =
|
||||
(uint16_t*)WebPSafeMalloc(dist_array_size, sizeof(*dist_array));
|
||||
|
||||
if (dist_array == NULL) goto Error;
|
||||
|
||||
if (!BackwardReferencesHashChainDistanceOnly(
|
||||
xsize, ysize, argb, cache_bits, hash_chain, refs_src, dist_array)) {
|
||||
goto Error;
|
||||
}
|
||||
TraceBackwards(dist_array, dist_array_size, &chosen_path, &chosen_path_size);
|
||||
if (!BackwardReferencesHashChainFollowChosenPath(
|
||||
argb, cache_bits, chosen_path, chosen_path_size, hash_chain,
|
||||
refs_dst)) {
|
||||
goto Error;
|
||||
}
|
||||
ok = 1;
|
||||
Error:
|
||||
WebPSafeFree(dist_array);
|
||||
return ok;
|
||||
}
|
||||
944
libsdl2_image/external/libwebp-1.0.2/src/enc/backward_references_enc.c
vendored
Normal file
944
libsdl2_image/external/libwebp-1.0.2/src/enc/backward_references_enc.c
vendored
Normal file
@ -0,0 +1,944 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Author: Jyrki Alakuijala (jyrki@google.com)
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "src/enc/backward_references_enc.h"
|
||||
#include "src/enc/histogram_enc.h"
|
||||
#include "src/dsp/lossless.h"
|
||||
#include "src/dsp/lossless_common.h"
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/utils/color_cache_utils.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
#define MIN_BLOCK_SIZE 256 // minimum block size for backward references
|
||||
|
||||
#define MAX_ENTROPY (1e30f)
|
||||
|
||||
// 1M window (4M bytes) minus 120 special codes for short distances.
|
||||
#define WINDOW_SIZE ((1 << WINDOW_SIZE_BITS) - 120)
|
||||
|
||||
// Minimum number of pixels for which it is cheaper to encode a
|
||||
// distance + length instead of each pixel as a literal.
|
||||
#define MIN_LENGTH 4
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static const uint8_t plane_to_code_lut[128] = {
|
||||
96, 73, 55, 39, 23, 13, 5, 1, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
101, 78, 58, 42, 26, 16, 8, 2, 0, 3, 9, 17, 27, 43, 59, 79,
|
||||
102, 86, 62, 46, 32, 20, 10, 6, 4, 7, 11, 21, 33, 47, 63, 87,
|
||||
105, 90, 70, 52, 37, 28, 18, 14, 12, 15, 19, 29, 38, 53, 71, 91,
|
||||
110, 99, 82, 66, 48, 35, 30, 24, 22, 25, 31, 36, 49, 67, 83, 100,
|
||||
115, 108, 94, 76, 64, 50, 44, 40, 34, 41, 45, 51, 65, 77, 95, 109,
|
||||
118, 113, 103, 92, 80, 68, 60, 56, 54, 57, 61, 69, 81, 93, 104, 114,
|
||||
119, 116, 111, 106, 97, 88, 84, 74, 72, 75, 85, 89, 98, 107, 112, 117
|
||||
};
|
||||
|
||||
extern int VP8LDistanceToPlaneCode(int xsize, int dist);
|
||||
int VP8LDistanceToPlaneCode(int xsize, int dist) {
|
||||
const int yoffset = dist / xsize;
|
||||
const int xoffset = dist - yoffset * xsize;
|
||||
if (xoffset <= 8 && yoffset < 8) {
|
||||
return plane_to_code_lut[yoffset * 16 + 8 - xoffset] + 1;
|
||||
} else if (xoffset > xsize - 8 && yoffset < 7) {
|
||||
return plane_to_code_lut[(yoffset + 1) * 16 + 8 + (xsize - xoffset)] + 1;
|
||||
}
|
||||
return dist + 120;
|
||||
}
|
||||
|
||||
// Returns the exact index where array1 and array2 are different. For an index
|
||||
// inferior or equal to best_len_match, the return value just has to be strictly
|
||||
// inferior to best_len_match. The current behavior is to return 0 if this index
|
||||
// is best_len_match, and the index itself otherwise.
|
||||
// If no two elements are the same, it returns max_limit.
|
||||
static WEBP_INLINE int FindMatchLength(const uint32_t* const array1,
|
||||
const uint32_t* const array2,
|
||||
int best_len_match, int max_limit) {
|
||||
// Before 'expensive' linear match, check if the two arrays match at the
|
||||
// current best length index.
|
||||
if (array1[best_len_match] != array2[best_len_match]) return 0;
|
||||
|
||||
return VP8LVectorMismatch(array1, array2, max_limit);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// VP8LBackwardRefs
|
||||
|
||||
struct PixOrCopyBlock {
|
||||
PixOrCopyBlock* next_; // next block (or NULL)
|
||||
PixOrCopy* start_; // data start
|
||||
int size_; // currently used size
|
||||
};
|
||||
|
||||
extern void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs);
|
||||
void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) {
|
||||
assert(refs != NULL);
|
||||
if (refs->tail_ != NULL) {
|
||||
*refs->tail_ = refs->free_blocks_; // recycle all blocks at once
|
||||
}
|
||||
refs->free_blocks_ = refs->refs_;
|
||||
refs->tail_ = &refs->refs_;
|
||||
refs->last_block_ = NULL;
|
||||
refs->refs_ = NULL;
|
||||
}
|
||||
|
||||
void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) {
|
||||
assert(refs != NULL);
|
||||
VP8LClearBackwardRefs(refs);
|
||||
while (refs->free_blocks_ != NULL) {
|
||||
PixOrCopyBlock* const next = refs->free_blocks_->next_;
|
||||
WebPSafeFree(refs->free_blocks_);
|
||||
refs->free_blocks_ = next;
|
||||
}
|
||||
}
|
||||
|
||||
void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size) {
|
||||
assert(refs != NULL);
|
||||
memset(refs, 0, sizeof(*refs));
|
||||
refs->tail_ = &refs->refs_;
|
||||
refs->block_size_ =
|
||||
(block_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : block_size;
|
||||
}
|
||||
|
||||
VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs) {
|
||||
VP8LRefsCursor c;
|
||||
c.cur_block_ = refs->refs_;
|
||||
if (refs->refs_ != NULL) {
|
||||
c.cur_pos = c.cur_block_->start_;
|
||||
c.last_pos_ = c.cur_pos + c.cur_block_->size_;
|
||||
} else {
|
||||
c.cur_pos = NULL;
|
||||
c.last_pos_ = NULL;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c) {
|
||||
PixOrCopyBlock* const b = c->cur_block_->next_;
|
||||
c->cur_pos = (b == NULL) ? NULL : b->start_;
|
||||
c->last_pos_ = (b == NULL) ? NULL : b->start_ + b->size_;
|
||||
c->cur_block_ = b;
|
||||
}
|
||||
|
||||
// Create a new block, either from the free list or allocated
|
||||
static PixOrCopyBlock* BackwardRefsNewBlock(VP8LBackwardRefs* const refs) {
|
||||
PixOrCopyBlock* b = refs->free_blocks_;
|
||||
if (b == NULL) { // allocate new memory chunk
|
||||
const size_t total_size =
|
||||
sizeof(*b) + refs->block_size_ * sizeof(*b->start_);
|
||||
b = (PixOrCopyBlock*)WebPSafeMalloc(1ULL, total_size);
|
||||
if (b == NULL) {
|
||||
refs->error_ |= 1;
|
||||
return NULL;
|
||||
}
|
||||
b->start_ = (PixOrCopy*)((uint8_t*)b + sizeof(*b)); // not always aligned
|
||||
} else { // recycle from free-list
|
||||
refs->free_blocks_ = b->next_;
|
||||
}
|
||||
*refs->tail_ = b;
|
||||
refs->tail_ = &b->next_;
|
||||
refs->last_block_ = b;
|
||||
b->next_ = NULL;
|
||||
b->size_ = 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
|
||||
const PixOrCopy v);
|
||||
void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
|
||||
const PixOrCopy v) {
|
||||
PixOrCopyBlock* b = refs->last_block_;
|
||||
if (b == NULL || b->size_ == refs->block_size_) {
|
||||
b = BackwardRefsNewBlock(refs);
|
||||
if (b == NULL) return; // refs->error_ is set
|
||||
}
|
||||
b->start_[b->size_++] = v;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Hash chains
|
||||
|
||||
int VP8LHashChainInit(VP8LHashChain* const p, int size) {
|
||||
assert(p->size_ == 0);
|
||||
assert(p->offset_length_ == NULL);
|
||||
assert(size > 0);
|
||||
p->offset_length_ =
|
||||
(uint32_t*)WebPSafeMalloc(size, sizeof(*p->offset_length_));
|
||||
if (p->offset_length_ == NULL) return 0;
|
||||
p->size_ = size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VP8LHashChainClear(VP8LHashChain* const p) {
|
||||
assert(p != NULL);
|
||||
WebPSafeFree(p->offset_length_);
|
||||
|
||||
p->size_ = 0;
|
||||
p->offset_length_ = NULL;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define HASH_MULTIPLIER_HI (0xc6a4a793ULL)
|
||||
#define HASH_MULTIPLIER_LO (0x5bd1e996ULL)
|
||||
|
||||
static WEBP_INLINE uint32_t GetPixPairHash64(const uint32_t* const argb) {
|
||||
uint32_t key;
|
||||
key = (argb[1] * HASH_MULTIPLIER_HI) & 0xffffffffu;
|
||||
key += (argb[0] * HASH_MULTIPLIER_LO) & 0xffffffffu;
|
||||
key = key >> (32 - HASH_BITS);
|
||||
return key;
|
||||
}
|
||||
|
||||
// Returns the maximum number of hash chain lookups to do for a
|
||||
// given compression quality. Return value in range [8, 86].
|
||||
static int GetMaxItersForQuality(int quality) {
|
||||
return 8 + (quality * quality) / 128;
|
||||
}
|
||||
|
||||
static int GetWindowSizeForHashChain(int quality, int xsize) {
|
||||
const int max_window_size = (quality > 75) ? WINDOW_SIZE
|
||||
: (quality > 50) ? (xsize << 8)
|
||||
: (quality > 25) ? (xsize << 6)
|
||||
: (xsize << 4);
|
||||
assert(xsize > 0);
|
||||
return (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE : max_window_size;
|
||||
}
|
||||
|
||||
static WEBP_INLINE int MaxFindCopyLength(int len) {
|
||||
return (len < MAX_LENGTH) ? len : MAX_LENGTH;
|
||||
}
|
||||
|
||||
int VP8LHashChainFill(VP8LHashChain* const p, int quality,
|
||||
const uint32_t* const argb, int xsize, int ysize,
|
||||
int low_effort) {
|
||||
const int size = xsize * ysize;
|
||||
const int iter_max = GetMaxItersForQuality(quality);
|
||||
const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize);
|
||||
int pos;
|
||||
int argb_comp;
|
||||
uint32_t base_position;
|
||||
int32_t* hash_to_first_index;
|
||||
// Temporarily use the p->offset_length_ as a hash chain.
|
||||
int32_t* chain = (int32_t*)p->offset_length_;
|
||||
assert(size > 0);
|
||||
assert(p->size_ != 0);
|
||||
assert(p->offset_length_ != NULL);
|
||||
|
||||
if (size <= 2) {
|
||||
p->offset_length_[0] = p->offset_length_[size - 1] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
hash_to_first_index =
|
||||
(int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index));
|
||||
if (hash_to_first_index == NULL) return 0;
|
||||
|
||||
// Set the int32_t array to -1.
|
||||
memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index));
|
||||
// Fill the chain linking pixels with the same hash.
|
||||
argb_comp = (argb[0] == argb[1]);
|
||||
for (pos = 0; pos < size - 2;) {
|
||||
uint32_t hash_code;
|
||||
const int argb_comp_next = (argb[pos + 1] == argb[pos + 2]);
|
||||
if (argb_comp && argb_comp_next) {
|
||||
// Consecutive pixels with the same color will share the same hash.
|
||||
// We therefore use a different hash: the color and its repetition
|
||||
// length.
|
||||
uint32_t tmp[2];
|
||||
uint32_t len = 1;
|
||||
tmp[0] = argb[pos];
|
||||
// Figure out how far the pixels are the same.
|
||||
// The last pixel has a different 64 bit hash, as its next pixel does
|
||||
// not have the same color, so we just need to get to the last pixel equal
|
||||
// to its follower.
|
||||
while (pos + (int)len + 2 < size && argb[pos + len + 2] == argb[pos]) {
|
||||
++len;
|
||||
}
|
||||
if (len > MAX_LENGTH) {
|
||||
// Skip the pixels that match for distance=1 and length>MAX_LENGTH
|
||||
// because they are linked to their predecessor and we automatically
|
||||
// check that in the main for loop below. Skipping means setting no
|
||||
// predecessor in the chain, hence -1.
|
||||
memset(chain + pos, 0xff, (len - MAX_LENGTH) * sizeof(*chain));
|
||||
pos += len - MAX_LENGTH;
|
||||
len = MAX_LENGTH;
|
||||
}
|
||||
// Process the rest of the hash chain.
|
||||
while (len) {
|
||||
tmp[1] = len--;
|
||||
hash_code = GetPixPairHash64(tmp);
|
||||
chain[pos] = hash_to_first_index[hash_code];
|
||||
hash_to_first_index[hash_code] = pos++;
|
||||
}
|
||||
argb_comp = 0;
|
||||
} else {
|
||||
// Just move one pixel forward.
|
||||
hash_code = GetPixPairHash64(argb + pos);
|
||||
chain[pos] = hash_to_first_index[hash_code];
|
||||
hash_to_first_index[hash_code] = pos++;
|
||||
argb_comp = argb_comp_next;
|
||||
}
|
||||
}
|
||||
// Process the penultimate pixel.
|
||||
chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)];
|
||||
|
||||
WebPSafeFree(hash_to_first_index);
|
||||
|
||||
// Find the best match interval at each pixel, defined by an offset to the
|
||||
// pixel and a length. The right-most pixel cannot match anything to the right
|
||||
// (hence a best length of 0) and the left-most pixel nothing to the left
|
||||
// (hence an offset of 0).
|
||||
assert(size > 2);
|
||||
p->offset_length_[0] = p->offset_length_[size - 1] = 0;
|
||||
for (base_position = size - 2; base_position > 0;) {
|
||||
const int max_len = MaxFindCopyLength(size - 1 - base_position);
|
||||
const uint32_t* const argb_start = argb + base_position;
|
||||
int iter = iter_max;
|
||||
int best_length = 0;
|
||||
uint32_t best_distance = 0;
|
||||
uint32_t best_argb;
|
||||
const int min_pos =
|
||||
(base_position > window_size) ? base_position - window_size : 0;
|
||||
const int length_max = (max_len < 256) ? max_len : 256;
|
||||
uint32_t max_base_position;
|
||||
|
||||
pos = chain[base_position];
|
||||
if (!low_effort) {
|
||||
int curr_length;
|
||||
// Heuristic: use the comparison with the above line as an initialization.
|
||||
if (base_position >= (uint32_t)xsize) {
|
||||
curr_length = FindMatchLength(argb_start - xsize, argb_start,
|
||||
best_length, max_len);
|
||||
if (curr_length > best_length) {
|
||||
best_length = curr_length;
|
||||
best_distance = xsize;
|
||||
}
|
||||
--iter;
|
||||
}
|
||||
// Heuristic: compare to the previous pixel.
|
||||
curr_length =
|
||||
FindMatchLength(argb_start - 1, argb_start, best_length, max_len);
|
||||
if (curr_length > best_length) {
|
||||
best_length = curr_length;
|
||||
best_distance = 1;
|
||||
}
|
||||
--iter;
|
||||
// Skip the for loop if we already have the maximum.
|
||||
if (best_length == MAX_LENGTH) pos = min_pos - 1;
|
||||
}
|
||||
best_argb = argb_start[best_length];
|
||||
|
||||
for (; pos >= min_pos && --iter; pos = chain[pos]) {
|
||||
int curr_length;
|
||||
assert(base_position > (uint32_t)pos);
|
||||
|
||||
if (argb[pos + best_length] != best_argb) continue;
|
||||
|
||||
curr_length = VP8LVectorMismatch(argb + pos, argb_start, max_len);
|
||||
if (best_length < curr_length) {
|
||||
best_length = curr_length;
|
||||
best_distance = base_position - pos;
|
||||
best_argb = argb_start[best_length];
|
||||
// Stop if we have reached a good enough length.
|
||||
if (best_length >= length_max) break;
|
||||
}
|
||||
}
|
||||
// We have the best match but in case the two intervals continue matching
|
||||
// to the left, we have the best matches for the left-extended pixels.
|
||||
max_base_position = base_position;
|
||||
while (1) {
|
||||
assert(best_length <= MAX_LENGTH);
|
||||
assert(best_distance <= WINDOW_SIZE);
|
||||
p->offset_length_[base_position] =
|
||||
(best_distance << MAX_LENGTH_BITS) | (uint32_t)best_length;
|
||||
--base_position;
|
||||
// Stop if we don't have a match or if we are out of bounds.
|
||||
if (best_distance == 0 || base_position == 0) break;
|
||||
// Stop if we cannot extend the matching intervals to the left.
|
||||
if (base_position < best_distance ||
|
||||
argb[base_position - best_distance] != argb[base_position]) {
|
||||
break;
|
||||
}
|
||||
// Stop if we are matching at its limit because there could be a closer
|
||||
// matching interval with the same maximum length. Then again, if the
|
||||
// matching interval is as close as possible (best_distance == 1), we will
|
||||
// never find anything better so let's continue.
|
||||
if (best_length == MAX_LENGTH && best_distance != 1 &&
|
||||
base_position + MAX_LENGTH < max_base_position) {
|
||||
break;
|
||||
}
|
||||
if (best_length < MAX_LENGTH) {
|
||||
++best_length;
|
||||
max_base_position = base_position;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache,
|
||||
VP8LColorCache* const hashers,
|
||||
VP8LBackwardRefs* const refs) {
|
||||
PixOrCopy v;
|
||||
if (use_color_cache) {
|
||||
const uint32_t key = VP8LColorCacheGetIndex(hashers, pixel);
|
||||
if (VP8LColorCacheLookup(hashers, key) == pixel) {
|
||||
v = PixOrCopyCreateCacheIdx(key);
|
||||
} else {
|
||||
v = PixOrCopyCreateLiteral(pixel);
|
||||
VP8LColorCacheSet(hashers, key, pixel);
|
||||
}
|
||||
} else {
|
||||
v = PixOrCopyCreateLiteral(pixel);
|
||||
}
|
||||
VP8LBackwardRefsCursorAdd(refs, v);
|
||||
}
|
||||
|
||||
static int BackwardReferencesRle(int xsize, int ysize,
|
||||
const uint32_t* const argb,
|
||||
int cache_bits, VP8LBackwardRefs* const refs) {
|
||||
const int pix_count = xsize * ysize;
|
||||
int i, k;
|
||||
const int use_color_cache = (cache_bits > 0);
|
||||
VP8LColorCache hashers;
|
||||
|
||||
if (use_color_cache && !VP8LColorCacheInit(&hashers, cache_bits)) {
|
||||
return 0;
|
||||
}
|
||||
VP8LClearBackwardRefs(refs);
|
||||
// Add first pixel as literal.
|
||||
AddSingleLiteral(argb[0], use_color_cache, &hashers, refs);
|
||||
i = 1;
|
||||
while (i < pix_count) {
|
||||
const int max_len = MaxFindCopyLength(pix_count - i);
|
||||
const int rle_len = FindMatchLength(argb + i, argb + i - 1, 0, max_len);
|
||||
const int prev_row_len = (i < xsize) ? 0 :
|
||||
FindMatchLength(argb + i, argb + i - xsize, 0, max_len);
|
||||
if (rle_len >= prev_row_len && rle_len >= MIN_LENGTH) {
|
||||
VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, rle_len));
|
||||
// We don't need to update the color cache here since it is always the
|
||||
// same pixel being copied, and that does not change the color cache
|
||||
// state.
|
||||
i += rle_len;
|
||||
} else if (prev_row_len >= MIN_LENGTH) {
|
||||
VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(xsize, prev_row_len));
|
||||
if (use_color_cache) {
|
||||
for (k = 0; k < prev_row_len; ++k) {
|
||||
VP8LColorCacheInsert(&hashers, argb[i + k]);
|
||||
}
|
||||
}
|
||||
i += prev_row_len;
|
||||
} else {
|
||||
AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (use_color_cache) VP8LColorCacheClear(&hashers);
|
||||
return !refs->error_;
|
||||
}
|
||||
|
||||
static int BackwardReferencesLz77(int xsize, int ysize,
|
||||
const uint32_t* const argb, int cache_bits,
|
||||
const VP8LHashChain* const hash_chain,
|
||||
VP8LBackwardRefs* const refs) {
|
||||
int i;
|
||||
int i_last_check = -1;
|
||||
int ok = 0;
|
||||
int cc_init = 0;
|
||||
const int use_color_cache = (cache_bits > 0);
|
||||
const int pix_count = xsize * ysize;
|
||||
VP8LColorCache hashers;
|
||||
|
||||
if (use_color_cache) {
|
||||
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
|
||||
if (!cc_init) goto Error;
|
||||
}
|
||||
VP8LClearBackwardRefs(refs);
|
||||
for (i = 0; i < pix_count;) {
|
||||
// Alternative#1: Code the pixels starting at 'i' using backward reference.
|
||||
int offset = 0;
|
||||
int len = 0;
|
||||
int j;
|
||||
VP8LHashChainFindCopy(hash_chain, i, &offset, &len);
|
||||
if (len >= MIN_LENGTH) {
|
||||
const int len_ini = len;
|
||||
int max_reach = 0;
|
||||
const int j_max =
|
||||
(i + len_ini >= pix_count) ? pix_count - 1 : i + len_ini;
|
||||
// Only start from what we have not checked already.
|
||||
i_last_check = (i > i_last_check) ? i : i_last_check;
|
||||
// We know the best match for the current pixel but we try to find the
|
||||
// best matches for the current pixel AND the next one combined.
|
||||
// The naive method would use the intervals:
|
||||
// [i,i+len) + [i+len, length of best match at i+len)
|
||||
// while we check if we can use:
|
||||
// [i,j) (where j<=i+len) + [j, length of best match at j)
|
||||
for (j = i_last_check + 1; j <= j_max; ++j) {
|
||||
const int len_j = VP8LHashChainFindLength(hash_chain, j);
|
||||
const int reach =
|
||||
j + (len_j >= MIN_LENGTH ? len_j : 1); // 1 for single literal.
|
||||
if (reach > max_reach) {
|
||||
len = j - i;
|
||||
max_reach = reach;
|
||||
if (max_reach >= pix_count) break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
len = 1;
|
||||
}
|
||||
// Go with literal or backward reference.
|
||||
assert(len > 0);
|
||||
if (len == 1) {
|
||||
AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
|
||||
} else {
|
||||
VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len));
|
||||
if (use_color_cache) {
|
||||
for (j = i; j < i + len; ++j) VP8LColorCacheInsert(&hashers, argb[j]);
|
||||
}
|
||||
}
|
||||
i += len;
|
||||
}
|
||||
|
||||
ok = !refs->error_;
|
||||
Error:
|
||||
if (cc_init) VP8LColorCacheClear(&hashers);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Compute an LZ77 by forcing matches to happen within a given distance cost.
|
||||
// We therefore limit the algorithm to the lowest 32 values in the PlaneCode
|
||||
// definition.
|
||||
#define WINDOW_OFFSETS_SIZE_MAX 32
|
||||
static int BackwardReferencesLz77Box(int xsize, int ysize,
|
||||
const uint32_t* const argb, int cache_bits,
|
||||
const VP8LHashChain* const hash_chain_best,
|
||||
VP8LHashChain* hash_chain,
|
||||
VP8LBackwardRefs* const refs) {
|
||||
int i;
|
||||
const int pix_count = xsize * ysize;
|
||||
uint16_t* counts;
|
||||
int window_offsets[WINDOW_OFFSETS_SIZE_MAX] = {0};
|
||||
int window_offsets_new[WINDOW_OFFSETS_SIZE_MAX] = {0};
|
||||
int window_offsets_size = 0;
|
||||
int window_offsets_new_size = 0;
|
||||
uint16_t* const counts_ini =
|
||||
(uint16_t*)WebPSafeMalloc(xsize * ysize, sizeof(*counts_ini));
|
||||
int best_offset_prev = -1, best_length_prev = -1;
|
||||
if (counts_ini == NULL) return 0;
|
||||
|
||||
// counts[i] counts how many times a pixel is repeated starting at position i.
|
||||
i = pix_count - 2;
|
||||
counts = counts_ini + i;
|
||||
counts[1] = 1;
|
||||
for (; i >= 0; --i, --counts) {
|
||||
if (argb[i] == argb[i + 1]) {
|
||||
// Max out the counts to MAX_LENGTH.
|
||||
counts[0] = counts[1] + (counts[1] != MAX_LENGTH);
|
||||
} else {
|
||||
counts[0] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out the window offsets around a pixel. They are stored in a
|
||||
// spiraling order around the pixel as defined by VP8LDistanceToPlaneCode.
|
||||
{
|
||||
int x, y;
|
||||
for (y = 0; y <= 6; ++y) {
|
||||
for (x = -6; x <= 6; ++x) {
|
||||
const int offset = y * xsize + x;
|
||||
int plane_code;
|
||||
// Ignore offsets that bring us after the pixel.
|
||||
if (offset <= 0) continue;
|
||||
plane_code = VP8LDistanceToPlaneCode(xsize, offset) - 1;
|
||||
if (plane_code >= WINDOW_OFFSETS_SIZE_MAX) continue;
|
||||
window_offsets[plane_code] = offset;
|
||||
}
|
||||
}
|
||||
// For narrow images, not all plane codes are reached, so remove those.
|
||||
for (i = 0; i < WINDOW_OFFSETS_SIZE_MAX; ++i) {
|
||||
if (window_offsets[i] == 0) continue;
|
||||
window_offsets[window_offsets_size++] = window_offsets[i];
|
||||
}
|
||||
// Given a pixel P, find the offsets that reach pixels unreachable from P-1
|
||||
// with any of the offsets in window_offsets[].
|
||||
for (i = 0; i < window_offsets_size; ++i) {
|
||||
int j;
|
||||
int is_reachable = 0;
|
||||
for (j = 0; j < window_offsets_size && !is_reachable; ++j) {
|
||||
is_reachable |= (window_offsets[i] == window_offsets[j] + 1);
|
||||
}
|
||||
if (!is_reachable) {
|
||||
window_offsets_new[window_offsets_new_size] = window_offsets[i];
|
||||
++window_offsets_new_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hash_chain->offset_length_[0] = 0;
|
||||
for (i = 1; i < pix_count; ++i) {
|
||||
int ind;
|
||||
int best_length = VP8LHashChainFindLength(hash_chain_best, i);
|
||||
int best_offset;
|
||||
int do_compute = 1;
|
||||
|
||||
if (best_length >= MAX_LENGTH) {
|
||||
// Do not recompute the best match if we already have a maximal one in the
|
||||
// window.
|
||||
best_offset = VP8LHashChainFindOffset(hash_chain_best, i);
|
||||
for (ind = 0; ind < window_offsets_size; ++ind) {
|
||||
if (best_offset == window_offsets[ind]) {
|
||||
do_compute = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_compute) {
|
||||
// Figure out if we should use the offset/length from the previous pixel
|
||||
// as an initial guess and therefore only inspect the offsets in
|
||||
// window_offsets_new[].
|
||||
const int use_prev =
|
||||
(best_length_prev > 1) && (best_length_prev < MAX_LENGTH);
|
||||
const int num_ind =
|
||||
use_prev ? window_offsets_new_size : window_offsets_size;
|
||||
best_length = use_prev ? best_length_prev - 1 : 0;
|
||||
best_offset = use_prev ? best_offset_prev : 0;
|
||||
// Find the longest match in a window around the pixel.
|
||||
for (ind = 0; ind < num_ind; ++ind) {
|
||||
int curr_length = 0;
|
||||
int j = i;
|
||||
int j_offset =
|
||||
use_prev ? i - window_offsets_new[ind] : i - window_offsets[ind];
|
||||
if (j_offset < 0 || argb[j_offset] != argb[i]) continue;
|
||||
// The longest match is the sum of how many times each pixel is
|
||||
// repeated.
|
||||
do {
|
||||
const int counts_j_offset = counts_ini[j_offset];
|
||||
const int counts_j = counts_ini[j];
|
||||
if (counts_j_offset != counts_j) {
|
||||
curr_length +=
|
||||
(counts_j_offset < counts_j) ? counts_j_offset : counts_j;
|
||||
break;
|
||||
}
|
||||
// The same color is repeated counts_pos times at j_offset and j.
|
||||
curr_length += counts_j_offset;
|
||||
j_offset += counts_j_offset;
|
||||
j += counts_j_offset;
|
||||
} while (curr_length <= MAX_LENGTH && j < pix_count &&
|
||||
argb[j_offset] == argb[j]);
|
||||
if (best_length < curr_length) {
|
||||
best_offset =
|
||||
use_prev ? window_offsets_new[ind] : window_offsets[ind];
|
||||
if (curr_length >= MAX_LENGTH) {
|
||||
best_length = MAX_LENGTH;
|
||||
break;
|
||||
} else {
|
||||
best_length = curr_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(i + best_length <= pix_count);
|
||||
assert(best_length <= MAX_LENGTH);
|
||||
if (best_length <= MIN_LENGTH) {
|
||||
hash_chain->offset_length_[i] = 0;
|
||||
best_offset_prev = 0;
|
||||
best_length_prev = 0;
|
||||
} else {
|
||||
hash_chain->offset_length_[i] =
|
||||
(best_offset << MAX_LENGTH_BITS) | (uint32_t)best_length;
|
||||
best_offset_prev = best_offset;
|
||||
best_length_prev = best_length;
|
||||
}
|
||||
}
|
||||
hash_chain->offset_length_[0] = 0;
|
||||
WebPSafeFree(counts_ini);
|
||||
|
||||
return BackwardReferencesLz77(xsize, ysize, argb, cache_bits, hash_chain,
|
||||
refs);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static void BackwardReferences2DLocality(int xsize,
|
||||
const VP8LBackwardRefs* const refs) {
|
||||
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
|
||||
while (VP8LRefsCursorOk(&c)) {
|
||||
if (PixOrCopyIsCopy(c.cur_pos)) {
|
||||
const int dist = c.cur_pos->argb_or_distance;
|
||||
const int transformed_dist = VP8LDistanceToPlaneCode(xsize, dist);
|
||||
c.cur_pos->argb_or_distance = transformed_dist;
|
||||
}
|
||||
VP8LRefsCursorNext(&c);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate optimal cache bits for the local color cache.
|
||||
// The input *best_cache_bits sets the maximum cache bits to use (passing 0
|
||||
// implies disabling the local color cache). The local color cache is also
|
||||
// disabled for the lower (<= 25) quality.
|
||||
// Returns 0 in case of memory error.
|
||||
static int CalculateBestCacheSize(const uint32_t* argb, int quality,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int* const best_cache_bits) {
|
||||
int i;
|
||||
const int cache_bits_max = (quality <= 25) ? 0 : *best_cache_bits;
|
||||
double entropy_min = MAX_ENTROPY;
|
||||
int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 };
|
||||
VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1];
|
||||
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
|
||||
VP8LHistogram* histos[MAX_COLOR_CACHE_BITS + 1] = { NULL };
|
||||
int ok = 0;
|
||||
|
||||
assert(cache_bits_max >= 0 && cache_bits_max <= MAX_COLOR_CACHE_BITS);
|
||||
|
||||
if (cache_bits_max == 0) {
|
||||
*best_cache_bits = 0;
|
||||
// Local color cache is disabled.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allocate data.
|
||||
for (i = 0; i <= cache_bits_max; ++i) {
|
||||
histos[i] = VP8LAllocateHistogram(i);
|
||||
if (histos[i] == NULL) goto Error;
|
||||
VP8LHistogramInit(histos[i], i, /*init_arrays=*/ 1);
|
||||
if (i == 0) continue;
|
||||
cc_init[i] = VP8LColorCacheInit(&hashers[i], i);
|
||||
if (!cc_init[i]) goto Error;
|
||||
}
|
||||
|
||||
// Find the cache_bits giving the lowest entropy. The search is done in a
|
||||
// brute-force way as the function (entropy w.r.t cache_bits) can be
|
||||
// anything in practice.
|
||||
while (VP8LRefsCursorOk(&c)) {
|
||||
const PixOrCopy* const v = c.cur_pos;
|
||||
if (PixOrCopyIsLiteral(v)) {
|
||||
const uint32_t pix = *argb++;
|
||||
const uint32_t a = (pix >> 24) & 0xff;
|
||||
const uint32_t r = (pix >> 16) & 0xff;
|
||||
const uint32_t g = (pix >> 8) & 0xff;
|
||||
const uint32_t b = (pix >> 0) & 0xff;
|
||||
// The keys of the caches can be derived from the longest one.
|
||||
int key = VP8LHashPix(pix, 32 - cache_bits_max);
|
||||
// Do not use the color cache for cache_bits = 0.
|
||||
++histos[0]->blue_[b];
|
||||
++histos[0]->literal_[g];
|
||||
++histos[0]->red_[r];
|
||||
++histos[0]->alpha_[a];
|
||||
// Deal with cache_bits > 0.
|
||||
for (i = cache_bits_max; i >= 1; --i, key >>= 1) {
|
||||
if (VP8LColorCacheLookup(&hashers[i], key) == pix) {
|
||||
++histos[i]->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key];
|
||||
} else {
|
||||
VP8LColorCacheSet(&hashers[i], key, pix);
|
||||
++histos[i]->blue_[b];
|
||||
++histos[i]->literal_[g];
|
||||
++histos[i]->red_[r];
|
||||
++histos[i]->alpha_[a];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We should compute the contribution of the (distance,length)
|
||||
// histograms but those are the same independently from the cache size.
|
||||
// As those constant contributions are in the end added to the other
|
||||
// histogram contributions, we can safely ignore them.
|
||||
int len = PixOrCopyLength(v);
|
||||
uint32_t argb_prev = *argb ^ 0xffffffffu;
|
||||
// Update the color caches.
|
||||
do {
|
||||
if (*argb != argb_prev) {
|
||||
// Efficiency: insert only if the color changes.
|
||||
int key = VP8LHashPix(*argb, 32 - cache_bits_max);
|
||||
for (i = cache_bits_max; i >= 1; --i, key >>= 1) {
|
||||
hashers[i].colors_[key] = *argb;
|
||||
}
|
||||
argb_prev = *argb;
|
||||
}
|
||||
argb++;
|
||||
} while (--len != 0);
|
||||
}
|
||||
VP8LRefsCursorNext(&c);
|
||||
}
|
||||
|
||||
for (i = 0; i <= cache_bits_max; ++i) {
|
||||
const double entropy = VP8LHistogramEstimateBits(histos[i]);
|
||||
if (i == 0 || entropy < entropy_min) {
|
||||
entropy_min = entropy;
|
||||
*best_cache_bits = i;
|
||||
}
|
||||
}
|
||||
ok = 1;
|
||||
Error:
|
||||
for (i = 0; i <= cache_bits_max; ++i) {
|
||||
if (cc_init[i]) VP8LColorCacheClear(&hashers[i]);
|
||||
VP8LFreeHistogram(histos[i]);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Update (in-place) backward references for specified cache_bits.
|
||||
static int BackwardRefsWithLocalCache(const uint32_t* const argb,
|
||||
int cache_bits,
|
||||
VP8LBackwardRefs* const refs) {
|
||||
int pixel_index = 0;
|
||||
VP8LColorCache hashers;
|
||||
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
|
||||
if (!VP8LColorCacheInit(&hashers, cache_bits)) return 0;
|
||||
|
||||
while (VP8LRefsCursorOk(&c)) {
|
||||
PixOrCopy* const v = c.cur_pos;
|
||||
if (PixOrCopyIsLiteral(v)) {
|
||||
const uint32_t argb_literal = v->argb_or_distance;
|
||||
const int ix = VP8LColorCacheContains(&hashers, argb_literal);
|
||||
if (ix >= 0) {
|
||||
// hashers contains argb_literal
|
||||
*v = PixOrCopyCreateCacheIdx(ix);
|
||||
} else {
|
||||
VP8LColorCacheInsert(&hashers, argb_literal);
|
||||
}
|
||||
++pixel_index;
|
||||
} else {
|
||||
// refs was created without local cache, so it can not have cache indexes.
|
||||
int k;
|
||||
assert(PixOrCopyIsCopy(v));
|
||||
for (k = 0; k < v->len; ++k) {
|
||||
VP8LColorCacheInsert(&hashers, argb[pixel_index++]);
|
||||
}
|
||||
}
|
||||
VP8LRefsCursorNext(&c);
|
||||
}
|
||||
VP8LColorCacheClear(&hashers);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static VP8LBackwardRefs* GetBackwardReferencesLowEffort(
|
||||
int width, int height, const uint32_t* const argb,
|
||||
int* const cache_bits, const VP8LHashChain* const hash_chain,
|
||||
VP8LBackwardRefs* const refs_lz77) {
|
||||
*cache_bits = 0;
|
||||
if (!BackwardReferencesLz77(width, height, argb, 0, hash_chain, refs_lz77)) {
|
||||
return NULL;
|
||||
}
|
||||
BackwardReferences2DLocality(width, refs_lz77);
|
||||
return refs_lz77;
|
||||
}
|
||||
|
||||
extern int VP8LBackwardReferencesTraceBackwards(
|
||||
int xsize, int ysize, const uint32_t* const argb, int cache_bits,
|
||||
const VP8LHashChain* const hash_chain,
|
||||
const VP8LBackwardRefs* const refs_src, VP8LBackwardRefs* const refs_dst);
|
||||
static VP8LBackwardRefs* GetBackwardReferences(
|
||||
int width, int height, const uint32_t* const argb, int quality,
|
||||
int lz77_types_to_try, int* const cache_bits,
|
||||
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* best,
|
||||
VP8LBackwardRefs* worst) {
|
||||
const int cache_bits_initial = *cache_bits;
|
||||
double bit_cost_best = -1;
|
||||
VP8LHistogram* histo = NULL;
|
||||
int lz77_type, lz77_type_best = 0;
|
||||
VP8LHashChain hash_chain_box;
|
||||
memset(&hash_chain_box, 0, sizeof(hash_chain_box));
|
||||
|
||||
histo = VP8LAllocateHistogram(MAX_COLOR_CACHE_BITS);
|
||||
if (histo == NULL) goto Error;
|
||||
|
||||
for (lz77_type = 1; lz77_types_to_try;
|
||||
lz77_types_to_try &= ~lz77_type, lz77_type <<= 1) {
|
||||
int res = 0;
|
||||
double bit_cost;
|
||||
int cache_bits_tmp = cache_bits_initial;
|
||||
if ((lz77_types_to_try & lz77_type) == 0) continue;
|
||||
switch (lz77_type) {
|
||||
case kLZ77RLE:
|
||||
res = BackwardReferencesRle(width, height, argb, 0, worst);
|
||||
break;
|
||||
case kLZ77Standard:
|
||||
// Compute LZ77 with no cache (0 bits), as the ideal LZ77 with a color
|
||||
// cache is not that different in practice.
|
||||
res = BackwardReferencesLz77(width, height, argb, 0, hash_chain, worst);
|
||||
break;
|
||||
case kLZ77Box:
|
||||
if (!VP8LHashChainInit(&hash_chain_box, width * height)) goto Error;
|
||||
res = BackwardReferencesLz77Box(width, height, argb, 0, hash_chain,
|
||||
&hash_chain_box, worst);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (!res) goto Error;
|
||||
|
||||
// Next, try with a color cache and update the references.
|
||||
if (!CalculateBestCacheSize(argb, quality, worst, &cache_bits_tmp)) {
|
||||
goto Error;
|
||||
}
|
||||
if (cache_bits_tmp > 0) {
|
||||
if (!BackwardRefsWithLocalCache(argb, cache_bits_tmp, worst)) {
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the best backward references.
|
||||
VP8LHistogramCreate(histo, worst, cache_bits_tmp);
|
||||
bit_cost = VP8LHistogramEstimateBits(histo);
|
||||
if (lz77_type_best == 0 || bit_cost < bit_cost_best) {
|
||||
VP8LBackwardRefs* const tmp = worst;
|
||||
worst = best;
|
||||
best = tmp;
|
||||
bit_cost_best = bit_cost;
|
||||
*cache_bits = cache_bits_tmp;
|
||||
lz77_type_best = lz77_type;
|
||||
}
|
||||
}
|
||||
assert(lz77_type_best > 0);
|
||||
|
||||
// Improve on simple LZ77 but only for high quality (TraceBackwards is
|
||||
// costly).
|
||||
if ((lz77_type_best == kLZ77Standard || lz77_type_best == kLZ77Box) &&
|
||||
quality >= 25) {
|
||||
const VP8LHashChain* const hash_chain_tmp =
|
||||
(lz77_type_best == kLZ77Standard) ? hash_chain : &hash_chain_box;
|
||||
if (VP8LBackwardReferencesTraceBackwards(width, height, argb, *cache_bits,
|
||||
hash_chain_tmp, best, worst)) {
|
||||
double bit_cost_trace;
|
||||
VP8LHistogramCreate(histo, worst, *cache_bits);
|
||||
bit_cost_trace = VP8LHistogramEstimateBits(histo);
|
||||
if (bit_cost_trace < bit_cost_best) best = worst;
|
||||
}
|
||||
}
|
||||
|
||||
BackwardReferences2DLocality(width, best);
|
||||
|
||||
Error:
|
||||
VP8LHashChainClear(&hash_chain_box);
|
||||
VP8LFreeHistogram(histo);
|
||||
return best;
|
||||
}
|
||||
|
||||
VP8LBackwardRefs* VP8LGetBackwardReferences(
|
||||
int width, int height, const uint32_t* const argb, int quality,
|
||||
int low_effort, int lz77_types_to_try, int* const cache_bits,
|
||||
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_tmp1,
|
||||
VP8LBackwardRefs* const refs_tmp2) {
|
||||
if (low_effort) {
|
||||
return GetBackwardReferencesLowEffort(width, height, argb, cache_bits,
|
||||
hash_chain, refs_tmp1);
|
||||
} else {
|
||||
return GetBackwardReferences(width, height, argb, quality,
|
||||
lz77_types_to_try, cache_bits, hash_chain,
|
||||
refs_tmp1, refs_tmp2);
|
||||
}
|
||||
}
|
||||
234
libsdl2_image/external/libwebp-1.0.2/src/enc/backward_references_enc.h
vendored
Normal file
234
libsdl2_image/external/libwebp-1.0.2/src/enc/backward_references_enc.h
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Author: Jyrki Alakuijala (jyrki@google.com)
|
||||
//
|
||||
|
||||
#ifndef WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
|
||||
#define WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "src/webp/types.h"
|
||||
#include "src/webp/format_constants.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// The maximum allowed limit is 11.
|
||||
#define MAX_COLOR_CACHE_BITS 10
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PixOrCopy
|
||||
|
||||
enum Mode {
|
||||
kLiteral,
|
||||
kCacheIdx,
|
||||
kCopy,
|
||||
kNone
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// mode as uint8_t to make the memory layout to be exactly 8 bytes.
|
||||
uint8_t mode;
|
||||
uint16_t len;
|
||||
uint32_t argb_or_distance;
|
||||
} PixOrCopy;
|
||||
|
||||
static WEBP_INLINE PixOrCopy PixOrCopyCreateCopy(uint32_t distance,
|
||||
uint16_t len) {
|
||||
PixOrCopy retval;
|
||||
retval.mode = kCopy;
|
||||
retval.argb_or_distance = distance;
|
||||
retval.len = len;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static WEBP_INLINE PixOrCopy PixOrCopyCreateCacheIdx(int idx) {
|
||||
PixOrCopy retval;
|
||||
assert(idx >= 0);
|
||||
assert(idx < (1 << MAX_COLOR_CACHE_BITS));
|
||||
retval.mode = kCacheIdx;
|
||||
retval.argb_or_distance = idx;
|
||||
retval.len = 1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static WEBP_INLINE PixOrCopy PixOrCopyCreateLiteral(uint32_t argb) {
|
||||
PixOrCopy retval;
|
||||
retval.mode = kLiteral;
|
||||
retval.argb_or_distance = argb;
|
||||
retval.len = 1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static WEBP_INLINE int PixOrCopyIsLiteral(const PixOrCopy* const p) {
|
||||
return (p->mode == kLiteral);
|
||||
}
|
||||
|
||||
static WEBP_INLINE int PixOrCopyIsCacheIdx(const PixOrCopy* const p) {
|
||||
return (p->mode == kCacheIdx);
|
||||
}
|
||||
|
||||
static WEBP_INLINE int PixOrCopyIsCopy(const PixOrCopy* const p) {
|
||||
return (p->mode == kCopy);
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t PixOrCopyLiteral(const PixOrCopy* const p,
|
||||
int component) {
|
||||
assert(p->mode == kLiteral);
|
||||
return (p->argb_or_distance >> (component * 8)) & 0xff;
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t PixOrCopyLength(const PixOrCopy* const p) {
|
||||
return p->len;
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) {
|
||||
assert(p->mode == kCacheIdx);
|
||||
assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS));
|
||||
return p->argb_or_distance;
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) {
|
||||
assert(p->mode == kCopy);
|
||||
return p->argb_or_distance;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// VP8LHashChain
|
||||
|
||||
#define HASH_BITS 18
|
||||
#define HASH_SIZE (1 << HASH_BITS)
|
||||
|
||||
// If you change this, you need MAX_LENGTH_BITS + WINDOW_SIZE_BITS <= 32 as it
|
||||
// is used in VP8LHashChain.
|
||||
#define MAX_LENGTH_BITS 12
|
||||
#define WINDOW_SIZE_BITS 20
|
||||
// We want the max value to be attainable and stored in MAX_LENGTH_BITS bits.
|
||||
#define MAX_LENGTH ((1 << MAX_LENGTH_BITS) - 1)
|
||||
#if MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32
|
||||
#error "MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32"
|
||||
#endif
|
||||
|
||||
typedef struct VP8LHashChain VP8LHashChain;
|
||||
struct VP8LHashChain {
|
||||
// The 20 most significant bits contain the offset at which the best match
|
||||
// is found. These 20 bits are the limit defined by GetWindowSizeForHashChain
|
||||
// (through WINDOW_SIZE = 1<<20).
|
||||
// The lower 12 bits contain the length of the match. The 12 bit limit is
|
||||
// defined in MaxFindCopyLength with MAX_LENGTH=4096.
|
||||
uint32_t* offset_length_;
|
||||
// This is the maximum size of the hash_chain that can be constructed.
|
||||
// Typically this is the pixel count (width x height) for a given image.
|
||||
int size_;
|
||||
};
|
||||
|
||||
// Must be called first, to set size.
|
||||
int VP8LHashChainInit(VP8LHashChain* const p, int size);
|
||||
// Pre-compute the best matches for argb.
|
||||
int VP8LHashChainFill(VP8LHashChain* const p, int quality,
|
||||
const uint32_t* const argb, int xsize, int ysize,
|
||||
int low_effort);
|
||||
void VP8LHashChainClear(VP8LHashChain* const p); // release memory
|
||||
|
||||
static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p,
|
||||
const int base_position) {
|
||||
return p->offset_length_[base_position] >> MAX_LENGTH_BITS;
|
||||
}
|
||||
|
||||
static WEBP_INLINE int VP8LHashChainFindLength(const VP8LHashChain* const p,
|
||||
const int base_position) {
|
||||
return p->offset_length_[base_position] & ((1U << MAX_LENGTH_BITS) - 1);
|
||||
}
|
||||
|
||||
static WEBP_INLINE void VP8LHashChainFindCopy(const VP8LHashChain* const p,
|
||||
int base_position,
|
||||
int* const offset_ptr,
|
||||
int* const length_ptr) {
|
||||
*offset_ptr = VP8LHashChainFindOffset(p, base_position);
|
||||
*length_ptr = VP8LHashChainFindLength(p, base_position);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// VP8LBackwardRefs (block-based backward-references storage)
|
||||
|
||||
// maximum number of reference blocks the image will be segmented into
|
||||
#define MAX_REFS_BLOCK_PER_IMAGE 16
|
||||
|
||||
typedef struct PixOrCopyBlock PixOrCopyBlock; // forward declaration
|
||||
typedef struct VP8LBackwardRefs VP8LBackwardRefs;
|
||||
|
||||
// Container for blocks chain
|
||||
struct VP8LBackwardRefs {
|
||||
int block_size_; // common block-size
|
||||
int error_; // set to true if some memory error occurred
|
||||
PixOrCopyBlock* refs_; // list of currently used blocks
|
||||
PixOrCopyBlock** tail_; // for list recycling
|
||||
PixOrCopyBlock* free_blocks_; // free-list
|
||||
PixOrCopyBlock* last_block_; // used for adding new refs (internal)
|
||||
};
|
||||
|
||||
// Initialize the object. 'block_size' is the common block size to store
|
||||
// references (typically, width * height / MAX_REFS_BLOCK_PER_IMAGE).
|
||||
void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size);
|
||||
// Release memory for backward references.
|
||||
void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs);
|
||||
|
||||
// Cursor for iterating on references content
|
||||
typedef struct {
|
||||
// public:
|
||||
PixOrCopy* cur_pos; // current position
|
||||
// private:
|
||||
PixOrCopyBlock* cur_block_; // current block in the refs list
|
||||
const PixOrCopy* last_pos_; // sentinel for switching to next block
|
||||
} VP8LRefsCursor;
|
||||
|
||||
// Returns a cursor positioned at the beginning of the references list.
|
||||
VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs);
|
||||
// Returns true if cursor is pointing at a valid position.
|
||||
static WEBP_INLINE int VP8LRefsCursorOk(const VP8LRefsCursor* const c) {
|
||||
return (c->cur_pos != NULL);
|
||||
}
|
||||
// Move to next block of references. Internal, not to be called directly.
|
||||
void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c);
|
||||
// Move to next position, or NULL. Should not be called if !VP8LRefsCursorOk().
|
||||
static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) {
|
||||
assert(c != NULL);
|
||||
assert(VP8LRefsCursorOk(c));
|
||||
if (++c->cur_pos == c->last_pos_) VP8LRefsCursorNextBlock(c);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Main entry points
|
||||
|
||||
enum VP8LLZ77Type {
|
||||
kLZ77Standard = 1,
|
||||
kLZ77RLE = 2,
|
||||
kLZ77Box = 4
|
||||
};
|
||||
|
||||
// Evaluates best possible backward references for specified quality.
|
||||
// The input cache_bits to 'VP8LGetBackwardReferences' sets the maximum cache
|
||||
// bits to use (passing 0 implies disabling the local color cache).
|
||||
// The optimal cache bits is evaluated and set for the *cache_bits parameter.
|
||||
// The return value is the pointer to the best of the two backward refs viz,
|
||||
// refs[0] or refs[1].
|
||||
VP8LBackwardRefs* VP8LGetBackwardReferences(
|
||||
int width, int height, const uint32_t* const argb, int quality,
|
||||
int low_effort, int lz77_types_to_try, int* const cache_bits,
|
||||
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_tmp1,
|
||||
VP8LBackwardRefs* const refs_tmp2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
|
||||
152
libsdl2_image/external/libwebp-1.0.2/src/enc/config_enc.c
vendored
Normal file
152
libsdl2_image/external/libwebp-1.0.2/src/enc/config_enc.c
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Coding tools configuration
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "src/webp/config.h"
|
||||
#endif
|
||||
|
||||
#include "src/webp/encode.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// WebPConfig
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int WebPConfigInitInternal(WebPConfig* config,
|
||||
WebPPreset preset, float quality, int version) {
|
||||
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
|
||||
return 0; // caller/system version mismatch!
|
||||
}
|
||||
if (config == NULL) return 0;
|
||||
|
||||
config->quality = quality;
|
||||
config->target_size = 0;
|
||||
config->target_PSNR = 0.;
|
||||
config->method = 4;
|
||||
config->sns_strength = 50;
|
||||
config->filter_strength = 60; // mid-filtering
|
||||
config->filter_sharpness = 0;
|
||||
config->filter_type = 1; // default: strong (so U/V is filtered too)
|
||||
config->partitions = 0;
|
||||
config->segments = 4;
|
||||
config->pass = 1;
|
||||
config->show_compressed = 0;
|
||||
config->preprocessing = 0;
|
||||
config->autofilter = 0;
|
||||
config->partition_limit = 0;
|
||||
config->alpha_compression = 1;
|
||||
config->alpha_filtering = 1;
|
||||
config->alpha_quality = 100;
|
||||
config->lossless = 0;
|
||||
config->exact = 0;
|
||||
config->image_hint = WEBP_HINT_DEFAULT;
|
||||
config->emulate_jpeg_size = 0;
|
||||
config->thread_level = 0;
|
||||
config->low_memory = 0;
|
||||
config->near_lossless = 100;
|
||||
config->use_delta_palette = 0;
|
||||
config->use_sharp_yuv = 0;
|
||||
|
||||
// TODO(skal): tune.
|
||||
switch (preset) {
|
||||
case WEBP_PRESET_PICTURE:
|
||||
config->sns_strength = 80;
|
||||
config->filter_sharpness = 4;
|
||||
config->filter_strength = 35;
|
||||
config->preprocessing &= ~2; // no dithering
|
||||
break;
|
||||
case WEBP_PRESET_PHOTO:
|
||||
config->sns_strength = 80;
|
||||
config->filter_sharpness = 3;
|
||||
config->filter_strength = 30;
|
||||
config->preprocessing |= 2;
|
||||
break;
|
||||
case WEBP_PRESET_DRAWING:
|
||||
config->sns_strength = 25;
|
||||
config->filter_sharpness = 6;
|
||||
config->filter_strength = 10;
|
||||
break;
|
||||
case WEBP_PRESET_ICON:
|
||||
config->sns_strength = 0;
|
||||
config->filter_strength = 0; // disable filtering to retain sharpness
|
||||
config->preprocessing &= ~2; // no dithering
|
||||
break;
|
||||
case WEBP_PRESET_TEXT:
|
||||
config->sns_strength = 0;
|
||||
config->filter_strength = 0; // disable filtering to retain sharpness
|
||||
config->preprocessing &= ~2; // no dithering
|
||||
config->segments = 2;
|
||||
break;
|
||||
case WEBP_PRESET_DEFAULT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return WebPValidateConfig(config);
|
||||
}
|
||||
|
||||
int WebPValidateConfig(const WebPConfig* config) {
|
||||
if (config == NULL) return 0;
|
||||
if (config->quality < 0 || config->quality > 100) return 0;
|
||||
if (config->target_size < 0) return 0;
|
||||
if (config->target_PSNR < 0) return 0;
|
||||
if (config->method < 0 || config->method > 6) return 0;
|
||||
if (config->segments < 1 || config->segments > 4) return 0;
|
||||
if (config->sns_strength < 0 || config->sns_strength > 100) return 0;
|
||||
if (config->filter_strength < 0 || config->filter_strength > 100) return 0;
|
||||
if (config->filter_sharpness < 0 || config->filter_sharpness > 7) return 0;
|
||||
if (config->filter_type < 0 || config->filter_type > 1) return 0;
|
||||
if (config->autofilter < 0 || config->autofilter > 1) return 0;
|
||||
if (config->pass < 1 || config->pass > 10) return 0;
|
||||
if (config->show_compressed < 0 || config->show_compressed > 1) return 0;
|
||||
if (config->preprocessing < 0 || config->preprocessing > 7) return 0;
|
||||
if (config->partitions < 0 || config->partitions > 3) return 0;
|
||||
if (config->partition_limit < 0 || config->partition_limit > 100) return 0;
|
||||
if (config->alpha_compression < 0) return 0;
|
||||
if (config->alpha_filtering < 0) return 0;
|
||||
if (config->alpha_quality < 0 || config->alpha_quality > 100) return 0;
|
||||
if (config->lossless < 0 || config->lossless > 1) return 0;
|
||||
if (config->near_lossless < 0 || config->near_lossless > 100) return 0;
|
||||
if (config->image_hint >= WEBP_HINT_LAST) return 0;
|
||||
if (config->emulate_jpeg_size < 0 || config->emulate_jpeg_size > 1) return 0;
|
||||
if (config->thread_level < 0 || config->thread_level > 1) return 0;
|
||||
if (config->low_memory < 0 || config->low_memory > 1) return 0;
|
||||
if (config->exact < 0 || config->exact > 1) return 0;
|
||||
if (config->use_delta_palette < 0 || config->use_delta_palette > 1) {
|
||||
return 0;
|
||||
}
|
||||
if (config->use_sharp_yuv < 0 || config->use_sharp_yuv > 1) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define MAX_LEVEL 9
|
||||
|
||||
// Mapping between -z level and -m / -q parameter settings.
|
||||
static const struct {
|
||||
uint8_t method_;
|
||||
uint8_t quality_;
|
||||
} kLosslessPresets[MAX_LEVEL + 1] = {
|
||||
{ 0, 0 }, { 1, 20 }, { 2, 25 }, { 3, 30 }, { 3, 50 },
|
||||
{ 4, 50 }, { 4, 75 }, { 4, 90 }, { 5, 90 }, { 6, 100 }
|
||||
};
|
||||
|
||||
int WebPConfigLosslessPreset(WebPConfig* config, int level) {
|
||||
if (config == NULL || level < 0 || level > MAX_LEVEL) return 0;
|
||||
config->lossless = 1;
|
||||
config->method = kLosslessPresets[level].method_;
|
||||
config->quality = kLosslessPresets[level].quality_;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
342
libsdl2_image/external/libwebp-1.0.2/src/enc/cost_enc.c
vendored
Normal file
342
libsdl2_image/external/libwebp-1.0.2/src/enc/cost_enc.c
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Cost tables for level and modes
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include "src/enc/cost_enc.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Level cost tables
|
||||
|
||||
// For each given level, the following table gives the pattern of contexts to
|
||||
// use for coding it (in [][0]) as well as the bit value to use for each
|
||||
// context (in [][1]).
|
||||
const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = {
|
||||
{0x001, 0x000}, {0x007, 0x001}, {0x00f, 0x005},
|
||||
{0x00f, 0x00d}, {0x033, 0x003}, {0x033, 0x003}, {0x033, 0x023},
|
||||
{0x033, 0x023}, {0x033, 0x023}, {0x033, 0x023}, {0x0d3, 0x013},
|
||||
{0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013},
|
||||
{0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x093},
|
||||
{0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093},
|
||||
{0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093},
|
||||
{0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093},
|
||||
{0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x153, 0x053},
|
||||
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
|
||||
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
|
||||
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
|
||||
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
|
||||
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
|
||||
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
|
||||
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
|
||||
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x153}
|
||||
};
|
||||
|
||||
static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) {
|
||||
int pattern = VP8LevelCodes[level - 1][0];
|
||||
int bits = VP8LevelCodes[level - 1][1];
|
||||
int cost = 0;
|
||||
int i;
|
||||
for (i = 2; pattern; ++i) {
|
||||
if (pattern & 1) {
|
||||
cost += VP8BitCost(bits & 1, probas[i]);
|
||||
}
|
||||
bits >>= 1;
|
||||
pattern >>= 1;
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Pre-calc level costs once for all
|
||||
|
||||
void VP8CalculateLevelCosts(VP8EncProba* const proba) {
|
||||
int ctype, band, ctx;
|
||||
|
||||
if (!proba->dirty_) return; // nothing to do.
|
||||
|
||||
for (ctype = 0; ctype < NUM_TYPES; ++ctype) {
|
||||
int n;
|
||||
for (band = 0; band < NUM_BANDS; ++band) {
|
||||
for (ctx = 0; ctx < NUM_CTX; ++ctx) {
|
||||
const uint8_t* const p = proba->coeffs_[ctype][band][ctx];
|
||||
uint16_t* const table = proba->level_cost_[ctype][band][ctx];
|
||||
const int cost0 = (ctx > 0) ? VP8BitCost(1, p[0]) : 0;
|
||||
const int cost_base = VP8BitCost(1, p[1]) + cost0;
|
||||
int v;
|
||||
table[0] = VP8BitCost(0, p[1]) + cost0;
|
||||
for (v = 1; v <= MAX_VARIABLE_LEVEL; ++v) {
|
||||
table[v] = cost_base + VariableLevelCost(v, p);
|
||||
}
|
||||
// Starting at level 67 and up, the variable part of the cost is
|
||||
// actually constant.
|
||||
}
|
||||
}
|
||||
for (n = 0; n < 16; ++n) { // replicate bands. We don't need to sentinel.
|
||||
for (ctx = 0; ctx < NUM_CTX; ++ctx) {
|
||||
proba->remapped_costs_[ctype][n][ctx] =
|
||||
proba->level_cost_[ctype][VP8EncBands[n]][ctx];
|
||||
}
|
||||
}
|
||||
}
|
||||
proba->dirty_ = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Mode cost tables.
|
||||
|
||||
// These are the fixed probabilities (in the coding trees) turned into bit-cost
|
||||
// by calling VP8BitCost().
|
||||
const uint16_t VP8FixedCostsUV[4] = { 302, 984, 439, 642 };
|
||||
// note: these values include the fixed VP8BitCost(1, 145) mode selection cost.
|
||||
const uint16_t VP8FixedCostsI16[4] = { 663, 919, 872, 919 };
|
||||
const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES] = {
|
||||
{ { 40, 1151, 1723, 1874, 2103, 2019, 1628, 1777, 2226, 2137 },
|
||||
{ 192, 469, 1296, 1308, 1849, 1794, 1781, 1703, 1713, 1522 },
|
||||
{ 142, 910, 762, 1684, 1849, 1576, 1460, 1305, 1801, 1657 },
|
||||
{ 559, 641, 1370, 421, 1182, 1569, 1612, 1725, 863, 1007 },
|
||||
{ 299, 1059, 1256, 1108, 636, 1068, 1581, 1883, 869, 1142 },
|
||||
{ 277, 1111, 707, 1362, 1089, 672, 1603, 1541, 1545, 1291 },
|
||||
{ 214, 781, 1609, 1303, 1632, 2229, 726, 1560, 1713, 918 },
|
||||
{ 152, 1037, 1046, 1759, 1983, 2174, 1358, 742, 1740, 1390 },
|
||||
{ 512, 1046, 1420, 753, 752, 1297, 1486, 1613, 460, 1207 },
|
||||
{ 424, 827, 1362, 719, 1462, 1202, 1199, 1476, 1199, 538 } },
|
||||
{ { 240, 402, 1134, 1491, 1659, 1505, 1517, 1555, 1979, 2099 },
|
||||
{ 467, 242, 960, 1232, 1714, 1620, 1834, 1570, 1676, 1391 },
|
||||
{ 500, 455, 463, 1507, 1699, 1282, 1564, 982, 2114, 2114 },
|
||||
{ 672, 643, 1372, 331, 1589, 1667, 1453, 1938, 996, 876 },
|
||||
{ 458, 783, 1037, 911, 738, 968, 1165, 1518, 859, 1033 },
|
||||
{ 504, 815, 504, 1139, 1219, 719, 1506, 1085, 1268, 1268 },
|
||||
{ 333, 630, 1445, 1239, 1883, 3672, 799, 1548, 1865, 598 },
|
||||
{ 399, 644, 746, 1342, 1856, 1350, 1493, 613, 1855, 1015 },
|
||||
{ 622, 749, 1205, 608, 1066, 1408, 1290, 1406, 546, 971 },
|
||||
{ 500, 753, 1041, 668, 1230, 1617, 1297, 1425, 1383, 523 } },
|
||||
{ { 394, 553, 523, 1502, 1536, 981, 1608, 1142, 1666, 2181 },
|
||||
{ 655, 430, 375, 1411, 1861, 1220, 1677, 1135, 1978, 1553 },
|
||||
{ 690, 640, 245, 1954, 2070, 1194, 1528, 982, 1972, 2232 },
|
||||
{ 559, 834, 741, 867, 1131, 980, 1225, 852, 1092, 784 },
|
||||
{ 690, 875, 516, 959, 673, 894, 1056, 1190, 1528, 1126 },
|
||||
{ 740, 951, 384, 1277, 1177, 492, 1579, 1155, 1846, 1513 },
|
||||
{ 323, 775, 1062, 1776, 3062, 1274, 813, 1188, 1372, 655 },
|
||||
{ 488, 971, 484, 1767, 1515, 1775, 1115, 503, 1539, 1461 },
|
||||
{ 740, 1006, 998, 709, 851, 1230, 1337, 788, 741, 721 },
|
||||
{ 522, 1073, 573, 1045, 1346, 887, 1046, 1146, 1203, 697 } },
|
||||
{ { 105, 864, 1442, 1009, 1934, 1840, 1519, 1920, 1673, 1579 },
|
||||
{ 534, 305, 1193, 683, 1388, 2164, 1802, 1894, 1264, 1170 },
|
||||
{ 305, 518, 877, 1108, 1426, 3215, 1425, 1064, 1320, 1242 },
|
||||
{ 683, 732, 1927, 257, 1493, 2048, 1858, 1552, 1055, 947 },
|
||||
{ 394, 814, 1024, 660, 959, 1556, 1282, 1289, 893, 1047 },
|
||||
{ 528, 615, 996, 940, 1201, 635, 1094, 2515, 803, 1358 },
|
||||
{ 347, 614, 1609, 1187, 3133, 1345, 1007, 1339, 1017, 667 },
|
||||
{ 218, 740, 878, 1605, 3650, 3650, 1345, 758, 1357, 1617 },
|
||||
{ 672, 750, 1541, 558, 1257, 1599, 1870, 2135, 402, 1087 },
|
||||
{ 592, 684, 1161, 430, 1092, 1497, 1475, 1489, 1095, 822 } },
|
||||
{ { 228, 1056, 1059, 1368, 752, 982, 1512, 1518, 987, 1782 },
|
||||
{ 494, 514, 818, 942, 965, 892, 1610, 1356, 1048, 1363 },
|
||||
{ 512, 648, 591, 1042, 761, 991, 1196, 1454, 1309, 1463 },
|
||||
{ 683, 749, 1043, 676, 841, 1396, 1133, 1138, 654, 939 },
|
||||
{ 622, 1101, 1126, 994, 361, 1077, 1203, 1318, 877, 1219 },
|
||||
{ 631, 1068, 857, 1650, 651, 477, 1650, 1419, 828, 1170 },
|
||||
{ 555, 727, 1068, 1335, 3127, 1339, 820, 1331, 1077, 429 },
|
||||
{ 504, 879, 624, 1398, 889, 889, 1392, 808, 891, 1406 },
|
||||
{ 683, 1602, 1289, 977, 578, 983, 1280, 1708, 406, 1122 },
|
||||
{ 399, 865, 1433, 1070, 1072, 764, 968, 1477, 1223, 678 } },
|
||||
{ { 333, 760, 935, 1638, 1010, 529, 1646, 1410, 1472, 2219 },
|
||||
{ 512, 494, 750, 1160, 1215, 610, 1870, 1868, 1628, 1169 },
|
||||
{ 572, 646, 492, 1934, 1208, 603, 1580, 1099, 1398, 1995 },
|
||||
{ 786, 789, 942, 581, 1018, 951, 1599, 1207, 731, 768 },
|
||||
{ 690, 1015, 672, 1078, 582, 504, 1693, 1438, 1108, 2897 },
|
||||
{ 768, 1267, 571, 2005, 1243, 244, 2881, 1380, 1786, 1453 },
|
||||
{ 452, 899, 1293, 903, 1311, 3100, 465, 1311, 1319, 813 },
|
||||
{ 394, 927, 942, 1103, 1358, 1104, 946, 593, 1363, 1109 },
|
||||
{ 559, 1005, 1007, 1016, 658, 1173, 1021, 1164, 623, 1028 },
|
||||
{ 564, 796, 632, 1005, 1014, 863, 2316, 1268, 938, 764 } },
|
||||
{ { 266, 606, 1098, 1228, 1497, 1243, 948, 1030, 1734, 1461 },
|
||||
{ 366, 585, 901, 1060, 1407, 1247, 876, 1134, 1620, 1054 },
|
||||
{ 452, 565, 542, 1729, 1479, 1479, 1016, 886, 2938, 1150 },
|
||||
{ 555, 1088, 1533, 950, 1354, 895, 834, 1019, 1021, 496 },
|
||||
{ 704, 815, 1193, 971, 973, 640, 1217, 2214, 832, 578 },
|
||||
{ 672, 1245, 579, 871, 875, 774, 872, 1273, 1027, 949 },
|
||||
{ 296, 1134, 2050, 1784, 1636, 3425, 442, 1550, 2076, 722 },
|
||||
{ 342, 982, 1259, 1846, 1848, 1848, 622, 568, 1847, 1052 },
|
||||
{ 555, 1064, 1304, 828, 746, 1343, 1075, 1329, 1078, 494 },
|
||||
{ 288, 1167, 1285, 1174, 1639, 1639, 833, 2254, 1304, 509 } },
|
||||
{ { 342, 719, 767, 1866, 1757, 1270, 1246, 550, 1746, 2151 },
|
||||
{ 483, 653, 694, 1509, 1459, 1410, 1218, 507, 1914, 1266 },
|
||||
{ 488, 757, 447, 2979, 1813, 1268, 1654, 539, 1849, 2109 },
|
||||
{ 522, 1097, 1085, 851, 1365, 1111, 851, 901, 961, 605 },
|
||||
{ 709, 716, 841, 728, 736, 945, 941, 862, 2845, 1057 },
|
||||
{ 512, 1323, 500, 1336, 1083, 681, 1342, 717, 1604, 1350 },
|
||||
{ 452, 1155, 1372, 1900, 1501, 3290, 311, 944, 1919, 922 },
|
||||
{ 403, 1520, 977, 2132, 1733, 3522, 1076, 276, 3335, 1547 },
|
||||
{ 559, 1374, 1101, 615, 673, 2462, 974, 795, 984, 984 },
|
||||
{ 547, 1122, 1062, 812, 1410, 951, 1140, 622, 1268, 651 } },
|
||||
{ { 165, 982, 1235, 938, 1334, 1366, 1659, 1578, 964, 1612 },
|
||||
{ 592, 422, 925, 847, 1139, 1112, 1387, 2036, 861, 1041 },
|
||||
{ 403, 837, 732, 770, 941, 1658, 1250, 809, 1407, 1407 },
|
||||
{ 896, 874, 1071, 381, 1568, 1722, 1437, 2192, 480, 1035 },
|
||||
{ 640, 1098, 1012, 1032, 684, 1382, 1581, 2106, 416, 865 },
|
||||
{ 559, 1005, 819, 914, 710, 770, 1418, 920, 838, 1435 },
|
||||
{ 415, 1258, 1245, 870, 1278, 3067, 770, 1021, 1287, 522 },
|
||||
{ 406, 990, 601, 1009, 1265, 1265, 1267, 759, 1017, 1277 },
|
||||
{ 968, 1182, 1329, 788, 1032, 1292, 1705, 1714, 203, 1403 },
|
||||
{ 732, 877, 1279, 471, 901, 1161, 1545, 1294, 755, 755 } },
|
||||
{ { 111, 931, 1378, 1185, 1933, 1648, 1148, 1714, 1873, 1307 },
|
||||
{ 406, 414, 1030, 1023, 1910, 1404, 1313, 1647, 1509, 793 },
|
||||
{ 342, 640, 575, 1088, 1241, 1349, 1161, 1350, 1756, 1502 },
|
||||
{ 559, 766, 1185, 357, 1682, 1428, 1329, 1897, 1219, 802 },
|
||||
{ 473, 909, 1164, 771, 719, 2508, 1427, 1432, 722, 782 },
|
||||
{ 342, 892, 785, 1145, 1150, 794, 1296, 1550, 973, 1057 },
|
||||
{ 208, 1036, 1326, 1343, 1606, 3395, 815, 1455, 1618, 712 },
|
||||
{ 228, 928, 890, 1046, 3499, 1711, 994, 829, 1720, 1318 },
|
||||
{ 768, 724, 1058, 636, 991, 1075, 1319, 1324, 616, 825 },
|
||||
{ 305, 1167, 1358, 899, 1587, 1587, 987, 1988, 1332, 501 } }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// helper functions for residuals struct VP8Residual.
|
||||
|
||||
void VP8InitResidual(int first, int coeff_type,
|
||||
VP8Encoder* const enc, VP8Residual* const res) {
|
||||
res->coeff_type = coeff_type;
|
||||
res->prob = enc->proba_.coeffs_[coeff_type];
|
||||
res->stats = enc->proba_.stats_[coeff_type];
|
||||
res->costs = enc->proba_.remapped_costs_[coeff_type];
|
||||
res->first = first;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Mode costs
|
||||
|
||||
int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) {
|
||||
const int x = (it->i4_ & 3), y = (it->i4_ >> 2);
|
||||
VP8Residual res;
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
int R = 0;
|
||||
int ctx;
|
||||
|
||||
VP8InitResidual(0, 3, enc, &res);
|
||||
ctx = it->top_nz_[x] + it->left_nz_[y];
|
||||
VP8SetResidualCoeffs(levels, &res);
|
||||
R += VP8GetResidualCost(ctx, &res);
|
||||
return R;
|
||||
}
|
||||
|
||||
int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) {
|
||||
VP8Residual res;
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
int x, y;
|
||||
int R = 0;
|
||||
|
||||
VP8IteratorNzToBytes(it); // re-import the non-zero context
|
||||
|
||||
// DC
|
||||
VP8InitResidual(0, 1, enc, &res);
|
||||
VP8SetResidualCoeffs(rd->y_dc_levels, &res);
|
||||
R += VP8GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res);
|
||||
|
||||
// AC
|
||||
VP8InitResidual(1, 0, enc, &res);
|
||||
for (y = 0; y < 4; ++y) {
|
||||
for (x = 0; x < 4; ++x) {
|
||||
const int ctx = it->top_nz_[x] + it->left_nz_[y];
|
||||
VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
|
||||
R += VP8GetResidualCost(ctx, &res);
|
||||
it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0);
|
||||
}
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) {
|
||||
VP8Residual res;
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
int ch, x, y;
|
||||
int R = 0;
|
||||
|
||||
VP8IteratorNzToBytes(it); // re-import the non-zero context
|
||||
|
||||
VP8InitResidual(0, 2, enc, &res);
|
||||
for (ch = 0; ch <= 2; ch += 2) {
|
||||
for (y = 0; y < 2; ++y) {
|
||||
for (x = 0; x < 2; ++x) {
|
||||
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
|
||||
VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
|
||||
R += VP8GetResidualCost(ctx, &res);
|
||||
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Recording of token probabilities.
|
||||
|
||||
// We keep the table-free variant around for reference, in case.
|
||||
#define USE_LEVEL_CODE_TABLE
|
||||
|
||||
// Simulate block coding, but only record statistics.
|
||||
// Note: no need to record the fixed probas.
|
||||
int VP8RecordCoeffs(int ctx, const VP8Residual* const res) {
|
||||
int n = res->first;
|
||||
// should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1
|
||||
proba_t* s = res->stats[n][ctx];
|
||||
if (res->last < 0) {
|
||||
VP8RecordStats(0, s + 0);
|
||||
return 0;
|
||||
}
|
||||
while (n <= res->last) {
|
||||
int v;
|
||||
VP8RecordStats(1, s + 0); // order of record doesn't matter
|
||||
while ((v = res->coeffs[n++]) == 0) {
|
||||
VP8RecordStats(0, s + 1);
|
||||
s = res->stats[VP8EncBands[n]][0];
|
||||
}
|
||||
VP8RecordStats(1, s + 1);
|
||||
if (!VP8RecordStats(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1
|
||||
s = res->stats[VP8EncBands[n]][1];
|
||||
} else {
|
||||
v = abs(v);
|
||||
#if !defined(USE_LEVEL_CODE_TABLE)
|
||||
if (!VP8RecordStats(v > 4, s + 3)) {
|
||||
if (VP8RecordStats(v != 2, s + 4))
|
||||
VP8RecordStats(v == 4, s + 5);
|
||||
} else if (!VP8RecordStats(v > 10, s + 6)) {
|
||||
VP8RecordStats(v > 6, s + 7);
|
||||
} else if (!VP8RecordStats((v >= 3 + (8 << 2)), s + 8)) {
|
||||
VP8RecordStats((v >= 3 + (8 << 1)), s + 9);
|
||||
} else {
|
||||
VP8RecordStats((v >= 3 + (8 << 3)), s + 10);
|
||||
}
|
||||
#else
|
||||
if (v > MAX_VARIABLE_LEVEL) {
|
||||
v = MAX_VARIABLE_LEVEL;
|
||||
}
|
||||
|
||||
{
|
||||
const int bits = VP8LevelCodes[v - 1][1];
|
||||
int pattern = VP8LevelCodes[v - 1][0];
|
||||
int i;
|
||||
for (i = 0; (pattern >>= 1) != 0; ++i) {
|
||||
const int mask = 2 << i;
|
||||
if (pattern & 1) VP8RecordStats(!!(bits & mask), s + 3 + i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
s = res->stats[VP8EncBands[n]][2];
|
||||
}
|
||||
}
|
||||
if (n < 16) VP8RecordStats(0, s + 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
82
libsdl2_image/external/libwebp-1.0.2/src/enc/cost_enc.h
vendored
Normal file
82
libsdl2_image/external/libwebp-1.0.2/src/enc/cost_enc.h
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Cost tables for level and modes.
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#ifndef WEBP_ENC_COST_ENC_H_
|
||||
#define WEBP_ENC_COST_ENC_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// On-the-fly info about the current set of residuals. Handy to avoid
|
||||
// passing zillions of params.
|
||||
typedef struct VP8Residual VP8Residual;
|
||||
struct VP8Residual {
|
||||
int first;
|
||||
int last;
|
||||
const int16_t* coeffs;
|
||||
|
||||
int coeff_type;
|
||||
ProbaArray* prob;
|
||||
StatsArray* stats;
|
||||
CostArrayPtr costs;
|
||||
};
|
||||
|
||||
void VP8InitResidual(int first, int coeff_type,
|
||||
VP8Encoder* const enc, VP8Residual* const res);
|
||||
|
||||
int VP8RecordCoeffs(int ctx, const VP8Residual* const res);
|
||||
|
||||
// Record proba context used.
|
||||
static WEBP_INLINE int VP8RecordStats(int bit, proba_t* const stats) {
|
||||
proba_t p = *stats;
|
||||
// An overflow is inbound. Note we handle this at 0xfffe0000u instead of
|
||||
// 0xffff0000u to make sure p + 1u does not overflow.
|
||||
if (p >= 0xfffe0000u) {
|
||||
p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2.
|
||||
}
|
||||
// record bit count (lower 16 bits) and increment total count (upper 16 bits).
|
||||
p += 0x00010000u + bit;
|
||||
*stats = p;
|
||||
return bit;
|
||||
}
|
||||
|
||||
// Cost of coding one event with probability 'proba'.
|
||||
static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) {
|
||||
return !bit ? VP8EntropyCost[proba] : VP8EntropyCost[255 - proba];
|
||||
}
|
||||
|
||||
// Level cost calculations
|
||||
extern const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2];
|
||||
void VP8CalculateLevelCosts(VP8EncProba* const proba);
|
||||
static WEBP_INLINE int VP8LevelCost(const uint16_t* const table, int level) {
|
||||
return VP8LevelFixedCosts[level]
|
||||
+ table[(level > MAX_VARIABLE_LEVEL) ? MAX_VARIABLE_LEVEL : level];
|
||||
}
|
||||
|
||||
// Mode costs
|
||||
extern const uint16_t VP8FixedCostsUV[4];
|
||||
extern const uint16_t VP8FixedCostsI16[4];
|
||||
extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // WEBP_ENC_COST_ENC_H_
|
||||
235
libsdl2_image/external/libwebp-1.0.2/src/enc/filter_enc.c
vendored
Normal file
235
libsdl2_image/external/libwebp-1.0.2/src/enc/filter_enc.c
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Selecting filter level
|
||||
//
|
||||
// Author: somnath@google.com (Somnath Banerjee)
|
||||
|
||||
#include <assert.h>
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/dsp/dsp.h"
|
||||
|
||||
// This table gives, for a given sharpness, the filtering strength to be
|
||||
// used (at least) in order to filter a given edge step delta.
|
||||
// This is constructed by brute force inspection: for all delta, we iterate
|
||||
// over all possible filtering strength / thresh until needs_filter() returns
|
||||
// true.
|
||||
#define MAX_DELTA_SIZE 64
|
||||
static const uint8_t kLevelsFromDelta[8][MAX_DELTA_SIZE] = {
|
||||
{ 0, 1, 2, 3, 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, 59, 60, 61, 62, 63 },
|
||||
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 17, 18,
|
||||
20, 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42,
|
||||
44, 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63,
|
||||
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
|
||||
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 19,
|
||||
20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43,
|
||||
44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63,
|
||||
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
|
||||
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19,
|
||||
21, 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43,
|
||||
45, 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63,
|
||||
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
|
||||
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20,
|
||||
21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44,
|
||||
45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63,
|
||||
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
|
||||
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 20,
|
||||
22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44,
|
||||
46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63, 63,
|
||||
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
|
||||
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21,
|
||||
22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, 45,
|
||||
46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63, 63,
|
||||
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
|
||||
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21,
|
||||
23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45,
|
||||
47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63, 63,
|
||||
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }
|
||||
};
|
||||
|
||||
int VP8FilterStrengthFromDelta(int sharpness, int delta) {
|
||||
const int pos = (delta < MAX_DELTA_SIZE) ? delta : MAX_DELTA_SIZE - 1;
|
||||
assert(sharpness >= 0 && sharpness <= 7);
|
||||
return kLevelsFromDelta[sharpness][pos];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Paragraph 15.4: compute the inner-edge filtering strength
|
||||
|
||||
#if !defined(WEBP_REDUCE_SIZE)
|
||||
|
||||
static int GetILevel(int sharpness, int level) {
|
||||
if (sharpness > 0) {
|
||||
if (sharpness > 4) {
|
||||
level >>= 2;
|
||||
} else {
|
||||
level >>= 1;
|
||||
}
|
||||
if (level > 9 - sharpness) {
|
||||
level = 9 - sharpness;
|
||||
}
|
||||
}
|
||||
if (level < 1) level = 1;
|
||||
return level;
|
||||
}
|
||||
|
||||
static void DoFilter(const VP8EncIterator* const it, int level) {
|
||||
const VP8Encoder* const enc = it->enc_;
|
||||
const int ilevel = GetILevel(enc->config_->filter_sharpness, level);
|
||||
const int limit = 2 * level + ilevel;
|
||||
|
||||
uint8_t* const y_dst = it->yuv_out2_ + Y_OFF_ENC;
|
||||
uint8_t* const u_dst = it->yuv_out2_ + U_OFF_ENC;
|
||||
uint8_t* const v_dst = it->yuv_out2_ + V_OFF_ENC;
|
||||
|
||||
// copy current block to yuv_out2_
|
||||
memcpy(y_dst, it->yuv_out_, YUV_SIZE_ENC * sizeof(uint8_t));
|
||||
|
||||
if (enc->filter_hdr_.simple_ == 1) { // simple
|
||||
VP8SimpleHFilter16i(y_dst, BPS, limit);
|
||||
VP8SimpleVFilter16i(y_dst, BPS, limit);
|
||||
} else { // complex
|
||||
const int hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
|
||||
VP8HFilter16i(y_dst, BPS, limit, ilevel, hev_thresh);
|
||||
VP8HFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh);
|
||||
VP8VFilter16i(y_dst, BPS, limit, ilevel, hev_thresh);
|
||||
VP8VFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// SSIM metric for one macroblock
|
||||
|
||||
static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) {
|
||||
int x, y;
|
||||
double sum = 0.;
|
||||
|
||||
// compute SSIM in a 10 x 10 window
|
||||
for (y = VP8_SSIM_KERNEL; y < 16 - VP8_SSIM_KERNEL; y++) {
|
||||
for (x = VP8_SSIM_KERNEL; x < 16 - VP8_SSIM_KERNEL; x++) {
|
||||
sum += VP8SSIMGetClipped(yuv1 + Y_OFF_ENC, BPS, yuv2 + Y_OFF_ENC, BPS,
|
||||
x, y, 16, 16);
|
||||
}
|
||||
}
|
||||
for (x = 1; x < 7; x++) {
|
||||
for (y = 1; y < 7; y++) {
|
||||
sum += VP8SSIMGetClipped(yuv1 + U_OFF_ENC, BPS, yuv2 + U_OFF_ENC, BPS,
|
||||
x, y, 8, 8);
|
||||
sum += VP8SSIMGetClipped(yuv1 + V_OFF_ENC, BPS, yuv2 + V_OFF_ENC, BPS,
|
||||
x, y, 8, 8);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
#endif // !defined(WEBP_REDUCE_SIZE)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exposed APIs: Encoder should call the following 3 functions to adjust
|
||||
// loop filter strength
|
||||
|
||||
void VP8InitFilter(VP8EncIterator* const it) {
|
||||
#if !defined(WEBP_REDUCE_SIZE)
|
||||
if (it->lf_stats_ != NULL) {
|
||||
int s, i;
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
|
||||
for (i = 0; i < MAX_LF_LEVELS; i++) {
|
||||
(*it->lf_stats_)[s][i] = 0;
|
||||
}
|
||||
}
|
||||
VP8SSIMDspInit();
|
||||
}
|
||||
#else
|
||||
(void)it;
|
||||
#endif
|
||||
}
|
||||
|
||||
void VP8StoreFilterStats(VP8EncIterator* const it) {
|
||||
#if !defined(WEBP_REDUCE_SIZE)
|
||||
int d;
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
const int s = it->mb_->segment_;
|
||||
const int level0 = enc->dqm_[s].fstrength_;
|
||||
|
||||
// explore +/-quant range of values around level0
|
||||
const int delta_min = -enc->dqm_[s].quant_;
|
||||
const int delta_max = enc->dqm_[s].quant_;
|
||||
const int step_size = (delta_max - delta_min >= 4) ? 4 : 1;
|
||||
|
||||
if (it->lf_stats_ == NULL) return;
|
||||
|
||||
// NOTE: Currently we are applying filter only across the sublock edges
|
||||
// There are two reasons for that.
|
||||
// 1. Applying filter on macro block edges will change the pixels in
|
||||
// the left and top macro blocks. That will be hard to restore
|
||||
// 2. Macro Blocks on the bottom and right are not yet compressed. So we
|
||||
// cannot apply filter on the right and bottom macro block edges.
|
||||
if (it->mb_->type_ == 1 && it->mb_->skip_) return;
|
||||
|
||||
// Always try filter level zero
|
||||
(*it->lf_stats_)[s][0] += GetMBSSIM(it->yuv_in_, it->yuv_out_);
|
||||
|
||||
for (d = delta_min; d <= delta_max; d += step_size) {
|
||||
const int level = level0 + d;
|
||||
if (level <= 0 || level >= MAX_LF_LEVELS) {
|
||||
continue;
|
||||
}
|
||||
DoFilter(it, level);
|
||||
(*it->lf_stats_)[s][level] += GetMBSSIM(it->yuv_in_, it->yuv_out2_);
|
||||
}
|
||||
#else // defined(WEBP_REDUCE_SIZE)
|
||||
(void)it;
|
||||
#endif // !defined(WEBP_REDUCE_SIZE)
|
||||
}
|
||||
|
||||
void VP8AdjustFilterStrength(VP8EncIterator* const it) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
#if !defined(WEBP_REDUCE_SIZE)
|
||||
if (it->lf_stats_ != NULL) {
|
||||
int s;
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
|
||||
int i, best_level = 0;
|
||||
// Improvement over filter level 0 should be at least 1e-5 (relatively)
|
||||
double best_v = 1.00001 * (*it->lf_stats_)[s][0];
|
||||
for (i = 1; i < MAX_LF_LEVELS; i++) {
|
||||
const double v = (*it->lf_stats_)[s][i];
|
||||
if (v > best_v) {
|
||||
best_v = v;
|
||||
best_level = i;
|
||||
}
|
||||
}
|
||||
enc->dqm_[s].fstrength_ = best_level;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif // !defined(WEBP_REDUCE_SIZE)
|
||||
if (enc->config_->filter_strength > 0) {
|
||||
int max_level = 0;
|
||||
int s;
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
|
||||
VP8SegmentInfo* const dqm = &enc->dqm_[s];
|
||||
// this '>> 3' accounts for some inverse WHT scaling
|
||||
const int delta = (dqm->max_edge_ * dqm->y2_.q_[1]) >> 3;
|
||||
const int level =
|
||||
VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, delta);
|
||||
if (level > dqm->fstrength_) {
|
||||
dqm->fstrength_ = level;
|
||||
}
|
||||
if (max_level < dqm->fstrength_) {
|
||||
max_level = dqm->fstrength_;
|
||||
}
|
||||
}
|
||||
enc->filter_hdr_.level_ = max_level;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
890
libsdl2_image/external/libwebp-1.0.2/src/enc/frame_enc.c
vendored
Normal file
890
libsdl2_image/external/libwebp-1.0.2/src/enc/frame_enc.c
vendored
Normal file
@ -0,0 +1,890 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// frame coding and analysis
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "src/enc/cost_enc.h"
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/webp/format_constants.h" // RIFF constants
|
||||
|
||||
#define SEGMENT_VISU 0
|
||||
#define DEBUG_SEARCH 0 // useful to track search convergence
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// multi-pass convergence
|
||||
|
||||
#define HEADER_SIZE_ESTIMATE (RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + \
|
||||
VP8_FRAME_HEADER_SIZE)
|
||||
#define DQ_LIMIT 0.4 // convergence is considered reached if dq < DQ_LIMIT
|
||||
// we allow 2k of extra head-room in PARTITION0 limit.
|
||||
#define PARTITION0_SIZE_LIMIT ((VP8_MAX_PARTITION0_SIZE - 2048ULL) << 11)
|
||||
|
||||
typedef struct { // struct for organizing convergence in either size or PSNR
|
||||
int is_first;
|
||||
float dq;
|
||||
float q, last_q;
|
||||
double value, last_value; // PSNR or size
|
||||
double target;
|
||||
int do_size_search;
|
||||
} PassStats;
|
||||
|
||||
static int InitPassStats(const VP8Encoder* const enc, PassStats* const s) {
|
||||
const uint64_t target_size = (uint64_t)enc->config_->target_size;
|
||||
const int do_size_search = (target_size != 0);
|
||||
const float target_PSNR = enc->config_->target_PSNR;
|
||||
|
||||
s->is_first = 1;
|
||||
s->dq = 10.f;
|
||||
s->q = s->last_q = enc->config_->quality;
|
||||
s->target = do_size_search ? (double)target_size
|
||||
: (target_PSNR > 0.) ? target_PSNR
|
||||
: 40.; // default, just in case
|
||||
s->value = s->last_value = 0.;
|
||||
s->do_size_search = do_size_search;
|
||||
return do_size_search;
|
||||
}
|
||||
|
||||
static float Clamp(float v, float min, float max) {
|
||||
return (v < min) ? min : (v > max) ? max : v;
|
||||
}
|
||||
|
||||
static float ComputeNextQ(PassStats* const s) {
|
||||
float dq;
|
||||
if (s->is_first) {
|
||||
dq = (s->value > s->target) ? -s->dq : s->dq;
|
||||
s->is_first = 0;
|
||||
} else if (s->value != s->last_value) {
|
||||
const double slope = (s->target - s->value) / (s->last_value - s->value);
|
||||
dq = (float)(slope * (s->last_q - s->q));
|
||||
} else {
|
||||
dq = 0.; // we're done?!
|
||||
}
|
||||
// Limit variable to avoid large swings.
|
||||
s->dq = Clamp(dq, -30.f, 30.f);
|
||||
s->last_q = s->q;
|
||||
s->last_value = s->value;
|
||||
s->q = Clamp(s->q + s->dq, 0.f, 100.f);
|
||||
return s->q;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tables for level coding
|
||||
|
||||
const uint8_t VP8Cat3[] = { 173, 148, 140 };
|
||||
const uint8_t VP8Cat4[] = { 176, 155, 140, 135 };
|
||||
const uint8_t VP8Cat5[] = { 180, 157, 141, 134, 130 };
|
||||
const uint8_t VP8Cat6[] =
|
||||
{ 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Reset the statistics about: number of skips, token proba, level cost,...
|
||||
|
||||
static void ResetStats(VP8Encoder* const enc) {
|
||||
VP8EncProba* const proba = &enc->proba_;
|
||||
VP8CalculateLevelCosts(proba);
|
||||
proba->nb_skip_ = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Skip decision probability
|
||||
|
||||
#define SKIP_PROBA_THRESHOLD 250 // value below which using skip_proba is OK.
|
||||
|
||||
static int CalcSkipProba(uint64_t nb, uint64_t total) {
|
||||
return (int)(total ? (total - nb) * 255 / total : 255);
|
||||
}
|
||||
|
||||
// Returns the bit-cost for coding the skip probability.
|
||||
static int FinalizeSkipProba(VP8Encoder* const enc) {
|
||||
VP8EncProba* const proba = &enc->proba_;
|
||||
const int nb_mbs = enc->mb_w_ * enc->mb_h_;
|
||||
const int nb_events = proba->nb_skip_;
|
||||
int size;
|
||||
proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs);
|
||||
proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD);
|
||||
size = 256; // 'use_skip_proba' bit
|
||||
if (proba->use_skip_proba_) {
|
||||
size += nb_events * VP8BitCost(1, proba->skip_proba_)
|
||||
+ (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_);
|
||||
size += 8 * 256; // cost of signaling the skip_proba_ itself.
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// Collect statistics and deduce probabilities for next coding pass.
|
||||
// Return the total bit-cost for coding the probability updates.
|
||||
static int CalcTokenProba(int nb, int total) {
|
||||
assert(nb <= total);
|
||||
return nb ? (255 - nb * 255 / total) : 255;
|
||||
}
|
||||
|
||||
// Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability.
|
||||
static int BranchCost(int nb, int total, int proba) {
|
||||
return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba);
|
||||
}
|
||||
|
||||
static void ResetTokenStats(VP8Encoder* const enc) {
|
||||
VP8EncProba* const proba = &enc->proba_;
|
||||
memset(proba->stats_, 0, sizeof(proba->stats_));
|
||||
}
|
||||
|
||||
static int FinalizeTokenProbas(VP8EncProba* const proba) {
|
||||
int has_changed = 0;
|
||||
int size = 0;
|
||||
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) {
|
||||
const proba_t stats = proba->stats_[t][b][c][p];
|
||||
const int nb = (stats >> 0) & 0xffff;
|
||||
const int total = (stats >> 16) & 0xffff;
|
||||
const int update_proba = VP8CoeffsUpdateProba[t][b][c][p];
|
||||
const int old_p = VP8CoeffsProba0[t][b][c][p];
|
||||
const int new_p = CalcTokenProba(nb, total);
|
||||
const int old_cost = BranchCost(nb, total, old_p)
|
||||
+ VP8BitCost(0, update_proba);
|
||||
const int new_cost = BranchCost(nb, total, new_p)
|
||||
+ VP8BitCost(1, update_proba)
|
||||
+ 8 * 256;
|
||||
const int use_new_p = (old_cost > new_cost);
|
||||
size += VP8BitCost(use_new_p, update_proba);
|
||||
if (use_new_p) { // only use proba that seem meaningful enough.
|
||||
proba->coeffs_[t][b][c][p] = new_p;
|
||||
has_changed |= (new_p != old_p);
|
||||
size += 8 * 256;
|
||||
} else {
|
||||
proba->coeffs_[t][b][c][p] = old_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
proba->dirty_ = has_changed;
|
||||
return size;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Finalize Segment probability based on the coding tree
|
||||
|
||||
static int GetProba(int a, int b) {
|
||||
const int total = a + b;
|
||||
return (total == 0) ? 255 // that's the default probability.
|
||||
: (255 * a + total / 2) / total; // rounded proba
|
||||
}
|
||||
|
||||
static void ResetSegments(VP8Encoder* const enc) {
|
||||
int n;
|
||||
for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
|
||||
enc->mb_info_[n].segment_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetSegmentProbas(VP8Encoder* const enc) {
|
||||
int p[NUM_MB_SEGMENTS] = { 0 };
|
||||
int n;
|
||||
|
||||
for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
|
||||
const VP8MBInfo* const mb = &enc->mb_info_[n];
|
||||
++p[mb->segment_];
|
||||
}
|
||||
#if !defined(WEBP_DISABLE_STATS)
|
||||
if (enc->pic_->stats != NULL) {
|
||||
for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
|
||||
enc->pic_->stats->segment_size[n] = p[n];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (enc->segment_hdr_.num_segments_ > 1) {
|
||||
uint8_t* const probas = enc->proba_.segments_;
|
||||
probas[0] = GetProba(p[0] + p[1], p[2] + p[3]);
|
||||
probas[1] = GetProba(p[0], p[1]);
|
||||
probas[2] = GetProba(p[2], p[3]);
|
||||
|
||||
enc->segment_hdr_.update_map_ =
|
||||
(probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255);
|
||||
if (!enc->segment_hdr_.update_map_) ResetSegments(enc);
|
||||
enc->segment_hdr_.size_ =
|
||||
p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) +
|
||||
p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) +
|
||||
p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) +
|
||||
p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2]));
|
||||
} else {
|
||||
enc->segment_hdr_.update_map_ = 0;
|
||||
enc->segment_hdr_.size_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Coefficient coding
|
||||
|
||||
static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) {
|
||||
int n = res->first;
|
||||
// should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
|
||||
const uint8_t* p = res->prob[n][ctx];
|
||||
if (!VP8PutBit(bw, res->last >= 0, p[0])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (n < 16) {
|
||||
const int c = res->coeffs[n++];
|
||||
const int sign = c < 0;
|
||||
int v = sign ? -c : c;
|
||||
if (!VP8PutBit(bw, v != 0, p[1])) {
|
||||
p = res->prob[VP8EncBands[n]][0];
|
||||
continue;
|
||||
}
|
||||
if (!VP8PutBit(bw, v > 1, p[2])) {
|
||||
p = res->prob[VP8EncBands[n]][1];
|
||||
} else {
|
||||
if (!VP8PutBit(bw, v > 4, p[3])) {
|
||||
if (VP8PutBit(bw, v != 2, p[4])) {
|
||||
VP8PutBit(bw, v == 4, p[5]);
|
||||
}
|
||||
} else if (!VP8PutBit(bw, v > 10, p[6])) {
|
||||
if (!VP8PutBit(bw, v > 6, p[7])) {
|
||||
VP8PutBit(bw, v == 6, 159);
|
||||
} else {
|
||||
VP8PutBit(bw, v >= 9, 165);
|
||||
VP8PutBit(bw, !(v & 1), 145);
|
||||
}
|
||||
} else {
|
||||
int mask;
|
||||
const uint8_t* tab;
|
||||
if (v < 3 + (8 << 1)) { // VP8Cat3 (3b)
|
||||
VP8PutBit(bw, 0, p[8]);
|
||||
VP8PutBit(bw, 0, p[9]);
|
||||
v -= 3 + (8 << 0);
|
||||
mask = 1 << 2;
|
||||
tab = VP8Cat3;
|
||||
} else if (v < 3 + (8 << 2)) { // VP8Cat4 (4b)
|
||||
VP8PutBit(bw, 0, p[8]);
|
||||
VP8PutBit(bw, 1, p[9]);
|
||||
v -= 3 + (8 << 1);
|
||||
mask = 1 << 3;
|
||||
tab = VP8Cat4;
|
||||
} else if (v < 3 + (8 << 3)) { // VP8Cat5 (5b)
|
||||
VP8PutBit(bw, 1, p[8]);
|
||||
VP8PutBit(bw, 0, p[10]);
|
||||
v -= 3 + (8 << 2);
|
||||
mask = 1 << 4;
|
||||
tab = VP8Cat5;
|
||||
} else { // VP8Cat6 (11b)
|
||||
VP8PutBit(bw, 1, p[8]);
|
||||
VP8PutBit(bw, 1, p[10]);
|
||||
v -= 3 + (8 << 3);
|
||||
mask = 1 << 10;
|
||||
tab = VP8Cat6;
|
||||
}
|
||||
while (mask) {
|
||||
VP8PutBit(bw, !!(v & mask), *tab++);
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
p = res->prob[VP8EncBands[n]][2];
|
||||
}
|
||||
VP8PutBitUniform(bw, sign);
|
||||
if (n == 16 || !VP8PutBit(bw, n <= res->last, p[0])) {
|
||||
return 1; // EOB
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it,
|
||||
const VP8ModeScore* const rd) {
|
||||
int x, y, ch;
|
||||
VP8Residual res;
|
||||
uint64_t pos1, pos2, pos3;
|
||||
const int i16 = (it->mb_->type_ == 1);
|
||||
const int segment = it->mb_->segment_;
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
|
||||
VP8IteratorNzToBytes(it);
|
||||
|
||||
pos1 = VP8BitWriterPos(bw);
|
||||
if (i16) {
|
||||
VP8InitResidual(0, 1, enc, &res);
|
||||
VP8SetResidualCoeffs(rd->y_dc_levels, &res);
|
||||
it->top_nz_[8] = it->left_nz_[8] =
|
||||
PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res);
|
||||
VP8InitResidual(1, 0, enc, &res);
|
||||
} else {
|
||||
VP8InitResidual(0, 3, enc, &res);
|
||||
}
|
||||
|
||||
// luma-AC
|
||||
for (y = 0; y < 4; ++y) {
|
||||
for (x = 0; x < 4; ++x) {
|
||||
const int ctx = it->top_nz_[x] + it->left_nz_[y];
|
||||
VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
|
||||
it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res);
|
||||
}
|
||||
}
|
||||
pos2 = VP8BitWriterPos(bw);
|
||||
|
||||
// U/V
|
||||
VP8InitResidual(0, 2, enc, &res);
|
||||
for (ch = 0; ch <= 2; ch += 2) {
|
||||
for (y = 0; y < 2; ++y) {
|
||||
for (x = 0; x < 2; ++x) {
|
||||
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
|
||||
VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
|
||||
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
|
||||
PutCoeffs(bw, ctx, &res);
|
||||
}
|
||||
}
|
||||
}
|
||||
pos3 = VP8BitWriterPos(bw);
|
||||
it->luma_bits_ = pos2 - pos1;
|
||||
it->uv_bits_ = pos3 - pos2;
|
||||
it->bit_count_[segment][i16] += it->luma_bits_;
|
||||
it->bit_count_[segment][2] += it->uv_bits_;
|
||||
VP8IteratorBytesToNz(it);
|
||||
}
|
||||
|
||||
// Same as CodeResiduals, but doesn't actually write anything.
|
||||
// Instead, it just records the event distribution.
|
||||
static void RecordResiduals(VP8EncIterator* const it,
|
||||
const VP8ModeScore* const rd) {
|
||||
int x, y, ch;
|
||||
VP8Residual res;
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
|
||||
VP8IteratorNzToBytes(it);
|
||||
|
||||
if (it->mb_->type_ == 1) { // i16x16
|
||||
VP8InitResidual(0, 1, enc, &res);
|
||||
VP8SetResidualCoeffs(rd->y_dc_levels, &res);
|
||||
it->top_nz_[8] = it->left_nz_[8] =
|
||||
VP8RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res);
|
||||
VP8InitResidual(1, 0, enc, &res);
|
||||
} else {
|
||||
VP8InitResidual(0, 3, enc, &res);
|
||||
}
|
||||
|
||||
// luma-AC
|
||||
for (y = 0; y < 4; ++y) {
|
||||
for (x = 0; x < 4; ++x) {
|
||||
const int ctx = it->top_nz_[x] + it->left_nz_[y];
|
||||
VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
|
||||
it->top_nz_[x] = it->left_nz_[y] = VP8RecordCoeffs(ctx, &res);
|
||||
}
|
||||
}
|
||||
|
||||
// U/V
|
||||
VP8InitResidual(0, 2, enc, &res);
|
||||
for (ch = 0; ch <= 2; ch += 2) {
|
||||
for (y = 0; y < 2; ++y) {
|
||||
for (x = 0; x < 2; ++x) {
|
||||
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
|
||||
VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
|
||||
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
|
||||
VP8RecordCoeffs(ctx, &res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VP8IteratorBytesToNz(it);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Token buffer
|
||||
|
||||
#if !defined(DISABLE_TOKEN_BUFFER)
|
||||
|
||||
static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd,
|
||||
VP8TBuffer* const tokens) {
|
||||
int x, y, ch;
|
||||
VP8Residual res;
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
|
||||
VP8IteratorNzToBytes(it);
|
||||
if (it->mb_->type_ == 1) { // i16x16
|
||||
const int ctx = it->top_nz_[8] + it->left_nz_[8];
|
||||
VP8InitResidual(0, 1, enc, &res);
|
||||
VP8SetResidualCoeffs(rd->y_dc_levels, &res);
|
||||
it->top_nz_[8] = it->left_nz_[8] =
|
||||
VP8RecordCoeffTokens(ctx, &res, tokens);
|
||||
VP8InitResidual(1, 0, enc, &res);
|
||||
} else {
|
||||
VP8InitResidual(0, 3, enc, &res);
|
||||
}
|
||||
|
||||
// luma-AC
|
||||
for (y = 0; y < 4; ++y) {
|
||||
for (x = 0; x < 4; ++x) {
|
||||
const int ctx = it->top_nz_[x] + it->left_nz_[y];
|
||||
VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
|
||||
it->top_nz_[x] = it->left_nz_[y] =
|
||||
VP8RecordCoeffTokens(ctx, &res, tokens);
|
||||
}
|
||||
}
|
||||
|
||||
// U/V
|
||||
VP8InitResidual(0, 2, enc, &res);
|
||||
for (ch = 0; ch <= 2; ch += 2) {
|
||||
for (y = 0; y < 2; ++y) {
|
||||
for (x = 0; x < 2; ++x) {
|
||||
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
|
||||
VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
|
||||
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
|
||||
VP8RecordCoeffTokens(ctx, &res, tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
VP8IteratorBytesToNz(it);
|
||||
return !tokens->error_;
|
||||
}
|
||||
|
||||
#endif // !DISABLE_TOKEN_BUFFER
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// ExtraInfo map / Debug function
|
||||
|
||||
#if !defined(WEBP_DISABLE_STATS)
|
||||
|
||||
#if SEGMENT_VISU
|
||||
static void SetBlock(uint8_t* p, int value, int size) {
|
||||
int y;
|
||||
for (y = 0; y < size; ++y) {
|
||||
memset(p, value, size);
|
||||
p += BPS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ResetSSE(VP8Encoder* const enc) {
|
||||
enc->sse_[0] = 0;
|
||||
enc->sse_[1] = 0;
|
||||
enc->sse_[2] = 0;
|
||||
// Note: enc->sse_[3] is managed by alpha.c
|
||||
enc->sse_count_ = 0;
|
||||
}
|
||||
|
||||
static void StoreSSE(const VP8EncIterator* const it) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
const uint8_t* const in = it->yuv_in_;
|
||||
const uint8_t* const out = it->yuv_out_;
|
||||
// Note: not totally accurate at boundary. And doesn't include in-loop filter.
|
||||
enc->sse_[0] += VP8SSE16x16(in + Y_OFF_ENC, out + Y_OFF_ENC);
|
||||
enc->sse_[1] += VP8SSE8x8(in + U_OFF_ENC, out + U_OFF_ENC);
|
||||
enc->sse_[2] += VP8SSE8x8(in + V_OFF_ENC, out + V_OFF_ENC);
|
||||
enc->sse_count_ += 16 * 16;
|
||||
}
|
||||
|
||||
static void StoreSideInfo(const VP8EncIterator* const it) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
const VP8MBInfo* const mb = it->mb_;
|
||||
WebPPicture* const pic = enc->pic_;
|
||||
|
||||
if (pic->stats != NULL) {
|
||||
StoreSSE(it);
|
||||
enc->block_count_[0] += (mb->type_ == 0);
|
||||
enc->block_count_[1] += (mb->type_ == 1);
|
||||
enc->block_count_[2] += (mb->skip_ != 0);
|
||||
}
|
||||
|
||||
if (pic->extra_info != NULL) {
|
||||
uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_];
|
||||
switch (pic->extra_info_type) {
|
||||
case 1: *info = mb->type_; break;
|
||||
case 2: *info = mb->segment_; break;
|
||||
case 3: *info = enc->dqm_[mb->segment_].quant_; break;
|
||||
case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break;
|
||||
case 5: *info = mb->uv_mode_; break;
|
||||
case 6: {
|
||||
const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3);
|
||||
*info = (b > 255) ? 255 : b; break;
|
||||
}
|
||||
case 7: *info = mb->alpha_; break;
|
||||
default: *info = 0; break;
|
||||
}
|
||||
}
|
||||
#if SEGMENT_VISU // visualize segments and prediction modes
|
||||
SetBlock(it->yuv_out_ + Y_OFF_ENC, mb->segment_ * 64, 16);
|
||||
SetBlock(it->yuv_out_ + U_OFF_ENC, it->preds_[0] * 64, 8);
|
||||
SetBlock(it->yuv_out_ + V_OFF_ENC, mb->uv_mode_ * 64, 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ResetSideInfo(const VP8EncIterator* const it) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
WebPPicture* const pic = enc->pic_;
|
||||
if (pic->stats != NULL) {
|
||||
memset(enc->block_count_, 0, sizeof(enc->block_count_));
|
||||
}
|
||||
ResetSSE(enc);
|
||||
}
|
||||
#else // defined(WEBP_DISABLE_STATS)
|
||||
static void ResetSSE(VP8Encoder* const enc) {
|
||||
(void)enc;
|
||||
}
|
||||
static void StoreSideInfo(const VP8EncIterator* const it) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
WebPPicture* const pic = enc->pic_;
|
||||
if (pic->extra_info != NULL) {
|
||||
if (it->x_ == 0 && it->y_ == 0) { // only do it once, at start
|
||||
memset(pic->extra_info, 0,
|
||||
enc->mb_w_ * enc->mb_h_ * sizeof(*pic->extra_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ResetSideInfo(const VP8EncIterator* const it) {
|
||||
(void)it;
|
||||
}
|
||||
#endif // !defined(WEBP_DISABLE_STATS)
|
||||
|
||||
static double GetPSNR(uint64_t mse, uint64_t size) {
|
||||
return (mse > 0 && size > 0) ? 10. * log10(255. * 255. * size / mse) : 99;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// StatLoop(): only collect statistics (number of skips, token usage, ...).
|
||||
// This is used for deciding optimal probabilities. It also modifies the
|
||||
// quantizer value if some target (size, PSNR) was specified.
|
||||
|
||||
static void SetLoopParams(VP8Encoder* const enc, float q) {
|
||||
// Make sure the quality parameter is inside valid bounds
|
||||
q = Clamp(q, 0.f, 100.f);
|
||||
|
||||
VP8SetSegmentParams(enc, q); // setup segment quantizations and filters
|
||||
SetSegmentProbas(enc); // compute segment probabilities
|
||||
|
||||
ResetStats(enc);
|
||||
ResetSSE(enc);
|
||||
}
|
||||
|
||||
static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt,
|
||||
int nb_mbs, int percent_delta,
|
||||
PassStats* const s) {
|
||||
VP8EncIterator it;
|
||||
uint64_t size = 0;
|
||||
uint64_t size_p0 = 0;
|
||||
uint64_t distortion = 0;
|
||||
const uint64_t pixel_count = nb_mbs * 384;
|
||||
|
||||
VP8IteratorInit(enc, &it);
|
||||
SetLoopParams(enc, s->q);
|
||||
do {
|
||||
VP8ModeScore info;
|
||||
VP8IteratorImport(&it, NULL);
|
||||
if (VP8Decimate(&it, &info, rd_opt)) {
|
||||
// Just record the number of skips and act like skip_proba is not used.
|
||||
++enc->proba_.nb_skip_;
|
||||
}
|
||||
RecordResiduals(&it, &info);
|
||||
size += info.R + info.H;
|
||||
size_p0 += info.H;
|
||||
distortion += info.D;
|
||||
if (percent_delta && !VP8IteratorProgress(&it, percent_delta)) {
|
||||
return 0;
|
||||
}
|
||||
VP8IteratorSaveBoundary(&it);
|
||||
} while (VP8IteratorNext(&it) && --nb_mbs > 0);
|
||||
|
||||
size_p0 += enc->segment_hdr_.size_;
|
||||
if (s->do_size_search) {
|
||||
size += FinalizeSkipProba(enc);
|
||||
size += FinalizeTokenProbas(&enc->proba_);
|
||||
size = ((size + size_p0 + 1024) >> 11) + HEADER_SIZE_ESTIMATE;
|
||||
s->value = (double)size;
|
||||
} else {
|
||||
s->value = GetPSNR(distortion, pixel_count);
|
||||
}
|
||||
return size_p0;
|
||||
}
|
||||
|
||||
static int StatLoop(VP8Encoder* const enc) {
|
||||
const int method = enc->method_;
|
||||
const int do_search = enc->do_search_;
|
||||
const int fast_probe = ((method == 0 || method == 3) && !do_search);
|
||||
int num_pass_left = enc->config_->pass;
|
||||
const int task_percent = 20;
|
||||
const int percent_per_pass =
|
||||
(task_percent + num_pass_left / 2) / num_pass_left;
|
||||
const int final_percent = enc->percent_ + task_percent;
|
||||
const VP8RDLevel rd_opt =
|
||||
(method >= 3 || do_search) ? RD_OPT_BASIC : RD_OPT_NONE;
|
||||
int nb_mbs = enc->mb_w_ * enc->mb_h_;
|
||||
PassStats stats;
|
||||
|
||||
InitPassStats(enc, &stats);
|
||||
ResetTokenStats(enc);
|
||||
|
||||
// Fast mode: quick analysis pass over few mbs. Better than nothing.
|
||||
if (fast_probe) {
|
||||
if (method == 3) { // we need more stats for method 3 to be reliable.
|
||||
nb_mbs = (nb_mbs > 200) ? nb_mbs >> 1 : 100;
|
||||
} else {
|
||||
nb_mbs = (nb_mbs > 200) ? nb_mbs >> 2 : 50;
|
||||
}
|
||||
}
|
||||
|
||||
while (num_pass_left-- > 0) {
|
||||
const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) ||
|
||||
(num_pass_left == 0) ||
|
||||
(enc->max_i4_header_bits_ == 0);
|
||||
const uint64_t size_p0 =
|
||||
OneStatPass(enc, rd_opt, nb_mbs, percent_per_pass, &stats);
|
||||
if (size_p0 == 0) return 0;
|
||||
#if (DEBUG_SEARCH > 0)
|
||||
printf("#%d value:%.1lf -> %.1lf q:%.2f -> %.2f\n",
|
||||
num_pass_left, stats.last_value, stats.value, stats.last_q, stats.q);
|
||||
#endif
|
||||
if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) {
|
||||
++num_pass_left;
|
||||
enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation...
|
||||
continue; // ...and start over
|
||||
}
|
||||
if (is_last_pass) {
|
||||
break;
|
||||
}
|
||||
// If no target size: just do several pass without changing 'q'
|
||||
if (do_search) {
|
||||
ComputeNextQ(&stats);
|
||||
if (fabs(stats.dq) <= DQ_LIMIT) break;
|
||||
}
|
||||
}
|
||||
if (!do_search || !stats.do_size_search) {
|
||||
// Need to finalize probas now, since it wasn't done during the search.
|
||||
FinalizeSkipProba(enc);
|
||||
FinalizeTokenProbas(&enc->proba_);
|
||||
}
|
||||
VP8CalculateLevelCosts(&enc->proba_); // finalize costs
|
||||
return WebPReportProgress(enc->pic_, final_percent, &enc->percent_);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Main loops
|
||||
//
|
||||
|
||||
static const uint8_t kAverageBytesPerMB[8] = { 50, 24, 16, 9, 7, 5, 3, 2 };
|
||||
|
||||
static int PreLoopInitialize(VP8Encoder* const enc) {
|
||||
int p;
|
||||
int ok = 1;
|
||||
const int average_bytes_per_MB = kAverageBytesPerMB[enc->base_quant_ >> 4];
|
||||
const int bytes_per_parts =
|
||||
enc->mb_w_ * enc->mb_h_ * average_bytes_per_MB / enc->num_parts_;
|
||||
// Initialize the bit-writers
|
||||
for (p = 0; ok && p < enc->num_parts_; ++p) {
|
||||
ok = VP8BitWriterInit(enc->parts_ + p, bytes_per_parts);
|
||||
}
|
||||
if (!ok) {
|
||||
VP8EncFreeBitWriters(enc); // malloc error occurred
|
||||
WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int PostLoopFinalize(VP8EncIterator* const it, int ok) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
if (ok) { // Finalize the partitions, check for extra errors.
|
||||
int p;
|
||||
for (p = 0; p < enc->num_parts_; ++p) {
|
||||
VP8BitWriterFinish(enc->parts_ + p);
|
||||
ok &= !enc->parts_[p].error_;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) { // All good. Finish up.
|
||||
#if !defined(WEBP_DISABLE_STATS)
|
||||
if (enc->pic_->stats != NULL) { // finalize byte counters...
|
||||
int i, s;
|
||||
for (i = 0; i <= 2; ++i) {
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||
enc->residual_bytes_[i][s] = (int)((it->bit_count_[s][i] + 7) >> 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
VP8AdjustFilterStrength(it); // ...and store filter stats.
|
||||
} else {
|
||||
// Something bad happened -> need to do some memory cleanup.
|
||||
VP8EncFreeBitWriters(enc);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VP8EncLoop(): does the final bitstream coding.
|
||||
|
||||
static void ResetAfterSkip(VP8EncIterator* const it) {
|
||||
if (it->mb_->type_ == 1) {
|
||||
*it->nz_ = 0; // reset all predictors
|
||||
it->left_nz_[8] = 0;
|
||||
} else {
|
||||
*it->nz_ &= (1 << 24); // preserve the dc_nz bit
|
||||
}
|
||||
}
|
||||
|
||||
int VP8EncLoop(VP8Encoder* const enc) {
|
||||
VP8EncIterator it;
|
||||
int ok = PreLoopInitialize(enc);
|
||||
if (!ok) return 0;
|
||||
|
||||
StatLoop(enc); // stats-collection loop
|
||||
|
||||
VP8IteratorInit(enc, &it);
|
||||
VP8InitFilter(&it);
|
||||
do {
|
||||
VP8ModeScore info;
|
||||
const int dont_use_skip = !enc->proba_.use_skip_proba_;
|
||||
const VP8RDLevel rd_opt = enc->rd_opt_level_;
|
||||
|
||||
VP8IteratorImport(&it, NULL);
|
||||
// Warning! order is important: first call VP8Decimate() and
|
||||
// *then* decide how to code the skip decision if there's one.
|
||||
if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) {
|
||||
CodeResiduals(it.bw_, &it, &info);
|
||||
} else { // reset predictors after a skip
|
||||
ResetAfterSkip(&it);
|
||||
}
|
||||
StoreSideInfo(&it);
|
||||
VP8StoreFilterStats(&it);
|
||||
VP8IteratorExport(&it);
|
||||
ok = VP8IteratorProgress(&it, 20);
|
||||
VP8IteratorSaveBoundary(&it);
|
||||
} while (ok && VP8IteratorNext(&it));
|
||||
|
||||
return PostLoopFinalize(&it, ok);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Single pass using Token Buffer.
|
||||
|
||||
#if !defined(DISABLE_TOKEN_BUFFER)
|
||||
|
||||
#define MIN_COUNT 96 // minimum number of macroblocks before updating stats
|
||||
|
||||
int VP8EncTokenLoop(VP8Encoder* const enc) {
|
||||
// Roughly refresh the proba eight times per pass
|
||||
int max_count = (enc->mb_w_ * enc->mb_h_) >> 3;
|
||||
int num_pass_left = enc->config_->pass;
|
||||
const int do_search = enc->do_search_;
|
||||
VP8EncIterator it;
|
||||
VP8EncProba* const proba = &enc->proba_;
|
||||
const VP8RDLevel rd_opt = enc->rd_opt_level_;
|
||||
const uint64_t pixel_count = enc->mb_w_ * enc->mb_h_ * 384;
|
||||
PassStats stats;
|
||||
int ok;
|
||||
|
||||
InitPassStats(enc, &stats);
|
||||
ok = PreLoopInitialize(enc);
|
||||
if (!ok) return 0;
|
||||
|
||||
if (max_count < MIN_COUNT) max_count = MIN_COUNT;
|
||||
|
||||
assert(enc->num_parts_ == 1);
|
||||
assert(enc->use_tokens_);
|
||||
assert(proba->use_skip_proba_ == 0);
|
||||
assert(rd_opt >= RD_OPT_BASIC); // otherwise, token-buffer won't be useful
|
||||
assert(num_pass_left > 0);
|
||||
|
||||
while (ok && num_pass_left-- > 0) {
|
||||
const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) ||
|
||||
(num_pass_left == 0) ||
|
||||
(enc->max_i4_header_bits_ == 0);
|
||||
uint64_t size_p0 = 0;
|
||||
uint64_t distortion = 0;
|
||||
int cnt = max_count;
|
||||
VP8IteratorInit(enc, &it);
|
||||
SetLoopParams(enc, stats.q);
|
||||
if (is_last_pass) {
|
||||
ResetTokenStats(enc);
|
||||
VP8InitFilter(&it); // don't collect stats until last pass (too costly)
|
||||
}
|
||||
VP8TBufferClear(&enc->tokens_);
|
||||
do {
|
||||
VP8ModeScore info;
|
||||
VP8IteratorImport(&it, NULL);
|
||||
if (--cnt < 0) {
|
||||
FinalizeTokenProbas(proba);
|
||||
VP8CalculateLevelCosts(proba); // refresh cost tables for rd-opt
|
||||
cnt = max_count;
|
||||
}
|
||||
VP8Decimate(&it, &info, rd_opt);
|
||||
ok = RecordTokens(&it, &info, &enc->tokens_);
|
||||
if (!ok) {
|
||||
WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
break;
|
||||
}
|
||||
size_p0 += info.H;
|
||||
distortion += info.D;
|
||||
if (is_last_pass) {
|
||||
StoreSideInfo(&it);
|
||||
VP8StoreFilterStats(&it);
|
||||
VP8IteratorExport(&it);
|
||||
ok = VP8IteratorProgress(&it, 20);
|
||||
}
|
||||
VP8IteratorSaveBoundary(&it);
|
||||
} while (ok && VP8IteratorNext(&it));
|
||||
if (!ok) break;
|
||||
|
||||
size_p0 += enc->segment_hdr_.size_;
|
||||
if (stats.do_size_search) {
|
||||
uint64_t size = FinalizeTokenProbas(&enc->proba_);
|
||||
size += VP8EstimateTokenSize(&enc->tokens_,
|
||||
(const uint8_t*)proba->coeffs_);
|
||||
size = (size + size_p0 + 1024) >> 11; // -> size in bytes
|
||||
size += HEADER_SIZE_ESTIMATE;
|
||||
stats.value = (double)size;
|
||||
} else { // compute and store PSNR
|
||||
stats.value = GetPSNR(distortion, pixel_count);
|
||||
}
|
||||
|
||||
#if (DEBUG_SEARCH > 0)
|
||||
printf("#%2d metric:%.1lf -> %.1lf last_q=%.2lf q=%.2lf dq=%.2lf\n",
|
||||
num_pass_left, stats.last_value, stats.value,
|
||||
stats.last_q, stats.q, stats.dq);
|
||||
#endif
|
||||
if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) {
|
||||
++num_pass_left;
|
||||
enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation...
|
||||
if (is_last_pass) {
|
||||
ResetSideInfo(&it);
|
||||
}
|
||||
continue; // ...and start over
|
||||
}
|
||||
if (is_last_pass) {
|
||||
break; // done
|
||||
}
|
||||
if (do_search) {
|
||||
ComputeNextQ(&stats); // Adjust q
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
if (!stats.do_size_search) {
|
||||
FinalizeTokenProbas(&enc->proba_);
|
||||
}
|
||||
ok = VP8EmitTokens(&enc->tokens_, enc->parts_ + 0,
|
||||
(const uint8_t*)proba->coeffs_, 1);
|
||||
}
|
||||
ok = ok && WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
|
||||
return PostLoopFinalize(&it, ok);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int VP8EncTokenLoop(VP8Encoder* const enc) {
|
||||
(void)enc;
|
||||
return 0; // we shouldn't be here.
|
||||
}
|
||||
|
||||
#endif // DISABLE_TOKEN_BUFFER
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
1250
libsdl2_image/external/libwebp-1.0.2/src/enc/histogram_enc.c
vendored
Normal file
1250
libsdl2_image/external/libwebp-1.0.2/src/enc/histogram_enc.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
128
libsdl2_image/external/libwebp-1.0.2/src/enc/histogram_enc.h
vendored
Normal file
128
libsdl2_image/external/libwebp-1.0.2/src/enc/histogram_enc.h
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Author: Jyrki Alakuijala (jyrki@google.com)
|
||||
//
|
||||
// Models the histograms of literal and distance codes.
|
||||
|
||||
#ifndef WEBP_ENC_HISTOGRAM_ENC_H_
|
||||
#define WEBP_ENC_HISTOGRAM_ENC_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "src/enc/backward_references_enc.h"
|
||||
#include "src/webp/format_constants.h"
|
||||
#include "src/webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Not a trivial literal symbol.
|
||||
#define VP8L_NON_TRIVIAL_SYM (0xffffffff)
|
||||
|
||||
// A simple container for histograms of data.
|
||||
typedef struct {
|
||||
// literal_ contains green literal, palette-code and
|
||||
// copy-length-prefix histogram
|
||||
uint32_t* literal_; // Pointer to the allocated buffer for literal.
|
||||
uint32_t red_[NUM_LITERAL_CODES];
|
||||
uint32_t blue_[NUM_LITERAL_CODES];
|
||||
uint32_t alpha_[NUM_LITERAL_CODES];
|
||||
// Backward reference prefix-code histogram.
|
||||
uint32_t distance_[NUM_DISTANCE_CODES];
|
||||
int palette_code_bits_;
|
||||
uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha
|
||||
// literal symbols are single valued.
|
||||
double bit_cost_; // cached value of bit cost.
|
||||
double literal_cost_; // Cached values of dominant entropy costs:
|
||||
double red_cost_; // literal, red & blue.
|
||||
double blue_cost_;
|
||||
uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance
|
||||
} VP8LHistogram;
|
||||
|
||||
// Collection of histograms with fixed capacity, allocated as one
|
||||
// big memory chunk. Can be destroyed by calling WebPSafeFree().
|
||||
typedef struct {
|
||||
int size; // number of slots currently in use
|
||||
int max_size; // maximum capacity
|
||||
VP8LHistogram** histograms;
|
||||
} VP8LHistogramSet;
|
||||
|
||||
// Create the histogram.
|
||||
//
|
||||
// The input data is the PixOrCopy data, which models the literals, stop
|
||||
// codes and backward references (both distances and lengths). Also: if
|
||||
// palette_code_bits is >= 0, initialize the histogram with this value.
|
||||
void VP8LHistogramCreate(VP8LHistogram* const p,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int palette_code_bits);
|
||||
|
||||
// Return the size of the histogram for a given palette_code_bits.
|
||||
int VP8LGetHistogramSize(int palette_code_bits);
|
||||
|
||||
// Set the palette_code_bits and reset the stats.
|
||||
// If init_arrays is true, the arrays are also filled with 0's.
|
||||
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
|
||||
int init_arrays);
|
||||
|
||||
// Collect all the references into a histogram (without reset)
|
||||
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
|
||||
VP8LHistogram* const histo);
|
||||
|
||||
// Free the memory allocated for the histogram.
|
||||
void VP8LFreeHistogram(VP8LHistogram* const histo);
|
||||
|
||||
// Free the memory allocated for the histogram set.
|
||||
void VP8LFreeHistogramSet(VP8LHistogramSet* const histo);
|
||||
|
||||
// Allocate an array of pointer to histograms, allocated and initialized
|
||||
// using 'cache_bits'. Return NULL in case of memory error.
|
||||
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
|
||||
|
||||
// Set the histograms in set to 0.
|
||||
void VP8LHistogramSetClear(VP8LHistogramSet* const set);
|
||||
|
||||
// Allocate and initialize histogram object with specified 'cache_bits'.
|
||||
// Returns NULL in case of memory error.
|
||||
// Special case of VP8LAllocateHistogramSet, with size equals 1.
|
||||
VP8LHistogram* VP8LAllocateHistogram(int cache_bits);
|
||||
|
||||
// Accumulate a token 'v' into a histogram.
|
||||
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
|
||||
const PixOrCopy* const v,
|
||||
int (*const distance_modifier)(int, int),
|
||||
int distance_modifier_arg0);
|
||||
|
||||
static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) {
|
||||
return NUM_LITERAL_CODES + NUM_LENGTH_CODES +
|
||||
((palette_code_bits > 0) ? (1 << palette_code_bits) : 0);
|
||||
}
|
||||
|
||||
// Builds the histogram image.
|
||||
int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int quality, int low_effort,
|
||||
int histogram_bits, int cache_bits,
|
||||
VP8LHistogramSet* const image_in,
|
||||
VP8LHistogram* const tmp_histo,
|
||||
uint16_t* const histogram_symbols);
|
||||
|
||||
// Returns the entropy for the symbols in the input array.
|
||||
double VP8LBitsEntropy(const uint32_t* const array, int n);
|
||||
|
||||
// Estimate how many bits the combined entropy of literals and distance
|
||||
// approximately maps to.
|
||||
double VP8LHistogramEstimateBits(VP8LHistogram* const p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WEBP_ENC_HISTOGRAM_ENC_H_
|
||||
459
libsdl2_image/external/libwebp-1.0.2/src/enc/iterator_enc.c
vendored
Normal file
459
libsdl2_image/external/libwebp-1.0.2/src/enc/iterator_enc.c
vendored
Normal file
@ -0,0 +1,459 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// VP8Iterator: block iterator
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VP8Iterator
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static void InitLeft(VP8EncIterator* const it) {
|
||||
it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] =
|
||||
(it->y_ > 0) ? 129 : 127;
|
||||
memset(it->y_left_, 129, 16);
|
||||
memset(it->u_left_, 129, 8);
|
||||
memset(it->v_left_, 129, 8);
|
||||
it->left_nz_[8] = 0;
|
||||
if (it->top_derr_ != NULL) {
|
||||
memset(&it->left_derr_, 0, sizeof(it->left_derr_));
|
||||
}
|
||||
}
|
||||
|
||||
static void InitTop(VP8EncIterator* const it) {
|
||||
const VP8Encoder* const enc = it->enc_;
|
||||
const size_t top_size = enc->mb_w_ * 16;
|
||||
memset(enc->y_top_, 127, 2 * top_size);
|
||||
memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_));
|
||||
if (enc->top_derr_ != NULL) {
|
||||
memset(enc->top_derr_, 0, enc->mb_w_ * sizeof(*enc->top_derr_));
|
||||
}
|
||||
}
|
||||
|
||||
void VP8IteratorSetRow(VP8EncIterator* const it, int y) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
it->x_ = 0;
|
||||
it->y_ = y;
|
||||
it->bw_ = &enc->parts_[y & (enc->num_parts_ - 1)];
|
||||
it->preds_ = enc->preds_ + y * 4 * enc->preds_w_;
|
||||
it->nz_ = enc->nz_;
|
||||
it->mb_ = enc->mb_info_ + y * enc->mb_w_;
|
||||
it->y_top_ = enc->y_top_;
|
||||
it->uv_top_ = enc->uv_top_;
|
||||
InitLeft(it);
|
||||
}
|
||||
|
||||
void VP8IteratorReset(VP8EncIterator* const it) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
VP8IteratorSetRow(it, 0);
|
||||
VP8IteratorSetCountDown(it, enc->mb_w_ * enc->mb_h_); // default
|
||||
InitTop(it);
|
||||
memset(it->bit_count_, 0, sizeof(it->bit_count_));
|
||||
it->do_trellis_ = 0;
|
||||
}
|
||||
|
||||
void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down) {
|
||||
it->count_down_ = it->count_down0_ = count_down;
|
||||
}
|
||||
|
||||
int VP8IteratorIsDone(const VP8EncIterator* const it) {
|
||||
return (it->count_down_ <= 0);
|
||||
}
|
||||
|
||||
void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) {
|
||||
it->enc_ = enc;
|
||||
it->yuv_in_ = (uint8_t*)WEBP_ALIGN(it->yuv_mem_);
|
||||
it->yuv_out_ = it->yuv_in_ + YUV_SIZE_ENC;
|
||||
it->yuv_out2_ = it->yuv_out_ + YUV_SIZE_ENC;
|
||||
it->yuv_p_ = it->yuv_out2_ + YUV_SIZE_ENC;
|
||||
it->lf_stats_ = enc->lf_stats_;
|
||||
it->percent0_ = enc->percent_;
|
||||
it->y_left_ = (uint8_t*)WEBP_ALIGN(it->yuv_left_mem_ + 1);
|
||||
it->u_left_ = it->y_left_ + 16 + 16;
|
||||
it->v_left_ = it->u_left_ + 16;
|
||||
it->top_derr_ = enc->top_derr_;
|
||||
VP8IteratorReset(it);
|
||||
}
|
||||
|
||||
int VP8IteratorProgress(const VP8EncIterator* const it, int delta) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
if (delta && enc->pic_->progress_hook != NULL) {
|
||||
const int done = it->count_down0_ - it->count_down_;
|
||||
const int percent = (it->count_down0_ <= 0)
|
||||
? it->percent0_
|
||||
: it->percent0_ + delta * done / it->count_down0_;
|
||||
return WebPReportProgress(enc->pic_, percent, &enc->percent_);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Import the source samples into the cache. Takes care of replicating
|
||||
// boundary pixels if necessary.
|
||||
|
||||
static WEBP_INLINE int MinSize(int a, int b) { return (a < b) ? a : b; }
|
||||
|
||||
static void ImportBlock(const uint8_t* src, int src_stride,
|
||||
uint8_t* dst, int w, int h, int size) {
|
||||
int i;
|
||||
for (i = 0; i < h; ++i) {
|
||||
memcpy(dst, src, w);
|
||||
if (w < size) {
|
||||
memset(dst + w, dst[w - 1], size - w);
|
||||
}
|
||||
dst += BPS;
|
||||
src += src_stride;
|
||||
}
|
||||
for (i = h; i < size; ++i) {
|
||||
memcpy(dst, dst - BPS, size);
|
||||
dst += BPS;
|
||||
}
|
||||
}
|
||||
|
||||
static void ImportLine(const uint8_t* src, int src_stride,
|
||||
uint8_t* dst, int len, int total_len) {
|
||||
int i;
|
||||
for (i = 0; i < len; ++i, src += src_stride) dst[i] = *src;
|
||||
for (; i < total_len; ++i) dst[i] = dst[len - 1];
|
||||
}
|
||||
|
||||
void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32) {
|
||||
const VP8Encoder* const enc = it->enc_;
|
||||
const int x = it->x_, y = it->y_;
|
||||
const WebPPicture* const pic = enc->pic_;
|
||||
const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16;
|
||||
const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8;
|
||||
const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8;
|
||||
const int w = MinSize(pic->width - x * 16, 16);
|
||||
const int h = MinSize(pic->height - y * 16, 16);
|
||||
const int uv_w = (w + 1) >> 1;
|
||||
const int uv_h = (h + 1) >> 1;
|
||||
|
||||
ImportBlock(ysrc, pic->y_stride, it->yuv_in_ + Y_OFF_ENC, w, h, 16);
|
||||
ImportBlock(usrc, pic->uv_stride, it->yuv_in_ + U_OFF_ENC, uv_w, uv_h, 8);
|
||||
ImportBlock(vsrc, pic->uv_stride, it->yuv_in_ + V_OFF_ENC, uv_w, uv_h, 8);
|
||||
|
||||
if (tmp_32 == NULL) return;
|
||||
|
||||
// Import source (uncompressed) samples into boundary.
|
||||
if (x == 0) {
|
||||
InitLeft(it);
|
||||
} else {
|
||||
if (y == 0) {
|
||||
it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = 127;
|
||||
} else {
|
||||
it->y_left_[-1] = ysrc[- 1 - pic->y_stride];
|
||||
it->u_left_[-1] = usrc[- 1 - pic->uv_stride];
|
||||
it->v_left_[-1] = vsrc[- 1 - pic->uv_stride];
|
||||
}
|
||||
ImportLine(ysrc - 1, pic->y_stride, it->y_left_, h, 16);
|
||||
ImportLine(usrc - 1, pic->uv_stride, it->u_left_, uv_h, 8);
|
||||
ImportLine(vsrc - 1, pic->uv_stride, it->v_left_, uv_h, 8);
|
||||
}
|
||||
|
||||
it->y_top_ = tmp_32 + 0;
|
||||
it->uv_top_ = tmp_32 + 16;
|
||||
if (y == 0) {
|
||||
memset(tmp_32, 127, 32 * sizeof(*tmp_32));
|
||||
} else {
|
||||
ImportLine(ysrc - pic->y_stride, 1, tmp_32, w, 16);
|
||||
ImportLine(usrc - pic->uv_stride, 1, tmp_32 + 16, uv_w, 8);
|
||||
ImportLine(vsrc - pic->uv_stride, 1, tmp_32 + 16 + 8, uv_w, 8);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Copy back the compressed samples into user space if requested.
|
||||
|
||||
static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride,
|
||||
int w, int h) {
|
||||
while (h-- > 0) {
|
||||
memcpy(dst, src, w);
|
||||
dst += dst_stride;
|
||||
src += BPS;
|
||||
}
|
||||
}
|
||||
|
||||
void VP8IteratorExport(const VP8EncIterator* const it) {
|
||||
const VP8Encoder* const enc = it->enc_;
|
||||
if (enc->config_->show_compressed) {
|
||||
const int x = it->x_, y = it->y_;
|
||||
const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC;
|
||||
const uint8_t* const usrc = it->yuv_out_ + U_OFF_ENC;
|
||||
const uint8_t* const vsrc = it->yuv_out_ + V_OFF_ENC;
|
||||
const WebPPicture* const pic = enc->pic_;
|
||||
uint8_t* const ydst = pic->y + (y * pic->y_stride + x) * 16;
|
||||
uint8_t* const udst = pic->u + (y * pic->uv_stride + x) * 8;
|
||||
uint8_t* const vdst = pic->v + (y * pic->uv_stride + x) * 8;
|
||||
int w = (pic->width - x * 16);
|
||||
int h = (pic->height - y * 16);
|
||||
|
||||
if (w > 16) w = 16;
|
||||
if (h > 16) h = 16;
|
||||
|
||||
// Luma plane
|
||||
ExportBlock(ysrc, ydst, pic->y_stride, w, h);
|
||||
|
||||
{ // U/V planes
|
||||
const int uv_w = (w + 1) >> 1;
|
||||
const int uv_h = (h + 1) >> 1;
|
||||
ExportBlock(usrc, udst, pic->uv_stride, uv_w, uv_h);
|
||||
ExportBlock(vsrc, vdst, pic->uv_stride, uv_w, uv_h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Non-zero contexts setup/teardown
|
||||
|
||||
// Nz bits:
|
||||
// 0 1 2 3 Y
|
||||
// 4 5 6 7
|
||||
// 8 9 10 11
|
||||
// 12 13 14 15
|
||||
// 16 17 U
|
||||
// 18 19
|
||||
// 20 21 V
|
||||
// 22 23
|
||||
// 24 DC-intra16
|
||||
|
||||
// Convert packed context to byte array
|
||||
#define BIT(nz, n) (!!((nz) & (1 << (n))))
|
||||
|
||||
void VP8IteratorNzToBytes(VP8EncIterator* const it) {
|
||||
const int tnz = it->nz_[0], lnz = it->nz_[-1];
|
||||
int* const top_nz = it->top_nz_;
|
||||
int* const left_nz = it->left_nz_;
|
||||
|
||||
// Top-Y
|
||||
top_nz[0] = BIT(tnz, 12);
|
||||
top_nz[1] = BIT(tnz, 13);
|
||||
top_nz[2] = BIT(tnz, 14);
|
||||
top_nz[3] = BIT(tnz, 15);
|
||||
// Top-U
|
||||
top_nz[4] = BIT(tnz, 18);
|
||||
top_nz[5] = BIT(tnz, 19);
|
||||
// Top-V
|
||||
top_nz[6] = BIT(tnz, 22);
|
||||
top_nz[7] = BIT(tnz, 23);
|
||||
// DC
|
||||
top_nz[8] = BIT(tnz, 24);
|
||||
|
||||
// left-Y
|
||||
left_nz[0] = BIT(lnz, 3);
|
||||
left_nz[1] = BIT(lnz, 7);
|
||||
left_nz[2] = BIT(lnz, 11);
|
||||
left_nz[3] = BIT(lnz, 15);
|
||||
// left-U
|
||||
left_nz[4] = BIT(lnz, 17);
|
||||
left_nz[5] = BIT(lnz, 19);
|
||||
// left-V
|
||||
left_nz[6] = BIT(lnz, 21);
|
||||
left_nz[7] = BIT(lnz, 23);
|
||||
// left-DC is special, iterated separately
|
||||
}
|
||||
|
||||
void VP8IteratorBytesToNz(VP8EncIterator* const it) {
|
||||
uint32_t nz = 0;
|
||||
const int* const top_nz = it->top_nz_;
|
||||
const int* const left_nz = it->left_nz_;
|
||||
// top
|
||||
nz |= (top_nz[0] << 12) | (top_nz[1] << 13);
|
||||
nz |= (top_nz[2] << 14) | (top_nz[3] << 15);
|
||||
nz |= (top_nz[4] << 18) | (top_nz[5] << 19);
|
||||
nz |= (top_nz[6] << 22) | (top_nz[7] << 23);
|
||||
nz |= (top_nz[8] << 24); // we propagate the _top_ bit, esp. for intra4
|
||||
// left
|
||||
nz |= (left_nz[0] << 3) | (left_nz[1] << 7);
|
||||
nz |= (left_nz[2] << 11);
|
||||
nz |= (left_nz[4] << 17) | (left_nz[6] << 21);
|
||||
|
||||
*it->nz_ = nz;
|
||||
}
|
||||
|
||||
#undef BIT
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Advance to the next position, doing the bookkeeping.
|
||||
|
||||
void VP8IteratorSaveBoundary(VP8EncIterator* const it) {
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
const int x = it->x_, y = it->y_;
|
||||
const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC;
|
||||
const uint8_t* const uvsrc = it->yuv_out_ + U_OFF_ENC;
|
||||
if (x < enc->mb_w_ - 1) { // left
|
||||
int i;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
it->y_left_[i] = ysrc[15 + i * BPS];
|
||||
}
|
||||
for (i = 0; i < 8; ++i) {
|
||||
it->u_left_[i] = uvsrc[7 + i * BPS];
|
||||
it->v_left_[i] = uvsrc[15 + i * BPS];
|
||||
}
|
||||
// top-left (before 'top'!)
|
||||
it->y_left_[-1] = it->y_top_[15];
|
||||
it->u_left_[-1] = it->uv_top_[0 + 7];
|
||||
it->v_left_[-1] = it->uv_top_[8 + 7];
|
||||
}
|
||||
if (y < enc->mb_h_ - 1) { // top
|
||||
memcpy(it->y_top_, ysrc + 15 * BPS, 16);
|
||||
memcpy(it->uv_top_, uvsrc + 7 * BPS, 8 + 8);
|
||||
}
|
||||
}
|
||||
|
||||
int VP8IteratorNext(VP8EncIterator* const it) {
|
||||
if (++it->x_ == it->enc_->mb_w_) {
|
||||
VP8IteratorSetRow(it, ++it->y_);
|
||||
} else {
|
||||
it->preds_ += 4;
|
||||
it->mb_ += 1;
|
||||
it->nz_ += 1;
|
||||
it->y_top_ += 16;
|
||||
it->uv_top_ += 16;
|
||||
}
|
||||
return (0 < --it->count_down_);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper function to set mode properties
|
||||
|
||||
void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) {
|
||||
uint8_t* preds = it->preds_;
|
||||
int y;
|
||||
for (y = 0; y < 4; ++y) {
|
||||
memset(preds, mode, 4);
|
||||
preds += it->enc_->preds_w_;
|
||||
}
|
||||
it->mb_->type_ = 1;
|
||||
}
|
||||
|
||||
void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes) {
|
||||
uint8_t* preds = it->preds_;
|
||||
int y;
|
||||
for (y = 4; y > 0; --y) {
|
||||
memcpy(preds, modes, 4 * sizeof(*modes));
|
||||
preds += it->enc_->preds_w_;
|
||||
modes += 4;
|
||||
}
|
||||
it->mb_->type_ = 0;
|
||||
}
|
||||
|
||||
void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode) {
|
||||
it->mb_->uv_mode_ = mode;
|
||||
}
|
||||
|
||||
void VP8SetSkip(const VP8EncIterator* const it, int skip) {
|
||||
it->mb_->skip_ = skip;
|
||||
}
|
||||
|
||||
void VP8SetSegment(const VP8EncIterator* const it, int segment) {
|
||||
it->mb_->segment_ = segment;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Intra4x4 sub-blocks iteration
|
||||
//
|
||||
// We store and update the boundary samples into an array of 37 pixels. They
|
||||
// are updated as we iterate and reconstructs each intra4x4 blocks in turn.
|
||||
// The position of the samples has the following snake pattern:
|
||||
//
|
||||
// 16|17 18 19 20|21 22 23 24|25 26 27 28|29 30 31 32|33 34 35 36 <- Top-right
|
||||
// --+-----------+-----------+-----------+-----------+
|
||||
// 15| 19| 23| 27| 31|
|
||||
// 14| 18| 22| 26| 30|
|
||||
// 13| 17| 21| 25| 29|
|
||||
// 12|13 14 15 16|17 18 19 20|21 22 23 24|25 26 27 28|
|
||||
// --+-----------+-----------+-----------+-----------+
|
||||
// 11| 15| 19| 23| 27|
|
||||
// 10| 14| 18| 22| 26|
|
||||
// 9| 13| 17| 21| 25|
|
||||
// 8| 9 10 11 12|13 14 15 16|17 18 19 20|21 22 23 24|
|
||||
// --+-----------+-----------+-----------+-----------+
|
||||
// 7| 11| 15| 19| 23|
|
||||
// 6| 10| 14| 18| 22|
|
||||
// 5| 9| 13| 17| 21|
|
||||
// 4| 5 6 7 8| 9 10 11 12|13 14 15 16|17 18 19 20|
|
||||
// --+-----------+-----------+-----------+-----------+
|
||||
// 3| 7| 11| 15| 19|
|
||||
// 2| 6| 10| 14| 18|
|
||||
// 1| 5| 9| 13| 17|
|
||||
// 0| 1 2 3 4| 5 6 7 8| 9 10 11 12|13 14 15 16|
|
||||
// --+-----------+-----------+-----------+-----------+
|
||||
|
||||
// Array to record the position of the top sample to pass to the prediction
|
||||
// functions in dsp.c.
|
||||
static const uint8_t VP8TopLeftI4[16] = {
|
||||
17, 21, 25, 29,
|
||||
13, 17, 21, 25,
|
||||
9, 13, 17, 21,
|
||||
5, 9, 13, 17
|
||||
};
|
||||
|
||||
void VP8IteratorStartI4(VP8EncIterator* const it) {
|
||||
const VP8Encoder* const enc = it->enc_;
|
||||
int i;
|
||||
|
||||
it->i4_ = 0; // first 4x4 sub-block
|
||||
it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[0];
|
||||
|
||||
// Import the boundary samples
|
||||
for (i = 0; i < 17; ++i) { // left
|
||||
it->i4_boundary_[i] = it->y_left_[15 - i];
|
||||
}
|
||||
for (i = 0; i < 16; ++i) { // top
|
||||
it->i4_boundary_[17 + i] = it->y_top_[i];
|
||||
}
|
||||
// top-right samples have a special case on the far right of the picture
|
||||
if (it->x_ < enc->mb_w_ - 1) {
|
||||
for (i = 16; i < 16 + 4; ++i) {
|
||||
it->i4_boundary_[17 + i] = it->y_top_[i];
|
||||
}
|
||||
} else { // else, replicate the last valid pixel four times
|
||||
for (i = 16; i < 16 + 4; ++i) {
|
||||
it->i4_boundary_[17 + i] = it->i4_boundary_[17 + 15];
|
||||
}
|
||||
}
|
||||
VP8IteratorNzToBytes(it); // import the non-zero context
|
||||
}
|
||||
|
||||
int VP8IteratorRotateI4(VP8EncIterator* const it,
|
||||
const uint8_t* const yuv_out) {
|
||||
const uint8_t* const blk = yuv_out + VP8Scan[it->i4_];
|
||||
uint8_t* const top = it->i4_top_;
|
||||
int i;
|
||||
|
||||
// Update the cache with 7 fresh samples
|
||||
for (i = 0; i <= 3; ++i) {
|
||||
top[-4 + i] = blk[i + 3 * BPS]; // store future top samples
|
||||
}
|
||||
if ((it->i4_ & 3) != 3) { // if not on the right sub-blocks #3, #7, #11, #15
|
||||
for (i = 0; i <= 2; ++i) { // store future left samples
|
||||
top[i] = blk[3 + (2 - i) * BPS];
|
||||
}
|
||||
} else { // else replicate top-right samples, as says the specs.
|
||||
for (i = 0; i <= 3; ++i) {
|
||||
top[i] = top[i + 4];
|
||||
}
|
||||
}
|
||||
// move pointers to next sub-block
|
||||
++it->i4_;
|
||||
if (it->i4_ == 16) { // we're done
|
||||
return 0;
|
||||
}
|
||||
|
||||
it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[it->i4_];
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
151
libsdl2_image/external/libwebp-1.0.2/src/enc/near_lossless_enc.c
vendored
Normal file
151
libsdl2_image/external/libwebp-1.0.2/src/enc/near_lossless_enc.c
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Near-lossless image preprocessing adjusts pixel values to help
|
||||
// compressibility with a guarantee of maximum deviation between original and
|
||||
// resulting pixel values.
|
||||
//
|
||||
// Author: Jyrki Alakuijala (jyrki@google.com)
|
||||
// Converted to C by Aleksander Kramarz (akramarz@google.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/dsp/lossless_common.h"
|
||||
#include "src/utils/utils.h"
|
||||
#include "src/enc/vp8li_enc.h"
|
||||
|
||||
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||
|
||||
#define MIN_DIM_FOR_NEAR_LOSSLESS 64
|
||||
#define MAX_LIMIT_BITS 5
|
||||
|
||||
// Quantizes the value up or down to a multiple of 1<<bits (or to 255),
|
||||
// choosing the closer one, resolving ties using bankers' rounding.
|
||||
static uint32_t FindClosestDiscretized(uint32_t a, int bits) {
|
||||
const uint32_t mask = (1u << bits) - 1;
|
||||
const uint32_t biased = a + (mask >> 1) + ((a >> bits) & 1);
|
||||
assert(bits > 0);
|
||||
if (biased > 0xff) return 0xff;
|
||||
return biased & ~mask;
|
||||
}
|
||||
|
||||
// Applies FindClosestDiscretized to all channels of pixel.
|
||||
static uint32_t ClosestDiscretizedArgb(uint32_t a, int bits) {
|
||||
return
|
||||
(FindClosestDiscretized(a >> 24, bits) << 24) |
|
||||
(FindClosestDiscretized((a >> 16) & 0xff, bits) << 16) |
|
||||
(FindClosestDiscretized((a >> 8) & 0xff, bits) << 8) |
|
||||
(FindClosestDiscretized(a & 0xff, bits));
|
||||
}
|
||||
|
||||
// Checks if distance between corresponding channel values of pixels a and b
|
||||
// is within the given limit.
|
||||
static int IsNear(uint32_t a, uint32_t b, int limit) {
|
||||
int k;
|
||||
for (k = 0; k < 4; ++k) {
|
||||
const int delta =
|
||||
(int)((a >> (k * 8)) & 0xff) - (int)((b >> (k * 8)) & 0xff);
|
||||
if (delta >= limit || delta <= -limit) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int IsSmooth(const uint32_t* const prev_row,
|
||||
const uint32_t* const curr_row,
|
||||
const uint32_t* const next_row,
|
||||
int ix, int limit) {
|
||||
// Check that all pixels in 4-connected neighborhood are smooth.
|
||||
return (IsNear(curr_row[ix], curr_row[ix - 1], limit) &&
|
||||
IsNear(curr_row[ix], curr_row[ix + 1], limit) &&
|
||||
IsNear(curr_row[ix], prev_row[ix], limit) &&
|
||||
IsNear(curr_row[ix], next_row[ix], limit));
|
||||
}
|
||||
|
||||
// Adjusts pixel values of image with given maximum error.
|
||||
static void NearLossless(int xsize, int ysize, const uint32_t* argb_src,
|
||||
int stride, int limit_bits, uint32_t* copy_buffer,
|
||||
uint32_t* argb_dst) {
|
||||
int x, y;
|
||||
const int limit = 1 << limit_bits;
|
||||
uint32_t* prev_row = copy_buffer;
|
||||
uint32_t* curr_row = prev_row + xsize;
|
||||
uint32_t* next_row = curr_row + xsize;
|
||||
memcpy(curr_row, argb_src, xsize * sizeof(argb_src[0]));
|
||||
memcpy(next_row, argb_src + stride, xsize * sizeof(argb_src[0]));
|
||||
|
||||
for (y = 0; y < ysize; ++y, argb_src += stride, argb_dst += xsize) {
|
||||
if (y == 0 || y == ysize - 1) {
|
||||
memcpy(argb_dst, argb_src, xsize * sizeof(argb_src[0]));
|
||||
} else {
|
||||
memcpy(next_row, argb_src + stride, xsize * sizeof(argb_src[0]));
|
||||
argb_dst[0] = argb_src[0];
|
||||
argb_dst[xsize - 1] = argb_src[xsize - 1];
|
||||
for (x = 1; x < xsize - 1; ++x) {
|
||||
if (IsSmooth(prev_row, curr_row, next_row, x, limit)) {
|
||||
argb_dst[x] = curr_row[x];
|
||||
} else {
|
||||
argb_dst[x] = ClosestDiscretizedArgb(curr_row[x], limit_bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// Three-way swap.
|
||||
uint32_t* const temp = prev_row;
|
||||
prev_row = curr_row;
|
||||
curr_row = next_row;
|
||||
next_row = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
|
||||
uint32_t* const argb_dst) {
|
||||
int i;
|
||||
const int xsize = picture->width;
|
||||
const int ysize = picture->height;
|
||||
const int stride = picture->argb_stride;
|
||||
uint32_t* const copy_buffer =
|
||||
(uint32_t*)WebPSafeMalloc(xsize * 3, sizeof(*copy_buffer));
|
||||
const int limit_bits = VP8LNearLosslessBits(quality);
|
||||
assert(argb_dst != NULL);
|
||||
assert(limit_bits > 0);
|
||||
assert(limit_bits <= MAX_LIMIT_BITS);
|
||||
if (copy_buffer == NULL) {
|
||||
return 0;
|
||||
}
|
||||
// For small icon images, don't attempt to apply near-lossless compression.
|
||||
if ((xsize < MIN_DIM_FOR_NEAR_LOSSLESS &&
|
||||
ysize < MIN_DIM_FOR_NEAR_LOSSLESS) ||
|
||||
ysize < 3) {
|
||||
for (i = 0; i < ysize; ++i) {
|
||||
memcpy(argb_dst + i * xsize, picture->argb + i * picture->argb_stride,
|
||||
xsize * sizeof(*argb_dst));
|
||||
}
|
||||
WebPSafeFree(copy_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NearLossless(xsize, ysize, picture->argb, stride, limit_bits, copy_buffer,
|
||||
argb_dst);
|
||||
for (i = limit_bits - 1; i != 0; --i) {
|
||||
NearLossless(xsize, ysize, argb_dst, xsize, i, copy_buffer, argb_dst);
|
||||
}
|
||||
WebPSafeFree(copy_buffer);
|
||||
return 1;
|
||||
}
|
||||
#else // (WEBP_NEAR_LOSSLESS == 1)
|
||||
|
||||
// Define a stub to suppress compiler warnings.
|
||||
extern void VP8LNearLosslessStub(void);
|
||||
void VP8LNearLosslessStub(void) {}
|
||||
|
||||
#endif // (WEBP_NEAR_LOSSLESS == 1)
|
||||
1206
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_csp_enc.c
vendored
Normal file
1206
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_csp_enc.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
296
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_enc.c
vendored
Normal file
296
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_enc.c
vendored
Normal file
@ -0,0 +1,296 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// WebPPicture class basis
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// WebPPicture
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static int DummyWriter(const uint8_t* data, size_t data_size,
|
||||
const WebPPicture* const picture) {
|
||||
// The following are to prevent 'unused variable' error message.
|
||||
(void)data;
|
||||
(void)data_size;
|
||||
(void)picture;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPPictureInitInternal(WebPPicture* picture, int version) {
|
||||
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
|
||||
return 0; // caller/system version mismatch!
|
||||
}
|
||||
if (picture != NULL) {
|
||||
memset(picture, 0, sizeof(*picture));
|
||||
picture->writer = DummyWriter;
|
||||
WebPEncodingSetError(picture, VP8_ENC_OK);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static void WebPPictureResetBufferARGB(WebPPicture* const picture) {
|
||||
picture->memory_argb_ = NULL;
|
||||
picture->argb = NULL;
|
||||
picture->argb_stride = 0;
|
||||
}
|
||||
|
||||
static void WebPPictureResetBufferYUVA(WebPPicture* const picture) {
|
||||
picture->memory_ = NULL;
|
||||
picture->y = picture->u = picture->v = picture->a = NULL;
|
||||
picture->y_stride = picture->uv_stride = 0;
|
||||
picture->a_stride = 0;
|
||||
}
|
||||
|
||||
void WebPPictureResetBuffers(WebPPicture* const picture) {
|
||||
WebPPictureResetBufferARGB(picture);
|
||||
WebPPictureResetBufferYUVA(picture);
|
||||
}
|
||||
|
||||
int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {
|
||||
void* memory;
|
||||
const uint64_t argb_size = (uint64_t)width * height;
|
||||
|
||||
assert(picture != NULL);
|
||||
|
||||
WebPSafeFree(picture->memory_argb_);
|
||||
WebPPictureResetBufferARGB(picture);
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
|
||||
}
|
||||
// allocate a new buffer.
|
||||
memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb));
|
||||
if (memory == NULL) {
|
||||
return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
picture->memory_argb_ = memory;
|
||||
picture->argb = (uint32_t*)WEBP_ALIGN(memory);
|
||||
picture->argb_stride = width;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
|
||||
const WebPEncCSP uv_csp =
|
||||
(WebPEncCSP)((int)picture->colorspace & WEBP_CSP_UV_MASK);
|
||||
const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT;
|
||||
const int y_stride = width;
|
||||
const int uv_width = (int)(((int64_t)width + 1) >> 1);
|
||||
const int uv_height = (int)(((int64_t)height + 1) >> 1);
|
||||
const int uv_stride = uv_width;
|
||||
int a_width, a_stride;
|
||||
uint64_t y_size, uv_size, a_size, total_size;
|
||||
uint8_t* mem;
|
||||
|
||||
assert(picture != NULL);
|
||||
|
||||
WebPSafeFree(picture->memory_);
|
||||
WebPPictureResetBufferYUVA(picture);
|
||||
|
||||
if (uv_csp != WEBP_YUV420) {
|
||||
return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
|
||||
}
|
||||
|
||||
// alpha
|
||||
a_width = has_alpha ? width : 0;
|
||||
a_stride = a_width;
|
||||
y_size = (uint64_t)y_stride * height;
|
||||
uv_size = (uint64_t)uv_stride * uv_height;
|
||||
a_size = (uint64_t)a_stride * height;
|
||||
|
||||
total_size = y_size + a_size + 2 * uv_size;
|
||||
|
||||
// Security and validation checks
|
||||
if (width <= 0 || height <= 0 || // luma/alpha param error
|
||||
uv_width <= 0 || uv_height <= 0) { // u/v param error
|
||||
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
|
||||
}
|
||||
// allocate a new buffer.
|
||||
mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));
|
||||
if (mem == NULL) {
|
||||
return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
// From now on, we're in the clear, we can no longer fail...
|
||||
picture->memory_ = (void*)mem;
|
||||
picture->y_stride = y_stride;
|
||||
picture->uv_stride = uv_stride;
|
||||
picture->a_stride = a_stride;
|
||||
|
||||
// TODO(skal): we could align the y/u/v planes and adjust stride.
|
||||
picture->y = mem;
|
||||
mem += y_size;
|
||||
|
||||
picture->u = mem;
|
||||
mem += uv_size;
|
||||
picture->v = mem;
|
||||
mem += uv_size;
|
||||
|
||||
if (a_size > 0) {
|
||||
picture->a = mem;
|
||||
mem += a_size;
|
||||
}
|
||||
(void)mem; // makes the static analyzer happy
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPPictureAlloc(WebPPicture* picture) {
|
||||
if (picture != NULL) {
|
||||
const int width = picture->width;
|
||||
const int height = picture->height;
|
||||
|
||||
WebPPictureFree(picture); // erase previous buffer
|
||||
|
||||
if (!picture->use_argb) {
|
||||
return WebPPictureAllocYUVA(picture, width, height);
|
||||
} else {
|
||||
return WebPPictureAllocARGB(picture, width, height);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void WebPPictureFree(WebPPicture* picture) {
|
||||
if (picture != NULL) {
|
||||
WebPSafeFree(picture->memory_);
|
||||
WebPSafeFree(picture->memory_argb_);
|
||||
WebPPictureResetBuffers(picture);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// WebPMemoryWriter: Write-to-memory
|
||||
|
||||
void WebPMemoryWriterInit(WebPMemoryWriter* writer) {
|
||||
writer->mem = NULL;
|
||||
writer->size = 0;
|
||||
writer->max_size = 0;
|
||||
}
|
||||
|
||||
int WebPMemoryWrite(const uint8_t* data, size_t data_size,
|
||||
const WebPPicture* picture) {
|
||||
WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr;
|
||||
uint64_t next_size;
|
||||
if (w == NULL) {
|
||||
return 1;
|
||||
}
|
||||
next_size = (uint64_t)w->size + data_size;
|
||||
if (next_size > w->max_size) {
|
||||
uint8_t* new_mem;
|
||||
uint64_t next_max_size = 2ULL * w->max_size;
|
||||
if (next_max_size < next_size) next_max_size = next_size;
|
||||
if (next_max_size < 8192ULL) next_max_size = 8192ULL;
|
||||
new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1);
|
||||
if (new_mem == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (w->size > 0) {
|
||||
memcpy(new_mem, w->mem, w->size);
|
||||
}
|
||||
WebPSafeFree(w->mem);
|
||||
w->mem = new_mem;
|
||||
// down-cast is ok, thanks to WebPSafeMalloc
|
||||
w->max_size = (size_t)next_max_size;
|
||||
}
|
||||
if (data_size > 0) {
|
||||
memcpy(w->mem + w->size, data, data_size);
|
||||
w->size += data_size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void WebPMemoryWriterClear(WebPMemoryWriter* writer) {
|
||||
if (writer != NULL) {
|
||||
WebPSafeFree(writer->mem);
|
||||
writer->mem = NULL;
|
||||
writer->size = 0;
|
||||
writer->max_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Simplest high-level calls:
|
||||
|
||||
typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);
|
||||
|
||||
static size_t Encode(const uint8_t* rgba, int width, int height, int stride,
|
||||
Importer import, float quality_factor, int lossless,
|
||||
uint8_t** output) {
|
||||
WebPPicture pic;
|
||||
WebPConfig config;
|
||||
WebPMemoryWriter wrt;
|
||||
int ok;
|
||||
|
||||
if (output == NULL) return 0;
|
||||
|
||||
if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) ||
|
||||
!WebPPictureInit(&pic)) {
|
||||
return 0; // shouldn't happen, except if system installation is broken
|
||||
}
|
||||
|
||||
config.lossless = !!lossless;
|
||||
pic.use_argb = !!lossless;
|
||||
pic.width = width;
|
||||
pic.height = height;
|
||||
pic.writer = WebPMemoryWrite;
|
||||
pic.custom_ptr = &wrt;
|
||||
WebPMemoryWriterInit(&wrt);
|
||||
|
||||
ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
|
||||
WebPPictureFree(&pic);
|
||||
if (!ok) {
|
||||
WebPMemoryWriterClear(&wrt);
|
||||
*output = NULL;
|
||||
return 0;
|
||||
}
|
||||
*output = wrt.mem;
|
||||
return wrt.size;
|
||||
}
|
||||
|
||||
#define ENCODE_FUNC(NAME, IMPORTER) \
|
||||
size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \
|
||||
uint8_t** out) { \
|
||||
return Encode(in, w, h, bps, IMPORTER, q, 0, out); \
|
||||
}
|
||||
|
||||
ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB)
|
||||
ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA)
|
||||
#if !defined(WEBP_REDUCE_CSP)
|
||||
ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR)
|
||||
ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA)
|
||||
#endif // WEBP_REDUCE_CSP
|
||||
|
||||
#undef ENCODE_FUNC
|
||||
|
||||
#define LOSSLESS_DEFAULT_QUALITY 70.
|
||||
#define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \
|
||||
size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \
|
||||
return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \
|
||||
}
|
||||
|
||||
LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB)
|
||||
LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA)
|
||||
#if !defined(WEBP_REDUCE_CSP)
|
||||
LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR)
|
||||
LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)
|
||||
#endif // WEBP_REDUCE_CSP
|
||||
|
||||
#undef LOSSLESS_ENCODE_FUNC
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
258
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_psnr_enc.c
vendored
Normal file
258
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_psnr_enc.c
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// WebPPicture tools for measuring distortion
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include "src/webp/encode.h"
|
||||
|
||||
#if !(defined(WEBP_DISABLE_STATS) || defined(WEBP_REDUCE_SIZE))
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
typedef double (*AccumulateFunc)(const uint8_t* src, int src_stride,
|
||||
const uint8_t* ref, int ref_stride,
|
||||
int w, int h);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// local-min distortion
|
||||
//
|
||||
// For every pixel in the *reference* picture, we search for the local best
|
||||
// match in the compressed image. This is not a symmetrical measure.
|
||||
|
||||
#define RADIUS 2 // search radius. Shouldn't be too large.
|
||||
|
||||
static double AccumulateLSIM(const uint8_t* src, int src_stride,
|
||||
const uint8_t* ref, int ref_stride,
|
||||
int w, int h) {
|
||||
int x, y;
|
||||
double total_sse = 0.;
|
||||
for (y = 0; y < h; ++y) {
|
||||
const int y_0 = (y - RADIUS < 0) ? 0 : y - RADIUS;
|
||||
const int y_1 = (y + RADIUS + 1 >= h) ? h : y + RADIUS + 1;
|
||||
for (x = 0; x < w; ++x) {
|
||||
const int x_0 = (x - RADIUS < 0) ? 0 : x - RADIUS;
|
||||
const int x_1 = (x + RADIUS + 1 >= w) ? w : x + RADIUS + 1;
|
||||
double best_sse = 255. * 255.;
|
||||
const double value = (double)ref[y * ref_stride + x];
|
||||
int i, j;
|
||||
for (j = y_0; j < y_1; ++j) {
|
||||
const uint8_t* const s = src + j * src_stride;
|
||||
for (i = x_0; i < x_1; ++i) {
|
||||
const double diff = s[i] - value;
|
||||
const double sse = diff * diff;
|
||||
if (sse < best_sse) best_sse = sse;
|
||||
}
|
||||
}
|
||||
total_sse += best_sse;
|
||||
}
|
||||
}
|
||||
return total_sse;
|
||||
}
|
||||
#undef RADIUS
|
||||
|
||||
static double AccumulateSSE(const uint8_t* src, int src_stride,
|
||||
const uint8_t* ref, int ref_stride,
|
||||
int w, int h) {
|
||||
int y;
|
||||
double total_sse = 0.;
|
||||
for (y = 0; y < h; ++y) {
|
||||
total_sse += VP8AccumulateSSE(src, ref, w);
|
||||
src += src_stride;
|
||||
ref += ref_stride;
|
||||
}
|
||||
return total_sse;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static double AccumulateSSIM(const uint8_t* src, int src_stride,
|
||||
const uint8_t* ref, int ref_stride,
|
||||
int w, int h) {
|
||||
const int w0 = (w < VP8_SSIM_KERNEL) ? w : VP8_SSIM_KERNEL;
|
||||
const int w1 = w - VP8_SSIM_KERNEL - 1;
|
||||
const int h0 = (h < VP8_SSIM_KERNEL) ? h : VP8_SSIM_KERNEL;
|
||||
const int h1 = h - VP8_SSIM_KERNEL - 1;
|
||||
int x, y;
|
||||
double sum = 0.;
|
||||
for (y = 0; y < h0; ++y) {
|
||||
for (x = 0; x < w; ++x) {
|
||||
sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h);
|
||||
}
|
||||
}
|
||||
for (; y < h1; ++y) {
|
||||
for (x = 0; x < w0; ++x) {
|
||||
sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h);
|
||||
}
|
||||
for (; x < w1; ++x) {
|
||||
const int off1 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * src_stride;
|
||||
const int off2 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * ref_stride;
|
||||
sum += VP8SSIMGet(src + off1, src_stride, ref + off2, ref_stride);
|
||||
}
|
||||
for (; x < w; ++x) {
|
||||
sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h);
|
||||
}
|
||||
}
|
||||
for (; y < h; ++y) {
|
||||
for (x = 0; x < w; ++x) {
|
||||
sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Distortion
|
||||
|
||||
// Max value returned in case of exact similarity.
|
||||
static const double kMinDistortion_dB = 99.;
|
||||
|
||||
static double GetPSNR(double v, double size) {
|
||||
return (v > 0. && size > 0.) ? -4.3429448 * log(v / (size * 255 * 255.))
|
||||
: kMinDistortion_dB;
|
||||
}
|
||||
|
||||
static double GetLogSSIM(double v, double size) {
|
||||
v = (size > 0.) ? v / size : 1.;
|
||||
return (v < 1.) ? -10.0 * log10(1. - v) : kMinDistortion_dB;
|
||||
}
|
||||
|
||||
int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
|
||||
const uint8_t* ref, size_t ref_stride,
|
||||
int width, int height, size_t x_step,
|
||||
int type, float* distortion, float* result) {
|
||||
uint8_t* allocated = NULL;
|
||||
const AccumulateFunc metric = (type == 0) ? AccumulateSSE :
|
||||
(type == 1) ? AccumulateSSIM :
|
||||
AccumulateLSIM;
|
||||
if (src == NULL || ref == NULL ||
|
||||
src_stride < x_step * width || ref_stride < x_step * width ||
|
||||
result == NULL || distortion == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
VP8SSIMDspInit();
|
||||
if (x_step != 1) { // extract a packed plane if needed
|
||||
int x, y;
|
||||
uint8_t* tmp1;
|
||||
uint8_t* tmp2;
|
||||
allocated =
|
||||
(uint8_t*)WebPSafeMalloc(2ULL * width * height, sizeof(*allocated));
|
||||
if (allocated == NULL) return 0;
|
||||
tmp1 = allocated;
|
||||
tmp2 = tmp1 + (size_t)width * height;
|
||||
for (y = 0; y < height; ++y) {
|
||||
for (x = 0; x < width; ++x) {
|
||||
tmp1[x + y * width] = src[x * x_step + y * src_stride];
|
||||
tmp2[x + y * width] = ref[x * x_step + y * ref_stride];
|
||||
}
|
||||
}
|
||||
src = tmp1;
|
||||
ref = tmp2;
|
||||
}
|
||||
*distortion = (float)metric(src, width, ref, width, width, height);
|
||||
WebPSafeFree(allocated);
|
||||
|
||||
*result = (type == 1) ? (float)GetLogSSIM(*distortion, (double)width * height)
|
||||
: (float)GetPSNR(*distortion, (double)width * height);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define BLUE_OFFSET 3 // uint32_t 0x000000ff is 0x00,00,00,ff in memory
|
||||
#else
|
||||
#define BLUE_OFFSET 0 // uint32_t 0x000000ff is 0xff,00,00,00 in memory
|
||||
#endif
|
||||
|
||||
int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref,
|
||||
int type, float results[5]) {
|
||||
int w, h, c;
|
||||
int ok = 0;
|
||||
WebPPicture p0, p1;
|
||||
double total_size = 0., total_distortion = 0.;
|
||||
if (src == NULL || ref == NULL ||
|
||||
src->width != ref->width || src->height != ref->height ||
|
||||
results == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
VP8SSIMDspInit();
|
||||
if (!WebPPictureInit(&p0) || !WebPPictureInit(&p1)) return 0;
|
||||
w = src->width;
|
||||
h = src->height;
|
||||
if (!WebPPictureView(src, 0, 0, w, h, &p0)) goto Error;
|
||||
if (!WebPPictureView(ref, 0, 0, w, h, &p1)) goto Error;
|
||||
|
||||
// We always measure distortion in ARGB space.
|
||||
if (p0.use_argb == 0 && !WebPPictureYUVAToARGB(&p0)) goto Error;
|
||||
if (p1.use_argb == 0 && !WebPPictureYUVAToARGB(&p1)) goto Error;
|
||||
for (c = 0; c < 4; ++c) {
|
||||
float distortion;
|
||||
const size_t stride0 = 4 * (size_t)p0.argb_stride;
|
||||
const size_t stride1 = 4 * (size_t)p1.argb_stride;
|
||||
// results are reported as BGRA
|
||||
const int offset = c ^ BLUE_OFFSET;
|
||||
if (!WebPPlaneDistortion((const uint8_t*)p0.argb + offset, stride0,
|
||||
(const uint8_t*)p1.argb + offset, stride1,
|
||||
w, h, 4, type, &distortion, results + c)) {
|
||||
goto Error;
|
||||
}
|
||||
total_distortion += distortion;
|
||||
total_size += w * h;
|
||||
}
|
||||
|
||||
results[4] = (type == 1) ? (float)GetLogSSIM(total_distortion, total_size)
|
||||
: (float)GetPSNR(total_distortion, total_size);
|
||||
ok = 1;
|
||||
|
||||
Error:
|
||||
WebPPictureFree(&p0);
|
||||
WebPPictureFree(&p1);
|
||||
return ok;
|
||||
}
|
||||
|
||||
#undef BLUE_OFFSET
|
||||
|
||||
#else // defined(WEBP_DISABLE_STATS)
|
||||
int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
|
||||
const uint8_t* ref, size_t ref_stride,
|
||||
int width, int height, size_t x_step,
|
||||
int type, float* distortion, float* result) {
|
||||
(void)src;
|
||||
(void)src_stride;
|
||||
(void)ref;
|
||||
(void)ref_stride;
|
||||
(void)width;
|
||||
(void)height;
|
||||
(void)x_step;
|
||||
(void)type;
|
||||
if (distortion == NULL || result == NULL) return 0;
|
||||
*distortion = 0.f;
|
||||
*result = 0.f;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref,
|
||||
int type, float results[5]) {
|
||||
int i;
|
||||
(void)src;
|
||||
(void)ref;
|
||||
(void)type;
|
||||
if (results == NULL) return 0;
|
||||
for (i = 0; i < 5; ++i) results[i] = 0.f;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // !defined(WEBP_DISABLE_STATS)
|
||||
309
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_rescale_enc.c
vendored
Normal file
309
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_rescale_enc.c
vendored
Normal file
@ -0,0 +1,309 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// WebPPicture tools: copy, crop, rescaling and view.
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include "src/webp/encode.h"
|
||||
|
||||
#if !defined(WEBP_REDUCE_SIZE)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/utils/rescaler_utils.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
#define HALVE(x) (((x) + 1) >> 1)
|
||||
|
||||
// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them
|
||||
// into 'dst'. Mark 'dst' as not owning any memory.
|
||||
static void PictureGrabSpecs(const WebPPicture* const src,
|
||||
WebPPicture* const dst) {
|
||||
assert(src != NULL && dst != NULL);
|
||||
*dst = *src;
|
||||
WebPPictureResetBuffers(dst);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Adjust top-left corner to chroma sample position.
|
||||
static void SnapTopLeftPosition(const WebPPicture* const pic,
|
||||
int* const left, int* const top) {
|
||||
if (!pic->use_argb) {
|
||||
*left &= ~1;
|
||||
*top &= ~1;
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust top-left corner and verify that the sub-rectangle is valid.
|
||||
static int AdjustAndCheckRectangle(const WebPPicture* const pic,
|
||||
int* const left, int* const top,
|
||||
int width, int height) {
|
||||
SnapTopLeftPosition(pic, left, top);
|
||||
if ((*left) < 0 || (*top) < 0) return 0;
|
||||
if (width <= 0 || height <= 0) return 0;
|
||||
if ((*left) + width > pic->width) return 0;
|
||||
if ((*top) + height > pic->height) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
|
||||
if (src == NULL || dst == NULL) return 0;
|
||||
if (src == dst) return 1;
|
||||
|
||||
PictureGrabSpecs(src, dst);
|
||||
if (!WebPPictureAlloc(dst)) return 0;
|
||||
|
||||
if (!src->use_argb) {
|
||||
WebPCopyPlane(src->y, src->y_stride,
|
||||
dst->y, dst->y_stride, dst->width, dst->height);
|
||||
WebPCopyPlane(src->u, src->uv_stride, dst->u, dst->uv_stride,
|
||||
HALVE(dst->width), HALVE(dst->height));
|
||||
WebPCopyPlane(src->v, src->uv_stride, dst->v, dst->uv_stride,
|
||||
HALVE(dst->width), HALVE(dst->height));
|
||||
if (dst->a != NULL) {
|
||||
WebPCopyPlane(src->a, src->a_stride,
|
||||
dst->a, dst->a_stride, dst->width, dst->height);
|
||||
}
|
||||
} else {
|
||||
WebPCopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride,
|
||||
(uint8_t*)dst->argb, 4 * dst->argb_stride,
|
||||
4 * dst->width, dst->height);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPPictureIsView(const WebPPicture* picture) {
|
||||
if (picture == NULL) return 0;
|
||||
if (picture->use_argb) {
|
||||
return (picture->memory_argb_ == NULL);
|
||||
}
|
||||
return (picture->memory_ == NULL);
|
||||
}
|
||||
|
||||
int WebPPictureView(const WebPPicture* src,
|
||||
int left, int top, int width, int height,
|
||||
WebPPicture* dst) {
|
||||
if (src == NULL || dst == NULL) return 0;
|
||||
|
||||
// verify rectangle position.
|
||||
if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0;
|
||||
|
||||
if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'.
|
||||
PictureGrabSpecs(src, dst);
|
||||
}
|
||||
dst->width = width;
|
||||
dst->height = height;
|
||||
if (!src->use_argb) {
|
||||
dst->y = src->y + top * src->y_stride + left;
|
||||
dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1);
|
||||
dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1);
|
||||
dst->y_stride = src->y_stride;
|
||||
dst->uv_stride = src->uv_stride;
|
||||
if (src->a != NULL) {
|
||||
dst->a = src->a + top * src->a_stride + left;
|
||||
dst->a_stride = src->a_stride;
|
||||
}
|
||||
} else {
|
||||
dst->argb = src->argb + top * src->argb_stride + left;
|
||||
dst->argb_stride = src->argb_stride;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Picture cropping
|
||||
|
||||
int WebPPictureCrop(WebPPicture* pic,
|
||||
int left, int top, int width, int height) {
|
||||
WebPPicture tmp;
|
||||
|
||||
if (pic == NULL) return 0;
|
||||
if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0;
|
||||
|
||||
PictureGrabSpecs(pic, &tmp);
|
||||
tmp.width = width;
|
||||
tmp.height = height;
|
||||
if (!WebPPictureAlloc(&tmp)) return 0;
|
||||
|
||||
if (!pic->use_argb) {
|
||||
const int y_offset = top * pic->y_stride + left;
|
||||
const int uv_offset = (top / 2) * pic->uv_stride + left / 2;
|
||||
WebPCopyPlane(pic->y + y_offset, pic->y_stride,
|
||||
tmp.y, tmp.y_stride, width, height);
|
||||
WebPCopyPlane(pic->u + uv_offset, pic->uv_stride,
|
||||
tmp.u, tmp.uv_stride, HALVE(width), HALVE(height));
|
||||
WebPCopyPlane(pic->v + uv_offset, pic->uv_stride,
|
||||
tmp.v, tmp.uv_stride, HALVE(width), HALVE(height));
|
||||
|
||||
if (tmp.a != NULL) {
|
||||
const int a_offset = top * pic->a_stride + left;
|
||||
WebPCopyPlane(pic->a + a_offset, pic->a_stride,
|
||||
tmp.a, tmp.a_stride, width, height);
|
||||
}
|
||||
} else {
|
||||
const uint8_t* const src =
|
||||
(const uint8_t*)(pic->argb + top * pic->argb_stride + left);
|
||||
WebPCopyPlane(src, pic->argb_stride * 4, (uint8_t*)tmp.argb,
|
||||
tmp.argb_stride * 4, width * 4, height);
|
||||
}
|
||||
WebPPictureFree(pic);
|
||||
*pic = tmp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Simple picture rescaler
|
||||
|
||||
static void RescalePlane(const uint8_t* src,
|
||||
int src_width, int src_height, int src_stride,
|
||||
uint8_t* dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
rescaler_t* const work,
|
||||
int num_channels) {
|
||||
WebPRescaler rescaler;
|
||||
int y = 0;
|
||||
WebPRescalerInit(&rescaler, src_width, src_height,
|
||||
dst, dst_width, dst_height, dst_stride,
|
||||
num_channels, work);
|
||||
while (y < src_height) {
|
||||
y += WebPRescalerImport(&rescaler, src_height - y,
|
||||
src + y * src_stride, src_stride);
|
||||
WebPRescalerExport(&rescaler);
|
||||
}
|
||||
}
|
||||
|
||||
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
|
||||
assert(pic->argb != NULL);
|
||||
WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb),
|
||||
pic->width, pic->height, inverse);
|
||||
}
|
||||
|
||||
static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
|
||||
if (pic->a != NULL) {
|
||||
WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride,
|
||||
pic->width, pic->height, inverse);
|
||||
}
|
||||
}
|
||||
|
||||
int WebPPictureRescale(WebPPicture* pic, int width, int height) {
|
||||
WebPPicture tmp;
|
||||
int prev_width, prev_height;
|
||||
rescaler_t* work;
|
||||
|
||||
if (pic == NULL) return 0;
|
||||
prev_width = pic->width;
|
||||
prev_height = pic->height;
|
||||
if (!WebPRescalerGetScaledDimensions(
|
||||
prev_width, prev_height, &width, &height)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PictureGrabSpecs(pic, &tmp);
|
||||
tmp.width = width;
|
||||
tmp.height = height;
|
||||
if (!WebPPictureAlloc(&tmp)) return 0;
|
||||
|
||||
if (!pic->use_argb) {
|
||||
work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
|
||||
if (work == NULL) {
|
||||
WebPPictureFree(&tmp);
|
||||
return 0;
|
||||
}
|
||||
// If present, we need to rescale alpha first (for AlphaMultiplyY).
|
||||
if (pic->a != NULL) {
|
||||
WebPInitAlphaProcessing();
|
||||
RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
|
||||
tmp.a, width, height, tmp.a_stride, work, 1);
|
||||
}
|
||||
|
||||
// We take transparency into account on the luma plane only. That's not
|
||||
// totally exact blending, but still is a good approximation.
|
||||
AlphaMultiplyY(pic, 0);
|
||||
RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
|
||||
tmp.y, width, height, tmp.y_stride, work, 1);
|
||||
AlphaMultiplyY(&tmp, 1);
|
||||
|
||||
RescalePlane(pic->u,
|
||||
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
|
||||
tmp.u,
|
||||
HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
|
||||
RescalePlane(pic->v,
|
||||
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
|
||||
tmp.v,
|
||||
HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
|
||||
} else {
|
||||
work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
|
||||
if (work == NULL) {
|
||||
WebPPictureFree(&tmp);
|
||||
return 0;
|
||||
}
|
||||
// In order to correctly interpolate colors, we need to apply the alpha
|
||||
// weighting first (black-matting), scale the RGB values, and remove
|
||||
// the premultiplication afterward (while preserving the alpha channel).
|
||||
WebPInitAlphaProcessing();
|
||||
AlphaMultiplyARGB(pic, 0);
|
||||
RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
|
||||
pic->argb_stride * 4,
|
||||
(uint8_t*)tmp.argb, width, height,
|
||||
tmp.argb_stride * 4,
|
||||
work, 4);
|
||||
AlphaMultiplyARGB(&tmp, 1);
|
||||
}
|
||||
WebPPictureFree(pic);
|
||||
WebPSafeFree(work);
|
||||
*pic = tmp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else // defined(WEBP_REDUCE_SIZE)
|
||||
|
||||
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
|
||||
(void)src;
|
||||
(void)dst;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebPPictureIsView(const WebPPicture* picture) {
|
||||
(void)picture;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebPPictureView(const WebPPicture* src,
|
||||
int left, int top, int width, int height,
|
||||
WebPPicture* dst) {
|
||||
(void)src;
|
||||
(void)left;
|
||||
(void)top;
|
||||
(void)width;
|
||||
(void)height;
|
||||
(void)dst;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebPPictureCrop(WebPPicture* pic,
|
||||
int left, int top, int width, int height) {
|
||||
(void)pic;
|
||||
(void)left;
|
||||
(void)top;
|
||||
(void)width;
|
||||
(void)height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebPPictureRescale(WebPPicture* pic, int width, int height) {
|
||||
(void)pic;
|
||||
(void)width;
|
||||
(void)height;
|
||||
return 0;
|
||||
}
|
||||
#endif // !defined(WEBP_REDUCE_SIZE)
|
||||
278
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_tools_enc.c
vendored
Normal file
278
libsdl2_image/external/libwebp-1.0.2/src/enc/picture_tools_enc.c
vendored
Normal file
@ -0,0 +1,278 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// WebPPicture tools: alpha handling, etc.
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/dsp/yuv.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper: clean up fully transparent area to help compressibility.
|
||||
|
||||
#define SIZE 8
|
||||
#define SIZE2 (SIZE / 2)
|
||||
static int IsTransparentARGBArea(const uint32_t* ptr, int stride, int size) {
|
||||
int y, x;
|
||||
for (y = 0; y < size; ++y) {
|
||||
for (x = 0; x < size; ++x) {
|
||||
if (ptr[x] & 0xff000000u) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ptr += stride;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void Flatten(uint8_t* ptr, int v, int stride, int size) {
|
||||
int y;
|
||||
for (y = 0; y < size; ++y) {
|
||||
memset(ptr, v, size);
|
||||
ptr += stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FlattenARGB(uint32_t* ptr, uint32_t v, int stride, int size) {
|
||||
int x, y;
|
||||
for (y = 0; y < size; ++y) {
|
||||
for (x = 0; x < size; ++x) ptr[x] = v;
|
||||
ptr += stride;
|
||||
}
|
||||
}
|
||||
|
||||
// Smoothen the luma components of transparent pixels. Return true if the whole
|
||||
// block is transparent.
|
||||
static int SmoothenBlock(const uint8_t* a_ptr, int a_stride, uint8_t* y_ptr,
|
||||
int y_stride, int width, int height) {
|
||||
int sum = 0, count = 0;
|
||||
int x, y;
|
||||
const uint8_t* alpha_ptr = a_ptr;
|
||||
uint8_t* luma_ptr = y_ptr;
|
||||
for (y = 0; y < height; ++y) {
|
||||
for (x = 0; x < width; ++x) {
|
||||
if (alpha_ptr[x] != 0) {
|
||||
++count;
|
||||
sum += luma_ptr[x];
|
||||
}
|
||||
}
|
||||
alpha_ptr += a_stride;
|
||||
luma_ptr += y_stride;
|
||||
}
|
||||
if (count > 0 && count < width * height) {
|
||||
const uint8_t avg_u8 = (uint8_t)(sum / count);
|
||||
alpha_ptr = a_ptr;
|
||||
luma_ptr = y_ptr;
|
||||
for (y = 0; y < height; ++y) {
|
||||
for (x = 0; x < width; ++x) {
|
||||
if (alpha_ptr[x] == 0) luma_ptr[x] = avg_u8;
|
||||
}
|
||||
alpha_ptr += a_stride;
|
||||
luma_ptr += y_stride;
|
||||
}
|
||||
}
|
||||
return (count == 0);
|
||||
}
|
||||
|
||||
void WebPCleanupTransparentArea(WebPPicture* pic) {
|
||||
int x, y, w, h;
|
||||
if (pic == NULL) return;
|
||||
w = pic->width / SIZE;
|
||||
h = pic->height / SIZE;
|
||||
|
||||
// note: we ignore the left-overs on right/bottom, except for SmoothenBlock().
|
||||
if (pic->use_argb) {
|
||||
uint32_t argb_value = 0;
|
||||
for (y = 0; y < h; ++y) {
|
||||
int need_reset = 1;
|
||||
for (x = 0; x < w; ++x) {
|
||||
const int off = (y * pic->argb_stride + x) * SIZE;
|
||||
if (IsTransparentARGBArea(pic->argb + off, pic->argb_stride, SIZE)) {
|
||||
if (need_reset) {
|
||||
argb_value = pic->argb[off];
|
||||
need_reset = 0;
|
||||
}
|
||||
FlattenARGB(pic->argb + off, argb_value, pic->argb_stride, SIZE);
|
||||
} else {
|
||||
need_reset = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const int width = pic->width;
|
||||
const int height = pic->height;
|
||||
const int y_stride = pic->y_stride;
|
||||
const int uv_stride = pic->uv_stride;
|
||||
const int a_stride = pic->a_stride;
|
||||
uint8_t* y_ptr = pic->y;
|
||||
uint8_t* u_ptr = pic->u;
|
||||
uint8_t* v_ptr = pic->v;
|
||||
const uint8_t* a_ptr = pic->a;
|
||||
int values[3] = { 0 };
|
||||
if (a_ptr == NULL || y_ptr == NULL || u_ptr == NULL || v_ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
for (y = 0; y + SIZE <= height; y += SIZE) {
|
||||
int need_reset = 1;
|
||||
for (x = 0; x + SIZE <= width; x += SIZE) {
|
||||
if (SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride,
|
||||
SIZE, SIZE)) {
|
||||
if (need_reset) {
|
||||
values[0] = y_ptr[x];
|
||||
values[1] = u_ptr[x >> 1];
|
||||
values[2] = v_ptr[x >> 1];
|
||||
need_reset = 0;
|
||||
}
|
||||
Flatten(y_ptr + x, values[0], y_stride, SIZE);
|
||||
Flatten(u_ptr + (x >> 1), values[1], uv_stride, SIZE2);
|
||||
Flatten(v_ptr + (x >> 1), values[2], uv_stride, SIZE2);
|
||||
} else {
|
||||
need_reset = 1;
|
||||
}
|
||||
}
|
||||
if (x < width) {
|
||||
SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride,
|
||||
width - x, SIZE);
|
||||
}
|
||||
a_ptr += SIZE * a_stride;
|
||||
y_ptr += SIZE * y_stride;
|
||||
u_ptr += SIZE2 * uv_stride;
|
||||
v_ptr += SIZE2 * uv_stride;
|
||||
}
|
||||
if (y < height) {
|
||||
const int sub_height = height - y;
|
||||
for (x = 0; x + SIZE <= width; x += SIZE) {
|
||||
SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride,
|
||||
SIZE, sub_height);
|
||||
}
|
||||
if (x < width) {
|
||||
SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride,
|
||||
width - x, sub_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef SIZE
|
||||
#undef SIZE2
|
||||
|
||||
void WebPCleanupTransparentAreaLossless(WebPPicture* const pic) {
|
||||
int x, y, w, h;
|
||||
uint32_t* argb;
|
||||
assert(pic != NULL && pic->use_argb);
|
||||
w = pic->width;
|
||||
h = pic->height;
|
||||
argb = pic->argb;
|
||||
|
||||
for (y = 0; y < h; ++y) {
|
||||
for (x = 0; x < w; ++x) {
|
||||
if ((argb[x] & 0xff000000) == 0) {
|
||||
argb[x] = 0x00000000;
|
||||
}
|
||||
}
|
||||
argb += pic->argb_stride;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Blend color and remove transparency info
|
||||
|
||||
#define BLEND(V0, V1, ALPHA) \
|
||||
((((V0) * (255 - (ALPHA)) + (V1) * (ALPHA)) * 0x101 + 256) >> 16)
|
||||
#define BLEND_10BIT(V0, V1, ALPHA) \
|
||||
((((V0) * (1020 - (ALPHA)) + (V1) * (ALPHA)) * 0x101 + 1024) >> 18)
|
||||
|
||||
static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) {
|
||||
return (0xff000000u | (r << 16) | (g << 8) | b);
|
||||
}
|
||||
|
||||
void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
|
||||
const int red = (background_rgb >> 16) & 0xff;
|
||||
const int green = (background_rgb >> 8) & 0xff;
|
||||
const int blue = (background_rgb >> 0) & 0xff;
|
||||
int x, y;
|
||||
if (pic == NULL) return;
|
||||
if (!pic->use_argb) {
|
||||
const int uv_width = (pic->width >> 1); // omit last pixel during u/v loop
|
||||
const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF);
|
||||
// VP8RGBToU/V expects the u/v values summed over four pixels
|
||||
const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
|
||||
const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
|
||||
const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT;
|
||||
uint8_t* y_ptr = pic->y;
|
||||
uint8_t* u_ptr = pic->u;
|
||||
uint8_t* v_ptr = pic->v;
|
||||
uint8_t* a_ptr = pic->a;
|
||||
if (!has_alpha || a_ptr == NULL) return; // nothing to do
|
||||
for (y = 0; y < pic->height; ++y) {
|
||||
// Luma blending
|
||||
for (x = 0; x < pic->width; ++x) {
|
||||
const uint8_t alpha = a_ptr[x];
|
||||
if (alpha < 0xff) {
|
||||
y_ptr[x] = BLEND(Y0, y_ptr[x], alpha);
|
||||
}
|
||||
}
|
||||
// Chroma blending every even line
|
||||
if ((y & 1) == 0) {
|
||||
uint8_t* const a_ptr2 =
|
||||
(y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride;
|
||||
for (x = 0; x < uv_width; ++x) {
|
||||
// Average four alpha values into a single blending weight.
|
||||
// TODO(skal): might lead to visible contouring. Can we do better?
|
||||
const uint32_t alpha =
|
||||
a_ptr[2 * x + 0] + a_ptr[2 * x + 1] +
|
||||
a_ptr2[2 * x + 0] + a_ptr2[2 * x + 1];
|
||||
u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
|
||||
v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
|
||||
}
|
||||
if (pic->width & 1) { // rightmost pixel
|
||||
const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
|
||||
u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
|
||||
v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
|
||||
}
|
||||
} else {
|
||||
u_ptr += pic->uv_stride;
|
||||
v_ptr += pic->uv_stride;
|
||||
}
|
||||
memset(a_ptr, 0xff, pic->width); // reset alpha value to opaque
|
||||
a_ptr += pic->a_stride;
|
||||
y_ptr += pic->y_stride;
|
||||
}
|
||||
} else {
|
||||
uint32_t* argb = pic->argb;
|
||||
const uint32_t background = MakeARGB32(red, green, blue);
|
||||
for (y = 0; y < pic->height; ++y) {
|
||||
for (x = 0; x < pic->width; ++x) {
|
||||
const int alpha = (argb[x] >> 24) & 0xff;
|
||||
if (alpha != 0xff) {
|
||||
if (alpha > 0) {
|
||||
int r = (argb[x] >> 16) & 0xff;
|
||||
int g = (argb[x] >> 8) & 0xff;
|
||||
int b = (argb[x] >> 0) & 0xff;
|
||||
r = BLEND(red, r, alpha);
|
||||
g = BLEND(green, g, alpha);
|
||||
b = BLEND(blue, b, alpha);
|
||||
argb[x] = MakeARGB32(r, g, b);
|
||||
} else {
|
||||
argb[x] = background;
|
||||
}
|
||||
}
|
||||
}
|
||||
argb += pic->argb_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef BLEND
|
||||
#undef BLEND_10BIT
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
772
libsdl2_image/external/libwebp-1.0.2/src/enc/predictor_enc.c
vendored
Normal file
772
libsdl2_image/external/libwebp-1.0.2/src/enc/predictor_enc.c
vendored
Normal file
@ -0,0 +1,772 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Image transform methods for lossless encoder.
|
||||
//
|
||||
// Authors: Vikas Arora (vikaas.arora@gmail.com)
|
||||
// Jyrki Alakuijala (jyrki@google.com)
|
||||
// Urvang Joshi (urvang@google.com)
|
||||
// Vincent Rabaud (vrabaud@google.com)
|
||||
|
||||
#include "src/dsp/lossless.h"
|
||||
#include "src/dsp/lossless_common.h"
|
||||
#include "src/enc/vp8li_enc.h"
|
||||
|
||||
#define MAX_DIFF_COST (1e30f)
|
||||
|
||||
static const float kSpatialPredictorBias = 15.f;
|
||||
static const int kPredLowEffort = 11;
|
||||
static const uint32_t kMaskAlpha = 0xff000000;
|
||||
|
||||
// Mostly used to reduce code size + readability
|
||||
static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Methods to calculate Entropy (Shannon).
|
||||
|
||||
static float PredictionCostSpatial(const int counts[256], int weight_0,
|
||||
double exp_val) {
|
||||
const int significant_symbols = 256 >> 4;
|
||||
const double exp_decay_factor = 0.6;
|
||||
double bits = weight_0 * counts[0];
|
||||
int i;
|
||||
for (i = 1; i < significant_symbols; ++i) {
|
||||
bits += exp_val * (counts[i] + counts[256 - i]);
|
||||
exp_val *= exp_decay_factor;
|
||||
}
|
||||
return (float)(-0.1 * bits);
|
||||
}
|
||||
|
||||
static float PredictionCostSpatialHistogram(const int accumulated[4][256],
|
||||
const int tile[4][256]) {
|
||||
int i;
|
||||
double retval = 0;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
const double kExpValue = 0.94;
|
||||
retval += PredictionCostSpatial(tile[i], 1, kExpValue);
|
||||
retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]);
|
||||
}
|
||||
return (float)retval;
|
||||
}
|
||||
|
||||
static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) {
|
||||
++histo_argb[0][argb >> 24];
|
||||
++histo_argb[1][(argb >> 16) & 0xff];
|
||||
++histo_argb[2][(argb >> 8) & 0xff];
|
||||
++histo_argb[3][argb & 0xff];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Spatial transform functions.
|
||||
|
||||
static WEBP_INLINE void PredictBatch(int mode, int x_start, int y,
|
||||
int num_pixels, const uint32_t* current,
|
||||
const uint32_t* upper, uint32_t* out) {
|
||||
if (x_start == 0) {
|
||||
if (y == 0) {
|
||||
// ARGB_BLACK.
|
||||
VP8LPredictorsSub[0](current, NULL, 1, out);
|
||||
} else {
|
||||
// Top one.
|
||||
VP8LPredictorsSub[2](current, upper, 1, out);
|
||||
}
|
||||
++x_start;
|
||||
++out;
|
||||
--num_pixels;
|
||||
}
|
||||
if (y == 0) {
|
||||
// Left one.
|
||||
VP8LPredictorsSub[1](current + x_start, NULL, num_pixels, out);
|
||||
} else {
|
||||
VP8LPredictorsSub[mode](current + x_start, upper + x_start, num_pixels,
|
||||
out);
|
||||
}
|
||||
}
|
||||
|
||||
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||
static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; }
|
||||
|
||||
static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) {
|
||||
const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24));
|
||||
const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff));
|
||||
const int diff_g = abs((int)((p1 >> 8) & 0xff) - (int)((p2 >> 8) & 0xff));
|
||||
const int diff_b = abs((int)(p1 & 0xff) - (int)(p2 & 0xff));
|
||||
return GetMax(GetMax(diff_a, diff_r), GetMax(diff_g, diff_b));
|
||||
}
|
||||
|
||||
static int MaxDiffAroundPixel(uint32_t current, uint32_t up, uint32_t down,
|
||||
uint32_t left, uint32_t right) {
|
||||
const int diff_up = MaxDiffBetweenPixels(current, up);
|
||||
const int diff_down = MaxDiffBetweenPixels(current, down);
|
||||
const int diff_left = MaxDiffBetweenPixels(current, left);
|
||||
const int diff_right = MaxDiffBetweenPixels(current, right);
|
||||
return GetMax(GetMax(diff_up, diff_down), GetMax(diff_left, diff_right));
|
||||
}
|
||||
|
||||
static uint32_t AddGreenToBlueAndRed(uint32_t argb) {
|
||||
const uint32_t green = (argb >> 8) & 0xff;
|
||||
uint32_t red_blue = argb & 0x00ff00ffu;
|
||||
red_blue += (green << 16) | green;
|
||||
red_blue &= 0x00ff00ffu;
|
||||
return (argb & 0xff00ff00u) | red_blue;
|
||||
}
|
||||
|
||||
static void MaxDiffsForRow(int width, int stride, const uint32_t* const argb,
|
||||
uint8_t* const max_diffs, int used_subtract_green) {
|
||||
uint32_t current, up, down, left, right;
|
||||
int x;
|
||||
if (width <= 2) return;
|
||||
current = argb[0];
|
||||
right = argb[1];
|
||||
if (used_subtract_green) {
|
||||
current = AddGreenToBlueAndRed(current);
|
||||
right = AddGreenToBlueAndRed(right);
|
||||
}
|
||||
// max_diffs[0] and max_diffs[width - 1] are never used.
|
||||
for (x = 1; x < width - 1; ++x) {
|
||||
up = argb[-stride + x];
|
||||
down = argb[stride + x];
|
||||
left = current;
|
||||
current = right;
|
||||
right = argb[x + 1];
|
||||
if (used_subtract_green) {
|
||||
up = AddGreenToBlueAndRed(up);
|
||||
down = AddGreenToBlueAndRed(down);
|
||||
right = AddGreenToBlueAndRed(right);
|
||||
}
|
||||
max_diffs[x] = MaxDiffAroundPixel(current, up, down, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
// Quantize the difference between the actual component value and its prediction
|
||||
// to a multiple of quantization, working modulo 256, taking care not to cross
|
||||
// a boundary (inclusive upper limit).
|
||||
static uint8_t NearLosslessComponent(uint8_t value, uint8_t predict,
|
||||
uint8_t boundary, int quantization) {
|
||||
const int residual = (value - predict) & 0xff;
|
||||
const int boundary_residual = (boundary - predict) & 0xff;
|
||||
const int lower = residual & ~(quantization - 1);
|
||||
const int upper = lower + quantization;
|
||||
// Resolve ties towards a value closer to the prediction (i.e. towards lower
|
||||
// if value comes after prediction and towards upper otherwise).
|
||||
const int bias = ((boundary - value) & 0xff) < boundary_residual;
|
||||
if (residual - lower < upper - residual + bias) {
|
||||
// lower is closer to residual than upper.
|
||||
if (residual > boundary_residual && lower <= boundary_residual) {
|
||||
// Halve quantization step to avoid crossing boundary. This midpoint is
|
||||
// on the same side of boundary as residual because midpoint >= residual
|
||||
// (since lower is closer than upper) and residual is above the boundary.
|
||||
return lower + (quantization >> 1);
|
||||
}
|
||||
return lower;
|
||||
} else {
|
||||
// upper is closer to residual than lower.
|
||||
if (residual <= boundary_residual && upper > boundary_residual) {
|
||||
// Halve quantization step to avoid crossing boundary. This midpoint is
|
||||
// on the same side of boundary as residual because midpoint <= residual
|
||||
// (since upper is closer than lower) and residual is below the boundary.
|
||||
return lower + (quantization >> 1);
|
||||
}
|
||||
return upper & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint8_t NearLosslessDiff(uint8_t a, uint8_t b) {
|
||||
return (uint8_t)((((int)(a) - (int)(b))) & 0xff);
|
||||
}
|
||||
|
||||
// Quantize every component of the difference between the actual pixel value and
|
||||
// its prediction to a multiple of a quantization (a power of 2, not larger than
|
||||
// max_quantization which is a power of 2, smaller than max_diff). Take care if
|
||||
// value and predict have undergone subtract green, which means that red and
|
||||
// blue are represented as offsets from green.
|
||||
static uint32_t NearLossless(uint32_t value, uint32_t predict,
|
||||
int max_quantization, int max_diff,
|
||||
int used_subtract_green) {
|
||||
int quantization;
|
||||
uint8_t new_green = 0;
|
||||
uint8_t green_diff = 0;
|
||||
uint8_t a, r, g, b;
|
||||
if (max_diff <= 2) {
|
||||
return VP8LSubPixels(value, predict);
|
||||
}
|
||||
quantization = max_quantization;
|
||||
while (quantization >= max_diff) {
|
||||
quantization >>= 1;
|
||||
}
|
||||
if ((value >> 24) == 0 || (value >> 24) == 0xff) {
|
||||
// Preserve transparency of fully transparent or fully opaque pixels.
|
||||
a = NearLosslessDiff(value >> 24, predict >> 24);
|
||||
} else {
|
||||
a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization);
|
||||
}
|
||||
g = NearLosslessComponent((value >> 8) & 0xff, (predict >> 8) & 0xff, 0xff,
|
||||
quantization);
|
||||
if (used_subtract_green) {
|
||||
// The green offset will be added to red and blue components during decoding
|
||||
// to obtain the actual red and blue values.
|
||||
new_green = ((predict >> 8) + g) & 0xff;
|
||||
// The amount by which green has been adjusted during quantization. It is
|
||||
// subtracted from red and blue for compensation, to avoid accumulating two
|
||||
// quantization errors in them.
|
||||
green_diff = NearLosslessDiff(new_green, value >> 8);
|
||||
}
|
||||
r = NearLosslessComponent(NearLosslessDiff(value >> 16, green_diff),
|
||||
(predict >> 16) & 0xff, 0xff - new_green,
|
||||
quantization);
|
||||
b = NearLosslessComponent(NearLosslessDiff(value, green_diff),
|
||||
predict & 0xff, 0xff - new_green, quantization);
|
||||
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
#endif // (WEBP_NEAR_LOSSLESS == 1)
|
||||
|
||||
// Stores the difference between the pixel and its prediction in "out".
|
||||
// In case of a lossy encoding, updates the source image to avoid propagating
|
||||
// the deviation further to pixels which depend on the current pixel for their
|
||||
// predictions.
|
||||
static WEBP_INLINE void GetResidual(
|
||||
int width, int height, uint32_t* const upper_row,
|
||||
uint32_t* const current_row, const uint8_t* const max_diffs, int mode,
|
||||
int x_start, int x_end, int y, int max_quantization, int exact,
|
||||
int used_subtract_green, uint32_t* const out) {
|
||||
if (exact) {
|
||||
PredictBatch(mode, x_start, y, x_end - x_start, current_row, upper_row,
|
||||
out);
|
||||
} else {
|
||||
const VP8LPredictorFunc pred_func = VP8LPredictors[mode];
|
||||
int x;
|
||||
for (x = x_start; x < x_end; ++x) {
|
||||
uint32_t predict;
|
||||
uint32_t residual;
|
||||
if (y == 0) {
|
||||
predict = (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left.
|
||||
} else if (x == 0) {
|
||||
predict = upper_row[x]; // Top.
|
||||
} else {
|
||||
predict = pred_func(current_row[x - 1], upper_row + x);
|
||||
}
|
||||
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||
if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 ||
|
||||
x == 0 || x == width - 1) {
|
||||
residual = VP8LSubPixels(current_row[x], predict);
|
||||
} else {
|
||||
residual = NearLossless(current_row[x], predict, max_quantization,
|
||||
max_diffs[x], used_subtract_green);
|
||||
// Update the source image.
|
||||
current_row[x] = VP8LAddPixels(predict, residual);
|
||||
// x is never 0 here so we do not need to update upper_row like below.
|
||||
}
|
||||
#else
|
||||
(void)max_diffs;
|
||||
(void)height;
|
||||
(void)max_quantization;
|
||||
(void)used_subtract_green;
|
||||
residual = VP8LSubPixels(current_row[x], predict);
|
||||
#endif
|
||||
if ((current_row[x] & kMaskAlpha) == 0) {
|
||||
// If alpha is 0, cleanup RGB. We can choose the RGB values of the
|
||||
// residual for best compression. The prediction of alpha itself can be
|
||||
// non-zero and must be kept though. We choose RGB of the residual to be
|
||||
// 0.
|
||||
residual &= kMaskAlpha;
|
||||
// Update the source image.
|
||||
current_row[x] = predict & ~kMaskAlpha;
|
||||
// The prediction for the rightmost pixel in a row uses the leftmost
|
||||
// pixel
|
||||
// in that row as its top-right context pixel. Hence if we change the
|
||||
// leftmost pixel of current_row, the corresponding change must be
|
||||
// applied
|
||||
// to upper_row as well where top-right context is being read from.
|
||||
if (x == 0 && y != 0) upper_row[width] = current_row[0];
|
||||
}
|
||||
out[x - x_start] = residual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns best predictor and updates the accumulated histogram.
|
||||
// If max_quantization > 1, assumes that near lossless processing will be
|
||||
// applied, quantizing residuals to multiples of quantization levels up to
|
||||
// max_quantization (the actual quantization level depends on smoothness near
|
||||
// the given pixel).
|
||||
static int GetBestPredictorForTile(int width, int height,
|
||||
int tile_x, int tile_y, int bits,
|
||||
int accumulated[4][256],
|
||||
uint32_t* const argb_scratch,
|
||||
const uint32_t* const argb,
|
||||
int max_quantization,
|
||||
int exact, int used_subtract_green,
|
||||
const uint32_t* const modes) {
|
||||
const int kNumPredModes = 14;
|
||||
const int start_x = tile_x << bits;
|
||||
const int start_y = tile_y << bits;
|
||||
const int tile_size = 1 << bits;
|
||||
const int max_y = GetMin(tile_size, height - start_y);
|
||||
const int max_x = GetMin(tile_size, width - start_x);
|
||||
// Whether there exist columns just outside the tile.
|
||||
const int have_left = (start_x > 0);
|
||||
// Position and size of the strip covering the tile and adjacent columns if
|
||||
// they exist.
|
||||
const int context_start_x = start_x - have_left;
|
||||
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||
const int context_width = max_x + have_left + (max_x < width - start_x);
|
||||
#endif
|
||||
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
||||
// Prediction modes of the left and above neighbor tiles.
|
||||
const int left_mode = (tile_x > 0) ?
|
||||
(modes[tile_y * tiles_per_row + tile_x - 1] >> 8) & 0xff : 0xff;
|
||||
const int above_mode = (tile_y > 0) ?
|
||||
(modes[(tile_y - 1) * tiles_per_row + tile_x] >> 8) & 0xff : 0xff;
|
||||
// The width of upper_row and current_row is one pixel larger than image width
|
||||
// to allow the top right pixel to point to the leftmost pixel of the next row
|
||||
// when at the right edge.
|
||||
uint32_t* upper_row = argb_scratch;
|
||||
uint32_t* current_row = upper_row + width + 1;
|
||||
uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1);
|
||||
float best_diff = MAX_DIFF_COST;
|
||||
int best_mode = 0;
|
||||
int mode;
|
||||
int histo_stack_1[4][256];
|
||||
int histo_stack_2[4][256];
|
||||
// Need pointers to be able to swap arrays.
|
||||
int (*histo_argb)[256] = histo_stack_1;
|
||||
int (*best_histo)[256] = histo_stack_2;
|
||||
int i, j;
|
||||
uint32_t residuals[1 << MAX_TRANSFORM_BITS];
|
||||
assert(bits <= MAX_TRANSFORM_BITS);
|
||||
assert(max_x <= (1 << MAX_TRANSFORM_BITS));
|
||||
|
||||
for (mode = 0; mode < kNumPredModes; ++mode) {
|
||||
float cur_diff;
|
||||
int relative_y;
|
||||
memset(histo_argb, 0, sizeof(histo_stack_1));
|
||||
if (start_y > 0) {
|
||||
// Read the row above the tile which will become the first upper_row.
|
||||
// Include a pixel to the left if it exists; include a pixel to the right
|
||||
// in all cases (wrapping to the leftmost pixel of the next row if it does
|
||||
// not exist).
|
||||
memcpy(current_row + context_start_x,
|
||||
argb + (start_y - 1) * width + context_start_x,
|
||||
sizeof(*argb) * (max_x + have_left + 1));
|
||||
}
|
||||
for (relative_y = 0; relative_y < max_y; ++relative_y) {
|
||||
const int y = start_y + relative_y;
|
||||
int relative_x;
|
||||
uint32_t* tmp = upper_row;
|
||||
upper_row = current_row;
|
||||
current_row = tmp;
|
||||
// Read current_row. Include a pixel to the left if it exists; include a
|
||||
// pixel to the right in all cases except at the bottom right corner of
|
||||
// the image (wrapping to the leftmost pixel of the next row if it does
|
||||
// not exist in the current row).
|
||||
memcpy(current_row + context_start_x,
|
||||
argb + y * width + context_start_x,
|
||||
sizeof(*argb) * (max_x + have_left + (y + 1 < height)));
|
||||
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||
if (max_quantization > 1 && y >= 1 && y + 1 < height) {
|
||||
MaxDiffsForRow(context_width, width, argb + y * width + context_start_x,
|
||||
max_diffs + context_start_x, used_subtract_green);
|
||||
}
|
||||
#endif
|
||||
|
||||
GetResidual(width, height, upper_row, current_row, max_diffs, mode,
|
||||
start_x, start_x + max_x, y, max_quantization, exact,
|
||||
used_subtract_green, residuals);
|
||||
for (relative_x = 0; relative_x < max_x; ++relative_x) {
|
||||
UpdateHisto(histo_argb, residuals[relative_x]);
|
||||
}
|
||||
}
|
||||
cur_diff = PredictionCostSpatialHistogram(
|
||||
(const int (*)[256])accumulated, (const int (*)[256])histo_argb);
|
||||
// Favor keeping the areas locally similar.
|
||||
if (mode == left_mode) cur_diff -= kSpatialPredictorBias;
|
||||
if (mode == above_mode) cur_diff -= kSpatialPredictorBias;
|
||||
|
||||
if (cur_diff < best_diff) {
|
||||
int (*tmp)[256] = histo_argb;
|
||||
histo_argb = best_histo;
|
||||
best_histo = tmp;
|
||||
best_diff = cur_diff;
|
||||
best_mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 256; j++) {
|
||||
accumulated[i][j] += best_histo[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
return best_mode;
|
||||
}
|
||||
|
||||
// Converts pixels of the image to residuals with respect to predictions.
|
||||
// If max_quantization > 1, applies near lossless processing, quantizing
|
||||
// residuals to multiples of quantization levels up to max_quantization
|
||||
// (the actual quantization level depends on smoothness near the given pixel).
|
||||
static void CopyImageWithPrediction(int width, int height,
|
||||
int bits, uint32_t* const modes,
|
||||
uint32_t* const argb_scratch,
|
||||
uint32_t* const argb,
|
||||
int low_effort, int max_quantization,
|
||||
int exact, int used_subtract_green) {
|
||||
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
||||
// The width of upper_row and current_row is one pixel larger than image width
|
||||
// to allow the top right pixel to point to the leftmost pixel of the next row
|
||||
// when at the right edge.
|
||||
uint32_t* upper_row = argb_scratch;
|
||||
uint32_t* current_row = upper_row + width + 1;
|
||||
uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1);
|
||||
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||
uint8_t* lower_max_diffs = current_max_diffs + width;
|
||||
#endif
|
||||
int y;
|
||||
|
||||
for (y = 0; y < height; ++y) {
|
||||
int x;
|
||||
uint32_t* const tmp32 = upper_row;
|
||||
upper_row = current_row;
|
||||
current_row = tmp32;
|
||||
memcpy(current_row, argb + y * width,
|
||||
sizeof(*argb) * (width + (y + 1 < height)));
|
||||
|
||||
if (low_effort) {
|
||||
PredictBatch(kPredLowEffort, 0, y, width, current_row, upper_row,
|
||||
argb + y * width);
|
||||
} else {
|
||||
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||
if (max_quantization > 1) {
|
||||
// Compute max_diffs for the lower row now, because that needs the
|
||||
// contents of argb for the current row, which we will overwrite with
|
||||
// residuals before proceeding with the next row.
|
||||
uint8_t* const tmp8 = current_max_diffs;
|
||||
current_max_diffs = lower_max_diffs;
|
||||
lower_max_diffs = tmp8;
|
||||
if (y + 2 < height) {
|
||||
MaxDiffsForRow(width, width, argb + (y + 1) * width, lower_max_diffs,
|
||||
used_subtract_green);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (x = 0; x < width;) {
|
||||
const int mode =
|
||||
(modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff;
|
||||
int x_end = x + (1 << bits);
|
||||
if (x_end > width) x_end = width;
|
||||
GetResidual(width, height, upper_row, current_row, current_max_diffs,
|
||||
mode, x, x_end, y, max_quantization, exact,
|
||||
used_subtract_green, argb + y * width + x);
|
||||
x = x_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finds the best predictor for each tile, and converts the image to residuals
|
||||
// with respect to predictions. If near_lossless_quality < 100, applies
|
||||
// near lossless processing, shaving off more bits of residuals for lower
|
||||
// qualities.
|
||||
void VP8LResidualImage(int width, int height, int bits, int low_effort,
|
||||
uint32_t* const argb, uint32_t* const argb_scratch,
|
||||
uint32_t* const image, int near_lossless_quality,
|
||||
int exact, int used_subtract_green) {
|
||||
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
||||
const int tiles_per_col = VP8LSubSampleSize(height, bits);
|
||||
int tile_y;
|
||||
int histo[4][256];
|
||||
const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality);
|
||||
if (low_effort) {
|
||||
int i;
|
||||
for (i = 0; i < tiles_per_row * tiles_per_col; ++i) {
|
||||
image[i] = ARGB_BLACK | (kPredLowEffort << 8);
|
||||
}
|
||||
} else {
|
||||
memset(histo, 0, sizeof(histo));
|
||||
for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
|
||||
int tile_x;
|
||||
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
|
||||
const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y,
|
||||
bits, histo, argb_scratch, argb, max_quantization, exact,
|
||||
used_subtract_green, image);
|
||||
image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb,
|
||||
low_effort, max_quantization, exact,
|
||||
used_subtract_green);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Color transform functions.
|
||||
|
||||
static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) {
|
||||
m->green_to_red_ = 0;
|
||||
m->green_to_blue_ = 0;
|
||||
m->red_to_blue_ = 0;
|
||||
}
|
||||
|
||||
static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code,
|
||||
VP8LMultipliers* const m) {
|
||||
m->green_to_red_ = (color_code >> 0) & 0xff;
|
||||
m->green_to_blue_ = (color_code >> 8) & 0xff;
|
||||
m->red_to_blue_ = (color_code >> 16) & 0xff;
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t MultipliersToColorCode(
|
||||
const VP8LMultipliers* const m) {
|
||||
return 0xff000000u |
|
||||
((uint32_t)(m->red_to_blue_) << 16) |
|
||||
((uint32_t)(m->green_to_blue_) << 8) |
|
||||
m->green_to_red_;
|
||||
}
|
||||
|
||||
static float PredictionCostCrossColor(const int accumulated[256],
|
||||
const int counts[256]) {
|
||||
// Favor low entropy, locally and globally.
|
||||
// Favor small absolute values for PredictionCostSpatial
|
||||
static const double kExpValue = 2.4;
|
||||
return VP8LCombinedShannonEntropy(counts, accumulated) +
|
||||
PredictionCostSpatial(counts, 3, kExpValue);
|
||||
}
|
||||
|
||||
static float GetPredictionCostCrossColorRed(
|
||||
const uint32_t* argb, int stride, int tile_width, int tile_height,
|
||||
VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red,
|
||||
const int accumulated_red_histo[256]) {
|
||||
int histo[256] = { 0 };
|
||||
float cur_diff;
|
||||
|
||||
VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height,
|
||||
green_to_red, histo);
|
||||
|
||||
cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo);
|
||||
if ((uint8_t)green_to_red == prev_x.green_to_red_) {
|
||||
cur_diff -= 3; // favor keeping the areas locally similar
|
||||
}
|
||||
if ((uint8_t)green_to_red == prev_y.green_to_red_) {
|
||||
cur_diff -= 3; // favor keeping the areas locally similar
|
||||
}
|
||||
if (green_to_red == 0) {
|
||||
cur_diff -= 3;
|
||||
}
|
||||
return cur_diff;
|
||||
}
|
||||
|
||||
static void GetBestGreenToRed(
|
||||
const uint32_t* argb, int stride, int tile_width, int tile_height,
|
||||
VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality,
|
||||
const int accumulated_red_histo[256], VP8LMultipliers* const best_tx) {
|
||||
const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6]
|
||||
int green_to_red_best = 0;
|
||||
int iter, offset;
|
||||
float best_diff = GetPredictionCostCrossColorRed(
|
||||
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
||||
green_to_red_best, accumulated_red_histo);
|
||||
for (iter = 0; iter < kMaxIters; ++iter) {
|
||||
// ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to
|
||||
// one in color computation. Having initial delta here as 1 is sufficient
|
||||
// to explore the range of (-2, 2).
|
||||
const int delta = 32 >> iter;
|
||||
// Try a negative and a positive delta from the best known value.
|
||||
for (offset = -delta; offset <= delta; offset += 2 * delta) {
|
||||
const int green_to_red_cur = offset + green_to_red_best;
|
||||
const float cur_diff = GetPredictionCostCrossColorRed(
|
||||
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
||||
green_to_red_cur, accumulated_red_histo);
|
||||
if (cur_diff < best_diff) {
|
||||
best_diff = cur_diff;
|
||||
green_to_red_best = green_to_red_cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
best_tx->green_to_red_ = green_to_red_best;
|
||||
}
|
||||
|
||||
static float GetPredictionCostCrossColorBlue(
|
||||
const uint32_t* argb, int stride, int tile_width, int tile_height,
|
||||
VP8LMultipliers prev_x, VP8LMultipliers prev_y,
|
||||
int green_to_blue, int red_to_blue, const int accumulated_blue_histo[256]) {
|
||||
int histo[256] = { 0 };
|
||||
float cur_diff;
|
||||
|
||||
VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height,
|
||||
green_to_blue, red_to_blue, histo);
|
||||
|
||||
cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo);
|
||||
if ((uint8_t)green_to_blue == prev_x.green_to_blue_) {
|
||||
cur_diff -= 3; // favor keeping the areas locally similar
|
||||
}
|
||||
if ((uint8_t)green_to_blue == prev_y.green_to_blue_) {
|
||||
cur_diff -= 3; // favor keeping the areas locally similar
|
||||
}
|
||||
if ((uint8_t)red_to_blue == prev_x.red_to_blue_) {
|
||||
cur_diff -= 3; // favor keeping the areas locally similar
|
||||
}
|
||||
if ((uint8_t)red_to_blue == prev_y.red_to_blue_) {
|
||||
cur_diff -= 3; // favor keeping the areas locally similar
|
||||
}
|
||||
if (green_to_blue == 0) {
|
||||
cur_diff -= 3;
|
||||
}
|
||||
if (red_to_blue == 0) {
|
||||
cur_diff -= 3;
|
||||
}
|
||||
return cur_diff;
|
||||
}
|
||||
|
||||
#define kGreenRedToBlueNumAxis 8
|
||||
#define kGreenRedToBlueMaxIters 7
|
||||
static void GetBestGreenRedToBlue(
|
||||
const uint32_t* argb, int stride, int tile_width, int tile_height,
|
||||
VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality,
|
||||
const int accumulated_blue_histo[256],
|
||||
VP8LMultipliers* const best_tx) {
|
||||
const int8_t offset[kGreenRedToBlueNumAxis][2] =
|
||||
{{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
|
||||
const int8_t delta_lut[kGreenRedToBlueMaxIters] = { 16, 16, 8, 4, 2, 2, 2 };
|
||||
const int iters =
|
||||
(quality < 25) ? 1 : (quality > 50) ? kGreenRedToBlueMaxIters : 4;
|
||||
int green_to_blue_best = 0;
|
||||
int red_to_blue_best = 0;
|
||||
int iter;
|
||||
// Initial value at origin:
|
||||
float best_diff = GetPredictionCostCrossColorBlue(
|
||||
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
||||
green_to_blue_best, red_to_blue_best, accumulated_blue_histo);
|
||||
for (iter = 0; iter < iters; ++iter) {
|
||||
const int delta = delta_lut[iter];
|
||||
int axis;
|
||||
for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) {
|
||||
const int green_to_blue_cur =
|
||||
offset[axis][0] * delta + green_to_blue_best;
|
||||
const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best;
|
||||
const float cur_diff = GetPredictionCostCrossColorBlue(
|
||||
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
||||
green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo);
|
||||
if (cur_diff < best_diff) {
|
||||
best_diff = cur_diff;
|
||||
green_to_blue_best = green_to_blue_cur;
|
||||
red_to_blue_best = red_to_blue_cur;
|
||||
}
|
||||
if (quality < 25 && iter == 4) {
|
||||
// Only axis aligned diffs for lower quality.
|
||||
break; // next iter.
|
||||
}
|
||||
}
|
||||
if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) {
|
||||
// Further iterations would not help.
|
||||
break; // out of iter-loop.
|
||||
}
|
||||
}
|
||||
best_tx->green_to_blue_ = green_to_blue_best;
|
||||
best_tx->red_to_blue_ = red_to_blue_best;
|
||||
}
|
||||
#undef kGreenRedToBlueMaxIters
|
||||
#undef kGreenRedToBlueNumAxis
|
||||
|
||||
static VP8LMultipliers GetBestColorTransformForTile(
|
||||
int tile_x, int tile_y, int bits,
|
||||
VP8LMultipliers prev_x,
|
||||
VP8LMultipliers prev_y,
|
||||
int quality, int xsize, int ysize,
|
||||
const int accumulated_red_histo[256],
|
||||
const int accumulated_blue_histo[256],
|
||||
const uint32_t* const argb) {
|
||||
const int max_tile_size = 1 << bits;
|
||||
const int tile_y_offset = tile_y * max_tile_size;
|
||||
const int tile_x_offset = tile_x * max_tile_size;
|
||||
const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize);
|
||||
const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize);
|
||||
const int tile_width = all_x_max - tile_x_offset;
|
||||
const int tile_height = all_y_max - tile_y_offset;
|
||||
const uint32_t* const tile_argb = argb + tile_y_offset * xsize
|
||||
+ tile_x_offset;
|
||||
VP8LMultipliers best_tx;
|
||||
MultipliersClear(&best_tx);
|
||||
|
||||
GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height,
|
||||
prev_x, prev_y, quality, accumulated_red_histo, &best_tx);
|
||||
GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height,
|
||||
prev_x, prev_y, quality, accumulated_blue_histo,
|
||||
&best_tx);
|
||||
return best_tx;
|
||||
}
|
||||
|
||||
static void CopyTileWithColorTransform(int xsize, int ysize,
|
||||
int tile_x, int tile_y,
|
||||
int max_tile_size,
|
||||
VP8LMultipliers color_transform,
|
||||
uint32_t* argb) {
|
||||
const int xscan = GetMin(max_tile_size, xsize - tile_x);
|
||||
int yscan = GetMin(max_tile_size, ysize - tile_y);
|
||||
argb += tile_y * xsize + tile_x;
|
||||
while (yscan-- > 0) {
|
||||
VP8LTransformColor(&color_transform, argb, xscan);
|
||||
argb += xsize;
|
||||
}
|
||||
}
|
||||
|
||||
void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
|
||||
uint32_t* const argb, uint32_t* image) {
|
||||
const int max_tile_size = 1 << bits;
|
||||
const int tile_xsize = VP8LSubSampleSize(width, bits);
|
||||
const int tile_ysize = VP8LSubSampleSize(height, bits);
|
||||
int accumulated_red_histo[256] = { 0 };
|
||||
int accumulated_blue_histo[256] = { 0 };
|
||||
int tile_x, tile_y;
|
||||
VP8LMultipliers prev_x, prev_y;
|
||||
MultipliersClear(&prev_y);
|
||||
MultipliersClear(&prev_x);
|
||||
for (tile_y = 0; tile_y < tile_ysize; ++tile_y) {
|
||||
for (tile_x = 0; tile_x < tile_xsize; ++tile_x) {
|
||||
int y;
|
||||
const int tile_x_offset = tile_x * max_tile_size;
|
||||
const int tile_y_offset = tile_y * max_tile_size;
|
||||
const int all_x_max = GetMin(tile_x_offset + max_tile_size, width);
|
||||
const int all_y_max = GetMin(tile_y_offset + max_tile_size, height);
|
||||
const int offset = tile_y * tile_xsize + tile_x;
|
||||
if (tile_y != 0) {
|
||||
ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y);
|
||||
}
|
||||
prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits,
|
||||
prev_x, prev_y,
|
||||
quality, width, height,
|
||||
accumulated_red_histo,
|
||||
accumulated_blue_histo,
|
||||
argb);
|
||||
image[offset] = MultipliersToColorCode(&prev_x);
|
||||
CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset,
|
||||
max_tile_size, prev_x, argb);
|
||||
|
||||
// Gather accumulated histogram data.
|
||||
for (y = tile_y_offset; y < all_y_max; ++y) {
|
||||
int ix = y * width + tile_x_offset;
|
||||
const int ix_end = ix + all_x_max - tile_x_offset;
|
||||
for (; ix < ix_end; ++ix) {
|
||||
const uint32_t pix = argb[ix];
|
||||
if (ix >= 2 &&
|
||||
pix == argb[ix - 2] &&
|
||||
pix == argb[ix - 1]) {
|
||||
continue; // repeated pixels are handled by backward references
|
||||
}
|
||||
if (ix >= width + 2 &&
|
||||
argb[ix - 2] == argb[ix - width - 2] &&
|
||||
argb[ix - 1] == argb[ix - width - 1] &&
|
||||
pix == argb[ix - width]) {
|
||||
continue; // repeated pixels are handled by backward references
|
||||
}
|
||||
++accumulated_red_histo[(pix >> 16) & 0xff];
|
||||
++accumulated_blue_histo[(pix >> 0) & 0xff];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1358
libsdl2_image/external/libwebp-1.0.2/src/enc/quant_enc.c
vendored
Normal file
1358
libsdl2_image/external/libwebp-1.0.2/src/enc/quant_enc.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
388
libsdl2_image/external/libwebp-1.0.2/src/enc/syntax_enc.c
vendored
Normal file
388
libsdl2_image/external/libwebp-1.0.2/src/enc/syntax_enc.c
vendored
Normal file
@ -0,0 +1,388 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Header syntax writing
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "src/utils/utils.h"
|
||||
#include "src/webp/format_constants.h" // RIFF constants
|
||||
#include "src/webp/mux_types.h" // ALPHA_FLAG
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper functions
|
||||
|
||||
static int IsVP8XNeeded(const VP8Encoder* const enc) {
|
||||
return !!enc->has_alpha_; // Currently the only case when VP8X is needed.
|
||||
// This could change in the future.
|
||||
}
|
||||
|
||||
static int PutPaddingByte(const WebPPicture* const pic) {
|
||||
const uint8_t pad_byte[1] = { 0 };
|
||||
return !!pic->writer(pad_byte, 1, pic);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Writers for header's various pieces (in order of appearance)
|
||||
|
||||
static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc,
|
||||
size_t riff_size) {
|
||||
const WebPPicture* const pic = enc->pic_;
|
||||
uint8_t riff[RIFF_HEADER_SIZE] = {
|
||||
'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P'
|
||||
};
|
||||
assert(riff_size == (uint32_t)riff_size);
|
||||
PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
|
||||
if (!pic->writer(riff, sizeof(riff), pic)) {
|
||||
return VP8_ENC_ERROR_BAD_WRITE;
|
||||
}
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
|
||||
const WebPPicture* const pic = enc->pic_;
|
||||
uint8_t vp8x[CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE] = {
|
||||
'V', 'P', '8', 'X'
|
||||
};
|
||||
uint32_t flags = 0;
|
||||
|
||||
assert(IsVP8XNeeded(enc));
|
||||
assert(pic->width >= 1 && pic->height >= 1);
|
||||
assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE);
|
||||
|
||||
if (enc->has_alpha_) {
|
||||
flags |= ALPHA_FLAG;
|
||||
}
|
||||
|
||||
PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE);
|
||||
PutLE32(vp8x + CHUNK_HEADER_SIZE, flags);
|
||||
PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1);
|
||||
PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1);
|
||||
if (!pic->writer(vp8x, sizeof(vp8x), pic)) {
|
||||
return VP8_ENC_ERROR_BAD_WRITE;
|
||||
}
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
static WebPEncodingError PutAlphaChunk(const VP8Encoder* const enc) {
|
||||
const WebPPicture* const pic = enc->pic_;
|
||||
uint8_t alpha_chunk_hdr[CHUNK_HEADER_SIZE] = {
|
||||
'A', 'L', 'P', 'H'
|
||||
};
|
||||
|
||||
assert(enc->has_alpha_);
|
||||
|
||||
// Alpha chunk header.
|
||||
PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size_);
|
||||
if (!pic->writer(alpha_chunk_hdr, sizeof(alpha_chunk_hdr), pic)) {
|
||||
return VP8_ENC_ERROR_BAD_WRITE;
|
||||
}
|
||||
|
||||
// Alpha chunk data.
|
||||
if (!pic->writer(enc->alpha_data_, enc->alpha_data_size_, pic)) {
|
||||
return VP8_ENC_ERROR_BAD_WRITE;
|
||||
}
|
||||
|
||||
// Padding.
|
||||
if ((enc->alpha_data_size_ & 1) && !PutPaddingByte(pic)) {
|
||||
return VP8_ENC_ERROR_BAD_WRITE;
|
||||
}
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
static WebPEncodingError PutVP8Header(const WebPPicture* const pic,
|
||||
size_t vp8_size) {
|
||||
uint8_t vp8_chunk_hdr[CHUNK_HEADER_SIZE] = {
|
||||
'V', 'P', '8', ' '
|
||||
};
|
||||
assert(vp8_size == (uint32_t)vp8_size);
|
||||
PutLE32(vp8_chunk_hdr + TAG_SIZE, (uint32_t)vp8_size);
|
||||
if (!pic->writer(vp8_chunk_hdr, sizeof(vp8_chunk_hdr), pic)) {
|
||||
return VP8_ENC_ERROR_BAD_WRITE;
|
||||
}
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
static WebPEncodingError PutVP8FrameHeader(const WebPPicture* const pic,
|
||||
int profile, size_t size0) {
|
||||
uint8_t vp8_frm_hdr[VP8_FRAME_HEADER_SIZE];
|
||||
uint32_t bits;
|
||||
|
||||
if (size0 >= VP8_MAX_PARTITION0_SIZE) { // partition #0 is too big to fit
|
||||
return VP8_ENC_ERROR_PARTITION0_OVERFLOW;
|
||||
}
|
||||
|
||||
// Paragraph 9.1.
|
||||
bits = 0 // keyframe (1b)
|
||||
| (profile << 1) // profile (3b)
|
||||
| (1 << 4) // visible (1b)
|
||||
| ((uint32_t)size0 << 5); // partition length (19b)
|
||||
vp8_frm_hdr[0] = (bits >> 0) & 0xff;
|
||||
vp8_frm_hdr[1] = (bits >> 8) & 0xff;
|
||||
vp8_frm_hdr[2] = (bits >> 16) & 0xff;
|
||||
// signature
|
||||
vp8_frm_hdr[3] = (VP8_SIGNATURE >> 16) & 0xff;
|
||||
vp8_frm_hdr[4] = (VP8_SIGNATURE >> 8) & 0xff;
|
||||
vp8_frm_hdr[5] = (VP8_SIGNATURE >> 0) & 0xff;
|
||||
// dimensions
|
||||
vp8_frm_hdr[6] = pic->width & 0xff;
|
||||
vp8_frm_hdr[7] = pic->width >> 8;
|
||||
vp8_frm_hdr[8] = pic->height & 0xff;
|
||||
vp8_frm_hdr[9] = pic->height >> 8;
|
||||
|
||||
if (!pic->writer(vp8_frm_hdr, sizeof(vp8_frm_hdr), pic)) {
|
||||
return VP8_ENC_ERROR_BAD_WRITE;
|
||||
}
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
// WebP Headers.
|
||||
static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0,
|
||||
size_t vp8_size, size_t riff_size) {
|
||||
WebPPicture* const pic = enc->pic_;
|
||||
WebPEncodingError err = VP8_ENC_OK;
|
||||
|
||||
// RIFF header.
|
||||
err = PutRIFFHeader(enc, riff_size);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
|
||||
// VP8X.
|
||||
if (IsVP8XNeeded(enc)) {
|
||||
err = PutVP8XHeader(enc);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
}
|
||||
|
||||
// Alpha.
|
||||
if (enc->has_alpha_) {
|
||||
err = PutAlphaChunk(enc);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
}
|
||||
|
||||
// VP8 header.
|
||||
err = PutVP8Header(pic, vp8_size);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
|
||||
// VP8 frame header.
|
||||
err = PutVP8FrameHeader(pic, enc->profile_, size0);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
|
||||
// All OK.
|
||||
return 1;
|
||||
|
||||
// Error.
|
||||
Error:
|
||||
return WebPEncodingSetError(pic, err);
|
||||
}
|
||||
|
||||
// Segmentation header
|
||||
static void PutSegmentHeader(VP8BitWriter* const bw,
|
||||
const VP8Encoder* const enc) {
|
||||
const VP8EncSegmentHeader* const hdr = &enc->segment_hdr_;
|
||||
const VP8EncProba* const proba = &enc->proba_;
|
||||
if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) {
|
||||
// We always 'update' the quant and filter strength values
|
||||
const int update_data = 1;
|
||||
int s;
|
||||
VP8PutBitUniform(bw, hdr->update_map_);
|
||||
if (VP8PutBitUniform(bw, update_data)) {
|
||||
// we always use absolute values, not relative ones
|
||||
VP8PutBitUniform(bw, 1); // (segment_feature_mode = 1. Paragraph 9.3.)
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||
VP8PutSignedBits(bw, enc->dqm_[s].quant_, 7);
|
||||
}
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||
VP8PutSignedBits(bw, enc->dqm_[s].fstrength_, 6);
|
||||
}
|
||||
}
|
||||
if (hdr->update_map_) {
|
||||
for (s = 0; s < 3; ++s) {
|
||||
if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) {
|
||||
VP8PutBits(bw, proba->segments_[s], 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filtering parameters header
|
||||
static void PutFilterHeader(VP8BitWriter* const bw,
|
||||
const VP8EncFilterHeader* const hdr) {
|
||||
const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0);
|
||||
VP8PutBitUniform(bw, hdr->simple_);
|
||||
VP8PutBits(bw, hdr->level_, 6);
|
||||
VP8PutBits(bw, hdr->sharpness_, 3);
|
||||
if (VP8PutBitUniform(bw, use_lf_delta)) {
|
||||
// '0' is the default value for i4x4_lf_delta_ at frame #0.
|
||||
const int need_update = (hdr->i4x4_lf_delta_ != 0);
|
||||
if (VP8PutBitUniform(bw, need_update)) {
|
||||
// we don't use ref_lf_delta => emit four 0 bits
|
||||
VP8PutBits(bw, 0, 4);
|
||||
// we use mode_lf_delta for i4x4
|
||||
VP8PutSignedBits(bw, hdr->i4x4_lf_delta_, 6);
|
||||
VP8PutBits(bw, 0, 3); // all others unused
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nominal quantization parameters
|
||||
static void PutQuant(VP8BitWriter* const bw,
|
||||
const VP8Encoder* const enc) {
|
||||
VP8PutBits(bw, enc->base_quant_, 7);
|
||||
VP8PutSignedBits(bw, enc->dq_y1_dc_, 4);
|
||||
VP8PutSignedBits(bw, enc->dq_y2_dc_, 4);
|
||||
VP8PutSignedBits(bw, enc->dq_y2_ac_, 4);
|
||||
VP8PutSignedBits(bw, enc->dq_uv_dc_, 4);
|
||||
VP8PutSignedBits(bw, enc->dq_uv_ac_, 4);
|
||||
}
|
||||
|
||||
// Partition sizes
|
||||
static int EmitPartitionsSize(const VP8Encoder* const enc,
|
||||
WebPPicture* const pic) {
|
||||
uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)];
|
||||
int p;
|
||||
for (p = 0; p < enc->num_parts_ - 1; ++p) {
|
||||
const size_t part_size = VP8BitWriterSize(enc->parts_ + p);
|
||||
if (part_size >= VP8_MAX_PARTITION_SIZE) {
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW);
|
||||
}
|
||||
buf[3 * p + 0] = (part_size >> 0) & 0xff;
|
||||
buf[3 * p + 1] = (part_size >> 8) & 0xff;
|
||||
buf[3 * p + 2] = (part_size >> 16) & 0xff;
|
||||
}
|
||||
return p ? pic->writer(buf, 3 * p, pic) : 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static int GeneratePartition0(VP8Encoder* const enc) {
|
||||
VP8BitWriter* const bw = &enc->bw_;
|
||||
const int mb_size = enc->mb_w_ * enc->mb_h_;
|
||||
uint64_t pos1, pos2, pos3;
|
||||
|
||||
pos1 = VP8BitWriterPos(bw);
|
||||
if (!VP8BitWriterInit(bw, mb_size * 7 / 8)) { // ~7 bits per macroblock
|
||||
return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
VP8PutBitUniform(bw, 0); // colorspace
|
||||
VP8PutBitUniform(bw, 0); // clamp type
|
||||
|
||||
PutSegmentHeader(bw, enc);
|
||||
PutFilterHeader(bw, &enc->filter_hdr_);
|
||||
VP8PutBits(bw, enc->num_parts_ == 8 ? 3 :
|
||||
enc->num_parts_ == 4 ? 2 :
|
||||
enc->num_parts_ == 2 ? 1 : 0, 2);
|
||||
PutQuant(bw, enc);
|
||||
VP8PutBitUniform(bw, 0); // no proba update
|
||||
VP8WriteProbas(bw, &enc->proba_);
|
||||
pos2 = VP8BitWriterPos(bw);
|
||||
VP8CodeIntraModes(enc);
|
||||
VP8BitWriterFinish(bw);
|
||||
|
||||
pos3 = VP8BitWriterPos(bw);
|
||||
|
||||
#if !defined(WEBP_DISABLE_STATS)
|
||||
if (enc->pic_->stats) {
|
||||
enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3);
|
||||
enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3);
|
||||
enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_;
|
||||
}
|
||||
#else
|
||||
(void)pos1;
|
||||
(void)pos2;
|
||||
(void)pos3;
|
||||
#endif
|
||||
if (bw->error_) {
|
||||
return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VP8EncFreeBitWriters(VP8Encoder* const enc) {
|
||||
int p;
|
||||
VP8BitWriterWipeOut(&enc->bw_);
|
||||
for (p = 0; p < enc->num_parts_; ++p) {
|
||||
VP8BitWriterWipeOut(enc->parts_ + p);
|
||||
}
|
||||
}
|
||||
|
||||
int VP8EncWrite(VP8Encoder* const enc) {
|
||||
WebPPicture* const pic = enc->pic_;
|
||||
VP8BitWriter* const bw = &enc->bw_;
|
||||
const int task_percent = 19;
|
||||
const int percent_per_part = task_percent / enc->num_parts_;
|
||||
const int final_percent = enc->percent_ + task_percent;
|
||||
int ok = 0;
|
||||
size_t vp8_size, pad, riff_size;
|
||||
int p;
|
||||
|
||||
// Partition #0 with header and partition sizes
|
||||
ok = GeneratePartition0(enc);
|
||||
if (!ok) return 0;
|
||||
|
||||
// Compute VP8 size
|
||||
vp8_size = VP8_FRAME_HEADER_SIZE +
|
||||
VP8BitWriterSize(bw) +
|
||||
3 * (enc->num_parts_ - 1);
|
||||
for (p = 0; p < enc->num_parts_; ++p) {
|
||||
vp8_size += VP8BitWriterSize(enc->parts_ + p);
|
||||
}
|
||||
pad = vp8_size & 1;
|
||||
vp8_size += pad;
|
||||
|
||||
// Compute RIFF size
|
||||
// At the minimum it is: "WEBPVP8 nnnn" + VP8 data size.
|
||||
riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8_size;
|
||||
if (IsVP8XNeeded(enc)) { // Add size for: VP8X header + data.
|
||||
riff_size += CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
|
||||
}
|
||||
if (enc->has_alpha_) { // Add size for: ALPH header + data.
|
||||
const uint32_t padded_alpha_size = enc->alpha_data_size_ +
|
||||
(enc->alpha_data_size_ & 1);
|
||||
riff_size += CHUNK_HEADER_SIZE + padded_alpha_size;
|
||||
}
|
||||
// Sanity check.
|
||||
if (riff_size > 0xfffffffeU) {
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG);
|
||||
}
|
||||
|
||||
// Emit headers and partition #0
|
||||
{
|
||||
const uint8_t* const part0 = VP8BitWriterBuf(bw);
|
||||
const size_t size0 = VP8BitWriterSize(bw);
|
||||
ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size)
|
||||
&& pic->writer(part0, size0, pic)
|
||||
&& EmitPartitionsSize(enc, pic);
|
||||
VP8BitWriterWipeOut(bw); // will free the internal buffer.
|
||||
}
|
||||
|
||||
// Token partitions
|
||||
for (p = 0; p < enc->num_parts_; ++p) {
|
||||
const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p);
|
||||
const size_t size = VP8BitWriterSize(enc->parts_ + p);
|
||||
if (size) ok = ok && pic->writer(buf, size, pic);
|
||||
VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer.
|
||||
ok = ok && WebPReportProgress(pic, enc->percent_ + percent_per_part,
|
||||
&enc->percent_);
|
||||
}
|
||||
|
||||
// Padding byte
|
||||
if (ok && pad) {
|
||||
ok = PutPaddingByte(pic);
|
||||
}
|
||||
|
||||
enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size);
|
||||
ok = ok && WebPReportProgress(pic, final_percent, &enc->percent_);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
262
libsdl2_image/external/libwebp-1.0.2/src/enc/token_enc.c
vendored
Normal file
262
libsdl2_image/external/libwebp-1.0.2/src/enc/token_enc.c
vendored
Normal file
@ -0,0 +1,262 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Paginated token buffer
|
||||
//
|
||||
// A 'token' is a bit value associated with a probability, either fixed
|
||||
// or a later-to-be-determined after statistics have been collected.
|
||||
// For dynamic probability, we just record the slot id (idx) for the probability
|
||||
// value in the final probability array (uint8_t* probas in VP8EmitTokens).
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "src/enc/cost_enc.h"
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
#if !defined(DISABLE_TOKEN_BUFFER)
|
||||
|
||||
// we use pages to reduce the number of memcpy()
|
||||
#define MIN_PAGE_SIZE 8192 // minimum number of token per page
|
||||
#define FIXED_PROBA_BIT (1u << 14)
|
||||
|
||||
typedef uint16_t token_t; // bit #15: bit value
|
||||
// bit #14: flags for constant proba or idx
|
||||
// bits #0..13: slot or constant proba
|
||||
struct VP8Tokens {
|
||||
VP8Tokens* next_; // pointer to next page
|
||||
};
|
||||
// Token data is located in memory just after the next_ field.
|
||||
// This macro is used to return their address and hide the trick.
|
||||
#define TOKEN_DATA(p) ((const token_t*)&(p)[1])
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void VP8TBufferInit(VP8TBuffer* const b, int page_size) {
|
||||
b->tokens_ = NULL;
|
||||
b->pages_ = NULL;
|
||||
b->last_page_ = &b->pages_;
|
||||
b->left_ = 0;
|
||||
b->page_size_ = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size;
|
||||
b->error_ = 0;
|
||||
}
|
||||
|
||||
void VP8TBufferClear(VP8TBuffer* const b) {
|
||||
if (b != NULL) {
|
||||
VP8Tokens* p = b->pages_;
|
||||
while (p != NULL) {
|
||||
VP8Tokens* const next = p->next_;
|
||||
WebPSafeFree(p);
|
||||
p = next;
|
||||
}
|
||||
VP8TBufferInit(b, b->page_size_);
|
||||
}
|
||||
}
|
||||
|
||||
static int TBufferNewPage(VP8TBuffer* const b) {
|
||||
VP8Tokens* page = NULL;
|
||||
if (!b->error_) {
|
||||
const size_t size = sizeof(*page) + b->page_size_ * sizeof(token_t);
|
||||
page = (VP8Tokens*)WebPSafeMalloc(1ULL, size);
|
||||
}
|
||||
if (page == NULL) {
|
||||
b->error_ = 1;
|
||||
return 0;
|
||||
}
|
||||
page->next_ = NULL;
|
||||
|
||||
*b->last_page_ = page;
|
||||
b->last_page_ = &page->next_;
|
||||
b->left_ = b->page_size_;
|
||||
b->tokens_ = (token_t*)TOKEN_DATA(page);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define TOKEN_ID(t, b, ctx) \
|
||||
(NUM_PROBAS * ((ctx) + NUM_CTX * ((b) + NUM_BANDS * (t))))
|
||||
|
||||
static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, uint32_t bit,
|
||||
uint32_t proba_idx,
|
||||
proba_t* const stats) {
|
||||
assert(proba_idx < FIXED_PROBA_BIT);
|
||||
assert(bit <= 1);
|
||||
if (b->left_ > 0 || TBufferNewPage(b)) {
|
||||
const int slot = --b->left_;
|
||||
b->tokens_[slot] = (bit << 15) | proba_idx;
|
||||
}
|
||||
VP8RecordStats(bit, stats);
|
||||
return bit;
|
||||
}
|
||||
|
||||
static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b,
|
||||
uint32_t bit, uint32_t proba) {
|
||||
assert(proba < 256);
|
||||
assert(bit <= 1);
|
||||
if (b->left_ > 0 || TBufferNewPage(b)) {
|
||||
const int slot = --b->left_;
|
||||
b->tokens_[slot] = (bit << 15) | FIXED_PROBA_BIT | proba;
|
||||
}
|
||||
}
|
||||
|
||||
int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res,
|
||||
VP8TBuffer* const tokens) {
|
||||
const int16_t* const coeffs = res->coeffs;
|
||||
const int coeff_type = res->coeff_type;
|
||||
const int last = res->last;
|
||||
int n = res->first;
|
||||
uint32_t base_id = TOKEN_ID(coeff_type, n, ctx);
|
||||
// should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1
|
||||
proba_t* s = res->stats[n][ctx];
|
||||
if (!AddToken(tokens, last >= 0, base_id + 0, s + 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (n < 16) {
|
||||
const int c = coeffs[n++];
|
||||
const int sign = c < 0;
|
||||
const uint32_t v = sign ? -c : c;
|
||||
if (!AddToken(tokens, v != 0, base_id + 1, s + 1)) {
|
||||
base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 0); // ctx=0
|
||||
s = res->stats[VP8EncBands[n]][0];
|
||||
continue;
|
||||
}
|
||||
if (!AddToken(tokens, v > 1, base_id + 2, s + 2)) {
|
||||
base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 1); // ctx=1
|
||||
s = res->stats[VP8EncBands[n]][1];
|
||||
} else {
|
||||
if (!AddToken(tokens, v > 4, base_id + 3, s + 3)) {
|
||||
if (AddToken(tokens, v != 2, base_id + 4, s + 4)) {
|
||||
AddToken(tokens, v == 4, base_id + 5, s + 5);
|
||||
}
|
||||
} else if (!AddToken(tokens, v > 10, base_id + 6, s + 6)) {
|
||||
if (!AddToken(tokens, v > 6, base_id + 7, s + 7)) {
|
||||
AddConstantToken(tokens, v == 6, 159);
|
||||
} else {
|
||||
AddConstantToken(tokens, v >= 9, 165);
|
||||
AddConstantToken(tokens, !(v & 1), 145);
|
||||
}
|
||||
} else {
|
||||
int mask;
|
||||
const uint8_t* tab;
|
||||
uint32_t residue = v - 3;
|
||||
if (residue < (8 << 1)) { // VP8Cat3 (3b)
|
||||
AddToken(tokens, 0, base_id + 8, s + 8);
|
||||
AddToken(tokens, 0, base_id + 9, s + 9);
|
||||
residue -= (8 << 0);
|
||||
mask = 1 << 2;
|
||||
tab = VP8Cat3;
|
||||
} else if (residue < (8 << 2)) { // VP8Cat4 (4b)
|
||||
AddToken(tokens, 0, base_id + 8, s + 8);
|
||||
AddToken(tokens, 1, base_id + 9, s + 9);
|
||||
residue -= (8 << 1);
|
||||
mask = 1 << 3;
|
||||
tab = VP8Cat4;
|
||||
} else if (residue < (8 << 3)) { // VP8Cat5 (5b)
|
||||
AddToken(tokens, 1, base_id + 8, s + 8);
|
||||
AddToken(tokens, 0, base_id + 10, s + 9);
|
||||
residue -= (8 << 2);
|
||||
mask = 1 << 4;
|
||||
tab = VP8Cat5;
|
||||
} else { // VP8Cat6 (11b)
|
||||
AddToken(tokens, 1, base_id + 8, s + 8);
|
||||
AddToken(tokens, 1, base_id + 10, s + 9);
|
||||
residue -= (8 << 3);
|
||||
mask = 1 << 10;
|
||||
tab = VP8Cat6;
|
||||
}
|
||||
while (mask) {
|
||||
AddConstantToken(tokens, !!(residue & mask), *tab++);
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 2); // ctx=2
|
||||
s = res->stats[VP8EncBands[n]][2];
|
||||
}
|
||||
AddConstantToken(tokens, sign, 128);
|
||||
if (n == 16 || !AddToken(tokens, n <= last, base_id + 0, s + 0)) {
|
||||
return 1; // EOB
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef TOKEN_ID
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Final coding pass, with known probabilities
|
||||
|
||||
int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
|
||||
const uint8_t* const probas, int final_pass) {
|
||||
const VP8Tokens* p = b->pages_;
|
||||
assert(!b->error_);
|
||||
while (p != NULL) {
|
||||
const VP8Tokens* const next = p->next_;
|
||||
const int N = (next == NULL) ? b->left_ : 0;
|
||||
int n = b->page_size_;
|
||||
const token_t* const tokens = TOKEN_DATA(p);
|
||||
while (n-- > N) {
|
||||
const token_t token = tokens[n];
|
||||
const int bit = (token >> 15) & 1;
|
||||
if (token & FIXED_PROBA_BIT) {
|
||||
VP8PutBit(bw, bit, token & 0xffu); // constant proba
|
||||
} else {
|
||||
VP8PutBit(bw, bit, probas[token & 0x3fffu]);
|
||||
}
|
||||
}
|
||||
if (final_pass) WebPSafeFree((void*)p);
|
||||
p = next;
|
||||
}
|
||||
if (final_pass) b->pages_ = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Size estimation
|
||||
size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) {
|
||||
size_t size = 0;
|
||||
const VP8Tokens* p = b->pages_;
|
||||
assert(!b->error_);
|
||||
while (p != NULL) {
|
||||
const VP8Tokens* const next = p->next_;
|
||||
const int N = (next == NULL) ? b->left_ : 0;
|
||||
int n = b->page_size_;
|
||||
const token_t* const tokens = TOKEN_DATA(p);
|
||||
while (n-- > N) {
|
||||
const token_t token = tokens[n];
|
||||
const int bit = token & (1 << 15);
|
||||
if (token & FIXED_PROBA_BIT) {
|
||||
size += VP8BitCost(bit, token & 0xffu);
|
||||
} else {
|
||||
size += VP8BitCost(bit, probas[token & 0x3fffu]);
|
||||
}
|
||||
}
|
||||
p = next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#else // DISABLE_TOKEN_BUFFER
|
||||
|
||||
void VP8TBufferInit(VP8TBuffer* const b, int page_size) {
|
||||
(void)b;
|
||||
(void)page_size;
|
||||
}
|
||||
void VP8TBufferClear(VP8TBuffer* const b) {
|
||||
(void)b;
|
||||
}
|
||||
|
||||
#endif // !DISABLE_TOKEN_BUFFER
|
||||
|
||||
504
libsdl2_image/external/libwebp-1.0.2/src/enc/tree_enc.c
vendored
Normal file
504
libsdl2_image/external/libwebp-1.0.2/src/enc/tree_enc.c
vendored
Normal file
@ -0,0 +1,504 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Coding of token probabilities, intra modes and segments.
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Default probabilities
|
||||
|
||||
// Paragraph 13.5
|
||||
const uint8_t
|
||||
VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
|
||||
{ { { 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 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void VP8DefaultProbas(VP8Encoder* const enc) {
|
||||
VP8EncProba* const probas = &enc->proba_;
|
||||
probas->use_skip_proba_ = 0;
|
||||
memset(probas->segments_, 255u, sizeof(probas->segments_));
|
||||
memcpy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0));
|
||||
// Note: we could hard-code the level_costs_ corresponding to VP8CoeffsProba0,
|
||||
// but that's ~11k of static data. Better call VP8CalculateLevelCosts() later.
|
||||
probas->dirty_ = 1;
|
||||
}
|
||||
|
||||
// Paragraph 11.5. 900bytes.
|
||||
static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
|
||||
{ { 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 },
|
||||
{ 114, 26, 17, 163, 44, 195, 21, 10, 173 },
|
||||
{ 121, 24, 80, 195, 26, 62, 44, 64, 85 },
|
||||
{ 144, 71, 10, 38, 171, 213, 144, 34, 26 },
|
||||
{ 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 },
|
||||
{ 74, 43, 26, 146, 73, 166, 49, 23, 157 },
|
||||
{ 65, 38, 105, 160, 51, 52, 31, 115, 128 },
|
||||
{ 104, 79, 12, 27, 217, 255, 87, 17, 7 },
|
||||
{ 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 },
|
||||
{ 39, 28, 85, 171, 58, 165, 90, 98, 64 },
|
||||
{ 34, 22, 116, 206, 23, 34, 43, 166, 73 },
|
||||
{ 107, 54, 32, 26, 51, 1, 81, 43, 31 },
|
||||
{ 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 },
|
||||
{ 88, 43, 29, 140, 166, 213, 37, 43, 154 },
|
||||
{ 61, 63, 30, 155, 67, 45, 68, 1, 209 },
|
||||
{ 100, 80, 8, 43, 154, 1, 51, 26, 71 },
|
||||
{ 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 } },
|
||||
{ { 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 },
|
||||
{ 47, 15, 16, 183, 34, 223, 49, 45, 183 },
|
||||
{ 46, 17, 33, 183, 6, 98, 15, 32, 183 },
|
||||
{ 57, 46, 22, 24, 128, 1, 54, 17, 37 },
|
||||
{ 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 },
|
||||
{ 39, 19, 53, 221, 26, 114, 32, 73, 255 },
|
||||
{ 31, 9, 65, 234, 2, 15, 1, 118, 73 },
|
||||
{ 75, 32, 12, 51, 192, 255, 160, 43, 51 },
|
||||
{ 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 } },
|
||||
{ { 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 },
|
||||
{ 38, 33, 13, 121, 57, 73, 26, 1, 85 },
|
||||
{ 41, 10, 67, 138, 77, 110, 90, 47, 114 },
|
||||
{ 115, 21, 2, 10, 102, 255, 166, 23, 6 },
|
||||
{ 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 } },
|
||||
{ { 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 },
|
||||
{ 37, 43, 37, 154, 100, 163, 85, 160, 1 },
|
||||
{ 63, 9, 92, 136, 28, 64, 32, 201, 85 },
|
||||
{ 75, 15, 9, 9, 64, 255, 184, 119, 16 },
|
||||
{ 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 },
|
||||
{ 45, 16, 21, 91, 64, 222, 7, 1, 197 },
|
||||
{ 56, 21, 39, 155, 60, 138, 23, 102, 213 },
|
||||
{ 83, 12, 13, 54, 192, 255, 68, 47, 28 },
|
||||
{ 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 },
|
||||
{ 71, 30, 17, 119, 118, 255, 17, 18, 138 },
|
||||
{ 101, 38, 60, 138, 55, 70, 43, 26, 142 },
|
||||
{ 146, 36, 19, 30, 171, 255, 97, 27, 20 },
|
||||
{ 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 } }
|
||||
};
|
||||
|
||||
static int PutI4Mode(VP8BitWriter* const bw, int mode,
|
||||
const uint8_t* const prob) {
|
||||
if (VP8PutBit(bw, mode != B_DC_PRED, prob[0])) {
|
||||
if (VP8PutBit(bw, mode != B_TM_PRED, prob[1])) {
|
||||
if (VP8PutBit(bw, mode != B_VE_PRED, prob[2])) {
|
||||
if (!VP8PutBit(bw, mode >= B_LD_PRED, prob[3])) {
|
||||
if (VP8PutBit(bw, mode != B_HE_PRED, prob[4])) {
|
||||
VP8PutBit(bw, mode != B_RD_PRED, prob[5]);
|
||||
}
|
||||
} else {
|
||||
if (VP8PutBit(bw, mode != B_LD_PRED, prob[6])) {
|
||||
if (VP8PutBit(bw, mode != B_VL_PRED, prob[7])) {
|
||||
VP8PutBit(bw, mode != B_HD_PRED, prob[8]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
static void PutI16Mode(VP8BitWriter* const bw, int mode) {
|
||||
if (VP8PutBit(bw, (mode == TM_PRED || mode == H_PRED), 156)) {
|
||||
VP8PutBit(bw, mode == TM_PRED, 128); // TM or HE
|
||||
} else {
|
||||
VP8PutBit(bw, mode == V_PRED, 163); // VE or DC
|
||||
}
|
||||
}
|
||||
|
||||
static void PutUVMode(VP8BitWriter* const bw, int uv_mode) {
|
||||
if (VP8PutBit(bw, uv_mode != DC_PRED, 142)) {
|
||||
if (VP8PutBit(bw, uv_mode != V_PRED, 114)) {
|
||||
VP8PutBit(bw, uv_mode != H_PRED, 183); // else: TM_PRED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PutSegment(VP8BitWriter* const bw, int s, const uint8_t* p) {
|
||||
if (VP8PutBit(bw, s >= 2, p[0])) p += 1;
|
||||
VP8PutBit(bw, s & 1, p[1]);
|
||||
}
|
||||
|
||||
void VP8CodeIntraModes(VP8Encoder* const enc) {
|
||||
VP8BitWriter* const bw = &enc->bw_;
|
||||
VP8EncIterator it;
|
||||
VP8IteratorInit(enc, &it);
|
||||
do {
|
||||
const VP8MBInfo* const mb = it.mb_;
|
||||
const uint8_t* preds = it.preds_;
|
||||
if (enc->segment_hdr_.update_map_) {
|
||||
PutSegment(bw, mb->segment_, enc->proba_.segments_);
|
||||
}
|
||||
if (enc->proba_.use_skip_proba_) {
|
||||
VP8PutBit(bw, mb->skip_, enc->proba_.skip_proba_);
|
||||
}
|
||||
if (VP8PutBit(bw, (mb->type_ != 0), 145)) { // i16x16
|
||||
PutI16Mode(bw, preds[0]);
|
||||
} else {
|
||||
const int preds_w = enc->preds_w_;
|
||||
const uint8_t* top_pred = preds - preds_w;
|
||||
int x, y;
|
||||
for (y = 0; y < 4; ++y) {
|
||||
int left = preds[-1];
|
||||
for (x = 0; x < 4; ++x) {
|
||||
const uint8_t* const probas = kBModesProba[top_pred[x]][left];
|
||||
left = PutI4Mode(bw, preds[x], probas);
|
||||
}
|
||||
top_pred = preds;
|
||||
preds += preds_w;
|
||||
}
|
||||
}
|
||||
PutUVMode(bw, mb->uv_mode_);
|
||||
} while (VP8IteratorNext(&it));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Paragraph 13
|
||||
|
||||
const uint8_t
|
||||
VP8CoeffsUpdateProba[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 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas) {
|
||||
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) {
|
||||
const uint8_t p0 = probas->coeffs_[t][b][c][p];
|
||||
const int update = (p0 != VP8CoeffsProba0[t][b][c][p]);
|
||||
if (VP8PutBit(bw, update, VP8CoeffsUpdateProba[t][b][c][p])) {
|
||||
VP8PutBits(bw, p0, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (VP8PutBitUniform(bw, probas->use_skip_proba_)) {
|
||||
VP8PutBits(bw, probas->skip_proba_, 8);
|
||||
}
|
||||
}
|
||||
|
||||
518
libsdl2_image/external/libwebp-1.0.2/src/enc/vp8i_enc.h
vendored
Normal file
518
libsdl2_image/external/libwebp-1.0.2/src/enc/vp8i_enc.h
vendored
Normal file
@ -0,0 +1,518 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// WebP encoder: internal header.
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#ifndef WEBP_ENC_VP8I_ENC_H_
|
||||
#define WEBP_ENC_VP8I_ENC_H_
|
||||
|
||||
#include <string.h> // for memcpy()
|
||||
#include "src/dec/common_dec.h"
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/utils/bit_writer_utils.h"
|
||||
#include "src/utils/thread_utils.h"
|
||||
#include "src/utils/utils.h"
|
||||
#include "src/webp/encode.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Various defines and enums
|
||||
|
||||
// version numbers
|
||||
#define ENC_MAJ_VERSION 1
|
||||
#define ENC_MIN_VERSION 0
|
||||
#define ENC_REV_VERSION 2
|
||||
|
||||
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
|
||||
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
|
||||
MAX_LEVEL = 2047 // max level (note: max codable is 2047 + 67)
|
||||
};
|
||||
|
||||
typedef enum { // Rate-distortion optimization levels
|
||||
RD_OPT_NONE = 0, // no rd-opt
|
||||
RD_OPT_BASIC = 1, // basic scoring (no trellis)
|
||||
RD_OPT_TRELLIS = 2, // perform trellis-quant on the final decision only
|
||||
RD_OPT_TRELLIS_ALL = 3 // trellis-quant for every scoring (much slower)
|
||||
} VP8RDLevel;
|
||||
|
||||
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
||||
// The original or reconstructed samples can be accessed using VP8Scan[].
|
||||
// The predicted blocks can be accessed using offsets to yuv_p_ and
|
||||
// the arrays VP8*ModeOffsets[].
|
||||
// * YUV Samples area (yuv_in_/yuv_out_/yuv_out2_)
|
||||
// (see VP8Scan[] for accessing the blocks, along with
|
||||
// Y_OFF_ENC/U_OFF_ENC/V_OFF_ENC):
|
||||
// +----+----+
|
||||
// Y_OFF_ENC |YYYY|UUVV|
|
||||
// U_OFF_ENC |YYYY|UUVV|
|
||||
// V_OFF_ENC |YYYY|....| <- 25% wasted U/V area
|
||||
// |YYYY|....|
|
||||
// +----+----+
|
||||
// * Prediction area ('yuv_p_', size = PRED_SIZE_ENC)
|
||||
// Intra16 predictions (16x16 block each, two per row):
|
||||
// |I16DC16|I16TM16|
|
||||
// |I16VE16|I16HE16|
|
||||
// Chroma U/V predictions (16x8 block each, two per row):
|
||||
// |C8DC8|C8TM8|
|
||||
// |C8VE8|C8HE8|
|
||||
// Intra 4x4 predictions (4x4 block each)
|
||||
// |I4DC4 I4TM4 I4VE4 I4HE4|I4RD4 I4VR4 I4LD4 I4VL4|
|
||||
// |I4HD4 I4HU4 I4TMP .....|.......................| <- ~31% wasted
|
||||
#define YUV_SIZE_ENC (BPS * 16)
|
||||
#define PRED_SIZE_ENC (32 * BPS + 16 * BPS + 8 * BPS) // I16+Chroma+I4 preds
|
||||
#define Y_OFF_ENC (0)
|
||||
#define U_OFF_ENC (16)
|
||||
#define V_OFF_ENC (16 + 8)
|
||||
|
||||
extern const uint16_t VP8Scan[16];
|
||||
extern const uint16_t VP8UVModeOffsets[4];
|
||||
extern const uint16_t VP8I16ModeOffsets[4];
|
||||
extern const uint16_t VP8I4ModeOffsets[NUM_BMODES];
|
||||
|
||||
// Layout of prediction blocks
|
||||
// intra 16x16
|
||||
#define I16DC16 (0 * 16 * BPS)
|
||||
#define I16TM16 (I16DC16 + 16)
|
||||
#define I16VE16 (1 * 16 * BPS)
|
||||
#define I16HE16 (I16VE16 + 16)
|
||||
// chroma 8x8, two U/V blocks side by side (hence: 16x8 each)
|
||||
#define C8DC8 (2 * 16 * BPS)
|
||||
#define C8TM8 (C8DC8 + 1 * 16)
|
||||
#define C8VE8 (2 * 16 * BPS + 8 * BPS)
|
||||
#define C8HE8 (C8VE8 + 1 * 16)
|
||||
// intra 4x4
|
||||
#define I4DC4 (3 * 16 * BPS + 0)
|
||||
#define I4TM4 (I4DC4 + 4)
|
||||
#define I4VE4 (I4DC4 + 8)
|
||||
#define I4HE4 (I4DC4 + 12)
|
||||
#define I4RD4 (I4DC4 + 16)
|
||||
#define I4VR4 (I4DC4 + 20)
|
||||
#define I4LD4 (I4DC4 + 24)
|
||||
#define I4VL4 (I4DC4 + 28)
|
||||
#define I4HD4 (3 * 16 * BPS + 4 * BPS)
|
||||
#define I4HU4 (I4HD4 + 4)
|
||||
#define I4TMP (I4HD4 + 8)
|
||||
|
||||
typedef int64_t score_t; // type used for scores, rate, distortion
|
||||
// Note that MAX_COST is not the maximum allowed by sizeof(score_t),
|
||||
// in order to allow overflowing computations.
|
||||
#define MAX_COST ((score_t)0x7fffffffffffffLL)
|
||||
|
||||
#define QFIX 17
|
||||
#define BIAS(b) ((b) << (QFIX - 8))
|
||||
// Fun fact: this is the _only_ line where we're actually being lossy and
|
||||
// discarding bits.
|
||||
static WEBP_INLINE int QUANTDIV(uint32_t n, uint32_t iQ, uint32_t B) {
|
||||
return (int)((n * iQ + B) >> QFIX);
|
||||
}
|
||||
|
||||
// Uncomment the following to remove token-buffer code:
|
||||
// #define DISABLE_TOKEN_BUFFER
|
||||
|
||||
// quality below which error-diffusion is enabled
|
||||
#define ERROR_DIFFUSION_QUALITY 98
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
|
||||
typedef uint32_t proba_t; // 16b + 16b
|
||||
typedef uint8_t ProbaArray[NUM_CTX][NUM_PROBAS];
|
||||
typedef proba_t StatsArray[NUM_CTX][NUM_PROBAS];
|
||||
typedef uint16_t CostArray[NUM_CTX][MAX_VARIABLE_LEVEL + 1];
|
||||
typedef const uint16_t* (*CostArrayPtr)[NUM_CTX]; // for easy casting
|
||||
typedef const uint16_t* CostArrayMap[16][NUM_CTX];
|
||||
typedef double LFStats[NUM_MB_SEGMENTS][MAX_LF_LEVELS]; // filter stats
|
||||
|
||||
typedef struct VP8Encoder VP8Encoder;
|
||||
|
||||
// segment features
|
||||
typedef struct {
|
||||
int num_segments_; // Actual number of segments. 1 segment only = unused.
|
||||
int update_map_; // whether to update the segment map or not.
|
||||
// must be 0 if there's only 1 segment.
|
||||
int size_; // bit-cost for transmitting the segment map
|
||||
} VP8EncSegmentHeader;
|
||||
|
||||
// Struct collecting all frame-persistent probabilities.
|
||||
typedef struct {
|
||||
uint8_t segments_[3]; // probabilities for segment tree
|
||||
uint8_t skip_proba_; // final probability of being skipped.
|
||||
ProbaArray coeffs_[NUM_TYPES][NUM_BANDS]; // 1056 bytes
|
||||
StatsArray stats_[NUM_TYPES][NUM_BANDS]; // 4224 bytes
|
||||
CostArray level_cost_[NUM_TYPES][NUM_BANDS]; // 13056 bytes
|
||||
CostArrayMap remapped_costs_[NUM_TYPES]; // 1536 bytes
|
||||
int dirty_; // if true, need to call VP8CalculateLevelCosts()
|
||||
int use_skip_proba_; // Note: we always use skip_proba for now.
|
||||
int nb_skip_; // number of skipped blocks
|
||||
} VP8EncProba;
|
||||
|
||||
// Filter parameters. Not actually used in the code (we don't perform
|
||||
// the in-loop filtering), but filled from user's config
|
||||
typedef struct {
|
||||
int simple_; // filtering type: 0=complex, 1=simple
|
||||
int level_; // base filter level [0..63]
|
||||
int sharpness_; // [0..7]
|
||||
int i4x4_lf_delta_; // delta filter level for i4x4 relative to i16x16
|
||||
} VP8EncFilterHeader;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Informations about the macroblocks.
|
||||
|
||||
typedef struct {
|
||||
// block type
|
||||
unsigned int type_:2; // 0=i4x4, 1=i16x16
|
||||
unsigned int uv_mode_:2;
|
||||
unsigned int skip_:1;
|
||||
unsigned int segment_:2;
|
||||
uint8_t alpha_; // quantization-susceptibility
|
||||
} VP8MBInfo;
|
||||
|
||||
typedef struct VP8Matrix {
|
||||
uint16_t q_[16]; // quantizer steps
|
||||
uint16_t iq_[16]; // reciprocals, fixed point.
|
||||
uint32_t bias_[16]; // rounding bias
|
||||
uint32_t zthresh_[16]; // value below which a coefficient is zeroed
|
||||
uint16_t sharpen_[16]; // frequency boosters for slight sharpening
|
||||
} VP8Matrix;
|
||||
|
||||
typedef struct {
|
||||
VP8Matrix y1_, y2_, uv_; // quantization matrices
|
||||
int alpha_; // quant-susceptibility, range [-127,127]. Zero is neutral.
|
||||
// Lower values indicate a lower risk of blurriness.
|
||||
int beta_; // filter-susceptibility, range [0,255].
|
||||
int quant_; // final segment quantizer.
|
||||
int fstrength_; // final in-loop filtering strength
|
||||
int max_edge_; // max edge delta (for filtering strength)
|
||||
int min_disto_; // minimum distortion required to trigger filtering record
|
||||
// reactivities
|
||||
int lambda_i16_, lambda_i4_, lambda_uv_;
|
||||
int lambda_mode_, lambda_trellis_, tlambda_;
|
||||
int lambda_trellis_i16_, lambda_trellis_i4_, lambda_trellis_uv_;
|
||||
|
||||
// lambda values for distortion-based evaluation
|
||||
score_t i4_penalty_; // penalty for using Intra4
|
||||
} VP8SegmentInfo;
|
||||
|
||||
typedef int8_t DError[2 /* u/v */][2 /* top or left */];
|
||||
|
||||
// Handy transient struct to accumulate score and info during RD-optimization
|
||||
// and mode evaluation.
|
||||
typedef struct {
|
||||
score_t D, SD; // Distortion, spectral distortion
|
||||
score_t H, R, score; // header bits, rate, score.
|
||||
int16_t y_dc_levels[16]; // Quantized levels for luma-DC, luma-AC, chroma.
|
||||
int16_t y_ac_levels[16][16];
|
||||
int16_t uv_levels[4 + 4][16];
|
||||
int mode_i16; // mode number for intra16 prediction
|
||||
uint8_t modes_i4[16]; // mode numbers for intra4 predictions
|
||||
int mode_uv; // mode number of chroma prediction
|
||||
uint32_t nz; // non-zero blocks
|
||||
int8_t derr[2][3]; // DC diffusion errors for U/V for blocks #1/2/3
|
||||
} VP8ModeScore;
|
||||
|
||||
// Iterator structure to iterate through macroblocks, pointing to the
|
||||
// right neighbouring data (samples, predictions, contexts, ...)
|
||||
typedef struct {
|
||||
int x_, y_; // current macroblock
|
||||
uint8_t* yuv_in_; // input samples
|
||||
uint8_t* yuv_out_; // output samples
|
||||
uint8_t* yuv_out2_; // secondary buffer swapped with yuv_out_.
|
||||
uint8_t* yuv_p_; // scratch buffer for prediction
|
||||
VP8Encoder* enc_; // back-pointer
|
||||
VP8MBInfo* mb_; // current macroblock
|
||||
VP8BitWriter* bw_; // current bit-writer
|
||||
uint8_t* preds_; // intra mode predictors (4x4 blocks)
|
||||
uint32_t* nz_; // non-zero pattern
|
||||
uint8_t i4_boundary_[37]; // 32+5 boundary samples needed by intra4x4
|
||||
uint8_t* i4_top_; // pointer to the current top boundary sample
|
||||
int i4_; // current intra4x4 mode being tested
|
||||
int top_nz_[9]; // top-non-zero context.
|
||||
int left_nz_[9]; // left-non-zero. left_nz[8] is independent.
|
||||
uint64_t bit_count_[4][3]; // bit counters for coded levels.
|
||||
uint64_t luma_bits_; // macroblock bit-cost for luma
|
||||
uint64_t uv_bits_; // macroblock bit-cost for chroma
|
||||
LFStats* lf_stats_; // filter stats (borrowed from enc_)
|
||||
int do_trellis_; // if true, perform extra level optimisation
|
||||
int count_down_; // number of mb still to be processed
|
||||
int count_down0_; // starting counter value (for progress)
|
||||
int percent0_; // saved initial progress percent
|
||||
|
||||
DError left_derr_; // left error diffusion (u/v)
|
||||
DError *top_derr_; // top diffusion error - NULL if disabled
|
||||
|
||||
uint8_t* y_left_; // left luma samples (addressable from index -1 to 15).
|
||||
uint8_t* u_left_; // left u samples (addressable from index -1 to 7)
|
||||
uint8_t* v_left_; // left v samples (addressable from index -1 to 7)
|
||||
|
||||
uint8_t* y_top_; // top luma samples at position 'x_'
|
||||
uint8_t* uv_top_; // top u/v samples at position 'x_', packed as 16 bytes
|
||||
|
||||
// memory for storing y/u/v_left_
|
||||
uint8_t yuv_left_mem_[17 + 16 + 16 + 8 + WEBP_ALIGN_CST];
|
||||
// memory for yuv_*
|
||||
uint8_t yuv_mem_[3 * YUV_SIZE_ENC + PRED_SIZE_ENC + WEBP_ALIGN_CST];
|
||||
} VP8EncIterator;
|
||||
|
||||
// in iterator.c
|
||||
// must be called first
|
||||
void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it);
|
||||
// restart a scan
|
||||
void VP8IteratorReset(VP8EncIterator* const it);
|
||||
// reset iterator position to row 'y'
|
||||
void VP8IteratorSetRow(VP8EncIterator* const it, int y);
|
||||
// set count down (=number of iterations to go)
|
||||
void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down);
|
||||
// return true if iteration is finished
|
||||
int VP8IteratorIsDone(const VP8EncIterator* const it);
|
||||
// Import uncompressed samples from source.
|
||||
// If tmp_32 is not NULL, import boundary samples too.
|
||||
// tmp_32 is a 32-bytes scratch buffer that must be aligned in memory.
|
||||
void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32);
|
||||
// export decimated samples
|
||||
void VP8IteratorExport(const VP8EncIterator* const it);
|
||||
// go to next macroblock. Returns false if not finished.
|
||||
int VP8IteratorNext(VP8EncIterator* const it);
|
||||
// save the yuv_out_ boundary values to top_/left_ arrays for next iterations.
|
||||
void VP8IteratorSaveBoundary(VP8EncIterator* const it);
|
||||
// Report progression based on macroblock rows. Return 0 for user-abort request.
|
||||
int VP8IteratorProgress(const VP8EncIterator* const it,
|
||||
int final_delta_percent);
|
||||
// Intra4x4 iterations
|
||||
void VP8IteratorStartI4(VP8EncIterator* const it);
|
||||
// returns true if not done.
|
||||
int VP8IteratorRotateI4(VP8EncIterator* const it,
|
||||
const uint8_t* const yuv_out);
|
||||
|
||||
// Non-zero context setup/teardown
|
||||
void VP8IteratorNzToBytes(VP8EncIterator* const it);
|
||||
void VP8IteratorBytesToNz(VP8EncIterator* const it);
|
||||
|
||||
// Helper functions to set mode properties
|
||||
void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode);
|
||||
void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes);
|
||||
void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode);
|
||||
void VP8SetSkip(const VP8EncIterator* const it, int skip);
|
||||
void VP8SetSegment(const VP8EncIterator* const it, int segment);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Paginated token buffer
|
||||
|
||||
typedef struct VP8Tokens VP8Tokens; // struct details in token.c
|
||||
|
||||
typedef struct {
|
||||
#if !defined(DISABLE_TOKEN_BUFFER)
|
||||
VP8Tokens* pages_; // first page
|
||||
VP8Tokens** last_page_; // last page
|
||||
uint16_t* tokens_; // set to (*last_page_)->tokens_
|
||||
int left_; // how many free tokens left before the page is full
|
||||
int page_size_; // number of tokens per page
|
||||
#endif
|
||||
int error_; // true in case of malloc error
|
||||
} VP8TBuffer;
|
||||
|
||||
// initialize an empty buffer
|
||||
void VP8TBufferInit(VP8TBuffer* const b, int page_size);
|
||||
void VP8TBufferClear(VP8TBuffer* const b); // de-allocate pages memory
|
||||
|
||||
#if !defined(DISABLE_TOKEN_BUFFER)
|
||||
|
||||
// Finalizes bitstream when probabilities are known.
|
||||
// Deletes the allocated token memory if final_pass is true.
|
||||
int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
|
||||
const uint8_t* const probas, int final_pass);
|
||||
|
||||
// record the coding of coefficients without knowing the probabilities yet
|
||||
int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res,
|
||||
VP8TBuffer* const tokens);
|
||||
|
||||
// Estimate the final coded size given a set of 'probas'.
|
||||
size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas);
|
||||
|
||||
#endif // !DISABLE_TOKEN_BUFFER
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VP8Encoder
|
||||
|
||||
struct VP8Encoder {
|
||||
const WebPConfig* config_; // user configuration and parameters
|
||||
WebPPicture* pic_; // input / output picture
|
||||
|
||||
// headers
|
||||
VP8EncFilterHeader filter_hdr_; // filtering information
|
||||
VP8EncSegmentHeader segment_hdr_; // segment information
|
||||
|
||||
int profile_; // VP8's profile, deduced from Config.
|
||||
|
||||
// dimension, in macroblock units.
|
||||
int mb_w_, mb_h_;
|
||||
int preds_w_; // stride of the *preds_ prediction plane (=4*mb_w + 1)
|
||||
|
||||
// number of partitions (1, 2, 4 or 8 = MAX_NUM_PARTITIONS)
|
||||
int num_parts_;
|
||||
|
||||
// per-partition boolean decoders.
|
||||
VP8BitWriter bw_; // part0
|
||||
VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions
|
||||
VP8TBuffer tokens_; // token buffer
|
||||
|
||||
int percent_; // for progress
|
||||
|
||||
// transparency blob
|
||||
int has_alpha_;
|
||||
uint8_t* alpha_data_; // non-NULL if transparency is present
|
||||
uint32_t alpha_data_size_;
|
||||
WebPWorker alpha_worker_;
|
||||
|
||||
// quantization info (one set of DC/AC dequant factor per segment)
|
||||
VP8SegmentInfo dqm_[NUM_MB_SEGMENTS];
|
||||
int base_quant_; // nominal quantizer value. Only used
|
||||
// for relative coding of segments' quant.
|
||||
int alpha_; // global susceptibility (<=> complexity)
|
||||
int uv_alpha_; // U/V quantization susceptibility
|
||||
// global offset of quantizers, shared by all segments
|
||||
int dq_y1_dc_;
|
||||
int dq_y2_dc_, dq_y2_ac_;
|
||||
int dq_uv_dc_, dq_uv_ac_;
|
||||
|
||||
// probabilities and statistics
|
||||
VP8EncProba proba_;
|
||||
uint64_t sse_[4]; // sum of Y/U/V/A squared errors for all macroblocks
|
||||
uint64_t sse_count_; // pixel count for the sse_[] stats
|
||||
int coded_size_;
|
||||
int residual_bytes_[3][4];
|
||||
int block_count_[3];
|
||||
|
||||
// quality/speed settings
|
||||
int method_; // 0=fastest, 6=best/slowest.
|
||||
VP8RDLevel rd_opt_level_; // Deduced from method_.
|
||||
int max_i4_header_bits_; // partition #0 safeness factor
|
||||
int mb_header_limit_; // rough limit for header bits per MB
|
||||
int thread_level_; // derived from config->thread_level
|
||||
int do_search_; // derived from config->target_XXX
|
||||
int use_tokens_; // if true, use token buffer
|
||||
|
||||
// Memory
|
||||
VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1)
|
||||
uint8_t* preds_; // predictions modes: (4*mb_w+1) * (4*mb_h+1)
|
||||
uint32_t* nz_; // non-zero bit context: mb_w+1
|
||||
uint8_t* y_top_; // top luma samples.
|
||||
uint8_t* uv_top_; // top u/v samples.
|
||||
// U and V are packed into 16 bytes (8 U + 8 V)
|
||||
LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off)
|
||||
DError* top_derr_; // diffusion error (NULL if disabled)
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// internal functions. Not public.
|
||||
|
||||
// in tree.c
|
||||
extern const uint8_t VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS];
|
||||
extern const uint8_t
|
||||
VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS];
|
||||
// Reset the token probabilities to their initial (default) values
|
||||
void VP8DefaultProbas(VP8Encoder* const enc);
|
||||
// Write the token probabilities
|
||||
void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas);
|
||||
// Writes the partition #0 modes (that is: all intra modes)
|
||||
void VP8CodeIntraModes(VP8Encoder* const enc);
|
||||
|
||||
// in syntax.c
|
||||
// Generates the final bitstream by coding the partition0 and headers,
|
||||
// and appending an assembly of all the pre-coded token partitions.
|
||||
// Return true if everything is ok.
|
||||
int VP8EncWrite(VP8Encoder* const enc);
|
||||
// Release memory allocated for bit-writing in VP8EncLoop & seq.
|
||||
void VP8EncFreeBitWriters(VP8Encoder* const enc);
|
||||
|
||||
// in frame.c
|
||||
extern const uint8_t VP8Cat3[];
|
||||
extern const uint8_t VP8Cat4[];
|
||||
extern const uint8_t VP8Cat5[];
|
||||
extern const uint8_t VP8Cat6[];
|
||||
|
||||
// Form all the four Intra16x16 predictions in the yuv_p_ cache
|
||||
void VP8MakeLuma16Preds(const VP8EncIterator* const it);
|
||||
// Form all the four Chroma8x8 predictions in the yuv_p_ cache
|
||||
void VP8MakeChroma8Preds(const VP8EncIterator* const it);
|
||||
// Form all the ten Intra4x4 predictions in the yuv_p_ cache
|
||||
// for the 4x4 block it->i4_
|
||||
void VP8MakeIntra4Preds(const VP8EncIterator* const it);
|
||||
// Rate calculation
|
||||
int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd);
|
||||
int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]);
|
||||
int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd);
|
||||
// Main coding calls
|
||||
int VP8EncLoop(VP8Encoder* const enc);
|
||||
int VP8EncTokenLoop(VP8Encoder* const enc);
|
||||
|
||||
// in webpenc.c
|
||||
// Assign an error code to a picture. Return false for convenience.
|
||||
int WebPEncodingSetError(const WebPPicture* const pic, WebPEncodingError error);
|
||||
int WebPReportProgress(const WebPPicture* const pic,
|
||||
int percent, int* const percent_store);
|
||||
|
||||
// in analysis.c
|
||||
// Main analysis loop. Decides the segmentations and complexity.
|
||||
// Assigns a first guess for Intra16 and uvmode_ prediction modes.
|
||||
int VP8EncAnalyze(VP8Encoder* const enc);
|
||||
|
||||
// in quant.c
|
||||
// Sets up segment's quantization values, base_quant_ and filter strengths.
|
||||
void VP8SetSegmentParams(VP8Encoder* const enc, float quality);
|
||||
// Pick best modes and fills the levels. Returns true if skipped.
|
||||
int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
|
||||
VP8RDLevel rd_opt);
|
||||
|
||||
// in alpha.c
|
||||
void VP8EncInitAlpha(VP8Encoder* const enc); // initialize alpha compression
|
||||
int VP8EncStartAlpha(VP8Encoder* const enc); // start alpha coding process
|
||||
int VP8EncFinishAlpha(VP8Encoder* const enc); // finalize compressed data
|
||||
int VP8EncDeleteAlpha(VP8Encoder* const enc); // delete compressed data
|
||||
|
||||
// autofilter
|
||||
void VP8InitFilter(VP8EncIterator* const it);
|
||||
void VP8StoreFilterStats(VP8EncIterator* const it);
|
||||
void VP8AdjustFilterStrength(VP8EncIterator* const it);
|
||||
|
||||
// returns the approximate filtering strength needed to smooth a edge
|
||||
// step of 'delta', given a sharpness parameter 'sharpness'.
|
||||
int VP8FilterStrengthFromDelta(int sharpness, int delta);
|
||||
|
||||
// misc utils for picture_*.c:
|
||||
|
||||
// Remove reference to the ARGB/YUVA buffer (doesn't free anything).
|
||||
void WebPPictureResetBuffers(WebPPicture* const picture);
|
||||
|
||||
// Allocates ARGB buffer of given dimension (previous one is always free'd).
|
||||
// Preserves the YUV(A) buffer. Returns false in case of error (invalid param,
|
||||
// out-of-memory).
|
||||
int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height);
|
||||
|
||||
// Allocates YUVA buffer of given dimension (previous one is always free'd).
|
||||
// Uses picture->csp to determine whether an alpha buffer is needed.
|
||||
// Preserves the ARGB buffer.
|
||||
// Returns false in case of error (invalid param, out-of-memory).
|
||||
int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height);
|
||||
|
||||
// Clean-up the RGB samples under fully transparent area, to help lossless
|
||||
// compressibility (no guarantee, though). Assumes that pic->use_argb is true.
|
||||
void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // WEBP_ENC_VP8I_ENC_H_
|
||||
1917
libsdl2_image/external/libwebp-1.0.2/src/enc/vp8l_enc.c
vendored
Normal file
1917
libsdl2_image/external/libwebp-1.0.2/src/enc/vp8l_enc.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
118
libsdl2_image/external/libwebp-1.0.2/src/enc/vp8li_enc.h
vendored
Normal file
118
libsdl2_image/external/libwebp-1.0.2/src/enc/vp8li_enc.h
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Lossless encoder: internal header.
|
||||
//
|
||||
// Author: Vikas Arora (vikaas.arora@gmail.com)
|
||||
|
||||
#ifndef WEBP_ENC_VP8LI_ENC_H_
|
||||
#define WEBP_ENC_VP8LI_ENC_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "src/webp/config.h"
|
||||
#endif
|
||||
// Either WEBP_NEAR_LOSSLESS is defined as 0 in config.h when compiling to
|
||||
// disable near-lossless, or it is enabled by default.
|
||||
#ifndef WEBP_NEAR_LOSSLESS
|
||||
#define WEBP_NEAR_LOSSLESS 1
|
||||
#endif
|
||||
|
||||
#include "src/enc/backward_references_enc.h"
|
||||
#include "src/enc/histogram_enc.h"
|
||||
#include "src/utils/bit_writer_utils.h"
|
||||
#include "src/webp/encode.h"
|
||||
#include "src/webp/format_constants.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// maximum value of transform_bits_ in VP8LEncoder.
|
||||
#define MAX_TRANSFORM_BITS 6
|
||||
|
||||
typedef enum {
|
||||
kEncoderNone = 0,
|
||||
kEncoderARGB,
|
||||
kEncoderNearLossless,
|
||||
kEncoderPalette
|
||||
} VP8LEncoderARGBContent;
|
||||
|
||||
typedef struct {
|
||||
const WebPConfig* config_; // user configuration and parameters
|
||||
const WebPPicture* pic_; // input picture.
|
||||
|
||||
uint32_t* argb_; // Transformed argb image data.
|
||||
VP8LEncoderARGBContent argb_content_; // Content type of the argb buffer.
|
||||
uint32_t* argb_scratch_; // Scratch memory for argb rows
|
||||
// (used for prediction).
|
||||
uint32_t* transform_data_; // Scratch memory for transform data.
|
||||
uint32_t* transform_mem_; // Currently allocated memory.
|
||||
size_t transform_mem_size_; // Currently allocated memory size.
|
||||
|
||||
int current_width_; // Corresponds to packed image width.
|
||||
|
||||
// Encoding parameters derived from quality parameter.
|
||||
int histo_bits_;
|
||||
int transform_bits_; // <= MAX_TRANSFORM_BITS.
|
||||
int cache_bits_; // If equal to 0, don't use color cache.
|
||||
|
||||
// Encoding parameters derived from image characteristics.
|
||||
int use_cross_color_;
|
||||
int use_subtract_green_;
|
||||
int use_predict_;
|
||||
int use_palette_;
|
||||
int palette_size_;
|
||||
uint32_t palette_[MAX_PALETTE_SIZE];
|
||||
|
||||
// Some 'scratch' (potentially large) objects.
|
||||
struct VP8LBackwardRefs refs_[3]; // Backward Refs array for temporaries.
|
||||
VP8LHashChain hash_chain_; // HashChain data for constructing
|
||||
// backward references.
|
||||
} VP8LEncoder;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// internal functions. Not public.
|
||||
|
||||
// Encodes the picture.
|
||||
// Returns 0 if config or picture is NULL or picture doesn't have valid argb
|
||||
// input.
|
||||
int VP8LEncodeImage(const WebPConfig* const config,
|
||||
const WebPPicture* const picture);
|
||||
|
||||
// Encodes the main image stream using the supplied bit writer.
|
||||
// If 'use_cache' is false, disables the use of color cache.
|
||||
WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
||||
const WebPPicture* const picture,
|
||||
VP8LBitWriter* const bw, int use_cache);
|
||||
|
||||
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||
// in near_lossless.c
|
||||
// Near lossless preprocessing in RGB color-space.
|
||||
int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
|
||||
uint32_t* const argb_dst);
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Image transforms in predictor.c.
|
||||
|
||||
void VP8LResidualImage(int width, int height, int bits, int low_effort,
|
||||
uint32_t* const argb, uint32_t* const argb_scratch,
|
||||
uint32_t* const image, int near_lossless, int exact,
|
||||
int used_subtract_green);
|
||||
|
||||
void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
|
||||
uint32_t* const argb, uint32_t* image);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // WEBP_ENC_VP8LI_ENC_H_
|
||||
410
libsdl2_image/external/libwebp-1.0.2/src/enc/webp_enc.c
vendored
Normal file
410
libsdl2_image/external/libwebp-1.0.2/src/enc/webp_enc.c
vendored
Normal file
@ -0,0 +1,410 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// WebP encoder: main entry point
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "src/enc/cost_enc.h"
|
||||
#include "src/enc/vp8i_enc.h"
|
||||
#include "src/enc/vp8li_enc.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
// #define PRINT_MEMORY_INFO
|
||||
|
||||
#ifdef PRINT_MEMORY_INFO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int WebPGetEncoderVersion(void) {
|
||||
return (ENC_MAJ_VERSION << 16) | (ENC_MIN_VERSION << 8) | ENC_REV_VERSION;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VP8Encoder
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static void ResetSegmentHeader(VP8Encoder* const enc) {
|
||||
VP8EncSegmentHeader* const hdr = &enc->segment_hdr_;
|
||||
hdr->num_segments_ = enc->config_->segments;
|
||||
hdr->update_map_ = (hdr->num_segments_ > 1);
|
||||
hdr->size_ = 0;
|
||||
}
|
||||
|
||||
static void ResetFilterHeader(VP8Encoder* const enc) {
|
||||
VP8EncFilterHeader* const hdr = &enc->filter_hdr_;
|
||||
hdr->simple_ = 1;
|
||||
hdr->level_ = 0;
|
||||
hdr->sharpness_ = 0;
|
||||
hdr->i4x4_lf_delta_ = 0;
|
||||
}
|
||||
|
||||
static void ResetBoundaryPredictions(VP8Encoder* const enc) {
|
||||
// init boundary values once for all
|
||||
// Note: actually, initializing the preds_[] is only needed for intra4.
|
||||
int i;
|
||||
uint8_t* const top = enc->preds_ - enc->preds_w_;
|
||||
uint8_t* const left = enc->preds_ - 1;
|
||||
for (i = -1; i < 4 * enc->mb_w_; ++i) {
|
||||
top[i] = B_DC_PRED;
|
||||
}
|
||||
for (i = 0; i < 4 * enc->mb_h_; ++i) {
|
||||
left[i * enc->preds_w_] = B_DC_PRED;
|
||||
}
|
||||
enc->nz_[-1] = 0; // constant
|
||||
}
|
||||
|
||||
// Mapping from config->method_ to coding tools used.
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// Method | 0 | 1 | 2 | 3 |(4)| 5 | 6 |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// fast probe | x | | | x | | | |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// dynamic proba | ~ | x | x | x | x | x | x |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// fast mode analysis|[x]|[x]| | | x | x | x |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// basic rd-opt | | | | x | x | x | x |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// disto-refine i4/16| x | x | x | | | | |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// disto-refine uv | | x | x | | | | |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// rd-opt i4/16 | | | ~ | x | x | x | x |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// token buffer (opt)| | | | x | x | x | x |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// Trellis | | | | | | x |Ful|
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
// full-SNS | | | | | x | x | x |
|
||||
//-------------------+---+---+---+---+---+---+---+
|
||||
|
||||
static void MapConfigToTools(VP8Encoder* const enc) {
|
||||
const WebPConfig* const config = enc->config_;
|
||||
const int method = config->method;
|
||||
const int limit = 100 - config->partition_limit;
|
||||
enc->method_ = method;
|
||||
enc->rd_opt_level_ = (method >= 6) ? RD_OPT_TRELLIS_ALL
|
||||
: (method >= 5) ? RD_OPT_TRELLIS
|
||||
: (method >= 3) ? RD_OPT_BASIC
|
||||
: RD_OPT_NONE;
|
||||
enc->max_i4_header_bits_ =
|
||||
256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block
|
||||
(limit * limit) / (100 * 100); // ... modulated with a quadratic curve.
|
||||
|
||||
// partition0 = 512k max.
|
||||
enc->mb_header_limit_ =
|
||||
(score_t)256 * 510 * 8 * 1024 / (enc->mb_w_ * enc->mb_h_);
|
||||
|
||||
enc->thread_level_ = config->thread_level;
|
||||
|
||||
enc->do_search_ = (config->target_size > 0 || config->target_PSNR > 0);
|
||||
if (!config->low_memory) {
|
||||
#if !defined(DISABLE_TOKEN_BUFFER)
|
||||
enc->use_tokens_ = (enc->rd_opt_level_ >= RD_OPT_BASIC); // need rd stats
|
||||
#endif
|
||||
if (enc->use_tokens_) {
|
||||
enc->num_parts_ = 1; // doesn't work with multi-partition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Memory scaling with dimensions:
|
||||
// memory (bytes) ~= 2.25 * w + 0.0625 * w * h
|
||||
//
|
||||
// Typical memory footprint (614x440 picture)
|
||||
// encoder: 22111
|
||||
// info: 4368
|
||||
// preds: 17741
|
||||
// top samples: 1263
|
||||
// non-zero: 175
|
||||
// lf-stats: 0
|
||||
// total: 45658
|
||||
// Transient object sizes:
|
||||
// VP8EncIterator: 3360
|
||||
// VP8ModeScore: 872
|
||||
// VP8SegmentInfo: 732
|
||||
// VP8EncProba: 18352
|
||||
// LFStats: 2048
|
||||
// Picture size (yuv): 419328
|
||||
|
||||
static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
|
||||
WebPPicture* const picture) {
|
||||
VP8Encoder* enc;
|
||||
const int use_filter =
|
||||
(config->filter_strength > 0) || (config->autofilter > 0);
|
||||
const int mb_w = (picture->width + 15) >> 4;
|
||||
const int mb_h = (picture->height + 15) >> 4;
|
||||
const int preds_w = 4 * mb_w + 1;
|
||||
const int preds_h = 4 * mb_h + 1;
|
||||
const size_t preds_size = preds_w * preds_h * sizeof(*enc->preds_);
|
||||
const int top_stride = mb_w * 16;
|
||||
const size_t nz_size = (mb_w + 1) * sizeof(*enc->nz_) + WEBP_ALIGN_CST;
|
||||
const size_t info_size = mb_w * mb_h * sizeof(*enc->mb_info_);
|
||||
const size_t samples_size =
|
||||
2 * top_stride * sizeof(*enc->y_top_) // top-luma/u/v
|
||||
+ WEBP_ALIGN_CST; // align all
|
||||
const size_t lf_stats_size =
|
||||
config->autofilter ? sizeof(*enc->lf_stats_) + WEBP_ALIGN_CST : 0;
|
||||
const size_t top_derr_size =
|
||||
(config->quality <= ERROR_DIFFUSION_QUALITY || config->pass > 1) ?
|
||||
mb_w * sizeof(*enc->top_derr_) : 0;
|
||||
uint8_t* mem;
|
||||
const uint64_t size = (uint64_t)sizeof(*enc) // main struct
|
||||
+ WEBP_ALIGN_CST // cache alignment
|
||||
+ info_size // modes info
|
||||
+ preds_size // prediction modes
|
||||
+ samples_size // top/left samples
|
||||
+ top_derr_size // top diffusion error
|
||||
+ nz_size // coeff context bits
|
||||
+ lf_stats_size; // autofilter stats
|
||||
|
||||
#ifdef PRINT_MEMORY_INFO
|
||||
printf("===================================\n");
|
||||
printf("Memory used:\n"
|
||||
" encoder: %ld\n"
|
||||
" info: %ld\n"
|
||||
" preds: %ld\n"
|
||||
" top samples: %ld\n"
|
||||
" top diffusion: %ld\n"
|
||||
" non-zero: %ld\n"
|
||||
" lf-stats: %ld\n"
|
||||
" total: %ld\n",
|
||||
sizeof(*enc) + WEBP_ALIGN_CST, info_size,
|
||||
preds_size, samples_size, top_derr_size, nz_size, lf_stats_size, size);
|
||||
printf("Transient object sizes:\n"
|
||||
" VP8EncIterator: %ld\n"
|
||||
" VP8ModeScore: %ld\n"
|
||||
" VP8SegmentInfo: %ld\n"
|
||||
" VP8EncProba: %ld\n"
|
||||
" LFStats: %ld\n",
|
||||
sizeof(VP8EncIterator), sizeof(VP8ModeScore),
|
||||
sizeof(VP8SegmentInfo), sizeof(VP8EncProba),
|
||||
sizeof(LFStats));
|
||||
printf("Picture size (yuv): %ld\n",
|
||||
mb_w * mb_h * 384 * sizeof(uint8_t));
|
||||
printf("===================================\n");
|
||||
#endif
|
||||
mem = (uint8_t*)WebPSafeMalloc(size, sizeof(*mem));
|
||||
if (mem == NULL) {
|
||||
WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
enc = (VP8Encoder*)mem;
|
||||
mem = (uint8_t*)WEBP_ALIGN(mem + sizeof(*enc));
|
||||
memset(enc, 0, sizeof(*enc));
|
||||
enc->num_parts_ = 1 << config->partitions;
|
||||
enc->mb_w_ = mb_w;
|
||||
enc->mb_h_ = mb_h;
|
||||
enc->preds_w_ = preds_w;
|
||||
enc->mb_info_ = (VP8MBInfo*)mem;
|
||||
mem += info_size;
|
||||
enc->preds_ = mem + 1 + enc->preds_w_;
|
||||
mem += preds_size;
|
||||
enc->nz_ = 1 + (uint32_t*)WEBP_ALIGN(mem);
|
||||
mem += nz_size;
|
||||
enc->lf_stats_ = lf_stats_size ? (LFStats*)WEBP_ALIGN(mem) : NULL;
|
||||
mem += lf_stats_size;
|
||||
|
||||
// top samples (all 16-aligned)
|
||||
mem = (uint8_t*)WEBP_ALIGN(mem);
|
||||
enc->y_top_ = mem;
|
||||
enc->uv_top_ = enc->y_top_ + top_stride;
|
||||
mem += 2 * top_stride;
|
||||
enc->top_derr_ = top_derr_size ? (DError*)mem : NULL;
|
||||
mem += top_derr_size;
|
||||
assert(mem <= (uint8_t*)enc + size);
|
||||
|
||||
enc->config_ = config;
|
||||
enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2;
|
||||
enc->pic_ = picture;
|
||||
enc->percent_ = 0;
|
||||
|
||||
MapConfigToTools(enc);
|
||||
VP8EncDspInit();
|
||||
VP8DefaultProbas(enc);
|
||||
ResetSegmentHeader(enc);
|
||||
ResetFilterHeader(enc);
|
||||
ResetBoundaryPredictions(enc);
|
||||
VP8EncDspCostInit();
|
||||
VP8EncInitAlpha(enc);
|
||||
|
||||
// lower quality means smaller output -> we modulate a little the page
|
||||
// size based on quality. This is just a crude 1rst-order prediction.
|
||||
{
|
||||
const float scale = 1.f + config->quality * 5.f / 100.f; // in [1,6]
|
||||
VP8TBufferInit(&enc->tokens_, (int)(mb_w * mb_h * 4 * scale));
|
||||
}
|
||||
return enc;
|
||||
}
|
||||
|
||||
static int DeleteVP8Encoder(VP8Encoder* enc) {
|
||||
int ok = 1;
|
||||
if (enc != NULL) {
|
||||
ok = VP8EncDeleteAlpha(enc);
|
||||
VP8TBufferClear(&enc->tokens_);
|
||||
WebPSafeFree(enc);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if !defined(WEBP_DISABLE_STATS)
|
||||
static double GetPSNR(uint64_t err, uint64_t size) {
|
||||
return (err > 0 && size > 0) ? 10. * log10(255. * 255. * size / err) : 99.;
|
||||
}
|
||||
|
||||
static void FinalizePSNR(const VP8Encoder* const enc) {
|
||||
WebPAuxStats* stats = enc->pic_->stats;
|
||||
const uint64_t size = enc->sse_count_;
|
||||
const uint64_t* const sse = enc->sse_;
|
||||
stats->PSNR[0] = (float)GetPSNR(sse[0], size);
|
||||
stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4);
|
||||
stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4);
|
||||
stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2);
|
||||
stats->PSNR[4] = (float)GetPSNR(sse[3], size);
|
||||
}
|
||||
#endif // !defined(WEBP_DISABLE_STATS)
|
||||
|
||||
static void StoreStats(VP8Encoder* const enc) {
|
||||
#if !defined(WEBP_DISABLE_STATS)
|
||||
WebPAuxStats* const stats = enc->pic_->stats;
|
||||
if (stats != NULL) {
|
||||
int i, s;
|
||||
for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
|
||||
stats->segment_level[i] = enc->dqm_[i].fstrength_;
|
||||
stats->segment_quant[i] = enc->dqm_[i].quant_;
|
||||
for (s = 0; s <= 2; ++s) {
|
||||
stats->residual_bytes[s][i] = enc->residual_bytes_[s][i];
|
||||
}
|
||||
}
|
||||
FinalizePSNR(enc);
|
||||
stats->coded_size = enc->coded_size_;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
stats->block_count[i] = enc->block_count_[i];
|
||||
}
|
||||
}
|
||||
#else // defined(WEBP_DISABLE_STATS)
|
||||
WebPReportProgress(enc->pic_, 100, &enc->percent_); // done!
|
||||
#endif // !defined(WEBP_DISABLE_STATS)
|
||||
}
|
||||
|
||||
int WebPEncodingSetError(const WebPPicture* const pic,
|
||||
WebPEncodingError error) {
|
||||
assert((int)error < VP8_ENC_ERROR_LAST);
|
||||
assert((int)error >= VP8_ENC_OK);
|
||||
((WebPPicture*)pic)->error_code = error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebPReportProgress(const WebPPicture* const pic,
|
||||
int percent, int* const percent_store) {
|
||||
if (percent_store != NULL && percent != *percent_store) {
|
||||
*percent_store = percent;
|
||||
if (pic->progress_hook && !pic->progress_hook(percent, pic)) {
|
||||
// user abort requested
|
||||
WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1; // ok
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
|
||||
int ok = 0;
|
||||
if (pic == NULL) return 0;
|
||||
|
||||
WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far
|
||||
if (config == NULL) { // bad params
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
|
||||
}
|
||||
if (!WebPValidateConfig(config)) {
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
|
||||
}
|
||||
if (pic->width <= 0 || pic->height <= 0) {
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
|
||||
}
|
||||
if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) {
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
|
||||
}
|
||||
|
||||
if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats));
|
||||
|
||||
if (!config->lossless) {
|
||||
VP8Encoder* enc = NULL;
|
||||
|
||||
if (pic->use_argb || pic->y == NULL || pic->u == NULL || pic->v == NULL) {
|
||||
// Make sure we have YUVA samples.
|
||||
if (config->use_sharp_yuv || (config->preprocessing & 4)) {
|
||||
if (!WebPPictureSharpARGBToYUVA(pic)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
float dithering = 0.f;
|
||||
if (config->preprocessing & 2) {
|
||||
const float x = config->quality / 100.f;
|
||||
const float x2 = x * x;
|
||||
// slowly decreasing from max dithering at low quality (q->0)
|
||||
// to 0.5 dithering amplitude at high quality (q->100)
|
||||
dithering = 1.0f + (0.5f - 1.0f) * x2 * x2;
|
||||
}
|
||||
if (!WebPPictureARGBToYUVADithered(pic, WEBP_YUV420, dithering)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!config->exact) {
|
||||
WebPCleanupTransparentArea(pic);
|
||||
}
|
||||
|
||||
enc = InitVP8Encoder(config, pic);
|
||||
if (enc == NULL) return 0; // pic->error is already set.
|
||||
// Note: each of the tasks below account for 20% in the progress report.
|
||||
ok = VP8EncAnalyze(enc);
|
||||
|
||||
// Analysis is done, proceed to actual coding.
|
||||
ok = ok && VP8EncStartAlpha(enc); // possibly done in parallel
|
||||
if (!enc->use_tokens_) {
|
||||
ok = ok && VP8EncLoop(enc);
|
||||
} else {
|
||||
ok = ok && VP8EncTokenLoop(enc);
|
||||
}
|
||||
ok = ok && VP8EncFinishAlpha(enc);
|
||||
|
||||
ok = ok && VP8EncWrite(enc);
|
||||
StoreStats(enc);
|
||||
if (!ok) {
|
||||
VP8EncFreeBitWriters(enc);
|
||||
}
|
||||
ok &= DeleteVP8Encoder(enc); // must always be called, even if !ok
|
||||
} else {
|
||||
// Make sure we have ARGB samples.
|
||||
if (pic->argb == NULL && !WebPPictureYUVAToARGB(pic)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!config->exact) {
|
||||
WebPCleanupTransparentAreaLossless(pic);
|
||||
}
|
||||
|
||||
ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem.
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
Reference in New Issue
Block a user