summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/make/Makefile11
-rwxr-xr-xbuild/make/gen_msvs_proj.sh5
-rwxr-xr-xbuild/make/gen_msvs_vcxproj.sh5
-rwxr-xr-xconfigure12
-rw-r--r--examples.mk18
-rw-r--r--examples/vpx_temporal_scalable_patterns.c1
-rwxr-xr-xtest/tools_common.sh437
-rwxr-xr-xtest/vpxdec.sh65
-rwxr-xr-xtest/vpxenc.sh96
-rw-r--r--tools_common.h6
-rw-r--r--vp9/common/vp9_blockd.h2
-rw-r--r--vp9/common/vp9_reconinter.c7
-rw-r--r--vp9/decoder/vp9_decodeframe.c2
-rw-r--r--vp9/encoder/vp9_aq_cyclicrefresh.c2
-rw-r--r--vp9/encoder/vp9_bitstream.c14
-rw-r--r--vp9/encoder/vp9_encodeframe.c24
-rw-r--r--vp9/encoder/vp9_mcomp.c162
-rw-r--r--vp9/encoder/vp9_mcomp.h3
-rw-r--r--vp9/encoder/vp9_onyx_if.c4
-rw-r--r--vp9/encoder/vp9_onyx_int.h11
-rw-r--r--vp9/encoder/vp9_pickmode.c12
-rw-r--r--vp9/encoder/vp9_ratectrl.c30
-rw-r--r--vp9/encoder/vp9_rdopt.c13
-rw-r--r--vp9/encoder/vp9_speed_features.c55
-rw-r--r--vp9/encoder/vp9_speed_features.h11
-rw-r--r--vp9/encoder/vp9_temporal_filter.c11
-rw-r--r--vp9/vp9_cx_iface.c8
-rw-r--r--vp9/vp9_dx_iface.c287
-rw-r--r--vpx/vp8cx.h3
-rw-r--r--vpxenc.c73
-rw-r--r--webmenc.c331
-rw-r--r--webmenc.cc86
-rw-r--r--webmenc.h48
33 files changed, 1314 insertions, 541 deletions
diff --git a/build/make/Makefile b/build/make/Makefile
index 0c5ff64f4..dd7fb4a21 100644
--- a/build/make/Makefile
+++ b/build/make/Makefile
@@ -147,15 +147,6 @@ $(BUILD_PFX)%.cc.o: %.cc
$(if $(quiet),@echo " [CXX] $@")
$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
-$(BUILD_PFX)%.cpp.d: %.cpp
- $(if $(quiet),@echo " [DEP] $@")
- $(qexec)mkdir -p $(dir $@)
- $(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -M $< | $(fmt_deps) > $@
-
-$(BUILD_PFX)%.cpp.o: %.cpp
- $(if $(quiet),@echo " [CXX] $@")
- $(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
-
$(BUILD_PFX)%.asm.d: %.asm
$(if $(quiet),@echo " [DEP] $@")
$(qexec)mkdir -p $(dir $@)
@@ -227,7 +218,7 @@ cond_enabled=$(if $(filter yes,$($(1))), $(call enabled,$(2)))
find_file1=$(word 1,$(wildcard $(subst //,/,$(addsuffix /$(1),$(2)))))
find_file=$(foreach f,$(1),$(call find_file1,$(strip $(f)),$(strip $(2))) )
-obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o .cpp=.cpp.o
+obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o
objs=$(addprefix $(BUILD_PFX),$(foreach p,$(obj_pats),$(filter %.o,$(1:$(p))) ))
install_map_templates=$(eval $(call install_map_template,$(1),$(2)))
diff --git a/build/make/gen_msvs_proj.sh b/build/make/gen_msvs_proj.sh
index 5936370a7..df9143595 100755
--- a/build/make/gen_msvs_proj.sh
+++ b/build/make/gen_msvs_proj.sh
@@ -162,7 +162,8 @@ generate_filter() {
done
done
fi
- if [ "$pat" == "c" ] || [ "$pat" == "cc" ] ; then
+ if [ "$pat" == "c" ] || \
+ [ "$pat" == "cc" ] || [ "$pat" == "cpp" ]; then
for plat in "${platforms[@]}"; do
for cfg in Debug Release; do
open_tag FileConfiguration \
@@ -561,7 +562,7 @@ generate_vcproj() {
close_tag Configurations
open_tag Files
- generate_filter srcs "Source Files" "c;cc;def;odl;idl;hpj;bat;asm;asmx"
+ generate_filter srcs "Source Files" "c;cc;cpp;def;odl;idl;hpj;bat;asm;asmx"
generate_filter hdrs "Header Files" "h;hm;inl;inc;xsd"
generate_filter resrcs "Resource Files" "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
generate_filter resrcs "Build Files" "mk"
diff --git a/build/make/gen_msvs_vcxproj.sh b/build/make/gen_msvs_vcxproj.sh
index 7c8871ba2..23990a413 100755
--- a/build/make/gen_msvs_vcxproj.sh
+++ b/build/make/gen_msvs_vcxproj.sh
@@ -174,7 +174,8 @@ generate_filter() {
done
done
close_tag CustomBuild
- elif [ "$pat" == "c" ] || [ "$pat" == "cc" ] ; then
+ elif [ "$pat" == "c" ] || \
+ [ "$pat" == "cc" ] || [ "$pat" == "cpp" ]; then
open_tag ClCompile \
Include=".\\$f"
# Separate file names with Condition?
@@ -524,7 +525,7 @@ generate_vcxproj() {
done
open_tag ItemGroup
- generate_filter "Source Files" "c;cc;def;odl;idl;hpj;bat;asm;asmx;s"
+ generate_filter "Source Files" "c;cc;cpp;def;odl;idl;hpj;bat;asm;asmx;s"
close_tag ItemGroup
open_tag ItemGroup
generate_filter "Header Files" "h;hm;inl;inc;xsd"
diff --git a/configure b/configure
index 01c421d34..ff350cc3e 100755
--- a/configure
+++ b/configure
@@ -704,11 +704,13 @@ process_toolchain() {
enabled postproc || die "postproc_visualizer requires postproc to be enabled"
fi
+ # Enable WebM IO by default.
+ soft_enable webm_io
+
# Enable unit tests by default if we have a working C++ compiler.
case "$toolchain" in
*-vs*)
soft_enable unit_tests
- soft_enable webm_io
;;
*-android-*)
# GTestLog must be modified to use Android logging utilities.
@@ -724,21 +726,13 @@ process_toolchain() {
check_cxx "$@" <<EOF && soft_enable unit_tests
int z;
EOF
- check_cxx "$@" <<EOF && soft_enable webm_io
-int z;
-EOF
;;
*)
enabled pthread_h && check_cxx "$@" <<EOF && soft_enable unit_tests
int z;
EOF
- check_cxx "$@" <<EOF && soft_enable webm_io
-int z;
-EOF
;;
esac
- # libwebm needs to be linked with C++ standard library
- enabled webm_io && LD=${CXX}
}
diff --git a/examples.mk b/examples.mk
index f091c2de4..fa5d66cda 100644
--- a/examples.mk
+++ b/examples.mk
@@ -15,16 +15,6 @@ LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \
third_party/libyuv/source/scale.c \
third_party/libyuv/source/cpu_id.c
-LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer.cpp \
- third_party/libwebm/mkvmuxerutil.cpp \
- third_party/libwebm/mkvwriter.cpp \
- third_party/libwebm/mkvmuxer.hpp \
- third_party/libwebm/mkvmuxertypes.hpp \
- third_party/libwebm/mkvmuxerutil.hpp \
- third_party/libwebm/mkvparser.hpp \
- third_party/libwebm/mkvwriter.hpp \
- third_party/libwebm/webmids.hpp
-
# List of examples to build. UTILS are tools meant for distribution
# while EXAMPLES demonstrate specific portions of the API.
UTILS-$(CONFIG_DECODERS) += vpxdec.c
@@ -63,8 +53,10 @@ vpxenc.SRCS += vpx_ports/vpx_timer.h
vpxenc.SRCS += vpxstats.c vpxstats.h
vpxenc.SRCS += $(LIBYUV_SRCS)
ifeq ($(CONFIG_WEBM_IO),yes)
- vpxenc.SRCS += $(LIBWEBM_MUXER_SRCS)
- vpxenc.SRCS += webmenc.cc webmenc.h
+ vpxenc.SRCS += third_party/libmkv/EbmlIDs.h
+ vpxenc.SRCS += third_party/libmkv/EbmlWriter.c
+ vpxenc.SRCS += third_party/libmkv/EbmlWriter.h
+ vpxenc.SRCS += webmenc.c webmenc.h
endif
vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
vpxenc.DESCRIPTION = Full featured encoder
@@ -78,7 +70,7 @@ vp9_spatial_scalable_encoder.SRCS += vpxstats.c vpxstats.h
vp9_spatial_scalable_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
vp9_spatial_scalable_encoder.DESCRIPTION = Spatial Scalable Encoder
-ifeq ($(CONFIG_SHARED),no)
+ifneq ($(CONFIG_SHARED),yes)
EXAMPLES-$(CONFIG_VP9_ENCODER) += resize_util.c
endif
diff --git a/examples/vpx_temporal_scalable_patterns.c b/examples/vpx_temporal_scalable_patterns.c
index 3a4f05b92..5cb4ee9cf 100644
--- a/examples/vpx_temporal_scalable_patterns.c
+++ b/examples/vpx_temporal_scalable_patterns.c
@@ -575,6 +575,7 @@ int main(int argc, char **argv) {
} else if (strncmp(encoder->name, "vp9", 3) == 0) {
vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed);
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
+ vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0);
vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 0);
if (vpx_codec_control(&codec, VP9E_SET_SVC, 1)) {
die_codec(&codec, "Failed to set SVC");
diff --git a/test/tools_common.sh b/test/tools_common.sh
new file mode 100755
index 000000000..cd7977156
--- /dev/null
+++ b/test/tools_common.sh
@@ -0,0 +1,437 @@
+#!/bin/sh
+##
+## Copyright (c) 2014 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.
+##
+## This file contains shell code shared by test scripts for libvpx tools.
+set -e
+
+# Sets $VPX_TOOL_TEST to the name specified by positional parameter one.
+test_begin() {
+ VPX_TOOL_TEST="${1}"
+}
+
+# Clears the VPX_TOOL_TEST variable after confirming that $VPX_TOOL_TEST matches
+# positional parameter one.
+test_end() {
+ if [ "$1" != "${VPX_TOOL_TEST}" ]; then
+ echo "FAIL completed test mismatch!."
+ echo " completed test: ${1}"
+ echo " active test: ${VPX_TOOL_TEST}."
+ return 1
+ fi
+ VPX_TOOL_TEST='<unset>'
+}
+
+# Echoes the target configuration being tested.
+test_configuration_target() {
+ vpx_config_mk="${LIBVPX_CONFIG_PATH}/config.mk"
+ # Find the TOOLCHAIN line, split it using ':=' as the field separator, and
+ # print the last field to get the value. Then pipe the value to tr to consume
+ # any leading/trailing spaces while allowing tr to echo the output to stdout.
+ awk -F ':=' '/TOOLCHAIN/ { print $NF }' "${vpx_config_mk}" | tr -d ' '
+}
+
+# Trap function used for failure reports and tool output directory removal.
+# When the contents of $VPX_TOOL_TEST do not match the string '<unset>', reports
+# failure of test stored in $VPX_TOOL_TEST.
+cleanup() {
+ if [ -n "${VPX_TOOL_TEST}" ] && [ "${VPX_TOOL_TEST}" != '<unset>' ]; then
+ echo "FAIL: $VPX_TOOL_TEST"
+ fi
+ if [ -n "${VPX_TEST_OUTPUT_DIR}" ] && [ -d "${VPX_TEST_OUTPUT_DIR}" ]; then
+ rm -rf "${VPX_TEST_OUTPUT_DIR}"
+ fi
+}
+
+# Echoes the git hash portion of the VERSION_STRING variable defined in
+# $LIBVPX_CONFIG_PATH/config.mk to stdout, or the version number string when
+# no git hash is contained in VERSION_STRING.
+config_hash() {
+ vpx_config_mk="${LIBVPX_CONFIG_PATH}/config.mk"
+ # Find VERSION_STRING line, split it with "-g" and print the last field to
+ # output the git hash to stdout.
+ vpx_version=$(awk -F -g '/VERSION_STRING/ {print $NF}' "${vpx_config_mk}")
+ # Handle two situations here:
+ # 1. The default case: $vpx_version is a git hash, so echo it unchanged.
+ # 2. When being run a non-dev tree, the -g portion is not present in the
+ # version string: It's only the version number.
+ # In this case $vpx_version is something like 'VERSION_STRING=v1.3.0', so
+ # we echo only what is after the '='.
+ echo "${vpx_version##*=}"
+}
+
+# Echoes the short form of the current git hash.
+current_hash() {
+ if git --version > /dev/null 2>&1; then
+ (cd "$(dirname "${0}")"
+ git rev-parse --short HEAD)
+ else
+ # Return the config hash if git is unavailable: Fail silently, git hashes
+ # are used only for warnings.
+ config_hash
+ fi
+}
+
+# Echoes warnings to stdout when git hash in vpx_config.h does not match the
+# current git hash.
+check_git_hashes() {
+ hash_at_configure_time=$(config_hash)
+ hash_now=$(current_hash)
+
+ if [ "${hash_at_configure_time}" != "${hash_now}" ]; then
+ echo "Warning: git hash has changed since last configure."
+ fi
+}
+
+# This script requires that the LIBVPX_BIN_PATH, LIBVPX_CONFIG_PATH, and
+# LIBVPX_TEST_DATA_PATH variables are in the environment: Confirm that
+# the variables are set and that they all evaluate to directory paths.
+verify_vpx_test_environment() {
+ if [ ! -d "${LIBVPX_BIN_PATH}" ]; then
+ echo "The LIBVPX_BIN_PATH environment variable must be set."
+ return 1
+ fi
+ if [ ! -d "${LIBVPX_CONFIG_PATH}" ]; then
+ echo "The LIBVPX_CONFIG_PATH environment variable must be set."
+ return 1
+ fi
+ if [ ! -d "${LIBVPX_TEST_DATA_PATH}" ]; then
+ echo "The LIBVPX_TEST_DATA_PATH environment variable must be set."
+ return 1
+ fi
+}
+
+# Greps vpx_config.h in LIBVPX_CONFIG_PATH for positional parameter one, which
+# should be a LIBVPX preprocessor flag. Echoes yes to stdout when the feature
+# is available.
+vpx_config_option_enabled() {
+ vpx_config_option="${1}"
+ vpx_config_file="${LIBVPX_CONFIG_PATH}/vpx_config.h"
+ config_line=$(grep "${vpx_config_option}" "${vpx_config_file}")
+ if echo "${config_line}" | egrep -q '1$'; then
+ echo yes
+ fi
+}
+
+# Echoes yes when output of test_configuration_target() contains win32 or win64.
+is_windows_target() {
+ if test_configuration_target \
+ | grep -q -e win32 -e win64 > /dev/null 2>&1; then
+ echo yes
+ fi
+}
+
+# Echoes yes to stdout when the file named by positional parameter one exists
+# in LIBVPX_BIN_PATH, and is executable.
+vpx_tool_available() {
+ tool_name="${1}"
+ if [ "$(is_windows_target)" = "yes" ]; then
+ tool_name="${tool_name}.exe"
+ fi
+ [ -x "${LIBVPX_BIN_PATH}/${1}" ] && echo yes
+}
+
+# Echoes yes to stdout when vpx_config_option_enabled() reports yes for
+# CONFIG_VP8_DECODER.
+vp8_decode_available() {
+ [ "$(vpx_config_option_enabled CONFIG_VP8_DECODER)" = "yes" ] && echo yes
+}
+
+# Echoes yes to stdout when vpx_config_option_enabled() reports yes for
+# CONFIG_VP8_ENCODER.
+vp8_encode_available() {
+ [ "$(vpx_config_option_enabled CONFIG_VP8_ENCODER)" = "yes" ] && echo yes
+}
+
+# Echoes yes to stdout when vpx_config_option_enabled() reports yes for
+# CONFIG_VP9_DECODER.
+vp9_decode_available() {
+ [ "$(vpx_config_option_enabled CONFIG_VP9_DECODER)" = "yes" ] && echo yes
+}
+
+# Echoes yes to stdout when vpx_config_option_enabled() reports yes for
+# CONFIG_VP9_ENCODER.
+vp9_encode_available() {
+ [ "$(vpx_config_option_enabled CONFIG_VP9_ENCODER)" = "yes" ] && echo yes
+}
+
+# Echoes yes to stdout when vpx_config_option_enabled() reports yes for
+# CONFIG_WEBM_IO.
+webm_io_available() {
+ [ "$(vpx_config_option_enabled CONFIG_WEBM_IO)" = "yes" ] && echo yes
+}
+
+# Echoes yes to stdout when vpxdec exists according to vpx_tool_available().
+vpxdec_available() {
+ [ -n $(vpx_tool_available vpxdec) ] && echo yes
+}
+
+# Wrapper function for running vpxdec in noblit mode. Requires that
+# LIBVPX_BIN_PATH points to the directory containing vpxdec. Positional
+# parameter one is used as the input file path. Positional parameter two, when
+# present, is interpreted as a boolean flag that means the input should be sent
+# to vpxdec via pipe from cat instead of directly.
+vpxdec() {
+ input="${1}"
+ pipe_input=${2}
+
+ if [ $# -gt 2 ]; then
+ # shift away $1 and $2 so the remaining arguments can be passed to vpxdec
+ # via $@.
+ shift 2
+ fi
+
+ decoder="${LIBVPX_BIN_PATH}/vpxdec"
+
+ if [ "$(is_windows_target)" = "yes" ]; then
+ decoder="${decoder}.exe"
+ fi
+
+ if [ -z "${pipe_input}" ]; then
+ "${decoder}" "$input" --summary --noblit "$@" > /dev/null 2>&1
+ else
+ cat "${input}" | "${decoder}" - --summary --noblit "$@" > /dev/null 2>&1
+ fi
+}
+
+# Echoes yes to stdout when vpxenc exists according to vpx_tool_available().
+vpxenc_available() {
+ [ -n $(vpx_tool_available vpxenc) ] && echo yes
+}
+
+# Wrapper function for running vpxenc. Positional parameters are interpreted as
+# follows:
+# 1 - codec name
+# 2 - input width
+# 3 - input height
+# 4 - number of frames to encode
+# 5 - path to input file
+# 6 - path to output file
+# Note: The output file path must end in .ivf to output an IVF file.
+# 7 - extra flags
+# Note: Extra flags currently supports a special case: when set to "-"
+# input is piped to vpxenc via cat.
+vpxenc() {
+ encoder="${LIBVPX_BIN_PATH}/vpxenc"
+ codec="${1}"
+ width=${2}
+ height=${3}
+ frames=${4}
+ input=${5}
+ output="${VPX_TEST_OUTPUT_DIR}/${6}"
+ extra_flags=${7}
+
+ if [ "$(is_windows_target)" = "yes" ]; then
+ encoder="${encoder}.exe"
+ fi
+
+ # Because --ivf must be within the command line to get IVF from vpxenc.
+ if echo "${output}" | egrep -q 'ivf$'; then
+ use_ivf=--ivf
+ else
+ unset use_ivf
+ fi
+
+ if [ "${extra_flags}" = "-" ]; then
+ pipe_input=yes
+ extra_flags=${8}
+ else
+ unset pipe_input
+ fi
+
+ if [ -z "${pipe_input}" ]; then
+ "${encoder}" --codec=${codec} --width=${width} --height=${height} \
+ --limit=${frames} ${use_ivf} ${extra_flags} --output="${output}" \
+ "${input}" > /dev/null 2>&1
+ else
+ cat "${input}" \
+ | "${encoder}" --codec=${codec} --width=${width} --height=${height} \
+ --limit=${frames} ${use_ivf} ${extra_flags} --output="${output}" - \
+ > /dev/null 2>&1
+ fi
+
+ if [ ! -e "${output}" ]; then
+ # Return non-zero exit status: output file doesn't exist, so something
+ # definitely went wrong.
+ return 1
+ fi
+}
+
+# Filters strings from positional parameter one using the filter specified by
+# positional parameter two. Filter behavior depends on the presence of a third
+# positional parameter. When parameter three is present, strings that match the
+# filter are excluded. When omitted, strings matching the filter are included.
+# The filtered string is echoed to stdout.
+filter_strings() {
+ strings=${1}
+ filter=${2}
+ exclude=${3}
+
+ if [ -n "${exclude}" ]; then
+ # When positional parameter three exists the caller wants to remove strings.
+ # Tell grep to invert matches using the -v argument.
+ exclude='-v'
+ else
+ unset exclude
+ fi
+
+ if [ -n "${filter}" ]; then
+ for s in ${strings}; do
+ if echo "${s}" | egrep -q ${exclude} "${filter}" > /dev/null 2>&1; then
+ filtered_strings="${filtered_strings} ${s}"
+ fi
+ done
+ else
+ filtered_strings="${strings}"
+ fi
+ echo "${filtered_strings}"
+}
+
+# Runs user test functions passed via positional parameters one and two.
+# Functions in positional parameter one are treated as environment verification
+# functions and are run unconditionally. Functions in positional parameter two
+# are run according to the rules specified in vpx_test_usage().
+run_tests() {
+ env_tests="verify_vpx_test_environment ${1}"
+ tests_to_filter="${2}"
+
+ if [ "${VPX_TEST_RUN_DISABLED_TESTS}" != "yes" ]; then
+ # Filter out DISABLED tests.
+ tests_to_filter=$(filter_strings "${tests_to_filter}" ^DISABLED exclude)
+ fi
+
+ if [ -n "${VPX_TEST_FILTER}" ]; then
+ # Remove tests not matching the user's filter.
+ tests_to_filter=$(filter_strings "${tests_to_filter}" ${VPX_TEST_FILTER})
+ fi
+
+ tests_to_run="${env_tests} ${tests_to_filter}"
+
+ check_git_hashes
+
+ # Run tests.
+ for test in ${tests_to_run}; do
+ test_begin "${test}"
+ "${test}"
+ [ "${VPX_TEST_VERBOSE_OUTPUT}" = "yes" ] && echo " PASS ${test}"
+ test_end "${test}"
+ done
+
+ tested_config="$(test_configuration_target) @ $(current_hash)"
+ echo $(basename "${0%.*}"): Done, all tests pass for ${tested_config}.
+}
+
+vpx_test_usage() {
+cat << EOF
+ Usage: ${0##*/} [arguments]
+ --bin-path <path to libvpx binaries directory>
+ --config-path <path to libvpx config directory>
+ --filter <filter>: User test filter. Only tests matching filter are run.
+ --run-disabled-tests: Run disabled tests.
+ --help: Display this message and exit.
+ --test-data-path <path to libvpx test data directory>
+ --verbose: Verbose output.
+
+ When the --bin-path option is not specified the script attempts to use
+ \$LIBVPX_BIN_PATH and then the current directory.
+
+ When the --config-path option is not specified the script attempts to use
+ \$LIBVPX_CONFIG_PATH and then the current directory.
+
+ When the -test-data-path option is not specified the script attempts to use
+ \$LIBVPX_TEST_DATA_PATH and then the current directory.
+EOF
+}
+
+# Returns non-zero (failure) when required environment variables are empty
+# strings.
+vpx_test_check_environment() {
+ if [ -z "${LIBVPX_BIN_PATH}" ] || \
+ [ -z "${LIBVPX_CONFIG_PATH}" ] || \
+ [ -z "${LIBVPX_TEST_DATA_PATH}" ]; then
+ return 1
+ fi
+}
+
+# Parse the command line.
+while [ -n "$1" ]; do
+ case "$1" in
+ --bin-path)
+ LIBVPX_BIN_PATH="$2"
+ shift
+ ;;
+ --config-path)
+ LIBVPX_CONFIG_PATH="$2"
+ shift
+ ;;
+ --filter)
+ VPX_TEST_FILTER="$2"
+ shift
+ ;;
+ --run-disabled-tests)
+ VPX_TEST_RUN_DISABLED_TESTS=yes
+ ;;
+ --help)
+ vpx_test_usage
+ exit
+ ;;
+ --test-data-path)
+ LIBVPX_TEST_DATA_PATH="$2"
+ shift
+ ;;
+ --verbose)
+ VPX_TEST_VERBOSE_OUTPUT=yes
+ ;;
+ *)
+ vpx_test_usage
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+# Handle running the tests from a build directory without arguments when running
+# the tests on *nix/macosx.
+LIBVPX_BIN_PATH="${LIBVPX_BIN_PATH:-.}"
+LIBVPX_CONFIG_PATH="${LIBVPX_CONFIG_PATH:-.}"
+LIBVPX_TEST_DATA_PATH="${LIBVPX_TEST_DATA_PATH:-.}"
+
+# Create a temporary directory for output files, and a trap to clean it up.
+if [ -n "${TMPDIR}" ]; then
+ VPX_TEST_TEMP_ROOT="${TMPDIR}"
+elif [ -n "${TEMPDIR}" ]; then
+ VPX_TEST_TEMP_ROOT="${TEMPDIR}"
+else
+ VPX_TEST_TEMP_ROOT=/tmp
+fi
+
+VPX_TEST_RAND=$(awk 'BEGIN { srand(); printf "%d\n",(rand() * 32768)}')
+VPX_TEST_OUTPUT_DIR="${VPX_TEST_TEMP_ROOT}/vpx_test_${VPX_TEST_RAND}"
+
+if ! mkdir -p "${VPX_TEST_OUTPUT_DIR}" || \
+ [ ! -d "${VPX_TEST_OUTPUT_DIR}" ]; then
+ echo "${0##*/}: Cannot create output directory, giving up."
+ echo "${0##*/}: VPX_TEST_OUTPUT_DIR=${VPX_TEST_OUTPUT_DIR}"
+ exit 1
+fi
+
+trap cleanup EXIT
+
+if [ "${VPX_TEST_VERBOSE_OUTPUT}" = "yes" ]; then
+cat << EOF
+$(basename "${0%.*}") test configuration:
+ LIBVPX_BIN_PATH=${LIBVPX_BIN_PATH}
+ LIBVPX_CONFIG_PATH=${LIBVPX_CONFIG_PATH}
+ LIBVPX_TEST_DATA_PATH=${LIBVPX_TEST_DATA_PATH}
+ VPX_TEST_OUTPUT_DIR=${VPX_TEST_OUTPUT_DIR}
+ VPX_TEST_VERBOSE_OUTPUT=${VPX_TEST_VERBOSE_OUTPUT}
+ VPX_TEST_FILTER=${VPX_TEST_FILTER}
+ VPX_TEST_RUN_DISABLED_TESTS=${VPX_TEST_RUN_DISABLED_TESTS}
+EOF
+fi
diff --git a/test/vpxdec.sh b/test/vpxdec.sh
new file mode 100755
index 000000000..d236f973b
--- /dev/null
+++ b/test/vpxdec.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+##
+## Copyright (c) 2014 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.
+##
+## This file tests vpxdec. To add new tests to this file, do the following:
+## 1. Write a shell function (this is your test).
+## 2. Add the function to vpxdec_tests (on a new line).
+##
+. $(dirname $0)/tools_common.sh
+
+VP8_IVF_FILE="${LIBVPX_TEST_DATA_PATH}/vp80-00-comprehensive-001.ivf"
+VP9_WEBM_FILE="${LIBVPX_TEST_DATA_PATH}/vp90-2-00-quantizer-00.webm"
+
+# Environment check: Make sure input is available.
+vpxdec_verify_environment() {
+ if [ ! -e "${VP8_IVF_FILE}" ] || [ ! -e "${VP9_WEBM_FILE}" ]; then
+ echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
+ return 1
+ fi
+}
+
+vpxdec_can_decode_vp8() {
+ if [ "$(vpxdec_available)" = "yes" ] && \
+ [ "$(vp8_decode_available)" = "yes" ]; then
+ echo yes
+ fi
+}
+
+vpxdec_can_decode_vp9() {
+ if [ "$(vpxdec_available)" = "yes" ] && \
+ [ "$(vp9_decode_available)" = "yes" ]; then
+ echo yes
+ fi
+}
+
+vpxdec_vp8_ivf() {
+ if [ "$(vpxdec_can_decode_vp8)" = "yes" ]; then
+ vpxdec "${VP8_IVF_FILE}"
+ fi
+}
+
+vpxdec_vp8_ivf_pipe_input() {
+ if [ "$(vpxdec_can_decode_vp8)" = "yes" ]; then
+ vpxdec "${VP8_IVF_FILE}" -
+ fi
+}
+
+vpxdec_vp9_webm() {
+ if [ "$(vpxdec_can_decode_vp9)" = "yes" ] && \
+ [ "$(webm_io_available)" = "yes" ]; then
+ vpxdec "${VP9_WEBM_FILE}"
+ fi
+}
+
+vpxdec_tests="vpxdec_vp8_ivf
+ vpxdec_vp8_ivf_pipe_input
+ vpxdec_vp9_webm"
+
+run_tests vpxdec_verify_environment "${vpxdec_tests}"
diff --git a/test/vpxenc.sh b/test/vpxenc.sh
new file mode 100755
index 000000000..89e4eb39c
--- /dev/null
+++ b/test/vpxenc.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+##
+## Copyright (c) 2014 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.
+##
+## This file tests vpxenc using hantro_collage_w352h288.yuv as input. To add
+## new tests to this file, do the following:
+## 1. Write a shell function (this is your test).
+## 2. Add the function to vpxenc_tests (on a new line).
+##
+. $(dirname $0)/tools_common.sh
+
+YUV_RAW_INPUT="${LIBVPX_TEST_DATA_PATH}/hantro_collage_w352h288.yuv"
+YUV_RAW_INPUT_WIDTH=352
+YUV_RAW_INPUT_HEIGHT=288
+TEST_FRAMES=10
+
+# Environment check: Make sure input is available.
+vpxenc_verify_environment() {
+ if [ ! -e "${YUV_RAW_INPUT}" ]; then
+ echo "The file ${YUV_RAW_INPUT##*/} must exist in LIBVPX_TEST_DATA_PATH."
+ return 1
+ fi
+}
+
+vpxenc_can_encode_vp8() {
+ if [ "$(vpxenc_available)" = "yes" ] && \
+ [ "$(vp8_encode_available)" = "yes" ]; then
+ echo yes
+ fi
+}
+
+vpxenc_can_encode_vp9() {
+ if [ "$(vpxenc_available)" = "yes" ] && \
+ [ "$(vp9_encode_available)" = "yes" ]; then
+ echo yes
+ fi
+}
+
+vpxenc_vp8_ivf() {
+ if [ "$(vpxenc_can_encode_vp8)" = "yes" ]; then
+ vpxenc vp8 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \
+ "${YUV_RAW_INPUT}" vp8.ivf
+ fi
+}
+
+vpxenc_vp8_ivf_pipe_input() {
+ if [ "$(vpxenc_can_encode_vp8)" = "yes" ]; then
+ vpxenc vp8 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \
+ "${YUV_RAW_INPUT}" vp8.ivf -
+ fi
+}
+
+vpxenc_vp8_webm() {
+ if [ "$(vpxenc_can_encode_vp8)" = "yes" ] &&
+ [ "$(webm_io_available)" = "yes" ] ; then
+ vpxenc vp8 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \
+ "${YUV_RAW_INPUT}" vp8.webm
+ fi
+}
+
+vpxenc_vp9_ivf() {
+ if [ "$(vpxenc_can_encode_vp9)" = "yes" ]; then
+ vpxenc vp9 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \
+ "${YUV_RAW_INPUT}" vp9.ivf
+ fi
+}
+
+vpxenc_vp9_webm() {
+ if [ "$(vpxenc_can_encode_vp9)" = "yes" ] &&
+ [ "$(webm_io_available)" = "yes" ] ; then
+ vpxenc vp9 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \
+ "${YUV_RAW_INPUT}" vp9.webm
+ fi
+}
+
+DISABLED_vpxenc_vp9_ivf_lossless() {
+ if [ "$(vpxenc_can_encode_vp9)" = "yes" ]; then
+ vpxenc vp9 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \
+ "${YUV_RAW_INPUT}" vp9_lossless.ivf --lossless
+ fi
+}
+
+vpxenc_tests="vpxenc_vp8_ivf
+ vpxenc_vp8_webm
+ vpxenc_vp8_ivf_pipe_input
+ vpxenc_vp9_ivf
+ vpxenc_vp9_webm
+ DISABLED_vpxenc_vp9_ivf_lossless"
+
+run_tests vpxenc_verify_environment "${vpxenc_tests}"
diff --git a/tools_common.h b/tools_common.h
index 58894def0..549e895ec 100644
--- a/tools_common.h
+++ b/tools_common.h
@@ -22,10 +22,12 @@
#endif
#if defined(_MSC_VER)
-/* MSVS doesn't define off_t, and uses _f{seek,tell}i64. */
-typedef __int64 off_t;
+/* MSVS uses _f{seek,tell}i64. */
#define fseeko _fseeki64
#define ftello _ftelli64
+typedef long _off_t; // NOLINT - MSVS compatible type
+typedef __int64 off_t; // fseeki64 compatible type
+#define _OFF_T_DEFINED
#elif defined(_WIN32)
/* MinGW defines off_t as long and uses f{seek,tell}o64/off64_t for large
* files. */
diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h
index 1f7e6329d..55320a6a4 100644
--- a/vp9/common/vp9_blockd.h
+++ b/vp9/common/vp9_blockd.h
@@ -231,8 +231,6 @@ typedef struct macroblockd {
/* Inverse transform function pointers. */
void (*itxm_add)(const int16_t *input, uint8_t *dest, int stride, int eob);
- const InterpKernel *interp_kernel;
-
int corrupted;
DECLARE_ALIGNED(16, int16_t, dqcoeff[MAX_MB_PLANE][64 * 64]);
diff --git a/vp9/common/vp9_reconinter.c b/vp9/common/vp9_reconinter.c
index 0ab50d456..e722d6a3e 100644
--- a/vp9/common/vp9_reconinter.c
+++ b/vp9/common/vp9_reconinter.c
@@ -146,6 +146,7 @@ static void build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
struct macroblockd_plane *const pd = &xd->plane[plane];
const MODE_INFO *mi = xd->mi[0];
const int is_compound = has_second_ref(&mi->mbmi);
+ const InterpKernel *kernel = vp9_get_interp_kernel(mi->mbmi.interp_filter);
int ref;
for (ref = 0; ref < 1 + is_compound; ++ref) {
@@ -193,8 +194,7 @@ static void build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
+ (scaled_mv.col >> SUBPEL_BITS);
inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride,
- subpel_x, subpel_y, sf, w, h, ref, xd->interp_kernel,
- xs, ys);
+ subpel_x, subpel_y, sf, w, h, ref, kernel, xs, ys);
}
}
@@ -250,6 +250,7 @@ static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
struct macroblockd_plane *const pd = &xd->plane[plane];
const MODE_INFO *mi = xd->mi[0];
const int is_compound = has_second_ref(&mi->mbmi);
+ const InterpKernel *kernel = vp9_get_interp_kernel(mi->mbmi.interp_filter);
int ref;
for (ref = 0; ref < 1 + is_compound; ++ref) {
@@ -377,7 +378,7 @@ static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
}
inter_predictor(buf_ptr, buf_stride, dst, dst_buf->stride, subpel_x,
- subpel_y, sf, w, h, ref, xd->interp_kernel, xs, ys);
+ subpel_y, sf, w, h, ref, kernel, xs, ys);
}
}
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c
index 53f94f848..5a2e6f881 100644
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -360,8 +360,6 @@ static void decode_block(VP9_COMMON *const cm, MACROBLOCKD *const xd,
if (has_second_ref(mbmi))
set_ref(cm, xd, 1, mi_row, mi_col);
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
-
// Prediction
vp9_dec_build_inter_predictors_sb(xd, mi_row, mi_col, bsize);
diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.c b/vp9/encoder/vp9_aq_cyclicrefresh.c
index 1d272e1d9..2e1b4ef5f 100644
--- a/vp9/encoder/vp9_aq_cyclicrefresh.c
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.c
@@ -204,7 +204,7 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) {
// Some of these parameters may be set via codec-control function later.
cr->max_sbs_perframe = 10;
cr->max_qdelta_perc = 50;
- cr->min_block_size = BLOCK_16X16;
+ cr->min_block_size = BLOCK_8X8;
cr->time_for_refresh = 1;
// Set rate threshold to some fraction of target (and scaled by 256).
cr->thresh_rate_sb = (rc->sb64_target_rate * 256) >> 2;
diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
index 7c811e2a3..dbefe1ecf 100644
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -484,12 +484,12 @@ static void write_modes(VP9_COMP *cpi,
}
}
-static void build_tree_distribution(VP9_COMP *cpi, TX_SIZE tx_size) {
+static void build_tree_distribution(VP9_COMP *cpi, TX_SIZE tx_size,
+ vp9_coeff_stats *coef_branch_ct) {
vp9_coeff_probs_model *coef_probs = cpi->frame_coef_probs[tx_size];
vp9_coeff_count *coef_counts = cpi->coef_counts[tx_size];
unsigned int (*eob_branch_ct)[REF_TYPES][COEF_BANDS][COEFF_CONTEXTS] =
cpi->common.counts.eob_branch[tx_size];
- vp9_coeff_stats *coef_branch_ct = cpi->frame_branch_ct[tx_size];
int i, j, k, l, m;
for (i = 0; i < PLANE_TYPES; ++i) {
@@ -512,11 +512,11 @@ static void build_tree_distribution(VP9_COMP *cpi, TX_SIZE tx_size) {
}
static void update_coef_probs_common(vp9_writer* const bc, VP9_COMP *cpi,
- TX_SIZE tx_size) {
+ TX_SIZE tx_size,
+ vp9_coeff_stats *frame_branch_ct) {
vp9_coeff_probs_model *new_frame_coef_probs = cpi->frame_coef_probs[tx_size];
vp9_coeff_probs_model *old_frame_coef_probs =
cpi->common.fc.coef_probs[tx_size];
- vp9_coeff_stats *frame_branch_ct = cpi->frame_branch_ct[tx_size];
const vp9_prob upd = DIFF_UPDATE_PROB;
const int entropy_nodes_update = UNCONSTRAINED_NODES;
int i, j, k, l, t;
@@ -669,13 +669,15 @@ static void update_coef_probs(VP9_COMP *cpi, vp9_writer* w) {
const TX_MODE tx_mode = cpi->common.tx_mode;
const TX_SIZE max_tx_size = tx_mode_to_biggest_tx_size[tx_mode];
TX_SIZE tx_size;
+ vp9_coeff_stats frame_branch_ct[TX_SIZES][PLANE_TYPES];
+
vp9_clear_system_state();
for (tx_size = TX_4X4; tx_size <= TX_32X32; ++tx_size)
- build_tree_distribution(cpi, tx_size);
+ build_tree_distribution(cpi, tx_size, frame_branch_ct[tx_size]);
for (tx_size = TX_4X4; tx_size <= max_tx_size; ++tx_size)
- update_coef_probs_common(w, cpi, tx_size);
+ update_coef_probs_common(w, cpi, tx_size, frame_branch_ct[tx_size]);
}
static void encode_loopfilter(struct loopfilter *lf,
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 42e1ac88f..67b8b0292 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -856,13 +856,22 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
*mi_addr = *mi;
- // For in frame adaptive Q, check for reseting the segment_id and updating
- // the cyclic refresh map.
- if ((cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) && seg->enabled &&
- output_enabled) {
- vp9_cyclic_refresh_update_segment(cpi, &xd->mi[0]->mbmi,
- mi_row, mi_col, bsize, 1);
- vp9_init_plane_quantizers(cpi, x);
+ // If segmentation in use
+ if (seg->enabled && output_enabled) {
+ // For in frame complexity AQ copy the segment id from the segment map.
+ if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) {
+ const uint8_t *const map = seg->update_map ? cpi->segmentation_map
+ : cm->last_frame_seg_map;
+ mi_addr->mbmi.segment_id =
+ vp9_get_segment_id(cm, map, bsize, mi_row, mi_col);
+ }
+ // Else for cyclic refresh mode update the segment map, set the segment id
+ // and then update the quantizer.
+ else if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
+ vp9_cyclic_refresh_update_segment(cpi, &xd->mi[0]->mbmi,
+ mi_row, mi_col, bsize, 1);
+ vp9_init_plane_quantizers(cpi, x);
+ }
}
max_plane = is_inter_block(mbmi) ? MAX_MB_PLANE : 1;
@@ -3430,7 +3439,6 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
}
} else {
set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
// Adjust the zbin based on this MB rate.
diff --git a/vp9/encoder/vp9_mcomp.c b/vp9/encoder/vp9_mcomp.c
index e0299f07f..d40701046 100644
--- a/vp9/encoder/vp9_mcomp.c
+++ b/vp9/encoder/vp9_mcomp.c
@@ -500,8 +500,7 @@ static int vp9_pattern_search(const MACROBLOCK *x,
MV *ref_mv,
int search_param,
int sad_per_bit,
- int do_init_search,
- int do_refine,
+ int do_init_search, int do_refine,
const vp9_variance_fn_ptr_t *vfp,
int use_mvcost,
const MV *center_mv, MV *best_mv,
@@ -513,20 +512,15 @@ static int vp9_pattern_search(const MACROBLOCK *x,
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
};
int i, j, s, t;
- const uint8_t *what = x->plane[0].src.buf;
- const int what_stride = x->plane[0].src.stride;
- const int in_what_stride = xd->plane[0].pre[0].stride;
+ const struct buf_2d *const what = &x->plane[0].src;
+ const struct buf_2d *const in_what = &xd->plane[0].pre[0];
int br, bc;
- MV this_mv;
int bestsad = INT_MAX;
int thissad;
- const uint8_t *base_offset;
- const uint8_t *this_offset;
int k = -1;
- int best_site = -1;
const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
int best_init_s = search_param_to_steps[search_param];
- const int *mvjsadcost = x->nmvjointsadcost;
+ const int *const mvjsadcost = x->nmvjointsadcost;
int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
// adjust ref_mv to make sure it is within MV range
@@ -535,13 +529,10 @@ static int vp9_pattern_search(const MACROBLOCK *x,
bc = ref_mv->col;
// Work out the start point for the search
- base_offset = xd->plane[0].pre[0].buf;
- this_offset = base_offset + (br * in_what_stride) + bc;
- this_mv.row = br;
- this_mv.col = bc;
- bestsad = vfp->sdf(what, what_stride, this_offset, in_what_stride, 0x7fffffff)
- + mvsad_err_cost(&this_mv, &fcenter_mv,
- mvjsadcost, mvsadcost, sad_per_bit);
+ bestsad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, ref_mv), in_what->stride,
+ 0x7fffffff) + mvsad_err_cost(ref_mv, &fcenter_mv,
+ mvjsadcost, mvsadcost, sad_per_bit);
// Search all possible scales upto the search param around the center point
// pick the scale of the point that is best as the starting scale of
@@ -550,27 +541,25 @@ static int vp9_pattern_search(const MACROBLOCK *x,
s = best_init_s;
best_init_s = -1;
for (t = 0; t <= s; ++t) {
- best_site = -1;
+ int best_site = -1;
if (check_bounds(x, br, bc, 1 << t)) {
for (i = 0; i < num_candidates[t]; i++) {
- this_mv.row = br + candidates[t][i].row;
- this_mv.col = bc + candidates[t][i].col;
- this_offset = base_offset + (this_mv.row * in_what_stride) +
- this_mv.col;
- thissad = vfp->sdf(what, what_stride, this_offset, in_what_stride,
- bestsad);
+ const MV this_mv = {br + candidates[t][i].row,
+ bc + candidates[t][i].col};
+ thissad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, &this_mv),
+ in_what->stride, bestsad);
CHECK_BETTER
}
} else {
for (i = 0; i < num_candidates[t]; i++) {
- this_mv.row = br + candidates[t][i].row;
- this_mv.col = bc + candidates[t][i].col;
+ const MV this_mv = {br + candidates[t][i].row,
+ bc + candidates[t][i].col};
if (!is_mv_in(x, &this_mv))
continue;
- this_offset = base_offset + (this_mv.row * in_what_stride) +
- this_mv.col;
- thissad = vfp->sdf(what, what_stride, this_offset, in_what_stride,
- bestsad);
+ thissad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, &this_mv),
+ in_what->stride, bestsad);
CHECK_BETTER
}
}
@@ -590,31 +579,30 @@ static int vp9_pattern_search(const MACROBLOCK *x,
// If the center point is still the best, just skip this and move to
// the refinement step.
if (best_init_s != -1) {
+ int best_site = -1;
s = best_init_s;
- best_site = -1;
+
do {
// No need to search all 6 points the 1st time if initial search was used
if (!do_init_search || s != best_init_s) {
if (check_bounds(x, br, bc, 1 << s)) {
for (i = 0; i < num_candidates[s]; i++) {
- this_mv.row = br + candidates[s][i].row;
- this_mv.col = bc + candidates[s][i].col;
- this_offset = base_offset + (this_mv.row * in_what_stride) +
- this_mv.col;
- thissad = vfp->sdf(what, what_stride, this_offset, in_what_stride,
- bestsad);
+ const MV this_mv = {br + candidates[s][i].row,
+ bc + candidates[s][i].col};
+ thissad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, &this_mv),
+ in_what->stride, bestsad);
CHECK_BETTER
}
} else {
for (i = 0; i < num_candidates[s]; i++) {
- this_mv.row = br + candidates[s][i].row;
- this_mv.col = bc + candidates[s][i].col;
+ const MV this_mv = {br + candidates[s][i].row,
+ bc + candidates[s][i].col};
if (!is_mv_in(x, &this_mv))
continue;
- this_offset = base_offset + (this_mv.row * in_what_stride) +
- this_mv.col;
- thissad = vfp->sdf(what, what_stride, this_offset, in_what_stride,
- bestsad);
+ thissad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, &this_mv),
+ in_what->stride, bestsad);
CHECK_BETTER
}
}
@@ -637,24 +625,22 @@ static int vp9_pattern_search(const MACROBLOCK *x,
if (check_bounds(x, br, bc, 1 << s)) {
for (i = 0; i < PATTERN_CANDIDATES_REF; i++) {
- this_mv.row = br + candidates[s][next_chkpts_indices[i]].row;
- this_mv.col = bc + candidates[s][next_chkpts_indices[i]].col;
- this_offset = base_offset + (this_mv.row * (in_what_stride)) +
- this_mv.col;
- thissad = vfp->sdf(what, what_stride, this_offset, in_what_stride,
- bestsad);
+ const MV this_mv = {br + candidates[s][next_chkpts_indices[i]].row,
+ bc + candidates[s][next_chkpts_indices[i]].col};
+ thissad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, &this_mv),
+ in_what->stride, bestsad);
CHECK_BETTER
}
} else {
for (i = 0; i < PATTERN_CANDIDATES_REF; i++) {
- this_mv.row = br + candidates[s][next_chkpts_indices[i]].row;
- this_mv.col = bc + candidates[s][next_chkpts_indices[i]].col;
+ const MV this_mv = {br + candidates[s][next_chkpts_indices[i]].row,
+ bc + candidates[s][next_chkpts_indices[i]].col};
if (!is_mv_in(x, &this_mv))
continue;
- this_offset = base_offset + (this_mv.row * (in_what_stride)) +
- this_mv.col;
- thissad = vfp->sdf(what, what_stride, this_offset, in_what_stride,
- bestsad);
+ thissad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, &this_mv),
+ in_what->stride, bestsad);
CHECK_BETTER
}
}
@@ -671,29 +657,28 @@ static int vp9_pattern_search(const MACROBLOCK *x,
// Check 4 1-away neighbors if do_refine is true.
// For most well-designed schemes do_refine will not be necessary.
if (do_refine) {
- static const MV neighbors[4] = { {0, -1}, { -1, 0}, {1, 0}, {0, 1} };
+ static const MV neighbors[4] = {{0, -1}, { -1, 0}, {1, 0}, {0, 1}};
+
for (j = 0; j < 16; j++) {
- best_site = -1;
+ int best_site = -1;
if (check_bounds(x, br, bc, 1)) {
for (i = 0; i < 4; i++) {
- this_mv.row = br + neighbors[i].row;
- this_mv.col = bc + neighbors[i].col;
- this_offset = base_offset + this_mv.row * in_what_stride +
- this_mv.col;
- thissad = vfp->sdf(what, what_stride, this_offset, in_what_stride,
- bestsad);
+ const MV this_mv = {br + neighbors[i].row,
+ bc + neighbors[i].col};
+ thissad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, &this_mv),
+ in_what->stride, bestsad);
CHECK_BETTER
}
} else {
for (i = 0; i < 4; i++) {
- this_mv.row = br + neighbors[i].row;
- this_mv.col = bc + neighbors[i].col;
+ const MV this_mv = {br + neighbors[i].row,
+ bc + neighbors[i].col};
if (!is_mv_in(x, &this_mv))
continue;
- this_offset = base_offset + this_mv.row * in_what_stride +
- this_mv.col;
- thissad = vfp->sdf(what, what_stride, this_offset, in_what_stride,
- bestsad);
+ thissad = vfp->sdf(what->buf, what->stride,
+ get_buf_from_mv(in_what, &this_mv),
+ in_what->stride, bestsad);
CHECK_BETTER
}
}
@@ -710,8 +695,6 @@ static int vp9_pattern_search(const MACROBLOCK *x,
best_mv->row = br;
best_mv->col = bc;
- this_mv.row = best_mv->row * 8;
- this_mv.col = best_mv->col * 8;
return bestsad;
}
@@ -719,39 +702,32 @@ int vp9_get_mvpred_var(const MACROBLOCK *x,
const MV *best_mv, const MV *center_mv,
const vp9_variance_fn_ptr_t *vfp,
int use_mvcost) {
- unsigned int unused;
-
const MACROBLOCKD *const xd = &x->e_mbd;
- const uint8_t *what = x->plane[0].src.buf;
- const int what_stride = x->plane[0].src.stride;
- const int in_what_stride = xd->plane[0].pre[0].stride;
- const uint8_t *base_offset = xd->plane[0].pre[0].buf;
- const uint8_t *this_offset = &base_offset[best_mv->row * in_what_stride +
- best_mv->col];
+ const struct buf_2d *const what = &x->plane[0].src;
+ const struct buf_2d *const in_what = &xd->plane[0].pre[0];
const MV mv = {best_mv->row * 8, best_mv->col * 8};
- return vfp->vf(what, what_stride, this_offset, in_what_stride, &unused) +
+ unsigned int unused;
+
+ return vfp->vf(what->buf, what->stride,
+ get_buf_from_mv(in_what, best_mv), in_what->stride, &unused) +
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmvjointcost,
x->mvcost, x->errorperbit) : 0);
}
int vp9_get_mvpred_av_var(const MACROBLOCK *x,
- MV *best_mv,
- const MV *center_mv,
+ const MV *best_mv, const MV *center_mv,
const uint8_t *second_pred,
const vp9_variance_fn_ptr_t *vfp,
int use_mvcost) {
- unsigned int bestsad;
const MACROBLOCKD *const xd = &x->e_mbd;
- const uint8_t *what = x->plane[0].src.buf;
- const int what_stride = x->plane[0].src.stride;
- const int in_what_stride = xd->plane[0].pre[0].stride;
- const uint8_t *base_offset = xd->plane[0].pre[0].buf;
- const uint8_t *this_offset = base_offset + (best_mv->row * in_what_stride) +
- best_mv->col;
- const MV this_mv = {best_mv->row * 8, best_mv->col * 8};
- return vfp->svaf(this_offset, in_what_stride, 0, 0, what, what_stride,
- &bestsad, second_pred) +
- (use_mvcost ? mv_err_cost(&this_mv, center_mv, x->nmvjointcost,
+ const struct buf_2d *const what = &x->plane[0].src;
+ const struct buf_2d *const in_what = &xd->plane[0].pre[0];
+ const MV mv = {best_mv->row * 8, best_mv->col * 8};
+ unsigned int unused;
+
+ return vfp->svaf(get_buf_from_mv(in_what, best_mv), in_what->stride, 0, 0,
+ what->buf, what->stride, &unused, second_pred) +
+ (use_mvcost ? mv_err_cost(&mv, center_mv, x->nmvjointcost,
x->mvcost, x->errorperbit) : 0);
}
diff --git a/vp9/encoder/vp9_mcomp.h b/vp9/encoder/vp9_mcomp.h
index 917de75e6..f7b7c5e49 100644
--- a/vp9/encoder/vp9_mcomp.h
+++ b/vp9/encoder/vp9_mcomp.h
@@ -42,8 +42,7 @@ int vp9_get_mvpred_var(const MACROBLOCK *x,
const vp9_variance_fn_ptr_t *vfp,
int use_mvcost);
int vp9_get_mvpred_av_var(const MACROBLOCK *x,
- MV *best_mv,
- const MV *center_mv,
+ const MV *best_mv, const MV *center_mv,
const uint8_t *second_pred,
const vp9_variance_fn_ptr_t *vfp,
int use_mvcost);
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c
index f8427cffd..9ecab5770 100644
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -1002,7 +1002,7 @@ static void cal_nmvjointsadcost(int *mvjointsadcost) {
mvjointsadcost[0] = 600;
mvjointsadcost[1] = 300;
mvjointsadcost[2] = 300;
- mvjointsadcost[0] = 300;
+ mvjointsadcost[3] = 300;
}
static void cal_nmvsadcosts(int *mvsadcost[2]) {
@@ -3198,8 +3198,6 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
}
set_ref_ptrs(cm, xd, LAST_FRAME, LAST_FRAME);
- xd->interp_kernel = vp9_get_interp_kernel(
- DEFAULT_INTERP_FILTER == SWITCHABLE ? EIGHTTAP : DEFAULT_INTERP_FILTER);
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
vp9_vaq_init();
diff --git a/vp9/encoder/vp9_onyx_int.h b/vp9/encoder/vp9_onyx_int.h
index 535bdaacb..d9dbd53da 100644
--- a/vp9/encoder/vp9_onyx_int.h
+++ b/vp9/encoder/vp9_onyx_int.h
@@ -232,6 +232,9 @@ typedef struct {
int lossless;
AQ_MODE aq_mode; // Adaptive Quantization mode
+ // Enable feature to reduce the frame quantization every x frames.
+ int frame_periodic_boost;
+
// two pass datarate control
int two_pass_vbrbias; // two pass datarate control tweaks
int two_pass_vbrmin_section;
@@ -385,7 +388,6 @@ typedef struct VP9_COMP {
vp9_coeff_count coef_counts[TX_SIZES][PLANE_TYPES];
vp9_coeff_probs_model frame_coef_probs[TX_SIZES][PLANE_TYPES];
- vp9_coeff_stats frame_branch_ct[TX_SIZES][PLANE_TYPES];
struct vpx_codec_pkt_list *output_pkt_list;
@@ -587,6 +589,13 @@ static INLINE YV12_BUFFER_CONFIG *get_ref_frame_buffer(
.buf;
}
+// Intra only frames, golden frames (except alt ref overlays) and
+// alt ref frames tend to be coded at a higher than ambient quality
+static INLINE int vp9_frame_is_boosted(const VP9_COMP *cpi) {
+ return frame_is_intra_only(&cpi->common) || cpi->refresh_alt_ref_frame ||
+ (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref);
+}
+
static INLINE int get_token_alloc(int mb_rows, int mb_cols) {
// TODO(JBB): make this work for alpha channel and double check we can't
// exceed this token count if we have a 32x32 transform crossing a boundary
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index b517d6cfe..f987de512 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -188,14 +188,12 @@ static void model_rd_for_sb_y(VP9_COMP *cpi, BLOCK_SIZE bsize,
struct macroblock_plane *const p = &x->plane[0];
struct macroblockd_plane *const pd = &xd->plane[0];
- const BLOCK_SIZE bs = get_plane_block_size(bsize, pd);
- int var = cpi->fn_ptr[bs].vf(p->src.buf, p->src.stride,
- pd->dst.buf, pd->dst.stride, &sse);
+ int var = cpi->fn_ptr[bsize].vf(p->src.buf, p->src.stride,
+ pd->dst.buf, pd->dst.stride, &sse);
- vp9_model_rd_from_var_lapndz(var + sse, 1 << num_pels_log2_lookup[bs],
+ vp9_model_rd_from_var_lapndz(sse + var, 1 << num_pels_log2_lookup[bsize],
pd->dequant[1] >> 3, &rate, &dist);
-
*out_rate_sum = rate;
*out_dist_sum = dist << 3;
}
@@ -212,7 +210,6 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
struct macroblock_plane *const p = &x->plane[0];
struct macroblockd_plane *const pd = &xd->plane[0];
- const BLOCK_SIZE block_size = get_plane_block_size(bsize, &xd->plane[0]);
MB_PREDICTION_MODE this_mode, best_mode = ZEROMV;
MV_REFERENCE_FRAME ref_frame, best_ref_frame = LAST_FRAME;
int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES];
@@ -256,13 +253,12 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
EIGHTTAP : cpi->common.interp_filter;
mbmi->skip = 0;
mbmi->segment_id = segment_id;
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
for (ref_frame = LAST_FRAME; ref_frame <= LAST_FRAME ; ++ref_frame) {
x->pred_mv_sad[ref_frame] = INT_MAX;
if (cpi->ref_frame_flags & flag_list[ref_frame]) {
vp9_setup_buffer_inter(cpi, x, tile,
- ref_frame, block_size, mi_row, mi_col,
+ ref_frame, bsize, mi_row, mi_col,
frame_mv[NEARESTMV], frame_mv[NEARMV], yv12_mb);
}
frame_mv[NEWMV][ref_frame].as_int = INVALID_MV;
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index 016901456..eb4db1a33 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -982,8 +982,8 @@ int vp9_rc_pick_q_and_bounds(const VP9_COMP *cpi,
if (cpi->sf.use_nonrd_pick_mode) {
if (q == 0)
q++;
- if (cpi->sf.partition_check == 1)
- q -= 10;
+ if (cpi->sf.force_frame_boost == 1)
+ q -= cpi->sf.max_delta_qindex;
if (q < *bottom_index)
*bottom_index = q;
@@ -1002,28 +1002,14 @@ void vp9_rc_compute_frame_size_bounds(const VP9_COMP *cpi,
*frame_under_shoot_limit = 0;
*frame_over_shoot_limit = INT_MAX;
} else {
- if (cpi->common.frame_type == KEY_FRAME) {
- *frame_over_shoot_limit = this_frame_target * 9 / 8;
- *frame_under_shoot_limit = this_frame_target * 7 / 8;
- } else {
- if (cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) {
- *frame_over_shoot_limit = this_frame_target * 9 / 8;
- *frame_under_shoot_limit = this_frame_target * 7 / 8;
- } else {
- // Strong overshoot limit for constrained quality
- if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) {
- *frame_over_shoot_limit = this_frame_target * 11 / 8;
- *frame_under_shoot_limit = this_frame_target * 2 / 8;
- } else {
- *frame_over_shoot_limit = this_frame_target * 11 / 8;
- *frame_under_shoot_limit = this_frame_target * 5 / 8;
- }
- }
- }
+ int recode_tolerance =
+ (cpi->sf.recode_tolerance * this_frame_target) / 100;
+
+ *frame_over_shoot_limit = this_frame_target + recode_tolerance;
+ *frame_under_shoot_limit = this_frame_target - recode_tolerance;
// For very small rate targets where the fractional adjustment
- // (eg * 7/8) may be tiny make sure there is at least a minimum
- // range.
+ // may be tiny make sure there is at least a minimum range.
*frame_over_shoot_limit += 200;
*frame_under_shoot_limit -= 200;
if (*frame_under_shoot_limit < 0)
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index d758d3bf5..a3e513277 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -1559,6 +1559,8 @@ static int64_t encode_inter_mb_segment(VP9_COMP *cpi,
int thisrate = 0, ref;
const scan_order *so = &vp9_default_scan_orders[TX_4X4];
const int is_compound = has_second_ref(&mi->mbmi);
+ const InterpKernel *kernel = vp9_get_interp_kernel(mi->mbmi.interp_filter);
+
for (ref = 0; ref < 1 + is_compound; ++ref) {
const uint8_t *pre = &pd->pre[ref].buf[raster_block_offset(BLOCK_8X8, i,
pd->pre[ref].stride)];
@@ -1566,7 +1568,7 @@ static int64_t encode_inter_mb_segment(VP9_COMP *cpi,
dst, pd->dst.stride,
&mi->bmi[i].as_mv[ref].as_mv,
&xd->block_refs[ref]->sf, width, height, ref,
- xd->interp_kernel, MV_PRECISION_Q3,
+ kernel, MV_PRECISION_Q3,
mi_col * MI_SIZE + 4 * (i % 2),
mi_row * MI_SIZE + 4 * (i / 2));
}
@@ -2544,6 +2546,7 @@ static void joint_motion_search(VP9_COMP *cpi, MACROBLOCK *x,
int ite, ref;
// Prediction buffer from second frame.
uint8_t *second_pred = vpx_memalign(16, pw * ph * sizeof(uint8_t));
+ const InterpKernel *kernel = vp9_get_interp_kernel(mbmi->interp_filter);
// Do joint motion search in compound mode to get more accurate mv.
struct buf_2d backup_yv12[2][MAX_MB_PLANE];
@@ -2597,7 +2600,7 @@ static void joint_motion_search(VP9_COMP *cpi, MACROBLOCK *x,
&frame_mv[refs[!id]].as_mv,
&xd->block_refs[!id]->sf,
pw, ph, 0,
- xd->interp_kernel, MV_PRECISION_Q3,
+ kernel, MV_PRECISION_Q3,
mi_col * MI_SIZE, mi_row * MI_SIZE);
// Compound motion search on first ref frame.
@@ -2812,7 +2815,6 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
int j;
int64_t rs_rd;
mbmi->interp_filter = i;
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
rs = get_switchable_rate(x);
rs_rd = RDCOST(x->rdmult, x->rddiv, rs, 0);
@@ -2883,7 +2885,6 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
// Set the appropriate filter
mbmi->interp_filter = cm->interp_filter != SWITCHABLE ?
cm->interp_filter : *best_filter;
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
rs = cm->interp_filter == SWITCHABLE ? get_switchable_rate(x) : 0;
if (pred_exists) {
@@ -3394,7 +3395,6 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
: cm->interp_filter;
x->skip = 0;
set_ref_ptrs(cm, xd, ref_frame, second_ref_frame);
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
// Select prediction reference frames.
for (i = 0; i < MAX_MB_PLANE; i++) {
@@ -3938,7 +3938,6 @@ int64_t vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x,
// them for this frame.
mbmi->interp_filter = cm->interp_filter == SWITCHABLE ? EIGHTTAP
: cm->interp_filter;
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
if (comp_pred) {
if (!(cpi->ref_frame_flags & flag_list[second_ref_frame]))
@@ -4061,7 +4060,6 @@ int64_t vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x,
int newbest, rs;
int64_t rs_rd;
mbmi->interp_filter = switchable_filter_index;
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
tmp_rd = rd_pick_best_mbsegmentation(cpi, x, tile,
&mbmi->ref_mvs[ref_frame][0],
second_ref,
@@ -4126,7 +4124,6 @@ int64_t vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x,
mbmi->interp_filter = (cm->interp_filter == SWITCHABLE ?
tmp_best_filter : cm->interp_filter);
- xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
if (!pred_exists) {
// Handles the special case when a filter that is not in the
// switchable list (bilinear, 6-tap) is indicated at the frame level
diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c
index f09035077..7b983f992 100644
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -13,24 +13,32 @@
#include "vp9/encoder/vp9_onyx_int.h"
#include "vp9/encoder/vp9_speed_features.h"
-#define ALL_INTRA_MODES 0x3FF
-#define INTRA_DC_ONLY 0x01
-#define INTRA_DC_TM ((1 << TM_PRED) | (1 << DC_PRED))
-#define INTRA_DC_H_V ((1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED))
+#define ALL_INTRA_MODES ((1 << DC_PRED) | \
+ (1 << V_PRED) | (1 << H_PRED) | \
+ (1 << D45_PRED) | (1 << D135_PRED) | \
+ (1 << D117_PRED) | (1 << D153_PRED) | \
+ (1 << D207_PRED) | (1 << D63_PRED) | \
+ (1 << TM_PRED))
+#define INTRA_DC_ONLY (1 << DC_PRED)
+#define INTRA_DC_TM ((1 << TM_PRED) | (1 << DC_PRED))
+#define INTRA_DC_H_V ((1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED))
#define INTRA_DC_TM_H_V (INTRA_DC_TM | (1 << V_PRED) | (1 << H_PRED))
// Masks for partially or completely disabling split mode
-#define DISABLE_ALL_SPLIT 0x3F
-#define DISABLE_ALL_INTER_SPLIT 0x1F
-#define DISABLE_COMPOUND_SPLIT 0x18
-#define LAST_AND_INTRA_SPLIT_ONLY 0x1E
-
-// Intra only frames, golden frames (except alt ref overlays) and
-// alt ref frames tend to be coded at a higher than ambient quality
-static INLINE int frame_is_boosted(const VP9_COMP *cpi) {
- return frame_is_intra_only(&cpi->common) || cpi->refresh_alt_ref_frame ||
- (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref);
-}
+#define DISABLE_ALL_INTER_SPLIT ((1 << THR_COMP_GA) | \
+ (1 << THR_COMP_LA) | \
+ (1 << THR_ALTR) | \
+ (1 << THR_GOLD) | \
+ (1 << THR_LAST))
+
+#define DISABLE_ALL_SPLIT ((1 << THR_INTRA) | DISABLE_ALL_INTER_SPLIT)
+
+#define DISABLE_COMPOUND_SPLIT ((1 << THR_COMP_GA) | (1 << THR_COMP_LA))
+
+#define LAST_AND_INTRA_SPLIT_ONLY ((1 << THR_COMP_GA) | \
+ (1 << THR_COMP_LA) | \
+ (1 << THR_ALTR) | \
+ (1 << THR_GOLD))
static void set_good_speed_feature(VP9_COMP *cpi,
VP9_COMMON *cm,
@@ -44,7 +52,7 @@ static void set_good_speed_feature(VP9_COMP *cpi,
if (speed >= 1) {
sf->use_square_partition_only = !frame_is_intra_only(cm);
sf->less_rectangular_check = 1;
- sf->tx_size_search_method = frame_is_boosted(cpi)
+ sf->tx_size_search_method = vp9_frame_is_boosted(cpi)
? USE_FULL_RD : USE_LARGESTALL;
if (MIN(cm->width, cm->height) >= 720)
@@ -68,7 +76,7 @@ static void set_good_speed_feature(VP9_COMP *cpi,
}
// Additions or changes from speed 1 for speed >= 2.
if (speed >= 2) {
- sf->tx_size_search_method = frame_is_boosted(cpi)
+ sf->tx_size_search_method = vp9_frame_is_boosted(cpi)
? USE_FULL_RD : USE_LARGESTALL;
if (MIN(cm->width, cm->height) >= 720)
@@ -251,6 +259,10 @@ static void set_rt_speed_feature(VP9_COMMON *cm,
sf->min_partition_size = BLOCK_8X8;
sf->partition_check =
(cm->current_video_frame % sf->last_partitioning_redo_frequency == 1);
+ sf->force_frame_boost = cm->frame_type == KEY_FRAME ||
+ (cm->current_video_frame %
+ (sf->last_partitioning_redo_frequency << 1) == 1);
+ sf->max_delta_qindex = (cm->frame_type == KEY_FRAME) ? 20 : 15;
sf->partition_search_type = REFERENCE_PARTITION;
sf->use_nonrd_pick_mode = 1;
sf->search_method = FAST_DIAMOND;
@@ -303,6 +315,8 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
sf->last_partitioning_redo_frequency = 4;
sf->disable_split_mask = 0;
sf->mode_search_skip_flags = 0;
+ sf->force_frame_boost = 0;
+ sf->max_delta_qindex = 0;
sf->disable_split_var_thresh = 0;
sf->disable_filter_search_var_thresh = 0;
for (i = 0; i < TX_SIZES; i++) {
@@ -326,6 +340,9 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
// to FIXED_PARTITION.
sf->always_this_block_size = BLOCK_16X16;
+ // Recode loop tolerence %.
+ sf->recode_tolerance = 25;
+
switch (cpi->oxcf.mode) {
case MODE_BESTQUALITY:
case MODE_SECONDPASS_BEST: // This is the best quality mode.
@@ -366,4 +383,8 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
if (sf->disable_split_mask == DISABLE_ALL_SPLIT)
sf->adaptive_pred_interp_filter = 0;
+
+ if (!cpi->oxcf.frame_periodic_boost) {
+ sf->max_delta_qindex = 0;
+ }
}
diff --git a/vp9/encoder/vp9_speed_features.h b/vp9/encoder/vp9_speed_features.h
index 5091e2b06..826043910 100644
--- a/vp9/encoder/vp9_speed_features.h
+++ b/vp9/encoder/vp9_speed_features.h
@@ -252,6 +252,13 @@ typedef struct {
// encoding process for RTC.
int partition_check;
+ // Use finer quantizer in every other few frames that run variable block
+ // partition type search.
+ int force_frame_boost;
+
+ // Maximally allowed base quantization index fluctuation.
+ int max_delta_qindex;
+
// Implements various heuristics to skip searching modes
// The heuristics selected are based on flags
// defined in the MODE_SEARCH_SKIP_HEURISTICS enum
@@ -301,6 +308,10 @@ typedef struct {
// calculation in the rd coefficient costing loop.
int use_fast_coef_costing;
+ // This feature controls the tolerence vs target used in deciding whether to
+ // recode a frame. It has no meaning if recode is disabled.
+ int recode_tolerance;
+
// This variable controls the maximum block size where intra blocks can be
// used in inter frames.
// TODO(aconverse): Fold this into one of the other many mode skips
diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c
index f8a641513..041027354 100644
--- a/vp9/encoder/vp9_temporal_filter.c
+++ b/vp9/encoder/vp9_temporal_filter.c
@@ -41,7 +41,10 @@ static void temporal_filter_predictors_mb_c(MACROBLOCKD *xd,
struct scale_factors *scale,
int x, int y) {
const int which_mv = 0;
- MV mv = { mv_row, mv_col };
+ const MV mv = { mv_row, mv_col };
+ const InterpKernel *const kernel =
+ vp9_get_interp_kernel(xd->mi[0]->mbmi.interp_filter);
+
enum mv_precision mv_precision_uv;
int uv_stride;
if (uv_block_size == 8) {
@@ -58,7 +61,7 @@ static void temporal_filter_predictors_mb_c(MACROBLOCKD *xd,
scale,
16, 16,
which_mv,
- xd->interp_kernel, MV_PRECISION_Q3, x, y);
+ kernel, MV_PRECISION_Q3, x, y);
vp9_build_inter_predictor(u_mb_ptr, uv_stride,
&pred[256], uv_block_size,
@@ -66,7 +69,7 @@ static void temporal_filter_predictors_mb_c(MACROBLOCKD *xd,
scale,
uv_block_size, uv_block_size,
which_mv,
- xd->interp_kernel, mv_precision_uv, x, y);
+ kernel, mv_precision_uv, x, y);
vp9_build_inter_predictor(v_mb_ptr, uv_stride,
&pred[512], uv_block_size,
@@ -74,7 +77,7 @@ static void temporal_filter_predictors_mb_c(MACROBLOCKD *xd,
scale,
uv_block_size, uv_block_size,
which_mv,
- xd->interp_kernel, mv_precision_uv, x, y);
+ kernel, mv_precision_uv, x, y);
}
void vp9_temporal_filter_apply_c(uint8_t *frame1,
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index a9fd8c11e..37a214e05 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -37,6 +37,7 @@ struct vp9_extracfg {
unsigned int lossless;
unsigned int frame_parallel_decoding_mode;
AQ_MODE aq_mode;
+ unsigned int frame_periodic_boost;
};
struct extraconfig_map {
@@ -65,6 +66,7 @@ static const struct extraconfig_map extracfg_map[] = {
0, // lossless
0, // frame_parallel_decoding_mode
NO_AQ, // aq_mode
+ 0, // frame_periodic_delta_q
}
}
};
@@ -150,7 +152,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer);
RANGE_CHECK_BOOL(extra_cfg, lossless);
RANGE_CHECK(extra_cfg, aq_mode, 0, AQ_MODE_COUNT - 1);
-
+ RANGE_CHECK(extra_cfg, frame_periodic_boost, 0, 1);
RANGE_CHECK_HI(cfg, g_threads, 64);
RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS);
RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_Q);
@@ -360,6 +362,8 @@ static vpx_codec_err_t set_vp9e_config(VP9_CONFIG *oxcf,
oxcf->aq_mode = extra_cfg->aq_mode;
+ oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost;
+
oxcf->ss_number_layers = cfg->ss_number_layers;
if (oxcf->ss_number_layers > 1) {
@@ -484,6 +488,7 @@ static vpx_codec_err_t set_param(vpx_codec_alg_priv_t *ctx, int ctrl_id,
MAP(VP9E_SET_FRAME_PARALLEL_DECODING,
extra_cfg.frame_parallel_decoding_mode);
MAP(VP9E_SET_AQ_MODE, extra_cfg.aq_mode);
+ MAP(VP9E_SET_FRAME_PERIODIC_BOOST, extra_cfg.frame_periodic_boost);
}
res = validate_config(ctx, &ctx->cfg, &extra_cfg);
@@ -1094,6 +1099,7 @@ static vpx_codec_ctrl_fn_map_t vp9e_ctf_maps[] = {
{VP9E_SET_LOSSLESS, set_param},
{VP9E_SET_FRAME_PARALLEL_DECODING, set_param},
{VP9E_SET_AQ_MODE, set_param},
+ {VP9E_SET_FRAME_PERIODIC_BOOST, set_param},
{VP9_GET_REFERENCE, get_reference},
{VP9E_SET_SVC, vp9e_set_svc},
{VP9E_SET_SVC_PARAMETERS, vp9e_set_svc_parameters},
diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c
index 271589c6b..3be945480 100644
--- a/vp9/vp9_dx_iface.c
+++ b/vp9/vp9_dx_iface.c
@@ -23,27 +23,10 @@
#define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
typedef vpx_codec_stream_info_t vp9_stream_info_t;
-/* Structures for handling memory allocations */
-typedef enum {
- VP9_SEG_ALG_PRIV = 256,
- VP9_SEG_MAX
-} mem_seg_id_t;
-#define NELEMENTS(x) ((int)(sizeof(x)/sizeof(x[0])))
-
-static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
- vpx_codec_flags_t flags);
-
-static const mem_req_t vp9_mem_req_segs[] = {
- {VP9_SEG_ALG_PRIV, 0, 8, VPX_CODEC_MEM_ZERO, priv_sz},
- {VP9_SEG_MAX, 0, 0, 0, NULL}
-};
-
struct vpx_codec_alg_priv {
vpx_codec_priv_t base;
- vpx_codec_mmap_t mmaps[NELEMENTS(vp9_mem_req_segs) - 1];
vpx_codec_dec_cfg_t cfg;
vp9_stream_info_t si;
- int defer_alloc;
int decoder_init;
struct VP9Decompressor *pbi;
int postproc_cfg_set;
@@ -66,80 +49,38 @@ struct vpx_codec_alg_priv {
vpx_release_frame_buffer_cb_fn_t release_ext_fb_cb;
};
-static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
- vpx_codec_flags_t flags) {
- /* Although this declaration is constant, we can't use it in the requested
- * segments list because we want to define the requested segments list
- * before defining the private type (so that the number of memory maps is
- * known)
- */
- (void)si;
- return sizeof(vpx_codec_alg_priv_t);
-}
-
-static void vp9_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) {
- int i;
-
- ctx->priv = (vpx_codec_priv_t *)mmap->base;
- ctx->priv->sz = sizeof(*ctx->priv);
- ctx->priv->iface = ctx->iface;
- ctx->priv->alg_priv = (struct vpx_codec_alg_priv *)mmap->base;
-
- for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++)
- ctx->priv->alg_priv->mmaps[i].id = vp9_mem_req_segs[i].id;
-
- ctx->priv->alg_priv->mmaps[0] = *mmap;
- ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
- ctx->priv->init_flags = ctx->init_flags;
-
- if (ctx->config.dec) {
- /* Update the reference to the config structure to an internal copy. */
- ctx->priv->alg_priv->cfg = *ctx->config.dec;
- ctx->config.dec = &ctx->priv->alg_priv->cfg;
- }
-}
-
-static void vp9_finalize_mmaps(vpx_codec_alg_priv_t *ctx) {
- /* nothing to clean up */
-}
-
static vpx_codec_err_t vp9_init(vpx_codec_ctx_t *ctx,
vpx_codec_priv_enc_mr_cfg_t *data) {
- vpx_codec_err_t res = VPX_CODEC_OK;
-
// This function only allocates space for the vpx_codec_alg_priv_t
// structure. More memory may be required at the time the stream
// information becomes known.
if (!ctx->priv) {
- vpx_codec_mmap_t mmap;
-
- mmap.id = vp9_mem_req_segs[0].id;
- mmap.sz = sizeof(vpx_codec_alg_priv_t);
- mmap.align = vp9_mem_req_segs[0].align;
- mmap.flags = vp9_mem_req_segs[0].flags;
-
- res = vpx_mmap_alloc(&mmap);
- if (!res) {
- vp9_init_ctx(ctx, &mmap);
-
- ctx->priv->alg_priv->defer_alloc = 1;
+ void *base = vpx_memalign(32, sizeof(vpx_codec_alg_priv_t));
+ if (base == NULL)
+ return VPX_CODEC_MEM_ERROR;
+
+ memset(base, 0, sizeof(vpx_codec_alg_priv_t));
+ ctx->priv = (vpx_codec_priv_t *)base;
+ ctx->priv->sz = sizeof(*ctx->priv);
+ ctx->priv->iface = ctx->iface;
+ ctx->priv->alg_priv = (vpx_codec_alg_priv_t *)base;
+ ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
+ ctx->priv->init_flags = ctx->init_flags;
+
+ if (ctx->config.dec) {
+ // Update the reference to the config structure to an internal copy.
+ ctx->priv->alg_priv->cfg = *ctx->config.dec;
+ ctx->config.dec = &ctx->priv->alg_priv->cfg;
}
}
- return res;
+ return VPX_CODEC_OK;
}
static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) {
- int i;
-
if (ctx->pbi)
vp9_remove_decompressor(ctx->pbi);
- for (i = NELEMENTS(ctx->mmaps) - 1; i >= 0; i--) {
- if (ctx->mmaps[i].dtor)
- ctx->mmaps[i].dtor(&ctx->mmaps[i]);
- }
-
return VPX_CODEC_OK;
}
@@ -231,94 +172,59 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
ctx->img_avail = 0;
- /* Determine the stream parameters. Note that we rely on peek_si to
- * validate that we have a buffer that does not wrap around the top
- * of the heap.
- */
+ // Determine the stream parameters. Note that we rely on peek_si to
+ // validate that we have a buffer that does not wrap around the top
+ // of the heap.
if (!ctx->si.h)
res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
-
- /* Perform deferred allocations, if required */
- if (!res && ctx->defer_alloc) {
- int i;
-
- for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++) {
- vpx_codec_dec_cfg_t cfg;
-
- cfg.w = ctx->si.w;
- cfg.h = ctx->si.h;
- ctx->mmaps[i].id = vp9_mem_req_segs[i].id;
- ctx->mmaps[i].sz = vp9_mem_req_segs[i].sz;
- ctx->mmaps[i].align = vp9_mem_req_segs[i].align;
- ctx->mmaps[i].flags = vp9_mem_req_segs[i].flags;
-
- if (!ctx->mmaps[i].sz)
- ctx->mmaps[i].sz = vp9_mem_req_segs[i].calc_sz(&cfg,
- ctx->base.init_flags);
-
- res = vpx_mmap_alloc(&ctx->mmaps[i]);
- }
-
- if (!res)
- vp9_finalize_mmaps(ctx);
-
- ctx->defer_alloc = 0;
- }
-
/* Initialize the decoder instance on the first frame*/
if (!res && !ctx->decoder_init) {
- res = vpx_validate_mmaps(&ctx->si, ctx->mmaps,
- vp9_mem_req_segs, NELEMENTS(vp9_mem_req_segs),
- ctx->base.init_flags);
-
- if (!res) {
- VP9D_CONFIG oxcf;
- struct VP9Decompressor *optr;
-
- vp9_initialize_dec();
-
- oxcf.width = ctx->si.w;
- oxcf.height = ctx->si.h;
- oxcf.version = 9;
- oxcf.max_threads = ctx->cfg.threads;
- oxcf.inv_tile_order = ctx->invert_tile_order;
- optr = vp9_create_decompressor(&oxcf);
-
- // If postprocessing was enabled by the application and a
- // configuration has not been provided, default it.
- if (!ctx->postproc_cfg_set &&
- (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
- ctx->postproc_cfg.post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
- ctx->postproc_cfg.deblocking_level = 4;
- ctx->postproc_cfg.noise_level = 0;
- }
-
- if (!optr) {
- res = VPX_CODEC_ERROR;
- } else {
- VP9D_COMP *const pbi = (VP9D_COMP*)optr;
- VP9_COMMON *const cm = &pbi->common;
+ VP9D_CONFIG oxcf;
+ struct VP9Decompressor *optr;
+
+ vp9_initialize_dec();
+
+ oxcf.width = ctx->si.w;
+ oxcf.height = ctx->si.h;
+ oxcf.version = 9;
+ oxcf.max_threads = ctx->cfg.threads;
+ oxcf.inv_tile_order = ctx->invert_tile_order;
+ optr = vp9_create_decompressor(&oxcf);
+
+ // If postprocessing was enabled by the application and a
+ // configuration has not been provided, default it.
+ if (!ctx->postproc_cfg_set &&
+ (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
+ ctx->postproc_cfg.post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
+ ctx->postproc_cfg.deblocking_level = 4;
+ ctx->postproc_cfg.noise_level = 0;
+ }
- // Set index to not initialized.
- cm->new_fb_idx = -1;
+ if (!optr) {
+ res = VPX_CODEC_ERROR;
+ } else {
+ VP9D_COMP *const pbi = (VP9D_COMP*)optr;
+ VP9_COMMON *const cm = &pbi->common;
- if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
- cm->get_fb_cb = ctx->get_ext_fb_cb;
- cm->release_fb_cb = ctx->release_ext_fb_cb;
- cm->cb_priv = ctx->ext_priv;
- } else {
- cm->get_fb_cb = vp9_get_frame_buffer;
- cm->release_fb_cb = vp9_release_frame_buffer;
+ // Set index to not initialized.
+ cm->new_fb_idx = -1;
- if (vp9_alloc_internal_frame_buffers(&cm->int_frame_buffers))
- vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to initialize internal frame buffers");
- cm->cb_priv = &cm->int_frame_buffers;
- }
+ if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
+ cm->get_fb_cb = ctx->get_ext_fb_cb;
+ cm->release_fb_cb = ctx->release_ext_fb_cb;
+ cm->cb_priv = ctx->ext_priv;
+ } else {
+ cm->get_fb_cb = vp9_get_frame_buffer;
+ cm->release_fb_cb = vp9_release_frame_buffer;
- ctx->pbi = optr;
+ if (vp9_alloc_internal_frame_buffers(&cm->int_frame_buffers))
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to initialize internal frame buffers");
+ cm->cb_priv = &cm->int_frame_buffers;
}
+
+ ctx->pbi = optr;
}
ctx->decoder_init = 1;
@@ -496,75 +402,6 @@ static vpx_codec_err_t vp9_set_fb_fn(
return VPX_CODEC_ERROR;
}
-static vpx_codec_err_t vp9_xma_get_mmap(const vpx_codec_ctx_t *ctx,
- vpx_codec_mmap_t *mmap,
- vpx_codec_iter_t *iter) {
- vpx_codec_err_t res;
- const mem_req_t *seg_iter = (const mem_req_t *)*iter;
-
- /* Get address of next segment request */
- do {
- if (!seg_iter)
- seg_iter = vp9_mem_req_segs;
- else if (seg_iter->id != VP9_SEG_MAX)
- seg_iter++;
-
- *iter = (vpx_codec_iter_t)seg_iter;
-
- if (seg_iter->id != VP9_SEG_MAX) {
- mmap->id = seg_iter->id;
- mmap->sz = seg_iter->sz;
- mmap->align = seg_iter->align;
- mmap->flags = seg_iter->flags;
-
- if (!seg_iter->sz)
- mmap->sz = seg_iter->calc_sz(ctx->config.dec, ctx->init_flags);
-
- res = VPX_CODEC_OK;
- } else {
- res = VPX_CODEC_LIST_END;
- }
- } while (!mmap->sz && res != VPX_CODEC_LIST_END);
-
- return res;
-}
-
-static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx,
- const vpx_codec_mmap_t *mmap) {
- vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
- int i, done;
-
- if (!ctx->priv) {
- if (mmap->id == VP9_SEG_ALG_PRIV) {
- if (!ctx->priv) {
- vp9_init_ctx(ctx, mmap);
- res = VPX_CODEC_OK;
- }
- }
- }
-
- done = 1;
-
- if (!res && ctx->priv->alg_priv) {
- for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) {
- if (ctx->priv->alg_priv->mmaps[i].id == mmap->id)
- if (!ctx->priv->alg_priv->mmaps[i].base) {
- ctx->priv->alg_priv->mmaps[i] = *mmap;
- res = VPX_CODEC_OK;
- }
-
- done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
- }
- }
-
- if (done && !res) {
- vp9_finalize_mmaps(ctx->priv->alg_priv);
- res = ctx->iface->init(ctx, NULL);
- }
-
- return res;
-}
-
static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
va_list args) {
vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
@@ -735,8 +572,8 @@ CODEC_INTERFACE(vpx_codec_vp9_dx) = {
vp9_init, /* vpx_codec_init_fn_t init; */
vp9_destroy, /* vpx_codec_destroy_fn_t destroy; */
ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */
- vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t get_mmap; */
- vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t set_mmap; */
+ NOT_IMPLEMENTED, /* vpx_codec_get_mmap_fn_t get_mmap; */
+ NOT_IMPLEMENTED, /* vpx_codec_set_mmap_fn_t set_mmap; */
{ // NOLINT
vp9_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */
vp9_get_si, /* vpx_codec_get_si_fn_t get_si; */
diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h
index 0b637d42f..8944a2664 100644
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -192,6 +192,7 @@ enum vp8e_enc_control_id {
VP9E_SET_TILE_ROWS,
VP9E_SET_FRAME_PARALLEL_DECODING,
VP9E_SET_AQ_MODE,
+ VP9E_SET_FRAME_PERIODIC_BOOST,
VP9E_SET_SVC,
VP9E_SET_SVC_PARAMETERS,
@@ -364,6 +365,8 @@ VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PARALLEL_DECODING, unsigned int)
VPX_CTRL_USE_TYPE(VP9E_SET_AQ_MODE, unsigned int)
+VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PERIODIC_BOOST, unsigned int)
+
/*! @} - end defgroup vp8_encoder */
#ifdef __cplusplus
} // extern "C"
diff --git a/vpxenc.c b/vpxenc.c
index f1c9c9a7b..c4d77f145 100644
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -123,6 +123,55 @@ int fourcc_is_ivf(const char detect[4]) {
return 0;
}
+#if CONFIG_WEBM_IO
+/* Murmur hash derived from public domain reference implementation at
+ * http:// sites.google.com/site/murmurhash/
+ */
+static unsigned int murmur(const void *key, int len, unsigned int seed) {
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ unsigned int h = seed ^ len;
+
+ const unsigned char *data = (const unsigned char *)key;
+
+ while (len >= 4) {
+ unsigned int k;
+
+ k = (unsigned int)data[0];
+ k |= (unsigned int)data[1] << 8;
+ k |= (unsigned int)data[2] << 16;
+ k |= (unsigned int)data[3] << 24;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ switch (len) {
+ case 3:
+ h ^= data[2] << 16;
+ case 2:
+ h ^= data[1] << 8;
+ case 1:
+ h ^= data[0];
+ h *= m;
+ };
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+#endif // CONFIG_WEBM_IO
+
static const arg_def_t debugmode = ARG_DEF("D", "debug", 0,
"Debug mode (makes output deterministic)");
static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
@@ -351,13 +400,17 @@ static const arg_def_t frame_parallel_decoding = ARG_DEF(
NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
static const arg_def_t aq_mode = ARG_DEF(
NULL, "aq-mode", 1,
- "Adaptive q mode (0: off (by default), 1: variance 2: complexity)");
+ "Adaptive q mode (0: off (by default), 1: variance 2: complexity, "
+ "3: cyclic refresh)");
+static const arg_def_t frame_periodic_boost = ARG_DEF(
+ NULL, "frame_boost", 1,
+ "Enable frame periodic boost (0: off (by default), 1: on)");
static const arg_def_t *vp9_args[] = {
&cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh,
&tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type,
&tune_ssim, &cq_level, &max_intra_rate_pct, &lossless,
- &frame_parallel_decoding, &aq_mode,
+ &frame_parallel_decoding, &aq_mode, &frame_periodic_boost,
NULL
};
static const int vp9_arg_ctrl_map[] = {
@@ -367,6 +420,7 @@ static const int vp9_arg_ctrl_map[] = {
VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
VP9E_SET_LOSSLESS, VP9E_SET_FRAME_PARALLEL_DECODING, VP9E_SET_AQ_MODE,
+ VP9E_SET_FRAME_PERIODIC_BOOST,
0
};
#endif
@@ -565,6 +619,7 @@ struct stream_state {
FILE *file;
struct rate_hist *rate_hist;
struct EbmlGlobal ebml;
+ uint32_t hash;
uint64_t psnr_sse_total;
uint64_t psnr_samples_total;
double psnr_totals[4];
@@ -786,9 +841,7 @@ static struct stream_state *new_stream(struct VpxEncoderConfig *global,
stream->config.stereo_fmt = STEREO_FORMAT_MONO;
stream->config.write_webm = 1;
#if CONFIG_WEBM_IO
- stream->ebml.last_pts_ns = -1;
- stream->ebml.writer = NULL;
- stream->ebml.segment = NULL;
+ stream->ebml.last_pts_ms = -1;
#endif
/* Allows removal of the application version from the EBML tags */
@@ -1123,7 +1176,9 @@ static void close_output_file(struct stream_state *stream,
#if CONFIG_WEBM_IO
if (stream->config.write_webm) {
- write_webm_file_footer(&stream->ebml);
+ write_webm_file_footer(&stream->ebml, stream->hash);
+ free(stream->ebml.cue_list);
+ stream->ebml.cue_list = NULL;
}
#endif
@@ -1279,6 +1334,12 @@ static void get_cx_data(struct stream_state *stream,
update_rate_histogram(stream->rate_hist, cfg, pkt);
#if CONFIG_WEBM_IO
if (stream->config.write_webm) {
+ /* Update the hash */
+ if (!stream->ebml.debug)
+ stream->hash = murmur(pkt->data.frame.buf,
+ (int)pkt->data.frame.sz,
+ stream->hash);
+
write_webm_block(&stream->ebml, cfg, pkt);
}
#endif
diff --git a/webmenc.c b/webmenc.c
new file mode 100644
index 000000000..17bbeec78
--- /dev/null
+++ b/webmenc.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2013 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 "webmenc.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include "third_party/libmkv/EbmlWriter.h"
+#include "third_party/libmkv/EbmlIDs.h"
+
+void Ebml_Write(struct EbmlGlobal *glob,
+ const void *buffer_in,
+ unsigned long len) {
+ (void) fwrite(buffer_in, 1, len, glob->stream);
+}
+
+#define WRITE_BUFFER(s) \
+for (i = len - 1; i >= 0; i--) { \
+ x = (char)(*(const s *)buffer_in >> (i * CHAR_BIT)); \
+ Ebml_Write(glob, &x, 1); \
+}
+
+void Ebml_Serialize(struct EbmlGlobal *glob,
+ const void *buffer_in,
+ int buffer_size,
+ unsigned long len) {
+ char x;
+ int i;
+
+ /* buffer_size:
+ * 1 - int8_t;
+ * 2 - int16_t;
+ * 3 - int32_t;
+ * 4 - int64_t;
+ */
+ switch (buffer_size) {
+ case 1:
+ WRITE_BUFFER(int8_t)
+ break;
+ case 2:
+ WRITE_BUFFER(int16_t)
+ break;
+ case 4:
+ WRITE_BUFFER(int32_t)
+ break;
+ case 8:
+ WRITE_BUFFER(int64_t)
+ break;
+ default:
+ break;
+ }
+}
+#undef WRITE_BUFFER
+
+/* Need a fixed size serializer for the track ID. libmkv provides a 64 bit
+ * one, but not a 32 bit one.
+ */
+static void Ebml_SerializeUnsigned32(struct EbmlGlobal *glob,
+ unsigned int class_id,
+ uint64_t ui) {
+ const unsigned char sizeSerialized = 4 | 0x80;
+ Ebml_WriteID(glob, class_id);
+ Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
+ Ebml_Serialize(glob, &ui, sizeof(ui), 4);
+}
+
+static void Ebml_StartSubElement(struct EbmlGlobal *glob,
+ EbmlLoc *ebmlLoc,
+ unsigned int class_id) {
+ const uint64_t kEbmlUnknownLength = LITERALU64(0x01FFFFFF, 0xFFFFFFFF);
+ Ebml_WriteID(glob, class_id);
+ *ebmlLoc = ftello(glob->stream);
+ Ebml_Serialize(glob, &kEbmlUnknownLength, sizeof(kEbmlUnknownLength), 8);
+}
+
+static void Ebml_EndSubElement(struct EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
+ off_t pos;
+ uint64_t size;
+
+ /* Save the current stream pointer. */
+ pos = ftello(glob->stream);
+
+ /* Calculate the size of this element. */
+ size = pos - *ebmlLoc - 8;
+ size |= LITERALU64(0x01000000, 0x00000000);
+
+ /* Seek back to the beginning of the element and write the new size. */
+ fseeko(glob->stream, *ebmlLoc, SEEK_SET);
+ Ebml_Serialize(glob, &size, sizeof(size), 8);
+
+ /* Reset the stream pointer. */
+ fseeko(glob->stream, pos, SEEK_SET);
+}
+
+void write_webm_seek_element(struct EbmlGlobal *ebml,
+ unsigned int id,
+ off_t pos) {
+ uint64_t offset = pos - ebml->position_reference;
+ EbmlLoc start;
+ Ebml_StartSubElement(ebml, &start, Seek);
+ Ebml_SerializeBinary(ebml, SeekID, id);
+ Ebml_SerializeUnsigned64(ebml, SeekPosition, offset);
+ Ebml_EndSubElement(ebml, &start);
+}
+
+void write_webm_seek_info(struct EbmlGlobal *ebml) {
+ off_t pos;
+ EbmlLoc start;
+ EbmlLoc startInfo;
+ uint64_t frame_time;
+ char version_string[64];
+
+ /* Save the current stream pointer. */
+ pos = ftello(ebml->stream);
+
+ if (ebml->seek_info_pos)
+ fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET);
+ else
+ ebml->seek_info_pos = pos;
+
+ Ebml_StartSubElement(ebml, &start, SeekHead);
+ write_webm_seek_element(ebml, Tracks, ebml->track_pos);
+ write_webm_seek_element(ebml, Cues, ebml->cue_pos);
+ write_webm_seek_element(ebml, Info, ebml->segment_info_pos);
+ Ebml_EndSubElement(ebml, &start);
+
+ /* Create and write the Segment Info. */
+ if (ebml->debug) {
+ strcpy(version_string, "vpxenc");
+ } else {
+ strcpy(version_string, "vpxenc ");
+ strncat(version_string,
+ vpx_codec_version_str(),
+ sizeof(version_string) - 1 - strlen(version_string));
+ }
+
+ frame_time = (uint64_t)1000 * ebml->framerate.den
+ / ebml->framerate.num;
+ ebml->segment_info_pos = ftello(ebml->stream);
+ Ebml_StartSubElement(ebml, &startInfo, Info);
+ Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000);
+ Ebml_SerializeFloat(ebml, Segment_Duration,
+ (double)(ebml->last_pts_ms + frame_time));
+ Ebml_SerializeString(ebml, 0x4D80, version_string);
+ Ebml_SerializeString(ebml, 0x5741, version_string);
+ Ebml_EndSubElement(ebml, &startInfo);
+}
+
+void write_webm_file_header(struct EbmlGlobal *glob,
+ const vpx_codec_enc_cfg_t *cfg,
+ const struct vpx_rational *fps,
+ stereo_format_t stereo_fmt,
+ unsigned int fourcc) {
+ EbmlLoc start;
+ EbmlLoc trackStart;
+ EbmlLoc videoStart;
+ unsigned int trackNumber = 1;
+ uint64_t trackID = 0;
+ unsigned int pixelWidth = cfg->g_w;
+ unsigned int pixelHeight = cfg->g_h;
+
+ /* Write the EBML header. */
+ Ebml_StartSubElement(glob, &start, EBML);
+ Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
+ Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1);
+ Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4);
+ Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8);
+ Ebml_SerializeString(glob, DocType, "webm");
+ Ebml_SerializeUnsigned(glob, DocTypeVersion, 2);
+ Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2);
+ Ebml_EndSubElement(glob, &start);
+
+ /* Open and begin writing the segment element. */
+ Ebml_StartSubElement(glob, &glob->startSegment, Segment);
+ glob->position_reference = ftello(glob->stream);
+ glob->framerate = *fps;
+ write_webm_seek_info(glob);
+
+ /* Open and write the Tracks element. */
+ glob->track_pos = ftello(glob->stream);
+ Ebml_StartSubElement(glob, &trackStart, Tracks);
+
+ /* Open and write the Track entry. */
+ Ebml_StartSubElement(glob, &start, TrackEntry);
+ Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
+ glob->track_id_pos = ftello(glob->stream);
+ Ebml_SerializeUnsigned32(glob, TrackUID, trackID);
+ Ebml_SerializeUnsigned(glob, TrackType, 1);
+ Ebml_SerializeString(glob, CodecID,
+ fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9");
+ Ebml_StartSubElement(glob, &videoStart, Video);
+ Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
+ Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
+ Ebml_SerializeUnsigned(glob, StereoMode, stereo_fmt);
+ Ebml_EndSubElement(glob, &videoStart);
+
+ /* Close Track entry. */
+ Ebml_EndSubElement(glob, &start);
+
+ /* Close Tracks element. */
+ Ebml_EndSubElement(glob, &trackStart);
+
+ /* Segment element remains open. */
+}
+
+void write_webm_block(struct EbmlGlobal *glob,
+ const vpx_codec_enc_cfg_t *cfg,
+ const vpx_codec_cx_pkt_t *pkt) {
+ unsigned int block_length;
+ unsigned char track_number;
+ uint16_t block_timecode = 0;
+ unsigned char flags;
+ int64_t pts_ms;
+ int start_cluster = 0, is_keyframe;
+
+ /* Calculate the PTS of this frame in milliseconds. */
+ pts_ms = pkt->data.frame.pts * 1000
+ * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den;
+
+ if (pts_ms <= glob->last_pts_ms)
+ pts_ms = glob->last_pts_ms + 1;
+
+ glob->last_pts_ms = pts_ms;
+
+ /* Calculate the relative time of this block. */
+ if (pts_ms - glob->cluster_timecode > SHRT_MAX)
+ start_cluster = 1;
+ else
+ block_timecode = (uint16_t)pts_ms - glob->cluster_timecode;
+
+ is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY);
+ if (start_cluster || is_keyframe) {
+ if (glob->cluster_open)
+ Ebml_EndSubElement(glob, &glob->startCluster);
+
+ /* Open the new cluster. */
+ block_timecode = 0;
+ glob->cluster_open = 1;
+ glob->cluster_timecode = (uint32_t)pts_ms;
+ glob->cluster_pos = ftello(glob->stream);
+ Ebml_StartSubElement(glob, &glob->startCluster, Cluster);
+ Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode);
+
+ /* Save a cue point if this is a keyframe. */
+ if (is_keyframe) {
+ struct cue_entry *cue, *new_cue_list;
+
+ new_cue_list = realloc(glob->cue_list,
+ (glob->cues + 1) * sizeof(struct cue_entry));
+ if (new_cue_list)
+ glob->cue_list = new_cue_list;
+ else
+ fatal("Failed to realloc cue list.");
+
+ cue = &glob->cue_list[glob->cues];
+ cue->time = glob->cluster_timecode;
+ cue->loc = glob->cluster_pos;
+ glob->cues++;
+ }
+ }
+
+ /* Write the Simple Block. */
+ Ebml_WriteID(glob, SimpleBlock);
+
+ block_length = (unsigned int)pkt->data.frame.sz + 4;
+ block_length |= 0x10000000;
+ Ebml_Serialize(glob, &block_length, sizeof(block_length), 4);
+
+ track_number = 1;
+ track_number |= 0x80;
+ Ebml_Write(glob, &track_number, 1);
+
+ Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2);
+
+ flags = 0;
+ if (is_keyframe)
+ flags |= 0x80;
+ if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
+ flags |= 0x08;
+ Ebml_Write(glob, &flags, 1);
+
+ Ebml_Write(glob, pkt->data.frame.buf, (unsigned int)pkt->data.frame.sz);
+}
+
+void write_webm_file_footer(struct EbmlGlobal *glob, int hash) {
+ EbmlLoc start_cues;
+ EbmlLoc start_cue_point;
+ EbmlLoc start_cue_tracks;
+ unsigned int i;
+
+ if (glob->cluster_open)
+ Ebml_EndSubElement(glob, &glob->startCluster);
+
+ glob->cue_pos = ftello(glob->stream);
+ Ebml_StartSubElement(glob, &start_cues, Cues);
+
+ for (i = 0; i < glob->cues; i++) {
+ struct cue_entry *cue = &glob->cue_list[i];
+ Ebml_StartSubElement(glob, &start_cue_point, CuePoint);
+ Ebml_SerializeUnsigned(glob, CueTime, cue->time);
+
+ Ebml_StartSubElement(glob, &start_cue_tracks, CueTrackPositions);
+ Ebml_SerializeUnsigned(glob, CueTrack, 1);
+ Ebml_SerializeUnsigned64(glob, CueClusterPosition,
+ cue->loc - glob->position_reference);
+ Ebml_EndSubElement(glob, &start_cue_tracks);
+
+ Ebml_EndSubElement(glob, &start_cue_point);
+ }
+
+ Ebml_EndSubElement(glob, &start_cues);
+
+ /* Close the Segment. */
+ Ebml_EndSubElement(glob, &glob->startSegment);
+
+ /* Patch up the seek info block. */
+ write_webm_seek_info(glob);
+
+ /* Patch up the track id. */
+ fseeko(glob->stream, glob->track_id_pos, SEEK_SET);
+ Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash);
+
+ fseeko(glob->stream, 0, SEEK_END);
+}
diff --git a/webmenc.cc b/webmenc.cc
deleted file mode 100644
index 6a3374d02..000000000
--- a/webmenc.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2014 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 "./webmenc.h"
-
-#include <string>
-
-#include "third_party/libwebm/mkvmuxer.hpp"
-#include "third_party/libwebm/mkvmuxerutil.hpp"
-#include "third_party/libwebm/mkvwriter.hpp"
-
-namespace {
-const uint64_t kDebugTrackUid = 0xDEADBEEF;
-const int kVideoTrackNumber = 1;
-} // namespace
-
-void write_webm_file_header(struct EbmlGlobal *glob,
- const vpx_codec_enc_cfg_t *cfg,
- const struct vpx_rational *fps,
- stereo_format_t stereo_fmt,
- unsigned int fourcc) {
- mkvmuxer::MkvWriter *const writer = new mkvmuxer::MkvWriter(glob->stream);
- mkvmuxer::Segment *const segment = new mkvmuxer::Segment();
- segment->Init(writer);
- segment->set_mode(mkvmuxer::Segment::kFile);
- segment->OutputCues(true);
-
- mkvmuxer::SegmentInfo *const info = segment->GetSegmentInfo();
- const uint64_t kTimecodeScale = 1000000;
- info->set_timecode_scale(kTimecodeScale);
- std::string version = "vpxenc";
- if (!glob->debug) {
- version.append(std::string(" ") + vpx_codec_version_str());
- }
- info->set_writing_app(version.c_str());
-
- const int video_track_id = segment->AddVideoTrack(static_cast<int>(cfg->g_w),
- static_cast<int>(cfg->g_h),
- kVideoTrackNumber);
- mkvmuxer::VideoTrack* const video_track =
- static_cast<mkvmuxer::VideoTrack*>(
- segment->GetTrackByNumber(video_track_id));
- video_track->SetStereoMode(stereo_fmt);
- video_track->set_codec_id(fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9");
- if (glob->debug) {
- video_track->set_uid(kDebugTrackUid);
- }
- glob->writer = writer;
- glob->segment = segment;
-}
-
-void write_webm_block(struct EbmlGlobal *glob,
- const vpx_codec_enc_cfg_t *cfg,
- const vpx_codec_cx_pkt_t *pkt) {
- mkvmuxer::Segment *const segment =
- reinterpret_cast<mkvmuxer::Segment*>(glob->segment);
- int64_t pts_ns = pkt->data.frame.pts * 1000000000ll *
- cfg->g_timebase.num / cfg->g_timebase.den;
- if (pts_ns <= glob->last_pts_ns)
- pts_ns = glob->last_pts_ns + 1000000;
- glob->last_pts_ns = pts_ns;
-
- segment->AddFrame(static_cast<uint8_t*>(pkt->data.frame.buf),
- pkt->data.frame.sz,
- kVideoTrackNumber,
- pts_ns,
- pkt->data.frame.flags & VPX_FRAME_IS_KEY);
-}
-
-void write_webm_file_footer(struct EbmlGlobal *glob) {
- mkvmuxer::MkvWriter *const writer =
- reinterpret_cast<mkvmuxer::MkvWriter*>(glob->writer);
- mkvmuxer::Segment *const segment =
- reinterpret_cast<mkvmuxer::Segment*>(glob->segment);
- segment->Finalize();
- delete segment;
- delete writer;
- glob->writer = NULL;
- glob->segment = NULL;
-}
diff --git a/webmenc.h b/webmenc.h
index 0ac606be4..362aa895f 100644
--- a/webmenc.h
+++ b/webmenc.h
@@ -13,6 +13,13 @@
#include <stdio.h>
#include <stdlib.h>
+#if defined(_MSC_VER)
+/* MSVS doesn't define off_t */
+typedef __int64 off_t;
+#else
+#include <stdint.h>
+#endif
+
#include "tools_common.h"
#include "vpx/vpx_encoder.h"
@@ -20,13 +27,40 @@
extern "C" {
#endif
-/* TODO(vigneshv): Rename this struct */
+typedef off_t EbmlLoc;
+
+struct cue_entry {
+ unsigned int time;
+ uint64_t loc;
+};
+
struct EbmlGlobal {
int debug;
+
FILE *stream;
- int64_t last_pts_ns;
- void *writer;
- void *segment;
+ int64_t last_pts_ms;
+ vpx_rational_t framerate;
+
+ /* These pointers are to the start of an element */
+ off_t position_reference;
+ off_t seek_info_pos;
+ off_t segment_info_pos;
+ off_t track_pos;
+ off_t cue_pos;
+ off_t cluster_pos;
+
+ /* This pointer is to a specific element to be serialized */
+ off_t track_id_pos;
+
+ /* These pointers are to the size field of the element */
+ EbmlLoc startSegment;
+ EbmlLoc startCluster;
+
+ uint32_t cluster_timecode;
+ int cluster_open;
+
+ struct cue_entry *cue_list;
+ unsigned int cues;
};
/* Stereo 3D packed frame format */
@@ -38,6 +72,10 @@ typedef enum stereo_format {
STEREO_FORMAT_RIGHT_LEFT = 11
} stereo_format_t;
+void write_webm_seek_element(struct EbmlGlobal *ebml,
+ unsigned int id,
+ off_t pos);
+
void write_webm_file_header(struct EbmlGlobal *glob,
const vpx_codec_enc_cfg_t *cfg,
const struct vpx_rational *fps,
@@ -48,7 +86,7 @@ void write_webm_block(struct EbmlGlobal *glob,
const vpx_codec_enc_cfg_t *cfg,
const vpx_codec_cx_pkt_t *pkt);
-void write_webm_file_footer(struct EbmlGlobal *glob);
+void write_webm_file_footer(struct EbmlGlobal *glob, int hash);
#ifdef __cplusplus
} // extern "C"