summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS5
-rw-r--r--CHANGELOG24
-rw-r--r--README4
-rw-r--r--build/make/Makefile4
-rw-r--r--build/make/configure.sh49
-rwxr-xr-xbuild/make/rtcd.pl35
-rwxr-xr-xconfigure2
-rw-r--r--examples/vp9_spatial_svc_encoder.c18
-rw-r--r--examples/vpx_temporal_svc_encoder.c2
-rw-r--r--libs.mk12
-rw-r--r--test/android/README2
-rw-r--r--test/avg_test.cc2
-rw-r--r--test/dct16x16_test.cc1
-rw-r--r--test/encode_test_driver.cc2
-rw-r--r--test/encode_test_driver.h7
-rw-r--r--test/fdct8x8_test.cc1
-rw-r--r--test/lpf_test.cc2
-rw-r--r--test/quantize_test.cc1
-rw-r--r--test/ratectrl_rtc_test.cc8
-rw-r--r--test/resize_test.cc4
-rwxr-xr-xtest/stress.sh2
-rw-r--r--test/sum_squares_test.cc1
-rw-r--r--test/svc_end_to_end_test.cc179
-rw-r--r--test/svc_test.cc13
-rw-r--r--test/test-data.mk4
-rw-r--r--test/test-data.sha12
-rw-r--r--test/test.mk1
-rw-r--r--test/variance_test.cc1
-rw-r--r--test/vp9_block_error_test.cc1
-rw-r--r--test/vp9_denoiser_test.cc1
-rw-r--r--test/vp9_ext_ratectrl_test.cc192
-rw-r--r--test/vp9_intrapred_test.cc2
-rw-r--r--third_party/googletest/README.libvpx2
-rw-r--r--third_party/googletest/src/src/gtest.cc4
-rw-r--r--vp8/common/generic/systemdependent.c4
-rw-r--r--vp8/common/threading.h15
-rw-r--r--vp9/common/vp9_onyxc_int.h12
-rw-r--r--vp9/encoder/vp9_encoder.c189
-rw-r--r--vp9/encoder/vp9_encoder.h46
-rw-r--r--vp9/encoder/vp9_ext_ratectrl.c151
-rw-r--r--vp9/encoder/vp9_ext_ratectrl.h48
-rw-r--r--vp9/encoder/vp9_firstpass.c4
-rw-r--r--vp9/encoder/vp9_ratectrl.c9
-rw-r--r--vp9/encoder/vp9_ratectrl.h3
-rw-r--r--vp9/encoder/vp9_speed_features.c4
-rw-r--r--vp9/encoder/vp9_svc_layercontext.c1
-rw-r--r--vp9/encoder/vp9_svc_layercontext.h1
-rw-r--r--vp9/simple_encode.cc150
-rw-r--r--vp9/simple_encode.h86
-rw-r--r--vp9/vp9_cx_iface.c179
-rw-r--r--vp9/vp9_cx_iface.h2
-rw-r--r--vp9/vp9cx.mk2
-rw-r--r--vpx/vp8cx.h37
-rw-r--r--vpx/vpx_codec.mk2
-rw-r--r--vpx/vpx_encoder.h5
-rw-r--r--vpx/vpx_ext_ratectrl.h353
-rw-r--r--vpx_ports/mips.h27
-rw-r--r--vpx_ports/mips_cpudetect.c57
-rw-r--r--vpx_ports/vpx_ports.mk3
-rw-r--r--vpxenc.c12
60 files changed, 1774 insertions, 218 deletions
diff --git a/AUTHORS b/AUTHORS
index ab11bfdd7..352c91fed 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -25,6 +25,7 @@ Angie Chiang <angiebird@google.com>
Aron Rosenberg <arosenberg@logitech.com>
Attila Nagy <attilanagy@google.com>
Birk Magnussen <birk.magnussen@googlemail.com>
+Brian Foley <bpfoley@google.com>
Brion Vibber <bvibber@wikimedia.org>
changjun.yang <changjun.yang@intel.com>
Charles 'Buck' Krasic <ckrasic@google.com>
@@ -33,6 +34,7 @@ Chi Yo Tsai <chiyotsai@google.com>
chm <chm@rock-chips.com>
Chris Cunningham <chcunningham@chromium.org>
Christian Duvivier <cduvivier@google.com>
+Clement Courbet <courbet@google.com>
Daniele Castagna <dcastagna@chromium.org>
Daniel Kang <ddkang@google.com>
Dan Zhu <zxdan@google.com>
@@ -91,6 +93,7 @@ John Koleszar <jkoleszar@google.com>
Johnny Klonaris <google@jawknee.com>
John Stark <jhnstrk@gmail.com>
Jon Kunkee <jkunkee@microsoft.com>
+Jorge E. Moreira <jemoreira@google.com>
Joshua Bleecher Snyder <josh@treelinelabs.com>
Joshua Litt <joshualitt@google.com>
Julia Robson <juliamrobson@gmail.com>
@@ -125,6 +128,7 @@ Mirko Bonadei <mbonadei@google.com>
Moriyoshi Koizumi <mozo@mozo.jp>
Morton Jonuschat <yabawock@gmail.com>
Nathan E. Egge <negge@mozilla.com>
+Neil Birkbeck <neil.birkbeck@gmail.com>
Nico Weber <thakis@chromium.org>
Niveditha Rau <niveditha.rau@gmail.com>
Parag Salasakar <img.mips1@gmail.com>
@@ -186,6 +190,7 @@ Vignesh Venkatasubramanian <vigneshv@google.com>
Vitaly Buka <vitalybuka@chromium.org>
Vlad Tsyrklevich <vtsyrklevich@chromium.org>
Wan-Teh Chang <wtc@google.com>
+Wonkap Jang <wonkap@google.com>
xiwei gu <guxiwei-hf@loongson.cn>
Yaowu Xu <yaowu@google.com>
Yi Luo <luoyi@google.com>
diff --git a/CHANGELOG b/CHANGELOG
index 345d3dc4d..e731fc612 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,27 @@
+2020-07-29 v1.9.0 "Quacking Duck"
+ This release adds support for NV12, a separate library for rate control, as
+ well as incremental improvements.
+
+ - Upgrading:
+ NV12 support is added to this release.
+ A new interface is added for VP9 rate control. The new library libvp9rc.a
+ must be linked by applications.
+ Googletest is updated to v1.10.0.
+ simple_encode.cc is compiled into a new library libsimple_encode.a with
+ CONFIG_RATE_CTRL.
+
+ - Enhancement:
+ Various changes to improve VP9 SVC, rate control, quality and speed to real
+ time encoding.
+
+ - Bug fixes:
+ Fix key frame update refresh simulcast flexible svc.
+ Fix to disable_16x16part speed feature for real time encoding.
+ Fix some signed integer overflows for VP9 rate control.
+ Fix initialization of delta_q_uv.
+ Fix condition in regulate_q for cyclic refresh.
+ Various fixes to dynamic resizing for VP9 SVC.
+
2019-12-09 v1.8.2 "Pekin Duck"
This release collects incremental improvements to many aspects of the library.
diff --git a/README b/README
index 45beda714..62fef3459 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-README - 9 December 2019
+README - 20 July 2020
Welcome to the WebM VP8/VP9 Codec SDK!
@@ -62,6 +62,7 @@ COMPILING THE APPLICATIONS/LIBRARIES:
arm64-android-gcc
arm64-darwin-gcc
+ arm64-darwin20-gcc
arm64-linux-gcc
arm64-win64-gcc
arm64-win64-vs15
@@ -113,6 +114,7 @@ COMPILING THE APPLICATIONS/LIBRARIES:
x86_64-darwin17-gcc
x86_64-darwin18-gcc
x86_64-darwin19-gcc
+ x86_64-darwin20-gcc
x86_64-iphonesimulator-gcc
x86_64-linux-gcc
x86_64-linux-icc
diff --git a/build/make/Makefile b/build/make/Makefile
index be2810229..9ca97c8c6 100644
--- a/build/make/Makefile
+++ b/build/make/Makefile
@@ -147,6 +147,10 @@ $(BUILD_PFX)%_avx512.c.o: CFLAGS += -mavx512f -mavx512cd -mavx512bw -mavx512dq -
$(BUILD_PFX)%_vsx.c.d: CFLAGS += -maltivec -mvsx
$(BUILD_PFX)%_vsx.c.o: CFLAGS += -maltivec -mvsx
+# MIPS
+$(BUILD_PFX)%_msa.c.d: CFLAGS += -mmsa
+$(BUILD_PFX)%_msa.c.o: CFLAGS += -mmsa
+
$(BUILD_PFX)%.c.d: %.c
$(if $(quiet),@echo " [DEP] $@")
$(qexec)mkdir -p $(dir $@)
diff --git a/build/make/configure.sh b/build/make/configure.sh
index 206b54f77..91a64b504 100644
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -262,6 +262,9 @@ if [ -z "$source_path" ] || [ "$source_path" = "." ]; then
source_path="`pwd`"
disable_feature source_path_used
fi
+# Makefiles greedily process the '#' character as a comment, even if it is
+# inside quotes. So, this character must be escaped in all paths in Makefiles.
+source_path_mk=$(echo $source_path | sed -e 's;\#;\\\#;g')
if test ! -z "$TMPDIR" ; then
TMPDIRx="${TMPDIR}"
@@ -481,11 +484,11 @@ write_common_target_config_mk() {
cat >> $1 << EOF
# This file automatically generated by configure. Do not edit!
-SRC_PATH="$source_path"
-SRC_PATH_BARE=$source_path
+SRC_PATH="$source_path_mk"
+SRC_PATH_BARE=$source_path_mk
BUILD_PFX=${BUILD_PFX}
TOOLCHAIN=${toolchain}
-ASM_CONVERSION=${asm_conversion_cmd:-${source_path}/build/make/ads2gas.pl}
+ASM_CONVERSION=${asm_conversion_cmd:-${source_path_mk}/build/make/ads2gas.pl}
GEN_VCPROJ=${gen_vcproj_cmd}
MSVS_ARCH_DIR=${msvs_arch_dir}
@@ -771,6 +774,10 @@ process_common_toolchain() {
tgt_isa=x86_64
tgt_os=`echo $gcctarget | sed 's/.*\(darwin1[0-9]\).*/\1/'`
;;
+ *darwin20*)
+ tgt_isa=`uname -m`
+ tgt_os=`echo $gcctarget | sed 's/.*\(darwin2[0-9]\).*/\1/'`
+ ;;
x86_64*mingw32*)
tgt_os=win64
;;
@@ -845,7 +852,7 @@ process_common_toolchain() {
# Handle darwin variants. Newer SDKs allow targeting older
# platforms, so use the newest one available.
case ${toolchain} in
- arm*-darwin*)
+ arm*-darwin-*)
add_cflags "-miphoneos-version-min=${IOS_VERSION_MIN}"
iphoneos_sdk_dir="$(show_darwin_sdk_path iphoneos)"
if [ -d "${iphoneos_sdk_dir}" ]; then
@@ -853,7 +860,7 @@ process_common_toolchain() {
add_ldflags "-isysroot ${iphoneos_sdk_dir}"
fi
;;
- x86*-darwin*)
+ *-darwin*)
osx_sdk_dir="$(show_darwin_sdk_path macosx)"
if [ -d "${osx_sdk_dir}" ]; then
add_cflags "-isysroot ${osx_sdk_dir}"
@@ -911,6 +918,10 @@ process_common_toolchain() {
add_cflags "-mmacosx-version-min=10.15"
add_ldflags "-mmacosx-version-min=10.15"
;;
+ *-darwin20-*)
+ add_cflags "-mmacosx-version-min=10.16"
+ add_ldflags "-mmacosx-version-min=10.16"
+ ;;
*-iphonesimulator-*)
add_cflags "-miphoneos-version-min=${IOS_VERSION_MIN}"
add_ldflags "-miphoneos-version-min=${IOS_VERSION_MIN}"
@@ -984,7 +995,7 @@ EOF
fi
enabled debug && add_asflags -g
- asm_conversion_cmd="${source_path}/build/make/ads2gas.pl"
+ asm_conversion_cmd="${source_path_mk}/build/make/ads2gas.pl"
case ${tgt_os} in
win*)
@@ -1006,7 +1017,7 @@ EOF
# respective SDKs' limitations. Fortunately, these are all 32-bit ABIs
# and so can be selected as 'win32'.
if [ ${tgt_os} = "win32" ]; then
- asm_conversion_cmd="${source_path}/build/make/ads2armasm_ms.pl"
+ asm_conversion_cmd="${source_path_mk}/build/make/ads2armasm_ms.pl"
AS_SFX=.S
msvs_arch_dir=arm-msvs
disable_feature multithread
@@ -1084,7 +1095,7 @@ EOF
soft_enable unit_tests
;;
- darwin*)
+ darwin)
if ! enabled external_build; then
XCRUN_FIND="xcrun --sdk iphoneos --find"
CXX="$(${XCRUN_FIND} clang++)"
@@ -1141,7 +1152,7 @@ EOF
fi
fi
- asm_conversion_cmd="${source_path}/build/make/ads2gas_apple.pl"
+ asm_conversion_cmd="${source_path_mk}/build/make/ads2gas_apple.pl"
;;
linux*)
@@ -1195,25 +1206,27 @@ EOF
check_add_asflags -mips64r6 -mabi=64 -mhard-float -mfp64
check_add_ldflags -mips64r6 -mabi=64 -mfp64
;;
+ loongson3*)
+ check_cflags -march=loongson3a && soft_enable mmi \
+ || disable_feature mmi
+ check_cflags -mmsa && soft_enable msa \
+ || disable_feature msa
+ tgt_isa=loongson3a
+ ;;
esac
+ if enabled mmi || enabled msa; then
+ soft_enable runtime_cpu_detect
+ fi
+
if enabled msa; then
# TODO(libyuv:793)
# The new mips functions in libyuv do not build
# with the toolchains we currently use for testing.
soft_disable libyuv
-
- add_cflags -mmsa
- add_asflags -mmsa
- add_ldflags -mmsa
fi
fi
- if enabled mmi; then
- tgt_isa=loongson3a
- check_add_ldflags -march=loongson3a
- fi
-
check_add_cflags -march=${tgt_isa}
check_add_asflags -march=${tgt_isa}
check_add_asflags -KPIC
diff --git a/build/make/rtcd.pl b/build/make/rtcd.pl
index 748320041..acb9f6e46 100755
--- a/build/make/rtcd.pl
+++ b/build/make/rtcd.pl
@@ -315,14 +315,26 @@ EOF
sub mips() {
determine_indirection("c", @ALL_ARCHS);
+
+ # Assign the helper variable for each enabled extension
+ foreach my $opt (@ALL_ARCHS) {
+ my $opt_uc = uc $opt;
+ eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
+ }
+
common_top;
print <<EOF;
#include "vpx_config.h"
#ifdef RTCD_C
+#include "vpx_ports/mips.h"
static void setup_rtcd_internal(void)
{
+ int flags = mips_cpu_caps();
+
+ (void)flags;
+
EOF
set_function_pointers("c", @ALL_ARCHS);
@@ -410,24 +422,35 @@ if ($opts{arch} eq 'x86') {
&require(@REQUIRES);
x86;
} elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') {
+ my $have_dspr2 = 0;
+ my $have_msa = 0;
+ my $have_mmi = 0;
@ALL_ARCHS = filter("$opts{arch}");
open CONFIG_FILE, $opts{config} or
die "Error opening config file '$opts{config}': $!\n";
while (<CONFIG_FILE>) {
if (/HAVE_DSPR2=yes/) {
- @ALL_ARCHS = filter("$opts{arch}", qw/dspr2/);
- last;
+ $have_dspr2 = 1;
}
if (/HAVE_MSA=yes/) {
- @ALL_ARCHS = filter("$opts{arch}", qw/msa/);
- last;
+ $have_msa = 1;
}
if (/HAVE_MMI=yes/) {
- @ALL_ARCHS = filter("$opts{arch}", qw/mmi/);
- last;
+ $have_mmi = 1;
}
}
close CONFIG_FILE;
+ if ($have_dspr2 == 1) {
+ @ALL_ARCHS = filter("$opts{arch}", qw/dspr2/);
+ } elsif ($have_msa == 1 && $have_mmi == 1) {
+ @ALL_ARCHS = filter("$opts{arch}", qw/mmi msa/);
+ } elsif ($have_msa == 1) {
+ @ALL_ARCHS = filter("$opts{arch}", qw/msa/);
+ } elsif ($have_mmi == 1) {
+ @ALL_ARCHS = filter("$opts{arch}", qw/mmi/);
+ } else {
+ unoptimized;
+ }
mips;
} elsif ($opts{arch} =~ /armv7\w?/) {
@ALL_ARCHS = filter(qw/neon_asm neon/);
diff --git a/configure b/configure
index 32272ce36..f7e11aaf2 100755
--- a/configure
+++ b/configure
@@ -99,6 +99,7 @@ EOF
# alphabetically by architecture, generic-gnu last.
all_platforms="${all_platforms} arm64-android-gcc"
all_platforms="${all_platforms} arm64-darwin-gcc"
+all_platforms="${all_platforms} arm64-darwin20-gcc"
all_platforms="${all_platforms} arm64-linux-gcc"
all_platforms="${all_platforms} arm64-win64-gcc"
all_platforms="${all_platforms} arm64-win64-vs15"
@@ -150,6 +151,7 @@ all_platforms="${all_platforms} x86_64-darwin16-gcc"
all_platforms="${all_platforms} x86_64-darwin17-gcc"
all_platforms="${all_platforms} x86_64-darwin18-gcc"
all_platforms="${all_platforms} x86_64-darwin19-gcc"
+all_platforms="${all_platforms} x86_64-darwin20-gcc"
all_platforms="${all_platforms} x86_64-iphonesimulator-gcc"
all_platforms="${all_platforms} x86_64-linux-gcc"
all_platforms="${all_platforms} x86_64-linux-icc"
diff --git a/examples/vp9_spatial_svc_encoder.c b/examples/vp9_spatial_svc_encoder.c
index b987989a8..630557297 100644
--- a/examples/vp9_spatial_svc_encoder.c
+++ b/examples/vp9_spatial_svc_encoder.c
@@ -828,12 +828,15 @@ static void svc_output_rc_stats(
vpx_codec_control(codec, VP9E_GET_SVC_LAYER_ID, layer_id);
parse_superframe_index(cx_pkt->data.frame.buf, cx_pkt->data.frame.sz,
sizes_parsed, &count);
- if (enc_cfg->ss_number_layers == 1) sizes[0] = cx_pkt->data.frame.sz;
- for (sl = 0; sl < enc_cfg->ss_number_layers; ++sl) {
- sizes[sl] = 0;
- if (cx_pkt->data.frame.spatial_layer_encoded[sl]) {
- sizes[sl] = sizes_parsed[num_layers_encoded];
- num_layers_encoded++;
+ if (enc_cfg->ss_number_layers == 1) {
+ sizes[0] = cx_pkt->data.frame.sz;
+ } else {
+ for (sl = 0; sl < enc_cfg->ss_number_layers; ++sl) {
+ sizes[sl] = 0;
+ if (cx_pkt->data.frame.spatial_layer_encoded[sl]) {
+ sizes[sl] = sizes_parsed[num_layers_encoded];
+ num_layers_encoded++;
+ }
}
}
for (sl = 0; sl < enc_cfg->ss_number_layers; ++sl) {
@@ -1050,6 +1053,9 @@ int main(int argc, const char **argv) {
vpx_codec_control(&encoder, VP9E_SET_TUNE_CONTENT, app_input.tune_content);
+ vpx_codec_control(&encoder, VP9E_SET_DISABLE_OVERSHOOT_MAXQ_CBR, 0);
+ vpx_codec_control(&encoder, VP9E_SET_DISABLE_LOOPFILTER, 0);
+
svc_drop_frame.framedrop_mode = FULL_SUPERFRAME_DROP;
for (sl = 0; sl < (unsigned int)svc_ctx.spatial_layers; ++sl)
svc_drop_frame.framedrop_thresh[sl] = enc_cfg.rc_dropframe_thresh;
diff --git a/examples/vpx_temporal_svc_encoder.c b/examples/vpx_temporal_svc_encoder.c
index 872751cef..ffeae2abc 100644
--- a/examples/vpx_temporal_svc_encoder.c
+++ b/examples/vpx_temporal_svc_encoder.c
@@ -831,6 +831,7 @@ int main(int argc, char **argv) {
} else if (strncmp(encoder->name, "vp9", 3) == 0) {
vpx_svc_extra_cfg_t svc_params;
memset(&svc_params, 0, sizeof(svc_params));
+ vpx_codec_control(&codec, VP9E_SET_DISABLE_OVERSHOOT_MAXQ_CBR, 0);
vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed);
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
vpx_codec_control(&codec, VP9E_SET_GF_CBR_BOOST_PCT, 0);
@@ -840,6 +841,7 @@ int main(int argc, char **argv) {
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
vpx_codec_control(&codec, VP9E_SET_TUNE_CONTENT, 0);
vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, get_msb(cfg.g_threads));
+ vpx_codec_control(&codec, VP9E_SET_DISABLE_LOOPFILTER, 0);
#if ROI_MAP
set_roi_map(encoder->name, &cfg, &roi);
if (vpx_codec_control(&codec, VP9E_SET_ROI_MAP, &roi))
diff --git a/libs.mk b/libs.mk
index 6362418e5..b5bc35755 100644
--- a/libs.mk
+++ b/libs.mk
@@ -63,6 +63,7 @@ ifeq ($(CONFIG_VP8_ENCODER),yes)
CODEC_SRCS-yes += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_CX_SRCS))
CODEC_EXPORTS-yes += $(addprefix $(VP8_PREFIX),$(VP8_CX_EXPORTS))
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h
+ INSTALL-LIBS-yes += include/vpx/vpx_ext_ratectrl.h
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP8_PREFIX)/%
CODEC_DOC_SECTIONS += vp8 vp8_encoder
endif
@@ -87,13 +88,16 @@ ifeq ($(CONFIG_VP9_ENCODER),yes)
CODEC_SRCS-yes += $(addprefix $(VP9_PREFIX),$(call enabled,VP9_CX_SRCS))
CODEC_EXPORTS-yes += $(addprefix $(VP9_PREFIX),$(VP9_CX_EXPORTS))
CODEC_SRCS-yes += $(VP9_PREFIX)vp9cx.mk vpx/vp8.h vpx/vp8cx.h
+ CODEC_SRCS-yes += vpx/vpx_ext_ratectrl.h
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h
+ INSTALL-LIBS-yes += include/vpx/vpx_ext_ratectrl.h
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/%
- CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h
+ CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h vpx/vpx_ext_ratectrl.h
CODEC_DOC_SECTIONS += vp9 vp9_encoder
RC_RTC_SRCS := $(addprefix $(VP9_PREFIX),$(call enabled,VP9_CX_SRCS))
RC_RTC_SRCS += $(VP9_PREFIX)vp9cx.mk vpx/vp8.h vpx/vp8cx.h
+ RC_RTC_SRCS += vpx/vpx_ext_ratectrl.h
RC_RTC_SRCS += $(VP9_PREFIX)ratectrl_rtc.cc
RC_RTC_SRCS += $(VP9_PREFIX)ratectrl_rtc.h
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)ratectrl_rtc.cc
@@ -282,7 +286,7 @@ LIBS-$(if yes,$(CONFIG_STATIC)) += $(BUILD_PFX)libvpx.a $(BUILD_PFX)libvpx_g.a
$(BUILD_PFX)libvpx_g.a: $(LIBVPX_OBJS)
SO_VERSION_MAJOR := 6
-SO_VERSION_MINOR := 2
+SO_VERSION_MINOR := 3
SO_VERSION_PATCH := 0
ifeq ($(filter darwin%,$(TGT_OS)),$(TGT_OS))
LIBVPX_SO := libvpx.$(SO_VERSION_MAJOR).dylib
@@ -416,13 +420,13 @@ ifeq ($(VPX_ARCH_X86)$(VPX_ARCH_X86_64),yes)
# YASM
$(BUILD_PFX)vpx_config.asm: $(BUILD_PFX)vpx_config.h
@echo " [CREATE] $@"
- @egrep "#define [A-Z0-9_]+ [01]" $< \
+ @LC_ALL=C egrep "#define [A-Z0-9_]+ [01]" $< \
| awk '{print $$2 " equ " $$3}' > $@
else
ADS2GAS=$(if $(filter yes,$(CONFIG_GCC)),| $(ASM_CONVERSION))
$(BUILD_PFX)vpx_config.asm: $(BUILD_PFX)vpx_config.h
@echo " [CREATE] $@"
- @egrep "#define [A-Z0-9_]+ [01]" $< \
+ @LC_ALL=C egrep "#define [A-Z0-9_]+ [01]" $< \
| awk '{print $$2 " EQU " $$3}' $(ADS2GAS) > $@
@echo " END" $(ADS2GAS) >> $@
CLEAN-OBJS += $(BUILD_PFX)vpx_config.asm
diff --git a/test/android/README b/test/android/README
index f67fea50c..0cd30779d 100644
--- a/test/android/README
+++ b/test/android/README
@@ -16,7 +16,7 @@ Note: Both adb and ndk-build are available at:
3) Run get_files.py to download the test files:
python get_files.py -i /path/to/test-data.sha1 -o /path/to/put/files \
- -u http://downloads.webmproject.org/test_data/libvpx
+ -u https://storage.googleapis.com/downloads.webmproject.org/test_data/libvpx
4) Transfer files to device using adb. Ensure you have proper permissions for
the target
diff --git a/test/avg_test.cc b/test/avg_test.cc
index 4bc1944b1..196522ce5 100644
--- a/test/avg_test.cc
+++ b/test/avg_test.cc
@@ -202,6 +202,7 @@ class IntProRowTest : public AverageTestBase<uint8_t>,
int16_t *hbuf_asm_;
int16_t *hbuf_c_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IntProRowTest);
typedef int16_t (*IntProColFunc)(uint8_t const *ref, const int width);
@@ -228,6 +229,7 @@ class IntProColTest : public AverageTestBase<uint8_t>,
int16_t sum_asm_;
int16_t sum_c_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IntProColTest);
#endif // HAVE_NEON || HAVE_SSE2 || HAVE_MSA
typedef int (*SatdFunc)(const tran_low_t *coeffs, int length);
diff --git a/test/dct16x16_test.cc b/test/dct16x16_test.cc
index 321c66e4e..c04880ec9 100644
--- a/test/dct16x16_test.cc
+++ b/test/dct16x16_test.cc
@@ -740,6 +740,7 @@ class InvTrans16x16DCT : public Trans16x16TestBase,
IdctFunc inv_txfm_;
int thresh_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InvTrans16x16DCT);
TEST_P(InvTrans16x16DCT, CompareReference) {
CompareInvReference(ref_txfm_, thresh_);
diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc
index 6914804ec..1ce39eaef 100644
--- a/test/encode_test_driver.cc
+++ b/test/encode_test_driver.cc
@@ -216,7 +216,7 @@ void EncoderTest::RunLoop(VideoSource *video) {
switch (pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT:
has_cxdata = true;
- if (decoder.get() != nullptr && DoDecode()) {
+ if (decoder != nullptr && DoDecode()) {
PreDecodeFrameHook(video, decoder.get());
vpx_codec_err_t res_dec = decoder->DecodeFrame(
(const uint8_t *)pkt->data.frame.buf, pkt->data.frame.sz);
diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h
index 3edba4b92..38c61952e 100644
--- a/test/encode_test_driver.h
+++ b/test/encode_test_driver.h
@@ -148,6 +148,13 @@ class Encoder {
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
+#if CONFIG_VP9_ENCODER
+ void Control(int ctrl_id, vpx_rc_funcs_t *arg) {
+ const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
+ ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
+ }
+#endif // CONFIG_VP9_ENCODER
+
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
void Control(int ctrl_id, vpx_active_map_t *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
diff --git a/test/fdct8x8_test.cc b/test/fdct8x8_test.cc
index 770337da0..0822666e7 100644
--- a/test/fdct8x8_test.cc
+++ b/test/fdct8x8_test.cc
@@ -625,6 +625,7 @@ class InvTrans8x8DCT : public FwdTrans8x8TestBase,
IdctFunc inv_txfm_;
int thresh_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InvTrans8x8DCT);
TEST_P(InvTrans8x8DCT, CompareReference) {
CompareInvReference(ref_txfm_, thresh_);
diff --git a/test/lpf_test.cc b/test/lpf_test.cc
index 2c632a5a8..62c6f30a0 100644
--- a/test/lpf_test.cc
+++ b/test/lpf_test.cc
@@ -145,6 +145,7 @@ class Loop8Test6Param : public ::testing::TestWithParam<loop8_param_t> {
loop_op_t loopfilter_op_;
loop_op_t ref_loopfilter_op_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Loop8Test6Param);
#if HAVE_NEON || HAVE_SSE2 || \
(HAVE_DSPR2 || HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH)
@@ -166,6 +167,7 @@ class Loop8Test9Param : public ::testing::TestWithParam<dualloop8_param_t> {
dual_loop_op_t loopfilter_op_;
dual_loop_op_t ref_loopfilter_op_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Loop8Test9Param);
#endif // HAVE_NEON || HAVE_SSE2 || (HAVE_DSPR2 || HAVE_MSA &&
// (!CONFIG_VP9_HIGHBITDEPTH))
diff --git a/test/quantize_test.cc b/test/quantize_test.cc
index b30b90f8f..792b21432 100644
--- a/test/quantize_test.cc
+++ b/test/quantize_test.cc
@@ -146,6 +146,7 @@ class QuantizeTest : public QuantizeTestBase,
VP8Quantize asm_quant_;
VP8Quantize c_quant_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(QuantizeTest);
TEST_P(QuantizeTest, TestZeroInput) {
FillCoeffConstant(0);
diff --git a/test/ratectrl_rtc_test.cc b/test/ratectrl_rtc_test.cc
index e044885e7..3a1c8469e 100644
--- a/test/ratectrl_rtc_test.cc
+++ b/test/ratectrl_rtc_test.cc
@@ -79,7 +79,7 @@ class RcInterfaceTest : public ::testing::Test {
protected:
void RunOneLayer() {
SetConfigOneLayer();
- rc_api_->Create(rc_cfg_);
+ rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
FrameInfo frame_info;
libvpx::VP9FrameParamsQpRTC frame_params;
frame_params.frame_type = KEY_FRAME;
@@ -88,7 +88,7 @@ class RcInterfaceTest : public ::testing::Test {
std::ifstream one_layer_file;
one_layer_file.open(libvpx_test::GetDataPath() +
"/rc_interface_test_one_layer");
- ASSERT_EQ(one_layer_file.rdstate() & std::ifstream::failbit, 0);
+ ASSERT_TRUE(one_layer_file.good());
for (size_t i = 0; i < kNumFrame; i++) {
one_layer_file >> frame_info;
if (frame_info.frame_id > 0) frame_params.frame_type = INTER_FRAME;
@@ -110,14 +110,14 @@ class RcInterfaceTest : public ::testing::Test {
void RunSVC() {
SetConfigSVC();
- rc_api_->Create(rc_cfg_);
+ rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
FrameInfo frame_info;
libvpx::VP9FrameParamsQpRTC frame_params;
frame_params.frame_type = KEY_FRAME;
std::ifstream svc_file;
svc_file.open(std::string(std::getenv("LIBVPX_TEST_DATA_PATH")) +
"/rc_interface_test_svc");
- ASSERT_EQ(svc_file.rdstate() & std::ifstream::failbit, 0);
+ ASSERT_TRUE(svc_file.good());
for (size_t i = 0; i < kNumFrame * rc_cfg_.ss_number_layers; i++) {
svc_file >> frame_info;
if (frame_info.frame_id > 0) frame_params.frame_type = INTER_FRAME;
diff --git a/test/resize_test.cc b/test/resize_test.cc
index 65b94fa4f..c57170ff9 100644
--- a/test/resize_test.cc
+++ b/test/resize_test.cc
@@ -271,8 +271,8 @@ class ResizingVideoSource : public ::libvpx_test::DummyVideoSource {
protected:
virtual void Next() {
++frame_;
- unsigned int width;
- unsigned int height;
+ unsigned int width = 0;
+ unsigned int height = 0;
ScaleForFrameNumber(frame_, kInitialWidth, kInitialHeight, &width, &height,
flag_codec_, smaller_width_larger_size_);
SetSize(width, height);
diff --git a/test/stress.sh b/test/stress.sh
index b11c658a9..ba79a52ac 100755
--- a/test/stress.sh
+++ b/test/stress.sh
@@ -18,7 +18,7 @@
YUV="${LIBVPX_TEST_DATA_PATH}/niklas_1280_720_30.yuv"
VP8="${LIBVPX_TEST_DATA_PATH}/tos_vp8.webm"
VP9="${LIBVPX_TEST_DATA_PATH}/vp90-2-sintel_1920x818_tile_1x4_fpm_2279kbps.webm"
-DATA_URL="http://downloads.webmproject.org/test_data/libvpx/"
+DATA_URL="https://storage.googleapis.com/downloads.webmproject.org/test_data/libvpx/"
SHA1_FILE="$(dirname $0)/test-data.sha1"
# Set sha1sum to proper sha program (sha1sum, shasum, sha1). This code is
diff --git a/test/sum_squares_test.cc b/test/sum_squares_test.cc
index a47f5b5b1..df6da8403 100644
--- a/test/sum_squares_test.cc
+++ b/test/sum_squares_test.cc
@@ -45,6 +45,7 @@ class SumSquaresTest : public ::testing::TestWithParam<SumSquaresParam> {
SSI16Func ref_func_;
SSI16Func tst_func_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SumSquaresTest);
TEST_P(SumSquaresTest, OperationCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
diff --git a/test/svc_end_to_end_test.cc b/test/svc_end_to_end_test.cc
index edd4c887f..518824d03 100644
--- a/test/svc_end_to_end_test.cc
+++ b/test/svc_end_to_end_test.cc
@@ -121,7 +121,8 @@ class SyncFrameOnePassCbrSvc : public OnePassCbrSvc,
frame_to_start_decode_(0), frame_to_sync_(0),
inter_layer_pred_mode_(GET_PARAM(1)), decode_to_layer_before_sync_(-1),
decode_to_layer_after_sync_(-1), denoiser_on_(0),
- intra_only_test_(false), mismatch_nframes_(0), num_nonref_frames_(0) {
+ intra_only_test_(false), loopfilter_off_(0), mismatch_nframes_(0),
+ num_nonref_frames_(0) {
SetMode(::libvpx_test::kRealTime);
memset(&svc_layer_sync_, 0, sizeof(svc_layer_sync_));
}
@@ -154,6 +155,8 @@ class SyncFrameOnePassCbrSvc : public OnePassCbrSvc,
// So set it here in these tess to avoid encoder-decoder
// mismatch check on color space setting.
encoder->Control(VP9E_SET_COLOR_SPACE, VPX_CS_BT_601);
+
+ encoder->Control(VP9E_SET_DISABLE_LOOPFILTER, loopfilter_off_);
}
if (video->frame() == frame_to_sync_) {
encoder->Control(VP9E_SET_SVC_SPATIAL_LAYER_SYNC, &svc_layer_sync_);
@@ -214,7 +217,10 @@ class SyncFrameOnePassCbrSvc : public OnePassCbrSvc,
int decode_to_layer_after_sync_;
int denoiser_on_;
bool intra_only_test_;
+ int loopfilter_off_;
vpx_svc_spatial_layer_sync_t svc_layer_sync_;
+ unsigned int mismatch_nframes_;
+ unsigned int num_nonref_frames_;
private:
virtual void SetConfig(const int num_temporal_layer) {
@@ -243,9 +249,6 @@ class SyncFrameOnePassCbrSvc : public OnePassCbrSvc,
cfg_.temporal_layering_mode = 1;
}
}
-
- unsigned int mismatch_nframes_;
- unsigned int num_nonref_frames_;
};
// Test for sync layer for 1 pass CBR SVC: 3 spatial layers and
@@ -470,8 +473,176 @@ TEST_P(SyncFrameOnePassCbrSvc, OnePassCbrSvc1SL3TLSyncFrameIntraOnlyQVGA) {
#endif
}
+// Params: Loopfilter modes.
+class LoopfilterOnePassCbrSvc : public OnePassCbrSvc,
+ public ::libvpx_test::CodecTestWithParam<int> {
+ public:
+ LoopfilterOnePassCbrSvc()
+ : OnePassCbrSvc(GET_PARAM(0)), loopfilter_off_(GET_PARAM(1)),
+ mismatch_nframes_(0), num_nonref_frames_(0) {
+ SetMode(::libvpx_test::kRealTime);
+ }
+
+ protected:
+ virtual ~LoopfilterOnePassCbrSvc() {}
+
+ virtual void SetUp() {
+ InitializeConfig();
+ speed_setting_ = 7;
+ }
+
+ virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
+ ::libvpx_test::Encoder *encoder) {
+ PreEncodeFrameHookSetup(video, encoder);
+ if (number_temporal_layers_ > 1 || number_spatial_layers_ > 1) {
+ // Consider 3 cases:
+ if (loopfilter_off_ == 0) {
+ // loopfilter is on for all spatial layers on every superrframe.
+ for (int i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
+ svc_params_.loopfilter_ctrl[i] = 0;
+ }
+ } else if (loopfilter_off_ == 1) {
+ // loopfilter is off for non-reference frames for all spatial layers.
+ for (int i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
+ svc_params_.loopfilter_ctrl[i] = 1;
+ }
+ } else {
+ // loopfilter is off for all SL0 frames, and off only for non-reference
+ // frames for SL > 0.
+ svc_params_.loopfilter_ctrl[0] = 2;
+ for (int i = 1; i < VPX_SS_MAX_LAYERS; ++i) {
+ svc_params_.loopfilter_ctrl[i] = 1;
+ }
+ }
+ encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_);
+ } else if (number_temporal_layers_ == 1 && number_spatial_layers_ == 1) {
+ // For non-SVC mode use the single layer control.
+ encoder->Control(VP9E_SET_DISABLE_LOOPFILTER, loopfilter_off_);
+ }
+ }
+
+ virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
+ // Keep track of number of non-reference frames, needed for mismatch check.
+ // Non-reference frames are top spatial and temporal layer frames,
+ // for TL > 0.
+ if (temporal_layer_id_ == number_temporal_layers_ - 1 &&
+ temporal_layer_id_ > 0 &&
+ pkt->data.frame.spatial_layer_encoded[number_spatial_layers_ - 1])
+ num_nonref_frames_++;
+ }
+
+ virtual void MismatchHook(const vpx_image_t * /*img1*/,
+ const vpx_image_t * /*img2*/) {
+ ++mismatch_nframes_;
+ }
+
+ virtual void SetConfig(const int /*num_temporal_layer*/) {}
+
+ int GetMismatchFrames() const { return mismatch_nframes_; }
+ int GetNonRefFrames() const { return num_nonref_frames_; }
+
+ int loopfilter_off_;
+
+ private:
+ int mismatch_nframes_;
+ int num_nonref_frames_;
+};
+
+TEST_P(LoopfilterOnePassCbrSvc, OnePassCbrSvc1SL1TLLoopfilterOff) {
+ SetSvcConfig(1, 1);
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.g_threads = 1;
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.rc_target_bitrate = 800;
+ cfg_.kf_max_dist = 9999;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.g_error_resilient = 1;
+ cfg_.ts_rate_decimator[0] = 1;
+ cfg_.temporal_layering_mode = 0;
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
+ cfg_.rc_target_bitrate = 600;
+ AssignLayerBitrates();
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+#if CONFIG_VP9_DECODER
+ if (loopfilter_off_ == 0)
+ EXPECT_EQ(GetNonRefFrames(), GetMismatchFrames());
+ else
+ EXPECT_EQ(GetMismatchFrames(), 0);
+#endif
+}
+
+TEST_P(LoopfilterOnePassCbrSvc, OnePassCbrSvc1SL3TLLoopfilterOff) {
+ SetSvcConfig(1, 3);
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.g_threads = 1;
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.rc_target_bitrate = 800;
+ cfg_.kf_max_dist = 9999;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.g_error_resilient = 1;
+ cfg_.ts_rate_decimator[0] = 4;
+ cfg_.ts_rate_decimator[1] = 2;
+ cfg_.ts_rate_decimator[2] = 1;
+ cfg_.temporal_layering_mode = 3;
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
+ cfg_.rc_target_bitrate = 600;
+ AssignLayerBitrates();
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+#if CONFIG_VP9_DECODER
+ if (loopfilter_off_ == 0)
+ EXPECT_EQ(GetNonRefFrames(), GetMismatchFrames());
+ else
+ EXPECT_EQ(GetMismatchFrames(), 0);
+#endif
+}
+
+TEST_P(LoopfilterOnePassCbrSvc, OnePassCbrSvc3SL3TLLoopfilterOff) {
+ SetSvcConfig(3, 3);
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.g_threads = 1;
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.rc_target_bitrate = 800;
+ cfg_.kf_max_dist = 9999;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.g_error_resilient = 1;
+ cfg_.ts_rate_decimator[0] = 4;
+ cfg_.ts_rate_decimator[1] = 2;
+ cfg_.ts_rate_decimator[2] = 1;
+ cfg_.temporal_layering_mode = 3;
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
+ cfg_.rc_target_bitrate = 600;
+ AssignLayerBitrates();
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+#if CONFIG_VP9_DECODER
+ if (loopfilter_off_ == 0)
+ EXPECT_EQ(GetNonRefFrames(), GetMismatchFrames());
+ else
+ EXPECT_EQ(GetMismatchFrames(), 0);
+#endif
+}
+
VP9_INSTANTIATE_TEST_SUITE(SyncFrameOnePassCbrSvc, ::testing::Range(0, 3));
+VP9_INSTANTIATE_TEST_SUITE(LoopfilterOnePassCbrSvc, ::testing::Range(0, 3));
+
INSTANTIATE_TEST_SUITE_P(
VP9, ScalePartitionOnePassCbrSvc,
::testing::Values(
diff --git a/test/svc_test.cc b/test/svc_test.cc
index 4798c7718..cbc0abe03 100644
--- a/test/svc_test.cc
+++ b/test/svc_test.cc
@@ -43,13 +43,14 @@ void OnePassCbrSvc::PreEncodeFrameHookSetup(::libvpx_test::VideoSource *video,
svc_params_.max_quantizers[i] = 63;
svc_params_.min_quantizers[i] = 0;
}
- svc_params_.speed_per_layer[0] = base_speed_setting_;
- for (int i = 1; i < VPX_SS_MAX_LAYERS; ++i) {
- svc_params_.speed_per_layer[i] = speed_setting_;
+ if (number_temporal_layers_ > 1 || number_spatial_layers_ > 1) {
+ svc_params_.speed_per_layer[0] = base_speed_setting_;
+ for (int i = 1; i < VPX_SS_MAX_LAYERS; ++i) {
+ svc_params_.speed_per_layer[i] = speed_setting_;
+ }
+ encoder->Control(VP9E_SET_SVC, 1);
+ encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_);
}
-
- encoder->Control(VP9E_SET_SVC, 1);
- encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_);
encoder->Control(VP8E_SET_CPUUSED, speed_setting_);
encoder->Control(VP9E_SET_AQ_MODE, 3);
encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 300);
diff --git a/test/test-data.mk b/test/test-data.mk
index ca2e11442..744901b11 100644
--- a/test/test-data.mk
+++ b/test/test-data.mk
@@ -27,7 +27,9 @@ LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += noisy_clip_640_360.y4m
LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rush_hour_444.y4m
LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += screendata.y4m
LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += niklas_640_480_30.yuv
-LIBVPX_TEST_DATA-$(CONFIG_RATE_CTRL) += bus_352x288_420_f20_b8.yuv
+LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rc_interface_test_one_layer
+LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rc_interface_test_svc
+LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += bus_352x288_420_f20_b8.yuv
# Test vectors
LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-001.ivf
diff --git a/test/test-data.sha1 b/test/test-data.sha1
index 668992fba..6f9021554 100644
--- a/test/test-data.sha1
+++ b/test/test-data.sha1
@@ -869,3 +869,5 @@ bac455906360b45338a16dd626ac5f19bc36a307 *desktop_office1.1280_720-020.yuv
518a0be998afece76d3df76047d51e256c591ff2 *invalid-bug-148271109.ivf
d3964f9dad9f60363c81b688324d95b4ec7c8038 *invalid-bug-148271109.ivf.res
ad18ca16f0a249fb3b7c38de0d9b327fed273f96 *hantro_collage_w352h288_nv12.yuv
+03f827c0e36ff9a6e23c5cc11936924e4f1827ab *rc_interface_test_one_layer
+99e4f4c2961d46dc286db230090a39d78460b25d *rc_interface_test_svc
diff --git a/test/test.mk b/test/test.mk
index c12fb786e..04902382d 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -58,6 +58,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.h
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_end_to_end_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += timestamp_test.cc
+LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_ext_ratectrl_test.cc
LIBVPX_TEST_SRCS-yes += decode_test_driver.cc
LIBVPX_TEST_SRCS-yes += decode_test_driver.h
diff --git a/test/variance_test.cc b/test/variance_test.cc
index 72306d90c..1b76b2041 100644
--- a/test/variance_test.cc
+++ b/test/variance_test.cc
@@ -840,6 +840,7 @@ INSTANTIATE_TEST_SUITE_P(
MseParams(4, 4, &vpx_highbd_8_mse8x16_c),
MseParams(4, 4, &vpx_highbd_8_mse8x8_c)));
*/
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VpxHBDMseTest);
INSTANTIATE_TEST_SUITE_P(
C, VpxHBDVarianceTest,
diff --git a/test/vp9_block_error_test.cc b/test/vp9_block_error_test.cc
index dc1ff49c6..b93b014e6 100644
--- a/test/vp9_block_error_test.cc
+++ b/test/vp9_block_error_test.cc
@@ -67,6 +67,7 @@ class BlockErrorTest : public ::testing::TestWithParam<BlockErrorParam> {
HBDBlockErrorFunc error_block_op_;
HBDBlockErrorFunc ref_error_block_op_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BlockErrorTest);
TEST_P(BlockErrorTest, OperationCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
diff --git a/test/vp9_denoiser_test.cc b/test/vp9_denoiser_test.cc
index 3d76edfaa..d884b7eb9 100644
--- a/test/vp9_denoiser_test.cc
+++ b/test/vp9_denoiser_test.cc
@@ -51,6 +51,7 @@ class VP9DenoiserTest
protected:
BLOCK_SIZE bs_;
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VP9DenoiserTest);
TEST_P(VP9DenoiserTest, BitexactCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
diff --git a/test/vp9_ext_ratectrl_test.cc b/test/vp9_ext_ratectrl_test.cc
new file mode 100644
index 000000000..812a18ed2
--- /dev/null
+++ b/test/vp9_ext_ratectrl_test.cc
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE 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.
+ */
+
+#include <new>
+
+#include "test/codec_factory.h"
+#include "test/encode_test_driver.h"
+#include "test/util.h"
+#include "test/yuv_video_source.h"
+#include "third_party/googletest/src/include/gtest/gtest.h"
+#include "vpx/vpx_ext_ratectrl.h"
+
+namespace {
+
+constexpr int kModelMagicNumber = 51396;
+constexpr unsigned int PrivMagicNumber = 5566;
+constexpr int kFrameNum = 5;
+constexpr int kLosslessCodingIndex = 2;
+
+struct ToyRateCtrl {
+ int magic_number;
+ int coding_index;
+};
+
+vpx_rc_status_t rc_create_model(void *priv,
+ const vpx_rc_config_t *ratectrl_config,
+ vpx_rc_model_t *rate_ctrl_model_pt) {
+ ToyRateCtrl *toy_rate_ctrl = new (std::nothrow) ToyRateCtrl;
+ EXPECT_NE(toy_rate_ctrl, nullptr);
+ toy_rate_ctrl->magic_number = kModelMagicNumber;
+ toy_rate_ctrl->coding_index = -1;
+ *rate_ctrl_model_pt = toy_rate_ctrl;
+ EXPECT_EQ(priv, reinterpret_cast<void *>(PrivMagicNumber));
+ EXPECT_EQ(ratectrl_config->frame_width, 352);
+ EXPECT_EQ(ratectrl_config->frame_height, 288);
+ EXPECT_EQ(ratectrl_config->show_frame_count, kFrameNum);
+ EXPECT_EQ(ratectrl_config->target_bitrate_kbps, 24000);
+ EXPECT_EQ(ratectrl_config->frame_rate_num, 30);
+ EXPECT_EQ(ratectrl_config->frame_rate_den, 1);
+ return VPX_RC_OK;
+}
+
+vpx_rc_status_t rc_send_firstpass_stats(
+ vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_firstpass_stats_t *first_pass_stats) {
+ const ToyRateCtrl *toy_rate_ctrl =
+ static_cast<ToyRateCtrl *>(rate_ctrl_model);
+ EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
+ EXPECT_EQ(first_pass_stats->num_frames, kFrameNum);
+ for (int i = 0; i < first_pass_stats->num_frames; ++i) {
+ EXPECT_DOUBLE_EQ(first_pass_stats->frame_stats[i].frame, i);
+ }
+ return VPX_RC_OK;
+}
+
+vpx_rc_status_t rc_get_encodeframe_decision(
+ vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_encodeframe_info_t *encode_frame_info,
+ vpx_rc_encodeframe_decision_t *frame_decision) {
+ ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
+ toy_rate_ctrl->coding_index += 1;
+
+ EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
+
+ EXPECT_LT(encode_frame_info->show_index, kFrameNum);
+ EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
+
+ if (encode_frame_info->coding_index == 0) {
+ EXPECT_EQ(encode_frame_info->gop_index, 0);
+ EXPECT_EQ(encode_frame_info->frame_type, 0 /*kFrameTypeKey*/);
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
+ 0); // kRefFrameTypeLast
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
+ 0); // kRefFrameTypePast
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
+ 0); // kRefFrameTypeFuture
+ }
+
+ if (encode_frame_info->coding_index == 1) {
+ EXPECT_EQ(encode_frame_info->gop_index, 1);
+ EXPECT_EQ(encode_frame_info->frame_type, 2 /*kFrameTypeAltRef*/);
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
+ 1); // kRefFrameTypeLast
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
+ 0); // kRefFrameTypePast
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
+ 0); // kRefFrameTypeFuture
+ EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
+ 0); // kRefFrameTypeLast
+ }
+
+ if (encode_frame_info->coding_index >= 2 &&
+ encode_frame_info->coding_index < 5) {
+ // In the first group of pictures, coding_index and gop_index are equal.
+ EXPECT_EQ(encode_frame_info->gop_index, encode_frame_info->coding_index);
+ EXPECT_EQ(encode_frame_info->frame_type, 1 /*kFrameTypeInter*/);
+ }
+
+ if (encode_frame_info->coding_index == 5) {
+ EXPECT_EQ(encode_frame_info->gop_index, 0);
+ EXPECT_EQ(encode_frame_info->frame_type, 3 /*kFrameTypeOverlay*/);
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
+ 1); // kRefFrameTypeLast
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
+ 1); // kRefFrameTypePast
+ EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
+ 1); // kRefFrameTypeFuture
+ EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
+ 4); // kRefFrameTypeLast
+ EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[1],
+ 0); // kRefFrameTypePast
+ EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[2],
+ 1); // kRefFrameTypeFuture
+ }
+ if (encode_frame_info->coding_index == kLosslessCodingIndex) {
+ // We should get sse == 0 at rc_update_encodeframe_result()
+ frame_decision->q_index = 0;
+ } else {
+ frame_decision->q_index = 100;
+ }
+ return VPX_RC_OK;
+}
+
+vpx_rc_status_t rc_update_encodeframe_result(
+ vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_encodeframe_result_t *encode_frame_result) {
+ const ToyRateCtrl *toy_rate_ctrl =
+ static_cast<ToyRateCtrl *>(rate_ctrl_model);
+ EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
+
+ const int64_t ref_pixel_count = 352 * 288 * 3 / 2;
+ EXPECT_EQ(encode_frame_result->pixel_count, ref_pixel_count);
+ if (toy_rate_ctrl->coding_index == kLosslessCodingIndex) {
+ EXPECT_EQ(encode_frame_result->sse, 0);
+ }
+ return VPX_RC_OK;
+}
+
+vpx_rc_status_t rc_delete_model(vpx_rc_model_t rate_ctrl_model) {
+ ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
+ EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
+ delete toy_rate_ctrl;
+ return VPX_RC_OK;
+}
+
+class ExtRateCtrlTest : public ::libvpx_test::EncoderTest,
+ public ::testing::Test {
+ protected:
+ ExtRateCtrlTest() : EncoderTest(&::libvpx_test::kVP9) {}
+
+ ~ExtRateCtrlTest() override = default;
+
+ void SetUp() override {
+ InitializeConfig();
+ SetMode(::libvpx_test::kTwoPassGood);
+ }
+
+ void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
+ ::libvpx_test::Encoder *encoder) override {
+ if (video->frame() == 0) {
+ vpx_rc_funcs_t rc_funcs;
+ rc_funcs.create_model = rc_create_model;
+ rc_funcs.send_firstpass_stats = rc_send_firstpass_stats;
+ rc_funcs.get_encodeframe_decision = rc_get_encodeframe_decision;
+ rc_funcs.update_encodeframe_result = rc_update_encodeframe_result;
+ rc_funcs.delete_model = rc_delete_model;
+ rc_funcs.priv = reinterpret_cast<void *>(PrivMagicNumber);
+ encoder->Control(VP9E_SET_EXTERNAL_RATE_CONTROL, &rc_funcs);
+ }
+ }
+};
+
+TEST_F(ExtRateCtrlTest, EncodeTest) {
+ cfg_.rc_target_bitrate = 24000;
+
+ std::unique_ptr<libvpx_test::VideoSource> video;
+ video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
+ "bus_352x288_420_f20_b8.yuv", VPX_IMG_FMT_I420, 352, 288, 30, 1, 0,
+ kFrameNum));
+
+ ASSERT_NE(video.get(), nullptr);
+ ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
+}
+
+} // namespace
diff --git a/test/vp9_intrapred_test.cc b/test/vp9_intrapred_test.cc
index fdcccd5c2..ccace719e 100644
--- a/test/vp9_intrapred_test.cc
+++ b/test/vp9_intrapred_test.cc
@@ -468,6 +468,8 @@ void IntraPredTest<uint16_t, HighbdIntraPredParam>::Predict() {
}
typedef IntraPredTest<uint16_t, HighbdIntraPredParam> VP9HighbdIntraPredTest;
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VP9HighbdIntraPredTest);
+
TEST_P(VP9HighbdIntraPredTest, HighbdIntraPredTests) {
// max block size is 32
DECLARE_ALIGNED(16, uint16_t, left_col[2 * 32]);
diff --git a/third_party/googletest/README.libvpx b/third_party/googletest/README.libvpx
index 0f6202cb7..ed55fb09f 100644
--- a/third_party/googletest/README.libvpx
+++ b/third_party/googletest/README.libvpx
@@ -19,3 +19,5 @@ Local Modifications:
LICENSE
README.md
src
+- Enable kErrorOnUninstantiatedParameterizedTest and
+ kErrorOnUninstantiatedTypeParameterizedTest in gtest.cc
diff --git a/third_party/googletest/src/src/gtest.cc b/third_party/googletest/src/src/gtest.cc
index 095778e6e..b8f6a5c31 100644
--- a/third_party/googletest/src/src/gtest.cc
+++ b/third_party/googletest/src/src/gtest.cc
@@ -414,8 +414,8 @@ namespace {
// inserted to report ether an error or a log message.
//
// This configuration bit will likely be removed at some point.
-constexpr bool kErrorOnUninstantiatedParameterizedTest = false;
-constexpr bool kErrorOnUninstantiatedTypeParameterizedTest = false;
+constexpr bool kErrorOnUninstantiatedParameterizedTest = true;
+constexpr bool kErrorOnUninstantiatedTypeParameterizedTest = true;
// A test that fails at a given file/line location with a given message.
class FailureTest : public Test {
diff --git a/vp8/common/generic/systemdependent.c b/vp8/common/generic/systemdependent.c
index 75ce7ef35..cd1b02c9c 100644
--- a/vp8/common/generic/systemdependent.c
+++ b/vp8/common/generic/systemdependent.c
@@ -16,6 +16,8 @@
#include "vpx_ports/x86.h"
#elif VPX_ARCH_PPC
#include "vpx_ports/ppc.h"
+#elif VPX_ARCH_MIPS
+#include "vpx_ports/mips.h"
#endif
#include "vp8/common/onyxc_int.h"
#include "vp8/common/systemdependent.h"
@@ -96,6 +98,8 @@ void vp8_machine_specific_config(VP8_COMMON *ctx) {
ctx->cpu_caps = x86_simd_caps();
#elif VPX_ARCH_PPC
ctx->cpu_caps = ppc_simd_caps();
+#elif VPX_ARCH_MIPS
+ ctx->cpu_caps = mips_cpu_caps();
#else
// generic-gnu targets.
ctx->cpu_caps = 0;
diff --git a/vp8/common/threading.h b/vp8/common/threading.h
index f92136938..1cfb9fec5 100644
--- a/vp8/common/threading.h
+++ b/vp8/common/threading.h
@@ -171,17 +171,20 @@ static inline int sem_destroy(sem_t *sem) {
#define sem_wait(sem) (semaphore_wait(*sem))
#define sem_post(sem) semaphore_signal(*sem)
#define sem_destroy(sem) semaphore_destroy(mach_task_self(), *sem)
-#define thread_sleep(nms)
-/* { struct timespec ts;ts.tv_sec=0; ts.tv_nsec =
- 1000*nms;nanosleep(&ts, NULL);} */
#else
#include <unistd.h>
#include <sched.h>
-#define thread_sleep(nms) sched_yield();
+#endif /* __APPLE__ */
+/* Not Windows. Assume pthreads */
+
+/* thread_sleep implementation: yield unless Linux/Unix. */
+#if defined(__unix__) || defined(__APPLE__)
+#define thread_sleep(nms)
/* {struct timespec ts;ts.tv_sec=0;
ts.tv_nsec = 1000*nms;nanosleep(&ts, NULL);} */
-#endif
-/* Not Windows. Assume pthreads */
+#else
+#define thread_sleep(nms) sched_yield();
+#endif /* __unix__ || __APPLE__ */
#endif
diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h
index 6f9c6985f..1cfc12f6f 100644
--- a/vp9/common/vp9_onyxc_int.h
+++ b/vp9/common/vp9_onyxc_int.h
@@ -75,12 +75,10 @@ typedef struct {
// TODO(angiebird): Set frame_index/frame_coding_index on the decoder side
// properly.
- int frame_index; // Display order in the video, it's equivalent to the
- // show_idx defined in EncodeFrameInfo.
-#if CONFIG_RATE_CTRL
+ int frame_index; // Display order in the video, it's equivalent to the
+ // show_idx defined in EncodeFrameInfo.
int frame_coding_index; // The coding order (starting from zero) of this
// frame.
-#endif // CONFIG_RATE_CTRL
vpx_codec_frame_buffer_t raw_frame_buffer;
YV12_BUFFER_CONFIG buf;
} RefCntBuffer;
@@ -240,13 +238,11 @@ typedef struct VP9Common {
// TODO(angiebird): current_video_frame/current_frame_coding_index into a
// structure
unsigned int current_video_frame;
-#if CONFIG_RATE_CTRL
// Each show or no show frame is assigned with a coding index based on its
// coding order (starting from zero).
// Current frame's coding index.
int current_frame_coding_index;
-#endif
BITSTREAM_PROFILE profile;
// VPX_BITS_8 in profile 0 or 1, VPX_BITS_10 or VPX_BITS_12 in profile 2 or 3.
@@ -276,9 +272,7 @@ typedef struct VP9Common {
static INLINE void init_frame_indexes(VP9_COMMON *cm) {
cm->current_video_frame = 0;
-#if CONFIG_RATE_CTRL
cm->current_frame_coding_index = 0;
-#endif // CONFIG_RATE_CTRL
}
static INLINE void update_frame_indexes(VP9_COMMON *cm, int show_frame) {
@@ -287,9 +281,7 @@ static INLINE void update_frame_indexes(VP9_COMMON *cm, int show_frame) {
// update not a real frame
++cm->current_video_frame;
}
-#if CONFIG_RATE_CTRL
++cm->current_frame_coding_index;
-#endif // CONFIG_RATE_CTRL
}
typedef struct {
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 048559061..37f644501 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -1025,6 +1025,7 @@ static void dealloc_compressor_data(VP9_COMP *cpi) {
free_partition_info(cpi);
free_motion_vector_info(cpi);
free_fp_motion_vector_info(cpi);
+ free_tpl_stats_info(cpi);
#endif
vp9_free_ref_frame_buffers(cm->buffer_pool);
@@ -2463,6 +2464,8 @@ VP9_COMP *vp9_create_compressor(const VP9EncoderConfig *oxcf,
cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
+ vp9_extrc_init(&cpi->ext_ratectrl);
+
#if !CONFIG_REALTIME_ONLY
if (oxcf->pass == 1) {
vp9_init_first_pass(cpi);
@@ -2663,6 +2666,7 @@ VP9_COMP *vp9_create_compressor(const VP9EncoderConfig *oxcf,
partition_info_init(cpi);
motion_vector_info_init(cpi);
fp_motion_vector_info_init(cpi);
+ tpl_stats_info_init(cpi);
#endif
return cpi;
@@ -2834,6 +2838,8 @@ void vp9_remove_compressor(VP9_COMP *cpi) {
}
#endif
+ vp9_extrc_delete(&cpi->ext_ratectrl);
+
vp9_remove_common(cm);
vp9_free_ref_frame_buffers(cm->buffer_pool);
#if CONFIG_VP9_POSTPROC
@@ -3316,6 +3322,13 @@ static void loopfilter_frame(VP9_COMP *cpi, VP9_COMMON *cm) {
return;
}
+ if (cpi->loopfilter_ctrl == NO_LOOPFILTER ||
+ (!is_reference_frame && cpi->loopfilter_ctrl == LOOPFILTER_REFERENCE)) {
+ lf->filter_level = 0;
+ vpx_extend_frame_inner_borders(cm->frame_to_show);
+ return;
+ }
+
if (xd->lossless) {
lf->filter_level = 0;
lf->last_filt_level = 0;
@@ -4195,6 +4208,27 @@ static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
return 1;
}
+static int get_ref_frame_flags(const VP9_COMP *cpi) {
+ const int *const map = cpi->common.ref_frame_map;
+ const int gold_is_last = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idx];
+ const int alt_is_last = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idx];
+ const int gold_is_alt = map[cpi->gld_fb_idx] == map[cpi->alt_fb_idx];
+ int flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
+
+ if (gold_is_last) flags &= ~VP9_GOLD_FLAG;
+
+ if (cpi->rc.frames_till_gf_update_due == INT_MAX &&
+ (cpi->svc.number_temporal_layers == 1 &&
+ cpi->svc.number_spatial_layers == 1))
+ flags &= ~VP9_GOLD_FLAG;
+
+ if (alt_is_last) flags &= ~VP9_ALT_FLAG;
+
+ if (gold_is_alt) flags &= ~VP9_ALT_FLAG;
+
+ return flags;
+}
+
#if !CONFIG_REALTIME_ONLY
#define MAX_QSTEP_ADJ 4
static int get_qstep_adj(int rate_excess, int rate_limit) {
@@ -4468,6 +4502,19 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
q = cpi->encode_command.external_quantize_index;
}
#endif
+ if (cpi->ext_ratectrl.ready) {
+ const GF_GROUP *gf_group = &cpi->twopass.gf_group;
+ vpx_rc_encodeframe_decision_t encode_frame_decision;
+ FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_group->index];
+ const int ref_frame_flags = get_ref_frame_flags(cpi);
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES];
+ get_ref_frame_bufs(cpi, ref_frame_bufs);
+ vp9_extrc_get_encodeframe_decision(
+ &cpi->ext_ratectrl, cm->current_video_frame,
+ cm->current_frame_coding_index, gf_group->index, update_type,
+ ref_frame_bufs, ref_frame_flags, &encode_frame_decision);
+ q = encode_frame_decision.q_index;
+ }
vp9_set_quantizer(cpi, q);
@@ -4507,6 +4554,9 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1;
}
+ if (cpi->ext_ratectrl.ready) {
+ break;
+ }
#if CONFIG_RATE_CTRL
// This part needs to be after save_coding_context() because
// restore_coding_context will be called in the end of this function.
@@ -4751,27 +4801,6 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
}
#endif // !CONFIG_REALTIME_ONLY
-static int get_ref_frame_flags(const VP9_COMP *cpi) {
- const int *const map = cpi->common.ref_frame_map;
- const int gold_is_last = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idx];
- const int alt_is_last = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idx];
- const int gold_is_alt = map[cpi->gld_fb_idx] == map[cpi->alt_fb_idx];
- int flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
-
- if (gold_is_last) flags &= ~VP9_GOLD_FLAG;
-
- if (cpi->rc.frames_till_gf_update_due == INT_MAX &&
- (cpi->svc.number_temporal_layers == 1 &&
- cpi->svc.number_spatial_layers == 1))
- flags &= ~VP9_GOLD_FLAG;
-
- if (alt_is_last) flags &= ~VP9_ALT_FLAG;
-
- if (gold_is_alt) flags &= ~VP9_ALT_FLAG;
-
- return flags;
-}
-
static void set_ext_overrides(VP9_COMP *cpi) {
// Overrides the defaults with the externally supplied values with
// vp9_update_reference() and vp9_update_entropy() calls
@@ -5076,9 +5105,7 @@ static void set_frame_index(VP9_COMP *cpi, VP9_COMMON *cm) {
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
ref_buffer->frame_index =
cm->current_video_frame + gf_group->arf_src_offset[gf_group->index];
-#if CONFIG_RATE_CTRL
ref_buffer->frame_coding_index = cm->current_frame_coding_index;
-#endif // CONFIG_RATE_CTRL
}
}
@@ -5281,6 +5308,7 @@ static void update_encode_frame_result(
#if CONFIG_RATE_CTRL
const PARTITION_INFO *partition_info,
const MOTION_VECTOR_INFO *motion_vector_info,
+ const TplDepStats *tpl_stats_info,
#endif // CONFIG_RATE_CTRL
ENCODE_FRAME_RESULT *encode_frame_result);
#endif // !CONFIG_REALTIME_ONLY
@@ -5456,6 +5484,13 @@ static void encode_frame_to_data_rate(
// build the bitstream
vp9_pack_bitstream(cpi, dest, size);
+ {
+ const RefCntBuffer *coded_frame_buf =
+ get_ref_cnt_buffer(cm, cm->new_fb_idx);
+ vp9_extrc_update_encodeframe_result(
+ &cpi->ext_ratectrl, (*size) << 3, cpi->Source, &coded_frame_buf->buf,
+ cm->bit_depth, cpi->oxcf.input_bit_depth);
+ }
#if CONFIG_REALTIME_ONLY
(void)encode_frame_result;
assert(encode_frame_result == NULL);
@@ -5486,9 +5521,9 @@ static void encode_frame_to_data_rate(
ref_frame_flags,
cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index],
cpi->Source, coded_frame_buf, ref_frame_bufs, vp9_get_quantizer(cpi),
- cpi->oxcf.input_bit_depth, cm->bit_depth, cpi->td.counts,
+ cm->bit_depth, cpi->oxcf.input_bit_depth, cpi->td.counts,
#if CONFIG_RATE_CTRL
- cpi->partition_info, cpi->motion_vector_info,
+ cpi->partition_info, cpi->motion_vector_info, cpi->tpl_stats_info,
#endif // CONFIG_RATE_CTRL
encode_frame_result);
}
@@ -5643,6 +5678,11 @@ static void Pass2Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
unsigned int *frame_flags,
ENCODE_FRAME_RESULT *encode_frame_result) {
cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
+
+ if (cpi->common.current_frame_coding_index == 0) {
+ vp9_extrc_send_firstpass_stats(&cpi->ext_ratectrl,
+ &cpi->twopass.first_pass_info);
+ }
#if CONFIG_MISMATCH_DEBUG
mismatch_move_frame_idx_w();
#endif
@@ -7334,6 +7374,48 @@ static void free_tpl_buffer(VP9_COMP *cpi) {
}
}
+#if CONFIG_RATE_CTRL
+static void accumulate_frame_tpl_stats(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ const GF_GROUP *gf_group = &cpi->twopass.gf_group;
+ int show_frame_count = 0;
+ int frame_idx;
+ // Accumulate tpl stats for each frame in the current group of picture.
+ for (frame_idx = 1; frame_idx < gf_group->gf_group_size; ++frame_idx) {
+ TplDepFrame *tpl_frame = &cpi->tpl_stats[frame_idx];
+ TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
+ const int tpl_stride = tpl_frame->stride;
+ int64_t intra_cost_base = 0;
+ int64_t inter_cost_base = 0;
+ int64_t mc_dep_cost_base = 0;
+ int64_t mc_ref_cost_base = 0;
+ int64_t mc_flow_base = 0;
+ int row, col;
+
+ if (!tpl_frame->is_valid) continue;
+
+ for (row = 0; row < cm->mi_rows && tpl_frame->is_valid; ++row) {
+ for (col = 0; col < cm->mi_cols; ++col) {
+ TplDepStats *this_stats = &tpl_stats[row * tpl_stride + col];
+ intra_cost_base += this_stats->intra_cost;
+ inter_cost_base += this_stats->inter_cost;
+ mc_dep_cost_base += this_stats->mc_dep_cost;
+ mc_ref_cost_base += this_stats->mc_ref_cost;
+ mc_flow_base += this_stats->mc_flow;
+ }
+ }
+
+ cpi->tpl_stats_info[show_frame_count].intra_cost = intra_cost_base;
+ cpi->tpl_stats_info[show_frame_count].inter_cost = inter_cost_base;
+ cpi->tpl_stats_info[show_frame_count].mc_dep_cost = mc_dep_cost_base;
+ cpi->tpl_stats_info[show_frame_count].mc_ref_cost = mc_ref_cost_base;
+ cpi->tpl_stats_info[show_frame_count].mc_flow = mc_flow_base;
+
+ ++show_frame_count;
+ }
+}
+#endif // CONFIG_RATE_CTRL
+
static void setup_tpl_stats(VP9_COMP *cpi) {
GF_PICTURE gf_picture[MAX_ARF_GOP_SIZE];
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
@@ -7356,6 +7438,34 @@ static void setup_tpl_stats(VP9_COMP *cpi) {
dump_tpl_stats(cpi, tpl_group_frames, gf_group, gf_picture, cpi->tpl_bsize);
#endif // DUMP_TPL_STATS
#endif // CONFIG_NON_GREEDY_MV
+
+#if CONFIG_RATE_CTRL
+ accumulate_frame_tpl_stats(cpi);
+#endif // CONFIG_RATE_CTRL
+}
+
+void vp9_get_ref_frame_info(FRAME_UPDATE_TYPE update_type, int ref_frame_flags,
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES],
+ int *ref_frame_coding_indexes,
+ int *ref_frame_valid_list) {
+ if (update_type != KF_UPDATE) {
+ const VP9_REFFRAME inter_ref_flags[MAX_INTER_REF_FRAMES] = { VP9_LAST_FLAG,
+ VP9_GOLD_FLAG,
+ VP9_ALT_FLAG };
+ int i;
+ for (i = 0; i < MAX_INTER_REF_FRAMES; ++i) {
+ assert(ref_frame_bufs[i] != NULL);
+ ref_frame_coding_indexes[i] = ref_frame_bufs[i]->frame_coding_index;
+ ref_frame_valid_list[i] = (ref_frame_flags & inter_ref_flags[i]) != 0;
+ }
+ } else {
+ // No reference frame is available when this is a key frame.
+ int i;
+ for (i = 0; i < MAX_INTER_REF_FRAMES; ++i) {
+ ref_frame_coding_indexes[i] = -1;
+ ref_frame_valid_list[i] = 0;
+ }
+ }
}
#if !CONFIG_REALTIME_ONLY
@@ -7505,6 +7615,7 @@ static void yv12_buffer_to_image_buffer(const YV12_BUFFER_CONFIG *yv12_buffer,
}
}
#endif // CONFIG_RATE_CTRL
+
static void update_encode_frame_result(
int ref_frame_flags, FRAME_UPDATE_TYPE update_type,
const YV12_BUFFER_CONFIG *source_frame, const RefCntBuffer *coded_frame_buf,
@@ -7513,12 +7624,13 @@ static void update_encode_frame_result(
#if CONFIG_RATE_CTRL
const PARTITION_INFO *partition_info,
const MOTION_VECTOR_INFO *motion_vector_info,
+ const TplDepStats *tpl_stats_info,
#endif // CONFIG_RATE_CTRL
ENCODE_FRAME_RESULT *encode_frame_result) {
#if CONFIG_RATE_CTRL
PSNR_STATS psnr;
#if CONFIG_VP9_HIGHBITDEPTH
- vpx_calc_highbd_psnr(source_frame, coded_frame_buf->buf, &psnr, bit_depth,
+ vpx_calc_highbd_psnr(source_frame, &coded_frame_buf->buf, &psnr, bit_depth,
input_bit_depth);
#else // CONFIG_VP9_HIGHBITDEPTH
(void)bit_depth;
@@ -7527,31 +7639,16 @@ static void update_encode_frame_result(
#endif // CONFIG_VP9_HIGHBITDEPTH
encode_frame_result->frame_coding_index = coded_frame_buf->frame_coding_index;
- if (update_type != KF_UPDATE) {
- const VP9_REFFRAME inter_ref_flags[MAX_INTER_REF_FRAMES] = { VP9_LAST_FLAG,
- VP9_GOLD_FLAG,
- VP9_ALT_FLAG };
- int i;
- for (i = 0; i < MAX_INTER_REF_FRAMES; ++i) {
- assert(ref_frame_bufs[i] != NULL);
- encode_frame_result->ref_frame_coding_indexes[i] =
- ref_frame_bufs[i]->frame_coding_index;
- encode_frame_result->ref_frame_valid_list[i] =
- (ref_frame_flags & inter_ref_flags[i]) != 0;
- }
- } else {
- // No reference frame is available when this is a key frame.
- int i;
- for (i = 0; i < MAX_INTER_REF_FRAMES; ++i) {
- encode_frame_result->ref_frame_coding_indexes[i] = -1;
- encode_frame_result->ref_frame_valid_list[i] = 0;
- }
- }
+ vp9_get_ref_frame_info(update_type, ref_frame_flags, ref_frame_bufs,
+ encode_frame_result->ref_frame_coding_indexes,
+ encode_frame_result->ref_frame_valid_list);
+
encode_frame_result->psnr = psnr.psnr[0];
encode_frame_result->sse = psnr.sse[0];
copy_frame_counts(counts, &encode_frame_result->frame_counts);
encode_frame_result->partition_info = partition_info;
encode_frame_result->motion_vector_info = motion_vector_info;
+ encode_frame_result->tpl_stats_info = tpl_stats_info;
if (encode_frame_result->coded_frame.allocated) {
yv12_buffer_to_image_buffer(&coded_frame_buf->buf,
&encode_frame_result->coded_frame);
diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h
index 26d35cccf..8763a5e78 100644
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -15,6 +15,7 @@
#include "./vpx_config.h"
#include "vpx/internal/vpx_codec_internal.h"
+#include "vpx/vpx_ext_ratectrl.h"
#include "vpx/vp8cx.h"
#if CONFIG_INTERNAL_STATS
#include "vpx_dsp/ssim.h"
@@ -38,6 +39,7 @@
#include "vp9/encoder/vp9_context_tree.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/encoder/vp9_ethread.h"
+#include "vp9/encoder/vp9_ext_ratectrl.h"
#include "vp9/encoder/vp9_firstpass.h"
#include "vp9/encoder/vp9_job_queue.h"
#include "vp9/encoder/vp9_lookahead.h"
@@ -147,6 +149,12 @@ typedef enum {
kVeryHighSad = 6,
} CONTENT_STATE_SB;
+typedef enum {
+ LOOPFILTER_ALL = 0,
+ LOOPFILTER_REFERENCE = 1, // Disable loopfilter on non reference frames.
+ NO_LOOPFILTER = 2, // Disable loopfilter on all frames.
+} LOOPFILTER_CONTROL;
+
typedef struct VP9EncoderConfig {
BITSTREAM_PROFILE profile;
vpx_bit_depth_t bit_depth; // Codec bit-depth.
@@ -958,14 +966,18 @@ typedef struct VP9_COMP {
int multi_layer_arf;
vpx_roi_map_t roi;
+
+ LOOPFILTER_CONTROL loopfilter_ctrl;
#if CONFIG_RATE_CTRL
ENCODE_COMMAND encode_command;
PARTITION_INFO *partition_info;
MOTION_VECTOR_INFO *motion_vector_info;
MOTION_VECTOR_INFO *fp_motion_vector_info;
+ TplDepStats *tpl_stats_info;
RATE_QSTEP_MODEL rq_model[ENCODE_FRAME_TYPES];
#endif
+ EXT_RATECTRL ext_ratectrl;
} VP9_COMP;
#if CONFIG_RATE_CTRL
@@ -1018,6 +1030,23 @@ static INLINE void free_motion_vector_info(struct VP9_COMP *cpi) {
cpi->motion_vector_info = NULL;
}
+// Allocates memory for the tpl stats information.
+// Only called once in vp9_create_compressor().
+static INLINE void tpl_stats_info_init(struct VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ CHECK_MEM_ERROR(
+ cm, cpi->tpl_stats_info,
+ (TplDepStats *)vpx_calloc(MAX_LAG_BUFFERS, sizeof(TplDepStats)));
+ memset(cpi->tpl_stats_info, 0, MAX_LAG_BUFFERS * sizeof(TplDepStats));
+}
+
+// Frees memory of the tpl stats information.
+// Only called once in dealloc_compressor_data().
+static INLINE void free_tpl_stats_info(struct VP9_COMP *cpi) {
+ vpx_free(cpi->tpl_stats_info);
+ cpi->tpl_stats_info = NULL;
+}
+
// Allocates memory for the first pass motion vector information.
// The unit size is each 16x16 block.
// Only called once in vp9_create_compressor().
@@ -1025,12 +1054,19 @@ static INLINE void fp_motion_vector_info_init(struct VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
const int unit_width = get_num_unit_16x16(cpi->frame_info.frame_width);
const int unit_height = get_num_unit_16x16(cpi->frame_info.frame_height);
- int i;
CHECK_MEM_ERROR(cm, cpi->fp_motion_vector_info,
(MOTION_VECTOR_INFO *)vpx_calloc(unit_width * unit_height,
sizeof(MOTION_VECTOR_INFO)));
+}
+
+static INLINE void fp_motion_vector_info_reset(
+ int frame_width, int frame_height,
+ MOTION_VECTOR_INFO *fp_motion_vector_info) {
+ const int unit_width = get_num_unit_16x16(frame_width);
+ const int unit_height = get_num_unit_16x16(frame_height);
+ int i;
for (i = 0; i < unit_width * unit_height; ++i) {
- reset_mv_info(cpi->fp_motion_vector_info + i);
+ reset_mv_info(fp_motion_vector_info + i);
}
}
@@ -1073,6 +1109,7 @@ typedef struct ENCODE_FRAME_RESULT {
FRAME_COUNTS frame_counts;
const PARTITION_INFO *partition_info;
const MOTION_VECTOR_INFO *motion_vector_info;
+ const TplDepStats *tpl_stats_info;
IMAGE_BUFFER coded_frame;
RATE_QINDEX_HISTORY rq_history;
#endif // CONFIG_RATE_CTRL
@@ -1250,6 +1287,11 @@ void vp9_scale_references(VP9_COMP *cpi);
void vp9_update_reference_frames(VP9_COMP *cpi);
+void vp9_get_ref_frame_info(FRAME_UPDATE_TYPE update_type, int ref_frame_flags,
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES],
+ int *ref_frame_coding_indexes,
+ int *ref_frame_valid_list);
+
void vp9_set_high_precision_mv(VP9_COMP *cpi, int allow_high_precision_mv);
YV12_BUFFER_CONFIG *vp9_svc_twostage_scale(
diff --git a/vp9/encoder/vp9_ext_ratectrl.c b/vp9/encoder/vp9_ext_ratectrl.c
new file mode 100644
index 000000000..a6a3e21d3
--- /dev/null
+++ b/vp9/encoder/vp9_ext_ratectrl.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE 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.
+ */
+
+#include "vp9/encoder/vp9_ext_ratectrl.h"
+#include "vp9/encoder/vp9_encoder.h"
+#include "vp9/common/vp9_common.h"
+#include "vpx_dsp/psnr.h"
+
+void vp9_extrc_init(EXT_RATECTRL *ext_ratectrl) { vp9_zero(*ext_ratectrl); }
+
+void vp9_extrc_create(vpx_rc_funcs_t funcs, vpx_rc_config_t ratectrl_config,
+ EXT_RATECTRL *ext_ratectrl) {
+ vpx_rc_firstpass_stats_t *rc_firstpass_stats;
+ vp9_extrc_delete(ext_ratectrl);
+ ext_ratectrl->funcs = funcs;
+ ext_ratectrl->ratectrl_config = ratectrl_config;
+ ext_ratectrl->funcs.create_model(ext_ratectrl->funcs.priv,
+ &ext_ratectrl->ratectrl_config,
+ &ext_ratectrl->model);
+ rc_firstpass_stats = &ext_ratectrl->rc_firstpass_stats;
+ rc_firstpass_stats->num_frames = ratectrl_config.show_frame_count;
+ rc_firstpass_stats->frame_stats =
+ vpx_malloc(sizeof(*rc_firstpass_stats->frame_stats) *
+ rc_firstpass_stats->num_frames);
+ ext_ratectrl->ready = 1;
+}
+
+void vp9_extrc_delete(EXT_RATECTRL *ext_ratectrl) {
+ if (ext_ratectrl->ready) {
+ ext_ratectrl->funcs.delete_model(ext_ratectrl->model);
+ vpx_free(ext_ratectrl->rc_firstpass_stats.frame_stats);
+ }
+ vp9_extrc_init(ext_ratectrl);
+}
+
+static void gen_rc_firstpass_stats(const FIRSTPASS_STATS *stats,
+ vpx_rc_frame_stats_t *rc_frame_stats) {
+ rc_frame_stats->frame = stats->frame;
+ rc_frame_stats->weight = stats->weight;
+ rc_frame_stats->intra_error = stats->intra_error;
+ rc_frame_stats->coded_error = stats->coded_error;
+ rc_frame_stats->sr_coded_error = stats->sr_coded_error;
+ rc_frame_stats->frame_noise_energy = stats->frame_noise_energy;
+ rc_frame_stats->pcnt_inter = stats->pcnt_inter;
+ rc_frame_stats->pcnt_motion = stats->pcnt_motion;
+ rc_frame_stats->pcnt_second_ref = stats->pcnt_second_ref;
+ rc_frame_stats->pcnt_neutral = stats->pcnt_neutral;
+ rc_frame_stats->pcnt_intra_low = stats->pcnt_intra_low;
+ rc_frame_stats->pcnt_intra_high = stats->pcnt_intra_high;
+ rc_frame_stats->intra_skip_pct = stats->intra_skip_pct;
+ rc_frame_stats->intra_smooth_pct = stats->intra_smooth_pct;
+ rc_frame_stats->inactive_zone_rows = stats->inactive_zone_rows;
+ rc_frame_stats->inactive_zone_cols = stats->inactive_zone_cols;
+ rc_frame_stats->MVr = stats->MVr;
+ rc_frame_stats->mvr_abs = stats->mvr_abs;
+ rc_frame_stats->MVc = stats->MVc;
+ rc_frame_stats->mvc_abs = stats->mvc_abs;
+ rc_frame_stats->MVrv = stats->MVrv;
+ rc_frame_stats->MVcv = stats->MVcv;
+ rc_frame_stats->mv_in_out_count = stats->mv_in_out_count;
+ rc_frame_stats->duration = stats->duration;
+ rc_frame_stats->count = stats->count;
+}
+
+void vp9_extrc_send_firstpass_stats(EXT_RATECTRL *ext_ratectrl,
+ const FIRST_PASS_INFO *first_pass_info) {
+ if (ext_ratectrl->ready) {
+ vpx_rc_firstpass_stats_t *rc_firstpass_stats =
+ &ext_ratectrl->rc_firstpass_stats;
+ int i;
+ assert(rc_firstpass_stats->num_frames == first_pass_info->num_frames);
+ for (i = 0; i < rc_firstpass_stats->num_frames; ++i) {
+ gen_rc_firstpass_stats(&first_pass_info->stats[i],
+ &rc_firstpass_stats->frame_stats[i]);
+ }
+ ext_ratectrl->funcs.send_firstpass_stats(ext_ratectrl->model,
+ rc_firstpass_stats);
+ }
+}
+
+static int extrc_get_frame_type(FRAME_UPDATE_TYPE update_type) {
+ // TODO(angiebird): Add unit test to make sure this function behaves like
+ // get_frame_type_from_update_type()
+ // TODO(angiebird): Merge this function with get_frame_type_from_update_type()
+ switch (update_type) {
+ case KF_UPDATE: return 0; // kFrameTypeKey;
+ case ARF_UPDATE: return 2; // kFrameTypeAltRef;
+ case GF_UPDATE: return 4; // kFrameTypeGolden;
+ case OVERLAY_UPDATE: return 3; // kFrameTypeOverlay;
+ case LF_UPDATE: return 1; // kFrameTypeInter;
+ default:
+ fprintf(stderr, "Unsupported update_type %d\n", update_type);
+ abort();
+ return 1;
+ }
+}
+
+void vp9_extrc_get_encodeframe_decision(
+ EXT_RATECTRL *ext_ratectrl, int show_index, int coding_index, int gop_index,
+ FRAME_UPDATE_TYPE update_type,
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES], int ref_frame_flags,
+ vpx_rc_encodeframe_decision_t *encode_frame_decision) {
+ if (ext_ratectrl->ready) {
+ vpx_rc_encodeframe_info_t encode_frame_info;
+ encode_frame_info.show_index = show_index;
+ encode_frame_info.coding_index = coding_index;
+ encode_frame_info.gop_index = gop_index;
+ encode_frame_info.frame_type = extrc_get_frame_type(update_type);
+
+ vp9_get_ref_frame_info(update_type, ref_frame_flags, ref_frame_bufs,
+ encode_frame_info.ref_frame_coding_indexes,
+ encode_frame_info.ref_frame_valid_list);
+
+ ext_ratectrl->funcs.get_encodeframe_decision(
+ ext_ratectrl->model, &encode_frame_info, encode_frame_decision);
+ }
+}
+
+void vp9_extrc_update_encodeframe_result(EXT_RATECTRL *ext_ratectrl,
+ int64_t bit_count,
+ const YV12_BUFFER_CONFIG *source_frame,
+ const YV12_BUFFER_CONFIG *coded_frame,
+ uint32_t bit_depth,
+ uint32_t input_bit_depth) {
+ if (ext_ratectrl->ready) {
+ PSNR_STATS psnr;
+ vpx_rc_encodeframe_result_t encode_frame_result;
+ encode_frame_result.bit_count = bit_count;
+ encode_frame_result.pixel_count =
+ source_frame->y_width * source_frame->y_height +
+ 2 * source_frame->uv_width * source_frame->uv_height;
+#if CONFIG_VP9_HIGHBITDEPTH
+ vpx_calc_highbd_psnr(source_frame, coded_frame, &psnr, bit_depth,
+ input_bit_depth);
+#else
+ (void)bit_depth;
+ (void)input_bit_depth;
+ vpx_calc_psnr(source_frame, coded_frame, &psnr);
+#endif
+ encode_frame_result.sse = psnr.sse[0];
+ ext_ratectrl->funcs.update_encodeframe_result(ext_ratectrl->model,
+ &encode_frame_result);
+ }
+}
diff --git a/vp9/encoder/vp9_ext_ratectrl.h b/vp9/encoder/vp9_ext_ratectrl.h
new file mode 100644
index 000000000..6a86218da
--- /dev/null
+++ b/vp9/encoder/vp9_ext_ratectrl.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE 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.
+ */
+
+#ifndef VPX_VP9_ENCODER_VP9_EXT_RATECTRL_H_
+#define VPX_VP9_ENCODER_VP9_EXT_RATECTRL_H_
+
+#include "vpx/vpx_ext_ratectrl.h"
+#include "vp9/encoder/vp9_firstpass.h"
+
+typedef struct EXT_RATECTRL {
+ int ready;
+ vpx_rc_model_t model;
+ vpx_rc_funcs_t funcs;
+ vpx_rc_config_t ratectrl_config;
+ vpx_rc_firstpass_stats_t rc_firstpass_stats;
+} EXT_RATECTRL;
+
+void vp9_extrc_init(EXT_RATECTRL *ext_ratectrl);
+
+void vp9_extrc_create(vpx_rc_funcs_t funcs, vpx_rc_config_t ratectrl_config,
+ EXT_RATECTRL *ext_ratectrl);
+
+void vp9_extrc_delete(EXT_RATECTRL *ext_ratectrl);
+
+void vp9_extrc_send_firstpass_stats(EXT_RATECTRL *ext_ratectrl,
+ const FIRST_PASS_INFO *first_pass_info);
+
+void vp9_extrc_get_encodeframe_decision(
+ EXT_RATECTRL *ext_ratectrl, int show_index, int coding_index, int gop_index,
+ FRAME_UPDATE_TYPE update_type,
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES], int ref_frame_flags,
+ vpx_rc_encodeframe_decision_t *encode_frame_decision);
+
+void vp9_extrc_update_encodeframe_result(EXT_RATECTRL *ext_ratectrl,
+ int64_t bit_count,
+ const YV12_BUFFER_CONFIG *source_frame,
+ const YV12_BUFFER_CONFIG *coded_frame,
+ uint32_t bit_depth,
+ uint32_t input_bit_depth);
+
+#endif // VPX_VP9_ENCODER_VP9_EXT_RATECTRL_H_
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index 384775507..de954f757 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -1388,7 +1388,9 @@ static void first_pass_encode(VP9_COMP *cpi, FIRSTPASS_DATA *fp_acc_data) {
vp9_tile_init(tile, cm, 0, 0);
#if CONFIG_RATE_CTRL
- fp_motion_vector_info_init(cpi);
+ fp_motion_vector_info_reset(cpi->frame_info.frame_width,
+ cpi->frame_info.frame_height,
+ cpi->fp_motion_vector_info);
#endif
for (mb_row = 0; mb_row < cm->mb_rows; ++mb_row) {
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index 9bb8d45d2..4b87ff2f0 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -441,6 +441,7 @@ void vp9_rc_init(const VP9EncoderConfig *oxcf, int pass, RATE_CONTROL *rc) {
rc->last_post_encode_dropped_scene_change = 0;
rc->use_post_encode_drop = 0;
rc->ext_use_post_encode_drop = 0;
+ rc->disable_overshoot_maxq_cbr = 0;
rc->arf_active_best_quality_adjustment_factor = 1.0;
rc->arf_increase_active_best_quality = 0;
rc->preserve_arf_as_gld = 0;
@@ -2704,18 +2705,18 @@ int vp9_resize_one_pass_cbr(VP9_COMP *cpi) {
// Force downsize based on per-frame-bandwidth, for extreme case,
// for HD input.
if (cpi->resize_state == ORIG && cm->width * cm->height >= 1280 * 720) {
- if (rc->avg_frame_bandwidth < (int)(300000 / 30)) {
+ if (rc->avg_frame_bandwidth < 300000 / 30) {
resize_action = DOWN_ONEHALF;
cpi->resize_state = ONE_HALF;
force_downsize_rate = 1;
- } else if (rc->avg_frame_bandwidth < (int)(400000 / 30)) {
+ } else if (rc->avg_frame_bandwidth < 400000 / 30) {
resize_action = ONEHALFONLY_RESIZE ? DOWN_ONEHALF : DOWN_THREEFOUR;
cpi->resize_state = ONEHALFONLY_RESIZE ? ONE_HALF : THREE_QUARTER;
force_downsize_rate = 1;
}
} else if (cpi->resize_state == THREE_QUARTER &&
cm->width * cm->height >= 960 * 540) {
- if (rc->avg_frame_bandwidth < (int)(300000 / 30)) {
+ if (rc->avg_frame_bandwidth < 300000 / 30) {
resize_action = DOWN_ONEHALF;
cpi->resize_state = ONE_HALF;
force_downsize_rate = 1;
@@ -3262,7 +3263,7 @@ int vp9_encodedframe_overshoot(VP9_COMP *cpi, int frame_size, int *q) {
int tl = 0;
int sl = 0;
SVC *svc = &cpi->svc;
- for (sl = 0; sl < svc->first_spatial_layer_to_encode; ++sl) {
+ for (sl = 0; sl < VPXMAX(1, svc->first_spatial_layer_to_encode); ++sl) {
for (tl = 0; tl < svc->number_temporal_layers; ++tl) {
const int layer =
LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers);
diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h
index c5ffb153c..0120f90a0 100644
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -195,7 +195,8 @@ typedef struct {
int use_post_encode_drop;
// External flag to enable post encode frame dropping, controlled by user.
int ext_use_post_encode_drop;
-
+ // Flag to disable CBR feature to increase Q on overshoot detection.
+ int disable_overshoot_maxq_cbr;
int damped_adjustment[RATE_FACTOR_LEVELS];
double arf_active_best_quality_adjustment_factor;
int arf_increase_active_best_quality;
diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c
index 5bbe54923..585c9604c 100644
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -621,7 +621,7 @@ static void set_rt_speed_feature_framesize_independent(
// increase in encoding time.
if (cpi->use_svc && svc->spatial_layer_id > 0) sf->nonrd_keyframe = 1;
if (cm->frame_type != KEY_FRAME && cpi->resize_state == ORIG &&
- cpi->oxcf.rc_mode == VPX_CBR) {
+ cpi->oxcf.rc_mode == VPX_CBR && !cpi->rc.disable_overshoot_maxq_cbr) {
if (cm->width * cm->height <= 352 * 288 && !cpi->use_svc &&
cpi->oxcf.content != VP9E_CONTENT_SCREEN)
sf->overshoot_detection_cbr_rt = RE_ENCODE_MAXQ;
@@ -668,7 +668,7 @@ static void set_rt_speed_feature_framesize_independent(
sf->base_mv_aggressive = 1;
}
if (cm->frame_type != KEY_FRAME && cpi->resize_state == ORIG &&
- cpi->oxcf.rc_mode == VPX_CBR)
+ cpi->oxcf.rc_mode == VPX_CBR && !cpi->rc.disable_overshoot_maxq_cbr)
sf->overshoot_detection_cbr_rt = FAST_DETECTION_MAXQ;
}
diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c
index d85b3632c..b6c7c74e1 100644
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -357,6 +357,7 @@ void vp9_restore_layer_context(VP9_COMP *const cpi) {
if (is_one_pass_cbr_svc(cpi) && lc->speed > 0) {
cpi->oxcf.speed = lc->speed;
}
+ cpi->loopfilter_ctrl = lc->loopfilter_ctrl;
// Reset the frames_since_key and frames_to_key counters to their values
// before the layer restore. Keep these defined for the stream (not layer).
if (cpi->svc.number_temporal_layers > 1 ||
diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h
index e7d9712aa..b12e7e01a 100644
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -71,6 +71,7 @@ typedef struct {
int actual_num_seg2_blocks;
int counter_encode_maxq_scene_change;
uint8_t speed;
+ int loopfilter_ctrl;
} LAYER_CONTEXT;
typedef struct SVC {
diff --git a/vp9/simple_encode.cc b/vp9/simple_encode.cc
index 46b25d1fd..d4eb0c669 100644
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -90,12 +90,20 @@ static int img_read(vpx_image_t *img, FILE *file) {
return 1;
}
+// Assume every config in VP9EncoderConfig is less than 100 characters.
+#define ENCODE_CONFIG_BUF_SIZE 100
+struct EncodeConfig {
+ char name[ENCODE_CONFIG_BUF_SIZE];
+ char value[ENCODE_CONFIG_BUF_SIZE];
+};
+
class SimpleEncode::EncodeImpl {
public:
VP9_COMP *cpi;
vpx_img_fmt_t img_fmt;
vpx_image_t tmp_img;
std::vector<FIRSTPASS_STATS> first_pass_stats;
+ std::vector<EncodeConfig> encode_config_list;
};
static VP9_COMP *init_encoder(const VP9EncoderConfig *oxcf,
@@ -199,6 +207,24 @@ static void update_motion_vector_info(
}
}
+static void update_tpl_stats_info(const TplDepStats *input_tpl_stats_info,
+ const int show_frame_count,
+ TplStatsInfo *output_tpl_stats_info) {
+ int frame_idx;
+ for (frame_idx = 0; frame_idx < show_frame_count; ++frame_idx) {
+ output_tpl_stats_info[frame_idx].intra_cost =
+ input_tpl_stats_info[frame_idx].intra_cost;
+ output_tpl_stats_info[frame_idx].inter_cost =
+ input_tpl_stats_info[frame_idx].inter_cost;
+ output_tpl_stats_info[frame_idx].mc_flow =
+ input_tpl_stats_info[frame_idx].mc_flow;
+ output_tpl_stats_info[frame_idx].mc_dep_cost =
+ input_tpl_stats_info[frame_idx].mc_dep_cost;
+ output_tpl_stats_info[frame_idx].mc_ref_cost =
+ input_tpl_stats_info[frame_idx].mc_ref_cost;
+ }
+}
+
static void update_frame_counts(const FRAME_COUNTS *input_counts,
FrameCounts *output_counts) {
// Init array sizes.
@@ -478,6 +504,7 @@ static bool init_encode_frame_result(EncodeFrameResult *encode_frame_result,
encode_frame_result->num_cols_4x4);
encode_frame_result->motion_vector_info.resize(
encode_frame_result->num_rows_4x4 * encode_frame_result->num_cols_4x4);
+ encode_frame_result->tpl_stats_info.resize(MAX_LAG_BUFFERS);
if (encode_frame_result->coding_data.get() == nullptr) {
return false;
@@ -499,7 +526,7 @@ static void encode_frame_result_update_rq_history(
}
static void update_encode_frame_result(
- EncodeFrameResult *encode_frame_result,
+ EncodeFrameResult *encode_frame_result, const int show_frame_count,
const ENCODE_FRAME_RESULT *encode_frame_info) {
encode_frame_result->coding_data_bit_size =
encode_frame_result->coding_data_byte_size * 8;
@@ -528,6 +555,10 @@ static void update_encode_frame_result(
kMotionVectorSubPixelPrecision);
update_frame_counts(&encode_frame_info->frame_counts,
&encode_frame_result->frame_counts);
+ if (encode_frame_result->frame_type == kFrameTypeAltRef) {
+ update_tpl_stats_info(encode_frame_info->tpl_stats_info, show_frame_count,
+ &encode_frame_result->tpl_stats_info[0]);
+ }
encode_frame_result_update_rq_history(&encode_frame_info->rq_history,
encode_frame_result);
}
@@ -711,6 +742,60 @@ static void UpdateGroupOfPicture(const VP9_COMP *cpi, int start_coding_index,
start_ref_frame_info, group_of_picture);
}
+#define SET_STRUCT_VALUE(config, structure, ret, field) \
+ if (strcmp(config.name, #field) == 0) { \
+ structure->field = atoi(config.value); \
+ ret = 1; \
+ }
+
+static void UpdateEncodeConfig(const EncodeConfig &config,
+ VP9EncoderConfig *oxcf) {
+ int ret = 0;
+ SET_STRUCT_VALUE(config, oxcf, ret, key_freq);
+ SET_STRUCT_VALUE(config, oxcf, ret, two_pass_vbrmin_section);
+ SET_STRUCT_VALUE(config, oxcf, ret, two_pass_vbrmax_section);
+ SET_STRUCT_VALUE(config, oxcf, ret, under_shoot_pct);
+ SET_STRUCT_VALUE(config, oxcf, ret, over_shoot_pct);
+ SET_STRUCT_VALUE(config, oxcf, ret, max_threads);
+ SET_STRUCT_VALUE(config, oxcf, ret, frame_parallel_decoding_mode);
+ SET_STRUCT_VALUE(config, oxcf, ret, tile_columns);
+ SET_STRUCT_VALUE(config, oxcf, ret, arnr_max_frames);
+ SET_STRUCT_VALUE(config, oxcf, ret, arnr_strength);
+ SET_STRUCT_VALUE(config, oxcf, ret, lag_in_frames);
+ SET_STRUCT_VALUE(config, oxcf, ret, encode_breakout);
+ SET_STRUCT_VALUE(config, oxcf, ret, enable_tpl_model);
+ SET_STRUCT_VALUE(config, oxcf, ret, enable_auto_arf);
+ if (strcmp(config.name, "rc_mode") == 0) {
+ int rc_mode = atoi(config.value);
+ if (rc_mode >= VPX_VBR && rc_mode <= VPX_Q) {
+ oxcf->rc_mode = (enum vpx_rc_mode)rc_mode;
+ ret = 1;
+ } else {
+ fprintf(stderr, "Invalid rc_mode value: %d\n", rc_mode);
+ }
+ }
+ SET_STRUCT_VALUE(config, oxcf, ret, cq_level);
+ if (ret == 0) {
+ fprintf(stderr, "Ignored unsupported encode_config %s\n", config.name);
+ }
+}
+
+static VP9EncoderConfig GetEncodeConfig(
+ int frame_width, int frame_height, vpx_rational_t frame_rate,
+ int target_bitrate, int encode_speed, vpx_enc_pass enc_pass,
+ const std::vector<EncodeConfig> &encode_config_list) {
+ VP9EncoderConfig oxcf =
+ vp9_get_encoder_config(frame_width, frame_height, frame_rate,
+ target_bitrate, encode_speed, enc_pass);
+ for (const auto &config : encode_config_list) {
+ UpdateEncodeConfig(config, &oxcf);
+ }
+ if (enc_pass == VPX_RC_FIRST_PASS) {
+ oxcf.lag_in_frames = 0;
+ }
+ return oxcf;
+}
+
SimpleEncode::SimpleEncode(int frame_width, int frame_height,
int frame_rate_num, int frame_rate_den,
int target_bitrate, int num_frames,
@@ -748,12 +833,45 @@ void SimpleEncode::SetEncodeSpeed(int encode_speed) {
encode_speed_ = encode_speed;
}
+StatusCode SimpleEncode::SetEncodeConfig(const char *name, const char *value) {
+ if (name == nullptr || value == nullptr) {
+ fprintf(stderr, "SetEncodeConfig: null pointer, name %p value %p\n", name,
+ value);
+ return StatusError;
+ }
+ EncodeConfig config;
+ snprintf(config.name, ENCODE_CONFIG_BUF_SIZE, "%s", name);
+ snprintf(config.value, ENCODE_CONFIG_BUF_SIZE, "%s", value);
+ impl_ptr_->encode_config_list.push_back(config);
+ return StatusOk;
+}
+
+StatusCode SimpleEncode::DumpEncodeConfigs(int pass, FILE *fp) {
+ if (fp == nullptr) {
+ fprintf(stderr, "DumpEncodeConfigs: null pointer, fp %p\n", fp);
+ return StatusError;
+ }
+ vpx_enc_pass enc_pass;
+ if (pass == 1) {
+ enc_pass = VPX_RC_FIRST_PASS;
+ } else {
+ enc_pass = VPX_RC_LAST_PASS;
+ }
+ const vpx_rational_t frame_rate =
+ make_vpx_rational(frame_rate_num_, frame_rate_den_);
+ const VP9EncoderConfig oxcf =
+ GetEncodeConfig(frame_width_, frame_height_, frame_rate, target_bitrate_,
+ encode_speed_, enc_pass, impl_ptr_->encode_config_list);
+ vp9_dump_encoder_config(&oxcf, fp);
+ return StatusOk;
+}
+
void SimpleEncode::ComputeFirstPassStats() {
vpx_rational_t frame_rate =
make_vpx_rational(frame_rate_num_, frame_rate_den_);
- const VP9EncoderConfig oxcf =
- vp9_get_encoder_config(frame_width_, frame_height_, frame_rate,
- target_bitrate_, encode_speed_, VPX_RC_FIRST_PASS);
+ const VP9EncoderConfig oxcf = GetEncodeConfig(
+ frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_,
+ VPX_RC_FIRST_PASS, impl_ptr_->encode_config_list);
VP9_COMP *cpi = init_encoder(&oxcf, impl_ptr_->img_fmt);
struct lookahead_ctx *lookahead = cpi->lookahead;
int i;
@@ -913,9 +1031,10 @@ void SimpleEncode::StartEncode() {
assert(impl_ptr_->first_pass_stats.size() > 0);
vpx_rational_t frame_rate =
make_vpx_rational(frame_rate_num_, frame_rate_den_);
- VP9EncoderConfig oxcf =
- vp9_get_encoder_config(frame_width_, frame_height_, frame_rate,
- target_bitrate_, encode_speed_, VPX_RC_LAST_PASS);
+ VP9EncoderConfig oxcf = GetEncodeConfig(
+ frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_,
+ VPX_RC_LAST_PASS, impl_ptr_->encode_config_list);
+
vpx_fixed_buf_t stats;
stats.buf = GetVectorData(impl_ptr_->first_pass_stats);
stats.sz = sizeof(impl_ptr_->first_pass_stats[0]) *
@@ -1083,7 +1202,10 @@ void SimpleEncode::EncodeFrame(EncodeFrameResult *encode_frame_result) {
abort();
}
- update_encode_frame_result(encode_frame_result, &encode_frame_info);
+ const GroupOfPicture group_of_picture = this->ObserveGroupOfPicture();
+ const int show_frame_count = group_of_picture.show_frame_count;
+ update_encode_frame_result(encode_frame_result, show_frame_count,
+ &encode_frame_info);
PostUpdateState(*encode_frame_result);
} else {
// TODO(angiebird): Clean up encode_frame_result.
@@ -1132,9 +1254,9 @@ int SimpleEncode::GetCodingFrameNum() const {
const int allow_alt_ref = 1;
vpx_rational_t frame_rate =
make_vpx_rational(frame_rate_num_, frame_rate_den_);
- const VP9EncoderConfig oxcf =
- vp9_get_encoder_config(frame_width_, frame_height_, frame_rate,
- target_bitrate_, encode_speed_, VPX_RC_LAST_PASS);
+ const VP9EncoderConfig oxcf = GetEncodeConfig(
+ frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_,
+ VPX_RC_LAST_PASS, impl_ptr_->encode_config_list);
FRAME_INFO frame_info = vp9_get_frame_info(&oxcf);
FIRST_PASS_INFO first_pass_info;
fps_init_first_pass_info(&first_pass_info,
@@ -1149,9 +1271,9 @@ std::vector<int> SimpleEncode::ComputeKeyFrameMap() const {
assert(impl_ptr_->first_pass_stats.size() == num_frames_ + 1);
vpx_rational_t frame_rate =
make_vpx_rational(frame_rate_num_, frame_rate_den_);
- const VP9EncoderConfig oxcf =
- vp9_get_encoder_config(frame_width_, frame_height_, frame_rate,
- target_bitrate_, encode_speed_, VPX_RC_LAST_PASS);
+ const VP9EncoderConfig oxcf = GetEncodeConfig(
+ frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_,
+ VPX_RC_LAST_PASS, impl_ptr_->encode_config_list);
FRAME_INFO frame_info = vp9_get_frame_info(&oxcf);
FIRST_PASS_INFO first_pass_info;
fps_init_first_pass_info(&first_pass_info,
diff --git a/vp9/simple_encode.h b/vp9/simple_encode.h
index 8f0d37439..e3ef3cea9 100644
--- a/vp9/simple_encode.h
+++ b/vp9/simple_encode.h
@@ -19,13 +19,18 @@
namespace vp9 {
+enum StatusCode {
+ StatusOk = 0,
+ StatusError,
+};
+
// TODO(angiebird): Add description for each frame type.
enum FrameType {
kFrameTypeKey = 0,
- kFrameTypeInter,
- kFrameTypeAltRef,
- kFrameTypeOverlay,
- kFrameTypeGolden,
+ kFrameTypeInter = 1,
+ kFrameTypeAltRef = 2,
+ kFrameTypeOverlay = 3,
+ kFrameTypeGolden = 4,
};
// TODO(angiebird): Add description for each reference frame type.
@@ -82,6 +87,24 @@ struct MotionVectorInfo {
double mv_column[2];
};
+// Accumulated tpl stats of all blocks in one frame.
+// For each frame, the tpl stats are computed per 32x32 block.
+struct TplStatsInfo {
+ // Intra complexity: the sum of absolute transform difference (SATD) of
+ // intra predicted residuals.
+ int64_t intra_cost;
+ // Inter complexity: the SATD of inter predicted residuals.
+ int64_t inter_cost;
+ // Motion compensated information flow. It measures how much information
+ // is propagated from the current frame to other frames.
+ int64_t mc_flow;
+ // Motion compensated dependency cost. It equals to its own intra_cost
+ // plus the mc_flow.
+ int64_t mc_dep_cost;
+ // Motion compensated reference cost.
+ int64_t mc_ref_cost;
+};
+
struct RefFrameInfo {
int coding_indexes[kRefFrameTypeMax];
@@ -256,6 +279,18 @@ struct EncodeFrameResult {
// Similar to partition info, all 4x4 blocks inside the same partition block
// share the same motion vector information.
std::vector<MotionVectorInfo> motion_vector_info;
+ // A vector of the tpl stats information.
+ // The tpl stats measure the complexity of a frame, as well as the
+ // informatioin propagated along the motion trajactory between frames, in
+ // the reference frame structure.
+ // The tpl stats could be used as a more accurate spatial and temporal
+ // complexity measure in addition to the first pass stats.
+ // The vector contains tpl stats for all show frames in a GOP.
+ // The tpl stats stored in the vector is according to the encoding order.
+ // For example, suppose there are N show frames for the current GOP.
+ // Then tpl_stats_info[0] stores the information of the first frame to be
+ // encoded for this GOP, i.e, the AltRef frame.
+ std::vector<TplStatsInfo> tpl_stats_info;
ImageBuffer coded_frame;
// recode_count, q_index_history and rate_history are only available when
@@ -322,6 +357,43 @@ class SimpleEncode {
// at the cost of lower compression efficiency.
void SetEncodeSpeed(int encode_speed);
+ // Set encoder config
+ // The following configs in VP9EncoderConfig are allowed to change in this
+ // function. See https://ffmpeg.org/ffmpeg-codecs.html#libvpx for each
+ // config's meaning.
+ // Configs in VP9EncoderConfig: Equivalent configs in ffmpeg:
+ // 1 key_freq -g
+ // 2 two_pass_vbrmin_section -minrate * 100LL / bit_rate
+ // 3 two_pass_vbrmax_section -maxrate * 100LL / bit_rate
+ // 4 under_shoot_pct -undershoot-pct
+ // 5 over_shoot_pct -overshoot-pct
+ // 6 max_threads -threads
+ // 7 frame_parallel_decoding_mode -frame-parallel
+ // 8 tile_column -tile-columns
+ // 9 arnr_max_frames -arnr-maxframes
+ // 10 arnr_strength -arnr-strength
+ // 11 lag_in_frames -rc_lookahead
+ // 12 encode_breakout -static-thresh
+ // 13 enable_tpl_model -enable-tpl
+ // 14 enable_auto_arf -auto-alt-ref
+ // 15 rc_mode
+ // Possible Settings:
+ // 0 - Variable Bit Rate (VPX_VBR) -b:v <bit_rate>
+ // 1 - Constant Bit Rate (VPX_CBR) -b:v <bit_rate> -minrate <bit_rate>
+ // -maxrate <bit_rate>
+ // two_pass_vbrmin_section == 100 i.e. bit_rate == minrate == maxrate
+ // two_pass_vbrmax_section == 100
+ // 2 - Constrained Quality (VPX_CQ) -crf <cq_level> -b:v bit_rate
+ // 3 - Constant Quality (VPX_Q) -crf <cq_level> -b:v 0
+ // See https://trac.ffmpeg.org/wiki/Encode/VP9 for more details.
+ // 16 cq_level see rc_mode for details.
+ StatusCode SetEncodeConfig(const char *name, const char *value);
+
+ // A debug function that dumps configs from VP9EncoderConfig
+ // pass = 1: first pass, pass = 2: second pass
+ // fp: file pointer for dumping config
+ StatusCode DumpEncodeConfigs(int pass, FILE *fp);
+
// Makes encoder compute the first pass stats and store it at
// impl_ptr_->first_pass_stats. key_frame_map_ is also computed based on the
// first pass stats.
@@ -400,9 +472,9 @@ class SimpleEncode {
// Encode a frame with target frame bits usage.
// The encoder will find a quantize index to make the actual frame bits usage
// match the target. EncodeFrameWithTargetFrameBits() will recode the frame
- // update to 7 times to find a q_index to make the actual_frame_bits to
- // satisfy following inequality.
- // |actual_frame_bits - target_frame_bits| * 100 / target_frame_bits
+ // up to 7 times to find a q_index to make the actual_frame_bits satisfy the
+ // following inequality. |actual_frame_bits - target_frame_bits| * 100 /
+ // target_frame_bits
// <= percent_diff.
void EncodeFrameWithTargetFrameBits(EncodeFrameResult *encode_frame_result,
int target_frame_bits,
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index 6caa4f739..a73683dfe 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -13,6 +13,7 @@
#include "./vpx_config.h"
#include "vpx/vpx_encoder.h"
+#include "vpx/vpx_ext_ratectrl.h"
#include "vpx_dsp/psnr.h"
#include "vpx_ports/vpx_once.h"
#include "vpx_ports/static_assert.h"
@@ -633,7 +634,7 @@ static vpx_codec_err_t set_encoder_config(
}
if (get_level_index(oxcf->target_level) >= 0) config_target_level(oxcf);
- // vp9_dump_encoder_config(oxcf);
+ // vp9_dump_encoder_config(oxcf, stderr);
return VPX_CODEC_OK;
}
@@ -1572,6 +1573,7 @@ static vpx_codec_err_t ctrl_set_svc_parameters(vpx_codec_alg_priv_t *ctx,
lc->scaling_factor_num = params->scaling_factor_num[sl];
lc->scaling_factor_den = params->scaling_factor_den[sl];
lc->speed = params->speed_per_layer[sl];
+ lc->loopfilter_ctrl = params->loopfilter_ctrl[sl];
}
}
@@ -1716,6 +1718,48 @@ static vpx_codec_err_t ctrl_set_postencode_drop(vpx_codec_alg_priv_t *ctx,
return VPX_CODEC_OK;
}
+static vpx_codec_err_t ctrl_set_disable_overshoot_maxq_cbr(
+ vpx_codec_alg_priv_t *ctx, va_list args) {
+ VP9_COMP *const cpi = ctx->cpi;
+ const unsigned int data = va_arg(args, unsigned int);
+ cpi->rc.disable_overshoot_maxq_cbr = data;
+ return VPX_CODEC_OK;
+}
+
+static vpx_codec_err_t ctrl_set_disable_loopfilter(vpx_codec_alg_priv_t *ctx,
+ va_list args) {
+ VP9_COMP *const cpi = ctx->cpi;
+ const unsigned int data = va_arg(args, unsigned int);
+ cpi->loopfilter_ctrl = data;
+ return VPX_CODEC_OK;
+}
+
+static vpx_codec_err_t ctrl_set_external_rate_control(vpx_codec_alg_priv_t *ctx,
+ va_list args) {
+ vpx_rc_funcs_t funcs = *CAST(VP9E_SET_EXTERNAL_RATE_CONTROL, args);
+ VP9_COMP *cpi = ctx->cpi;
+ EXT_RATECTRL *ext_ratectrl = &cpi->ext_ratectrl;
+ const VP9EncoderConfig *oxcf = &cpi->oxcf;
+ // TODO(angiebird): Check the possibility of this flag being set at pass == 1
+ if (oxcf->pass == 2) {
+ const FRAME_INFO *frame_info = &cpi->frame_info;
+ vpx_rc_config_t ratectrl_config;
+
+ ratectrl_config.frame_width = frame_info->frame_width;
+ ratectrl_config.frame_height = frame_info->frame_height;
+ ratectrl_config.show_frame_count = cpi->twopass.first_pass_info.num_frames;
+
+ // TODO(angiebird): Double check whether this is the proper way to set up
+ // target_bitrate and frame_rate.
+ ratectrl_config.target_bitrate_kbps = (int)(oxcf->target_bandwidth / 1000);
+ ratectrl_config.frame_rate_num = oxcf->g_timebase.den;
+ ratectrl_config.frame_rate_den = oxcf->g_timebase.num;
+
+ vp9_extrc_create(funcs, ratectrl_config, ext_ratectrl);
+ }
+ return VPX_CODEC_OK;
+}
+
static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{ VP8_COPY_REFERENCE, ctrl_copy_reference },
@@ -1760,12 +1804,15 @@ static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{ VP9E_SET_TARGET_LEVEL, ctrl_set_target_level },
{ VP9E_SET_ROW_MT, ctrl_set_row_mt },
{ VP9E_SET_POSTENCODE_DROP, ctrl_set_postencode_drop },
+ { VP9E_SET_DISABLE_OVERSHOOT_MAXQ_CBR, ctrl_set_disable_overshoot_maxq_cbr },
{ VP9E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test },
{ VP9E_SET_SVC_INTER_LAYER_PRED, ctrl_set_svc_inter_layer_pred },
{ VP9E_SET_SVC_FRAME_DROP_LAYER, ctrl_set_svc_frame_drop_layer },
{ VP9E_SET_SVC_GF_TEMPORAL_REF, ctrl_set_svc_gf_temporal_ref },
{ VP9E_SET_SVC_SPATIAL_LAYER_SYNC, ctrl_set_svc_spatial_layer_sync },
{ VP9E_SET_DELTA_Q_UV, ctrl_set_delta_q_uv },
+ { VP9E_SET_DISABLE_LOOPFILTER, ctrl_set_disable_loopfilter },
+ { VP9E_SET_EXTERNAL_RATE_CONTROL, ctrl_set_external_rate_control },
// Getters
{ VP8E_GET_LAST_QUANTIZER, ctrl_get_quantizer },
@@ -1952,46 +1999,46 @@ VP9EncoderConfig vp9_get_encoder_config(int frame_width, int frame_height,
return oxcf;
}
-#define DUMP_STRUCT_VALUE(struct, value) \
- printf(#value " %" PRId64 "\n", (int64_t)(struct)->value)
+#define DUMP_STRUCT_VALUE(fp, structure, value) \
+ fprintf(fp, #value " %" PRId64 "\n", (int64_t)(structure)->value)
-void vp9_dump_encoder_config(const VP9EncoderConfig *oxcf) {
- DUMP_STRUCT_VALUE(oxcf, profile);
- DUMP_STRUCT_VALUE(oxcf, bit_depth);
- DUMP_STRUCT_VALUE(oxcf, width);
- DUMP_STRUCT_VALUE(oxcf, height);
- DUMP_STRUCT_VALUE(oxcf, input_bit_depth);
- DUMP_STRUCT_VALUE(oxcf, init_framerate);
+void vp9_dump_encoder_config(const VP9EncoderConfig *oxcf, FILE *fp) {
+ DUMP_STRUCT_VALUE(fp, oxcf, profile);
+ DUMP_STRUCT_VALUE(fp, oxcf, bit_depth);
+ DUMP_STRUCT_VALUE(fp, oxcf, width);
+ DUMP_STRUCT_VALUE(fp, oxcf, height);
+ DUMP_STRUCT_VALUE(fp, oxcf, input_bit_depth);
+ DUMP_STRUCT_VALUE(fp, oxcf, init_framerate);
// TODO(angiebird): dump g_timebase
// TODO(angiebird): dump g_timebase_in_ts
- DUMP_STRUCT_VALUE(oxcf, target_bandwidth);
+ DUMP_STRUCT_VALUE(fp, oxcf, target_bandwidth);
- DUMP_STRUCT_VALUE(oxcf, noise_sensitivity);
- DUMP_STRUCT_VALUE(oxcf, sharpness);
- DUMP_STRUCT_VALUE(oxcf, speed);
- DUMP_STRUCT_VALUE(oxcf, rc_max_intra_bitrate_pct);
- DUMP_STRUCT_VALUE(oxcf, rc_max_inter_bitrate_pct);
- DUMP_STRUCT_VALUE(oxcf, gf_cbr_boost_pct);
+ DUMP_STRUCT_VALUE(fp, oxcf, noise_sensitivity);
+ DUMP_STRUCT_VALUE(fp, oxcf, sharpness);
+ DUMP_STRUCT_VALUE(fp, oxcf, speed);
+ DUMP_STRUCT_VALUE(fp, oxcf, rc_max_intra_bitrate_pct);
+ DUMP_STRUCT_VALUE(fp, oxcf, rc_max_inter_bitrate_pct);
+ DUMP_STRUCT_VALUE(fp, oxcf, gf_cbr_boost_pct);
- DUMP_STRUCT_VALUE(oxcf, mode);
- DUMP_STRUCT_VALUE(oxcf, pass);
+ DUMP_STRUCT_VALUE(fp, oxcf, mode);
+ DUMP_STRUCT_VALUE(fp, oxcf, pass);
// Key Framing Operations
- DUMP_STRUCT_VALUE(oxcf, auto_key);
- DUMP_STRUCT_VALUE(oxcf, key_freq);
+ DUMP_STRUCT_VALUE(fp, oxcf, auto_key);
+ DUMP_STRUCT_VALUE(fp, oxcf, key_freq);
- DUMP_STRUCT_VALUE(oxcf, lag_in_frames);
+ DUMP_STRUCT_VALUE(fp, oxcf, lag_in_frames);
// ----------------------------------------------------------------
// DATARATE CONTROL OPTIONS
// vbr, cbr, constrained quality or constant quality
- DUMP_STRUCT_VALUE(oxcf, rc_mode);
+ DUMP_STRUCT_VALUE(fp, oxcf, rc_mode);
// buffer targeting aggressiveness
- DUMP_STRUCT_VALUE(oxcf, under_shoot_pct);
- DUMP_STRUCT_VALUE(oxcf, over_shoot_pct);
+ DUMP_STRUCT_VALUE(fp, oxcf, under_shoot_pct);
+ DUMP_STRUCT_VALUE(fp, oxcf, over_shoot_pct);
// buffering parameters
// TODO(angiebird): dump tarting_buffer_level_ms
@@ -1999,37 +2046,37 @@ void vp9_dump_encoder_config(const VP9EncoderConfig *oxcf) {
// TODO(angiebird): dump maximum_buffer_size_ms
// Frame drop threshold.
- DUMP_STRUCT_VALUE(oxcf, drop_frames_water_mark);
+ DUMP_STRUCT_VALUE(fp, oxcf, drop_frames_water_mark);
// controlling quality
- DUMP_STRUCT_VALUE(oxcf, fixed_q);
- DUMP_STRUCT_VALUE(oxcf, worst_allowed_q);
- DUMP_STRUCT_VALUE(oxcf, best_allowed_q);
- DUMP_STRUCT_VALUE(oxcf, cq_level);
- DUMP_STRUCT_VALUE(oxcf, aq_mode);
+ DUMP_STRUCT_VALUE(fp, oxcf, fixed_q);
+ DUMP_STRUCT_VALUE(fp, oxcf, worst_allowed_q);
+ DUMP_STRUCT_VALUE(fp, oxcf, best_allowed_q);
+ DUMP_STRUCT_VALUE(fp, oxcf, cq_level);
+ DUMP_STRUCT_VALUE(fp, oxcf, aq_mode);
// Special handling of Adaptive Quantization for AltRef frames
- DUMP_STRUCT_VALUE(oxcf, alt_ref_aq);
+ DUMP_STRUCT_VALUE(fp, oxcf, alt_ref_aq);
// Internal frame size scaling.
- DUMP_STRUCT_VALUE(oxcf, resize_mode);
- DUMP_STRUCT_VALUE(oxcf, scaled_frame_width);
- DUMP_STRUCT_VALUE(oxcf, scaled_frame_height);
+ DUMP_STRUCT_VALUE(fp, oxcf, resize_mode);
+ DUMP_STRUCT_VALUE(fp, oxcf, scaled_frame_width);
+ DUMP_STRUCT_VALUE(fp, oxcf, scaled_frame_height);
// Enable feature to reduce the frame quantization every x frames.
- DUMP_STRUCT_VALUE(oxcf, frame_periodic_boost);
+ DUMP_STRUCT_VALUE(fp, oxcf, frame_periodic_boost);
// two pass datarate control
- DUMP_STRUCT_VALUE(oxcf, two_pass_vbrbias);
- DUMP_STRUCT_VALUE(oxcf, two_pass_vbrmin_section);
- DUMP_STRUCT_VALUE(oxcf, two_pass_vbrmax_section);
- DUMP_STRUCT_VALUE(oxcf, vbr_corpus_complexity);
+ DUMP_STRUCT_VALUE(fp, oxcf, two_pass_vbrbias);
+ DUMP_STRUCT_VALUE(fp, oxcf, two_pass_vbrmin_section);
+ DUMP_STRUCT_VALUE(fp, oxcf, two_pass_vbrmax_section);
+ DUMP_STRUCT_VALUE(fp, oxcf, vbr_corpus_complexity);
// END DATARATE CONTROL OPTIONS
// ----------------------------------------------------------------
// Spatial and temporal scalability.
- DUMP_STRUCT_VALUE(oxcf, ss_number_layers);
- DUMP_STRUCT_VALUE(oxcf, ts_number_layers);
+ DUMP_STRUCT_VALUE(fp, oxcf, ss_number_layers);
+ DUMP_STRUCT_VALUE(fp, oxcf, ts_number_layers);
// Bitrate allocation for spatial layers.
// TODO(angiebird): dump layer_target_bitrate[VPX_MAX_LAYERS]
@@ -2037,25 +2084,25 @@ void vp9_dump_encoder_config(const VP9EncoderConfig *oxcf) {
// TODO(angiebird): dump ss_enable_auto_arf[VPX_SS_MAX_LAYERS]
// TODO(angiebird): dump ts_rate_decimator[VPX_TS_MAX_LAYERS]
- DUMP_STRUCT_VALUE(oxcf, enable_auto_arf);
- DUMP_STRUCT_VALUE(oxcf, encode_breakout);
- DUMP_STRUCT_VALUE(oxcf, error_resilient_mode);
- DUMP_STRUCT_VALUE(oxcf, frame_parallel_decoding_mode);
+ DUMP_STRUCT_VALUE(fp, oxcf, enable_auto_arf);
+ DUMP_STRUCT_VALUE(fp, oxcf, encode_breakout);
+ DUMP_STRUCT_VALUE(fp, oxcf, error_resilient_mode);
+ DUMP_STRUCT_VALUE(fp, oxcf, frame_parallel_decoding_mode);
- DUMP_STRUCT_VALUE(oxcf, arnr_max_frames);
- DUMP_STRUCT_VALUE(oxcf, arnr_strength);
+ DUMP_STRUCT_VALUE(fp, oxcf, arnr_max_frames);
+ DUMP_STRUCT_VALUE(fp, oxcf, arnr_strength);
- DUMP_STRUCT_VALUE(oxcf, min_gf_interval);
- DUMP_STRUCT_VALUE(oxcf, max_gf_interval);
+ DUMP_STRUCT_VALUE(fp, oxcf, min_gf_interval);
+ DUMP_STRUCT_VALUE(fp, oxcf, max_gf_interval);
- DUMP_STRUCT_VALUE(oxcf, tile_columns);
- DUMP_STRUCT_VALUE(oxcf, tile_rows);
+ DUMP_STRUCT_VALUE(fp, oxcf, tile_columns);
+ DUMP_STRUCT_VALUE(fp, oxcf, tile_rows);
- DUMP_STRUCT_VALUE(oxcf, enable_tpl_model);
+ DUMP_STRUCT_VALUE(fp, oxcf, enable_tpl_model);
- DUMP_STRUCT_VALUE(oxcf, max_threads);
+ DUMP_STRUCT_VALUE(fp, oxcf, max_threads);
- DUMP_STRUCT_VALUE(oxcf, target_level);
+ DUMP_STRUCT_VALUE(fp, oxcf, target_level);
// TODO(angiebird): dump two_pass_stats_in
@@ -2063,19 +2110,19 @@ void vp9_dump_encoder_config(const VP9EncoderConfig *oxcf) {
// TODO(angiebird): dump firstpass_mb_stats_in
#endif
- DUMP_STRUCT_VALUE(oxcf, tuning);
- DUMP_STRUCT_VALUE(oxcf, content);
+ DUMP_STRUCT_VALUE(fp, oxcf, tuning);
+ DUMP_STRUCT_VALUE(fp, oxcf, content);
#if CONFIG_VP9_HIGHBITDEPTH
- DUMP_STRUCT_VALUE(oxcf, use_highbitdepth);
+ DUMP_STRUCT_VALUE(fp, oxcf, use_highbitdepth);
#endif
- DUMP_STRUCT_VALUE(oxcf, color_space);
- DUMP_STRUCT_VALUE(oxcf, color_range);
- DUMP_STRUCT_VALUE(oxcf, render_width);
- DUMP_STRUCT_VALUE(oxcf, render_height);
- DUMP_STRUCT_VALUE(oxcf, temporal_layering_mode);
-
- DUMP_STRUCT_VALUE(oxcf, row_mt);
- DUMP_STRUCT_VALUE(oxcf, motion_vector_unit_test);
+ DUMP_STRUCT_VALUE(fp, oxcf, color_space);
+ DUMP_STRUCT_VALUE(fp, oxcf, color_range);
+ DUMP_STRUCT_VALUE(fp, oxcf, render_width);
+ DUMP_STRUCT_VALUE(fp, oxcf, render_height);
+ DUMP_STRUCT_VALUE(fp, oxcf, temporal_layering_mode);
+
+ DUMP_STRUCT_VALUE(fp, oxcf, row_mt);
+ DUMP_STRUCT_VALUE(fp, oxcf, motion_vector_unit_test);
}
FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf) {
diff --git a/vp9/vp9_cx_iface.h b/vp9/vp9_cx_iface.h
index 3188575dd..01338adb4 100644
--- a/vp9/vp9_cx_iface.h
+++ b/vp9/vp9_cx_iface.h
@@ -22,7 +22,7 @@ VP9EncoderConfig vp9_get_encoder_config(int frame_width, int frame_height,
int target_bitrate, int encode_speed,
vpx_enc_pass enc_pass);
-void vp9_dump_encoder_config(const VP9EncoderConfig *oxcf);
+void vp9_dump_encoder_config(const VP9EncoderConfig *oxcf, FILE *fp);
FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf);
diff --git a/vp9/vp9cx.mk b/vp9/vp9cx.mk
index 666f22882..38e99165a 100644
--- a/vp9/vp9cx.mk
+++ b/vp9/vp9cx.mk
@@ -96,6 +96,8 @@ VP9_CX_SRCS-yes += encoder/vp9_skin_detection.c
VP9_CX_SRCS-yes += encoder/vp9_skin_detection.h
VP9_CX_SRCS-yes += encoder/vp9_noise_estimate.c
VP9_CX_SRCS-yes += encoder/vp9_noise_estimate.h
+VP9_CX_SRCS-yes += encoder/vp9_ext_ratectrl.c
+VP9_CX_SRCS-yes += encoder/vp9_ext_ratectrl.h
ifeq ($(CONFIG_VP9_POSTPROC),yes)
VP9_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/vp9_postproc.h
VP9_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/vp9_postproc.c
diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h
index dcdd710c0..37ad07d33 100644
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -17,6 +17,7 @@
*/
#include "./vp8.h"
#include "./vpx_encoder.h"
+#include "./vpx_ext_ratectrl.h"
/*!\file
* \brief Provides definitions for using VP8 or VP9 encoder algorithm within the
@@ -684,6 +685,33 @@ enum vp8e_enc_control_id {
* Supported in codecs: VP9
*/
VP9E_SET_DELTA_Q_UV,
+
+ /*!\brief Codec control function to disable increase Q on overshoot in CBR.
+ *
+ * 0: On (default), 1: Disable.
+ *
+ * Supported in codecs: VP9
+ */
+ VP9E_SET_DISABLE_OVERSHOOT_MAXQ_CBR,
+
+ /*!\brief Codec control function to disable loopfilter.
+ *
+ * 0: Loopfilter on all frames, 1: Disable on non reference frames.
+ * 2: Disable on all frames.
+ *
+ * Supported in codecs: VP9
+ */
+ VP9E_SET_DISABLE_LOOPFILTER,
+
+ /*!\brief Codec control function to enable external rate control library.
+ *
+ * args[0]: path of the rate control library
+ *
+ * args[1]: private config of the rate control library
+ *
+ * Supported in codecs: VP9
+ */
+ VP9E_SET_EXTERNAL_RATE_CONTROL,
};
/*!\brief vpx 1-D scaling mode
@@ -1034,6 +1062,15 @@ VPX_CTRL_USE_TYPE(VP9E_SET_POSTENCODE_DROP, unsigned int)
VPX_CTRL_USE_TYPE(VP9E_SET_DELTA_Q_UV, int)
#define VPX_CTRL_VP9E_SET_DELTA_Q_UV
+VPX_CTRL_USE_TYPE(VP9E_SET_DISABLE_OVERSHOOT_MAXQ_CBR, int)
+#define VPX_CTRL_VP9E_SET_DISABLE_OVERSHOOT_MAXQ_CBR
+
+VPX_CTRL_USE_TYPE(VP9E_SET_DISABLE_LOOPFILTER, int)
+#define VPX_CTRL_VP9E_SET_DISABLE_LOOPFILTER
+
+VPX_CTRL_USE_TYPE(VP9E_SET_EXTERNAL_RATE_CONTROL, vpx_rc_funcs_t *)
+#define VPX_CTRL_VP9E_SET_EXTERNAL_RATE_CONTROL
+
/*!\endcond */
/*! @} - end defgroup vp8_encoder */
#ifdef __cplusplus
diff --git a/vpx/vpx_codec.mk b/vpx/vpx_codec.mk
index 4ed77ad6d..350dc247b 100644
--- a/vpx/vpx_codec.mk
+++ b/vpx/vpx_codec.mk
@@ -24,6 +24,7 @@ API_DOC_SRCS-$(CONFIG_VP8_DECODER) += vp8dx.h
API_DOC_SRCS-yes += vpx_codec.h
API_DOC_SRCS-yes += vpx_decoder.h
API_DOC_SRCS-yes += vpx_encoder.h
+API_DOC_SRCS-yes += vpx_ext_ratectrl.h
API_DOC_SRCS-yes += vpx_frame_buffer.h
API_DOC_SRCS-yes += vpx_image.h
@@ -39,3 +40,4 @@ API_SRCS-yes += vpx_codec.mk
API_SRCS-yes += vpx_frame_buffer.h
API_SRCS-yes += vpx_image.h
API_SRCS-yes += vpx_integer.h
+API_SRCS-yes += vpx_ext_ratectrl.h
diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h
index c84d40f7f..da3609577 100644
--- a/vpx/vpx_encoder.h
+++ b/vpx/vpx_encoder.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
#include "./vpx_codec.h"
+#include "./vpx_ext_ratectrl.h"
/*! Temporal Scalability: Maximum length of the sequence defining frame
* layer membership
@@ -57,7 +58,8 @@ extern "C" {
* fields to structures
*/
#define VPX_ENCODER_ABI_VERSION \
- (14 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/
+ (14 + VPX_CODEC_ABI_VERSION + \
+ VPX_EXT_RATECTRL_ABI_VERSION) /**<\hideinitializer*/
/*! \brief Encoder capabilities bitfield
*
@@ -705,6 +707,7 @@ typedef struct vpx_svc_parameters {
int scaling_factor_den[VPX_MAX_LAYERS]; /**< Scaling factor-denominator */
int speed_per_layer[VPX_MAX_LAYERS]; /**< Speed setting for each sl */
int temporal_layering_mode; /**< Temporal layering mode */
+ int loopfilter_ctrl[VPX_MAX_LAYERS]; /**< Loopfilter ctrl for each sl */
} vpx_svc_extra_cfg_t;
/*!\brief Initialize an encoder instance
diff --git a/vpx/vpx_ext_ratectrl.h b/vpx/vpx_ext_ratectrl.h
new file mode 100644
index 000000000..dc4d856a8
--- /dev/null
+++ b/vpx/vpx_ext_ratectrl.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE 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.
+ */
+
+#ifndef VPX_VPX_VPX_EXT_RATECTRL_H_
+#define VPX_VPX_VPX_EXT_RATECTRL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "./vpx_integer.h"
+
+/*!\brief Current ABI version number
+ *
+ * \internal
+ * If this file is altered in any way that changes the ABI, this value
+ * must be bumped. Examples include, but are not limited to, changing
+ * types, removing or reassigning enums, adding/removing/rearranging
+ * fields to structures.
+ */
+#define VPX_EXT_RATECTRL_ABI_VERSION (1)
+
+/*!\brief Abstract rate control model handler
+ *
+ * The encoder will receive the model handler from create_model() defined in
+ * vpx_rc_funcs_t.
+ */
+typedef void *vpx_rc_model_t;
+
+/*!\brief Encode frame decision made by the external rate control model
+ *
+ * The encoder will receive the decision from the external rate control model
+ * through get_encodeframe_decision() defined in vpx_rc_funcs_t.
+ */
+typedef struct vpx_rc_encodeframe_decision {
+ int q_index; /**< Quantizer step index [0..255]*/
+} vpx_rc_encodeframe_decision_t;
+
+/*!\brief Information for the frame to be encoded.
+ *
+ * The encoder will send the information to external rate control model through
+ * get_encodeframe_decision() defined in vpx_rc_funcs_t.
+ *
+ */
+typedef struct vpx_rc_encodeframe_info {
+ /*!
+ * 0: Key frame
+ * 1: Inter frame
+ * 2: Alternate reference frame
+ * 3: Overlay frame
+ * 4: Golden frame
+ */
+ int frame_type;
+ int show_index; /**< display index, starts from zero*/
+ int coding_index; /**< coding index, starts from zero*/
+ /*!
+ * index in group of picture, starts from zero.
+ */
+ int gop_index;
+ int ref_frame_coding_indexes[3]; /**< three reference frames' coding indices*/
+ /*!
+ * The validity of the three reference frames.
+ * 0: Invalid
+ * 1: Valid
+ */
+ int ref_frame_valid_list[3];
+} vpx_rc_encodeframe_info_t;
+
+/*!\brief Frame coding result
+ *
+ * The encoder will send the result to the external rate control model through
+ * update_encodeframe_result() defined in vpx_rc_funcs_t.
+ */
+typedef struct vpx_rc_encodeframe_result {
+ int64_t sse; /**< sum of squared error of the reconstructed frame */
+ int64_t bit_count; /**< number of bits spent on coding the frame*/
+ int64_t pixel_count; /**< number of pixels in YUV planes of the frame*/
+} vpx_rc_encodeframe_result_t;
+
+/*!\brief Status returned by rate control callback functions.
+ */
+typedef enum vpx_rc_status {
+ VPX_RC_OK = 0,
+ VPX_RC_ERROR = 1,
+} vpx_rc_status_t;
+
+/*!\brief First pass frame stats
+ * This is a mirror of vp9's FIRSTPASS_STATS except that spatial_layer_id is
+ * omitted
+ */
+typedef struct vpx_rc_frame_stats {
+ /*!
+ * Frame number in display order, if stats are for a single frame.
+ * No real meaning for a collection of frames.
+ */
+ double frame;
+ /*!
+ * Weight assigned to this frame (or total weight for the collection of
+ * frames) currently based on intra factor and brightness factor. This is used
+ * to distribute bits between easier and harder frames.
+ */
+ double weight;
+ /*!
+ * Intra prediction error.
+ */
+ double intra_error;
+ /*!
+ * Best of intra pred error and inter pred error using last frame as ref.
+ */
+ double coded_error;
+ /*!
+ * Best of intra pred error and inter pred error using golden frame as ref.
+ */
+ double sr_coded_error;
+ /*!
+ * Estimate the noise energy of the current frame.
+ */
+ double frame_noise_energy;
+ /*!
+ * Percentage of blocks with inter pred error < intra pred error.
+ */
+ double pcnt_inter;
+ /*!
+ * Percentage of blocks using (inter prediction and) non-zero motion vectors.
+ */
+ double pcnt_motion;
+ /*!
+ * Percentage of blocks where golden frame was better than last or intra:
+ * inter pred error using golden frame < inter pred error using last frame and
+ * inter pred error using golden frame < intra pred error
+ */
+ double pcnt_second_ref;
+ /*!
+ * Percentage of blocks where intra and inter prediction errors were very
+ * close.
+ */
+ double pcnt_neutral;
+ /*!
+ * Percentage of blocks that have intra error < inter error and inter error <
+ * LOW_I_THRESH
+ * - bit_depth 8: LOW_I_THRESH = 24000
+ * - bit_depth 10: LOW_I_THRESH = 24000 << 4
+ * - bit_depth 12: LOW_I_THRESH = 24000 << 8
+ */
+ double pcnt_intra_low;
+ /*!
+ * Percentage of blocks that have intra error < inter error and intra error <
+ * LOW_I_THRESH but inter error >= LOW_I_THRESH LOW_I_THRESH
+ * - bit_depth 8: LOW_I_THRESH = 24000
+ * - bit_depth 10: LOW_I_THRESH = 24000 << 4
+ * - bit_depth 12: LOW_I_THRESH = 24000 << 8
+ */
+ double pcnt_intra_high;
+ /*!
+ * Percentage of blocks that have almost no intra error residual
+ * (i.e. are in effect completely flat and untextured in the intra
+ * domain). In natural videos this is uncommon, but it is much more
+ * common in animations, graphics and screen content, so may be used
+ * as a signal to detect these types of content.
+ */
+ double intra_skip_pct;
+ /*!
+ * Percentage of blocks that have intra error < SMOOTH_INTRA_THRESH
+ * - bit_depth 8: SMOOTH_INTRA_THRESH = 4000
+ * - bit_depth 10: SMOOTH_INTRA_THRESH = 4000 << 4
+ * - bit_depth 12: SMOOTH_INTRA_THRESH = 4000 << 8
+ */
+ double intra_smooth_pct;
+ /*!
+ * Image mask rows top and bottom.
+ */
+ double inactive_zone_rows;
+ /*!
+ * Image mask columns at left and right edges.
+ */
+ double inactive_zone_cols;
+ /*!
+ * Mean of row motion vectors.
+ */
+ double MVr;
+ /*!
+ * Mean of absolute value of row motion vectors.
+ */
+ double mvr_abs;
+ /*!
+ * Mean of column motion vectors.
+ */
+ double MVc;
+ /*!
+ * Mean of absolute value of column motion vectors.
+ */
+ double mvc_abs;
+ /*!
+ * Variance of row motion vectors.
+ */
+ double MVrv;
+ /*!
+ * Variance of column motion vectors.
+ */
+ double MVcv;
+ /*!
+ * Value in range [-1,1] indicating fraction of row and column motion vectors
+ * that point inwards (negative MV value) or outwards (positive MV value).
+ * For example, value of 1 indicates, all row/column MVs are inwards.
+ */
+ double mv_in_out_count;
+ /*!
+ * Duration of the frame / collection of frames.
+ */
+ double duration;
+ /*!
+ * 1.0 if stats are for a single frame, or
+ * number of frames whose stats are accumulated.
+ */
+ double count;
+} vpx_rc_frame_stats_t;
+
+/*!\brief Collection of first pass frame stats
+ */
+typedef struct vpx_rc_firstpass_stats {
+ /*!
+ * Pointer to first pass frame stats.
+ * The pointed array of vpx_rc_frame_stats_t should have length equal to
+ * number of show frames in the video.
+ */
+ vpx_rc_frame_stats_t *frame_stats;
+ /*!
+ * Number of show frames in the video.
+ */
+ int num_frames;
+} vpx_rc_firstpass_stats_t;
+
+/*!\brief Encode config sent to external rate control model
+ */
+typedef struct vpx_rc_config {
+ int frame_width; /**< frame width */
+ int frame_height; /**< frame height */
+ int show_frame_count; /**< number of visible frames in the video */
+ /*!
+ * Target bitrate in kilobytes per second
+ */
+ int target_bitrate_kbps;
+ int frame_rate_num; /**< numerator of frame rate */
+ int frame_rate_den; /**< denominator of frame rate */
+} vpx_rc_config_t;
+
+/*!\brief Create an external rate control model callback prototype
+ *
+ * This callback is invoked by the encoder to create an external rate control
+ * model.
+ *
+ * \param[in] priv Callback's private data
+ * \param[in] ratectrl_config Pointer to vpx_rc_config_t
+ * \param[out] rate_ctrl_model_pt Pointer to vpx_rc_model_t
+ */
+typedef vpx_rc_status_t (*vpx_rc_create_model_cb_fn_t)(
+ void *priv, const vpx_rc_config_t *ratectrl_config,
+ vpx_rc_model_t *rate_ctrl_model_pt);
+
+/*!\brief Send first pass stats to the external rate control model callback
+ * prototype
+ *
+ * This callback is invoked by the encoder to send first pass stats to the
+ * external rate control model.
+ *
+ * \param[in] rate_ctrl_model rate control model
+ * \param[in] first_pass_stats first pass stats
+ */
+typedef vpx_rc_status_t (*vpx_rc_send_firstpass_stats_cb_fn_t)(
+ vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_firstpass_stats_t *first_pass_stats);
+
+/*!\brief Receive encode frame decision callback prototype
+ *
+ * This callback is invoked by the encoder to receive encode frame decision from
+ * the external rate control model.
+ *
+ * \param[in] rate_ctrl_model rate control model
+ * \param[in] encode_frame_info information of the coding frame
+ * \param[out] frame_decision encode decision of the coding frame
+ */
+typedef vpx_rc_status_t (*vpx_rc_get_encodeframe_decision_cb_fn_t)(
+ vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_encodeframe_info_t *encode_frame_info,
+ vpx_rc_encodeframe_decision_t *frame_decision);
+
+/*!\brief Update encode frame result callback prototype
+ *
+ * This callback is invoked by the encoder to update encode frame result to the
+ * external rate control model.
+ *
+ * \param[in] rate_ctrl_model rate control model
+ * \param[out] encode_frame_result encode result of the coding frame
+ */
+typedef vpx_rc_status_t (*vpx_rc_update_encodeframe_result_cb_fn_t)(
+ vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_encodeframe_result_t *encode_frame_result);
+
+/*!\brief Delete the external rate control model callback prototype
+ *
+ * This callback is invoked by the encoder to delete the external rate control
+ * model.
+ *
+ * \param[in] rate_ctrl_model rate control model
+ */
+typedef vpx_rc_status_t (*vpx_rc_delete_model_cb_fn_t)(
+ vpx_rc_model_t rate_ctrl_model);
+
+/*!\brief Callback function set for external rate control.
+ *
+ * The user can enable external rate control by registering
+ * a set of callback functions with the codec control flag
+ * VP9E_SET_EXTERNAL_RATE_CONTROL.
+ */
+typedef struct vpx_rc_funcs {
+ /*!
+ * Create an external rate control model.
+ */
+ vpx_rc_create_model_cb_fn_t create_model;
+ /*!
+ * Send first pass stats to the external rate control model.
+ */
+ vpx_rc_send_firstpass_stats_cb_fn_t send_firstpass_stats;
+ /*!
+ * Get encodeframe decision from the external rate control model.
+ */
+ vpx_rc_get_encodeframe_decision_cb_fn_t get_encodeframe_decision;
+ /*!
+ * Update encodeframe result to the external rate control model.
+ */
+ vpx_rc_update_encodeframe_result_cb_fn_t update_encodeframe_result;
+ /*!
+ * Delete the external rate control model.
+ */
+ vpx_rc_delete_model_cb_fn_t delete_model;
+ /*!
+ * Private data for the external rate control model.
+ */
+ void *priv;
+} vpx_rc_funcs_t;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VPX_VPX_VPX_EXT_RATECTRL_H_
diff --git a/vpx_ports/mips.h b/vpx_ports/mips.h
new file mode 100644
index 000000000..bdc7525f7
--- /dev/null
+++ b/vpx_ports/mips.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE 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.
+ */
+
+#ifndef VPX_PORTS_MIPS_H_
+#define VPX_PORTS_MIPS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HAS_MMI 0x01
+#define HAS_MSA 0x02
+
+int mips_cpu_caps(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VPX_PORTS_MIPS_H_
diff --git a/vpx_ports/mips_cpudetect.c b/vpx_ports/mips_cpudetect.c
new file mode 100644
index 000000000..e0eca2d48
--- /dev/null
+++ b/vpx_ports/mips_cpudetect.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE 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.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "./vpx_config.h"
+#include "vpx_ports/mips.h"
+
+#if CONFIG_RUNTIME_CPU_DETECT
+#if defined(__mips__) && defined(__linux__)
+int mips_cpu_caps(void) {
+ char cpuinfo_line[512];
+ int flag = 0x0;
+ FILE *f = fopen("/proc/cpuinfo", "r");
+ if (!f) {
+ // Assume nothing if /proc/cpuinfo is unavailable.
+ // This will occur for Chrome sandbox for Pepper or Render process.
+ return 0;
+ }
+ while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f)) {
+ if (memcmp(cpuinfo_line, "cpu model", 9) == 0) {
+ // Workaround early kernel without mmi in ASEs line.
+ if (strstr(cpuinfo_line, "Loongson-3")) {
+ flag |= HAS_MMI;
+ } else if (strstr(cpuinfo_line, "Loongson-2K")) {
+ flag |= HAS_MMI | HAS_MSA;
+ }
+ }
+ if (memcmp(cpuinfo_line, "ASEs implemented", 16) == 0) {
+ if (strstr(cpuinfo_line, "loongson-mmi") &&
+ strstr(cpuinfo_line, "loongson-ext")) {
+ flag |= HAS_MMI;
+ }
+ if (strstr(cpuinfo_line, "msa")) {
+ flag |= HAS_MSA;
+ }
+ // ASEs is the last line, so we can break here.
+ break;
+ }
+ }
+ fclose(f);
+ return flag;
+}
+#else /* end __mips__ && __linux__ */
+#error \
+ "--enable-runtime-cpu-detect selected, but no CPU detection method " \
+"available for your platform. Reconfigure with --disable-runtime-cpu-detect."
+#endif
+#else /* end CONFIG_RUNTIME_CPU_DETECT */
+int mips_cpu_caps(void) { return 0; }
+#endif
diff --git a/vpx_ports/vpx_ports.mk b/vpx_ports/vpx_ports.mk
index 233177369..e5001be49 100644
--- a/vpx_ports/vpx_ports.mk
+++ b/vpx_ports/vpx_ports.mk
@@ -42,6 +42,9 @@ PORTS_SRCS-$(VPX_ARCH_ARM) += arm.h
PORTS_SRCS-$(VPX_ARCH_PPC) += ppc_cpudetect.c
PORTS_SRCS-$(VPX_ARCH_PPC) += ppc.h
+PORTS_SRCS-$(VPX_ARCH_MIPS) += mips_cpudetect.c
+PORTS_SRCS-$(VPX_ARCH_MIPS) += mips.h
+
ifeq ($(VPX_ARCH_MIPS), yes)
PORTS_SRCS-yes += asmdefs_mmi.h
endif
diff --git a/vpxenc.c b/vpxenc.c
index 64288e83d..5d7546eb2 100644
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -465,6 +465,13 @@ static const arg_def_t target_level = ARG_DEF(
static const arg_def_t row_mt =
ARG_DEF(NULL, "row-mt", 1,
"Enable row based non-deterministic multi-threading in VP9");
+
+static const arg_def_t disable_loopfilter =
+ ARG_DEF(NULL, "disable-loopfilter", 1,
+ "Control Loopfilter in VP9\n"
+ "0: Loopfilter on for all frames (default)\n"
+ "1: Loopfilter off for non reference frames\n"
+ "2: Loopfilter off for all frames");
#endif
#if CONFIG_VP9_ENCODER
@@ -495,6 +502,10 @@ static const arg_def_t *vp9_args[] = { &cpu_used_vp9,
&max_gf_interval,
&target_level,
&row_mt,
+ &disable_loopfilter,
+// NOTE: The entries above have a corresponding entry in vp9_arg_ctrl_map. The
+// entries below do not have a corresponding entry in vp9_arg_ctrl_map. They
+// must be listed at the end of vp9_args.
#if CONFIG_VP9_HIGHBITDEPTH
&bitdeptharg,
&inbitdeptharg,
@@ -527,6 +538,7 @@ static const int vp9_arg_ctrl_map[] = { VP8E_SET_CPUUSED,
VP9E_SET_MAX_GF_INTERVAL,
VP9E_SET_TARGET_LEVEL,
VP9E_SET_ROW_MT,
+ VP9E_SET_DISABLE_LOOPFILTER,
0 };
#endif