summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore10
-rwxr-xr-xbuild/make/ads2gas.pl2
-rwxr-xr-xbuild/make/ads2gas_apple.pl14
-rwxr-xr-xbuild/make/configure.sh2
-rwxr-xr-xbuild/make/gen_msvs_proj.sh6
-rw-r--r--examples.mk95
-rw-r--r--examples/decode_to_md5.c40
-rw-r--r--examples/decode_with_drops.c56
-rw-r--r--examples/postproc.c44
-rw-r--r--examples/simple_decoder.c44
-rw-r--r--examples/simple_encoder.c272
-rw-r--r--examples/twopass_encoder.c336
-rw-r--r--examples/vp8_set_maps.c4
-rw-r--r--examples/vpx_temporal_scalable_patterns.c551
-rw-r--r--ivfdec.c65
-rw-r--r--ivfdec.h28
-rw-r--r--libs.mk8
-rw-r--r--test/datarate_test.cc209
-rw-r--r--test/dct16x16_test.cc18
-rw-r--r--test/encode_test_driver.h5
-rw-r--r--test/fdct4x4_test.cc18
-rw-r--r--test/fdct8x8_test.cc18
-rw-r--r--third_party/libmkv/Makefile18
-rw-r--r--third_party/libmkv/WebMElement.c23
-rw-r--r--third_party/libmkv/WebMElement.h22
-rw-r--r--tools/diff.py3
-rw-r--r--tools_common.c22
-rw-r--r--tools_common.h4
-rw-r--r--video_common.h23
-rw-r--r--video_reader.c81
-rw-r--r--video_reader.h52
-rw-r--r--video_writer.c80
-rw-r--r--video_writer.h47
-rw-r--r--vp8/encoder/firstpass.c10
-rw-r--r--vp8/vp8_cx_iface.c5
-rw-r--r--vp8_scalable_patterns.c694
-rw-r--r--vp9/common/arm/neon/vp9_reconintra_neon.asm16
-rw-r--r--vp9/common/mips/dspr2/vp9_common_dspr2.h4
-rw-r--r--vp9/common/mips/dspr2/vp9_itrans16_dspr2.c34
-rw-r--r--vp9/common/mips/dspr2/vp9_itrans32_cols_dspr2.c4
-rw-r--r--vp9/common/mips/dspr2/vp9_itrans32_dspr2.c12
-rw-r--r--vp9/common/mips/dspr2/vp9_itrans4_dspr2.c26
-rw-r--r--vp9/common/mips/dspr2/vp9_itrans8_dspr2.c34
-rw-r--r--vp9/common/vp9_alloccommon.c12
-rw-r--r--vp9/common/vp9_blockd.h2
-rw-r--r--vp9/common/vp9_convolve.c2
-rw-r--r--vp9/common/vp9_entropy.h10
-rw-r--r--vp9/common/vp9_entropymode.c2
-rw-r--r--vp9/common/vp9_entropymv.c4
-rw-r--r--vp9/common/vp9_frame_buffers.c84
-rw-r--r--vp9/common/vp9_frame_buffers.h53
-rw-r--r--vp9/common/vp9_mv.h4
-rw-r--r--vp9/common/vp9_mvref_common.h2
-rw-r--r--vp9/common/vp9_onyx.h8
-rw-r--r--vp9/common/vp9_onyxc_int.h26
-rw-r--r--vp9/common/vp9_pred_common.c62
-rw-r--r--vp9/common/vp9_pred_common.h13
-rw-r--r--vp9/common/vp9_prob.c31
-rw-r--r--vp9/common/vp9_prob.h33
-rw-r--r--vp9/common/vp9_quant_common.c3
-rw-r--r--vp9/common/vp9_quant_common.h3
-rw-r--r--vp9/common/vp9_reconinter.c25
-rw-r--r--vp9/common/vp9_reconinter.h14
-rw-r--r--vp9/common/vp9_rtcd_defs.sh12
-rw-r--r--vp9/common/vp9_scale.h4
-rw-r--r--vp9/common/vp9_systemdependent.h21
-rw-r--r--vp9/common/x86/vp9_asm_stubs.c103
-rw-r--r--vp9/common/x86/vp9_subpixel_bilinear_ssse3.asm422
-rw-r--r--vp9/decoder/vp9_decodeframe.c13
-rw-r--r--vp9/decoder/vp9_dthread.c29
-rw-r--r--vp9/decoder/vp9_onyxd_if.c7
-rw-r--r--vp9/encoder/vp9_bitstream.c5
-rw-r--r--vp9/encoder/vp9_dct.c179
-rw-r--r--vp9/encoder/vp9_dct.h32
-rw-r--r--vp9/encoder/vp9_encodeframe.c299
-rw-r--r--vp9/encoder/vp9_encodemb.c60
-rw-r--r--vp9/encoder/vp9_encodemb.h20
-rw-r--r--vp9/encoder/vp9_firstpass.c305
-rw-r--r--vp9/encoder/vp9_firstpass.h89
-rw-r--r--vp9/encoder/vp9_lookahead.c3
-rw-r--r--vp9/encoder/vp9_mbgraph.h18
-rw-r--r--vp9/encoder/vp9_mcomp.c37
-rw-r--r--vp9/encoder/vp9_onyx_if.c508
-rw-r--r--vp9/encoder/vp9_onyx_int.h160
-rw-r--r--vp9/encoder/vp9_pickmode.c12
-rw-r--r--vp9/encoder/vp9_quantize.c102
-rw-r--r--vp9/encoder/vp9_ratectrl.c850
-rw-r--r--vp9/encoder/vp9_ratectrl.h83
-rw-r--r--vp9/encoder/vp9_rdopt.c81
-rw-r--r--vp9/encoder/vp9_sad.c (renamed from vp9/encoder/vp9_sad_c.c)0
-rw-r--r--vp9/encoder/vp9_temporal_filter.c32
-rw-r--r--vp9/encoder/vp9_variance.c (renamed from vp9/encoder/vp9_variance_c.c)0
-rw-r--r--vp9/encoder/vp9_writer.c5
-rw-r--r--vp9/encoder/vp9_writer.h11
-rw-r--r--vp9/encoder/x86/vp9_dct_avx2.c77
-rw-r--r--vp9/encoder/x86/vp9_dct_sse2.c83
-rw-r--r--vp9/encoder/x86/vp9_quantize_ssse3.asm5
-rw-r--r--vp9/vp9_common.mk5
-rw-r--r--vp9/vp9_cx_iface.c134
-rw-r--r--vp9/vp9_dx_iface.c21
-rw-r--r--vp9/vp9cx.mk7
-rw-r--r--vpx/src/svc_encodeframe.c23
-rw-r--r--vpx/src/vpx_encoder.c4
-rw-r--r--vpx/vp8cx.h12
-rw-r--r--vpx/vpx_codec.mk2
-rw-r--r--vpx/vpx_encoder.h39
-rw-r--r--vpx/vpx_frame_buffer.h74
-rw-r--r--vpx/vpx_integer.h2
-rw-r--r--vpx_scale/generic/yv12config.c49
-rw-r--r--vpx_scale/yv12config.h13
-rw-r--r--vpxdec.c4
-rw-r--r--vpxenc.c13
-rw-r--r--warnings.c7
113 files changed, 4368 insertions, 3160 deletions
diff --git a/.gitignore b/.gitignore
index a93b6a0f9..dfeae9971 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,18 +19,14 @@
/config.log
/config.mk
/decode_to_md5
-/decode_to_md5.c
/decode_to_md5.dox
/decode_with_drops
-/decode_with_drops.c
/decode_with_drops.dox
/docs/
/doxyfile
/error_resilient
-/error_resilient.c
/error_resilient.dox
/force_keyframe
-/force_keyframe.c
/force_keyframe.dox
/ivfdec
/ivfdec.dox
@@ -40,27 +36,21 @@
/libvpx.ver
/obj_int_extract
/postproc
-/postproc.c
/postproc.dox
/samples.dox
/simple_decoder
-/simple_decoder.c
/simple_decoder.dox
/simple_encoder
-/simple_encoder.c
/simple_encoder.dox
/test_libvpx
/twopass_encoder
-/twopass_encoder.c
/twopass_encoder.dox
/vp8_api1_migration.dox
/vp8_scalable_patterns
/vp8_scalable_patterns.dox
/vp8_set_maps
-/vp8_set_maps.c
/vp8_set_maps.dox
/vp8cx_set_ref
-/vp8cx_set_ref.c
/vp8cx_set_ref.dox
/vpx.pc
/vpx_config.c
diff --git a/build/make/ads2gas.pl b/build/make/ads2gas.pl
index 9c4190129..7272424af 100755
--- a/build/make/ads2gas.pl
+++ b/build/make/ads2gas.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
##
## Copyright (c) 2010 The WebM project authors. All Rights Reserved.
##
diff --git a/build/make/ads2gas_apple.pl b/build/make/ads2gas_apple.pl
index befb3dbe7..a82f3eba8 100755
--- a/build/make/ads2gas_apple.pl
+++ b/build/make/ads2gas_apple.pl
@@ -75,16 +75,16 @@ while (<STDIN>)
s/:SHR:/ >> /g;
# Convert ELSE to .else
- s/ELSE/.else/g;
+ s/\bELSE\b/.else/g;
# Convert ENDIF to .endif
- s/ENDIF/.endif/g;
+ s/\bENDIF\b/.endif/g;
# Convert ELSEIF to .elseif
- s/ELSEIF/.elseif/g;
+ s/\bELSEIF\b/.elseif/g;
# Convert LTORG to .ltorg
- s/LTORG/.ltorg/g;
+ s/\bLTORG\b/.ltorg/g;
# Convert IF :DEF:to .if
# gcc doesn't have the ability to do a conditional
@@ -164,7 +164,7 @@ while (<STDIN>)
s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/;
# ALIGN directive
- s/ALIGN/.balign/g;
+ s/\bALIGN\b/.balign/g;
# Strip ARM
s/\sARM/@ ARM/g;
@@ -184,7 +184,7 @@ while (<STDIN>)
s/(.*)EQU(.*)/.set $1, $2/;
# Begin macro definition
- if (/MACRO/)
+ if (/\bMACRO\b/)
{
# Process next line down, which will be the macro definition
$_ = <STDIN>;
@@ -215,7 +215,7 @@ while (<STDIN>)
# For macros, use \ to reference formal params
# s/\$/\\/g; # End macro definition
- s/MEND/.endm/; # No need to tell it where to stop assembling
+ s/\bMEND\b/.endm/; # No need to tell it where to stop assembling
next if /^\s*END\s*$/;
# Clang used by Chromium differs slightly from clang in XCode in what it
diff --git a/build/make/configure.sh b/build/make/configure.sh
index 8dcb9bbf4..b5151da13 100755
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -337,7 +337,7 @@ check_cxxflags() {
# Catch CFLAGS that trigger CXX warnings
case "$CXX" in
- *g++*) check_cxx -Werror "$@" <<EOF
+ *c++-analyzer|*clang++|*g++*) check_cxx -Werror "$@" <<EOF
int x;
EOF
;;
diff --git a/build/make/gen_msvs_proj.sh b/build/make/gen_msvs_proj.sh
index fc5011bef..7df0334c6 100755
--- a/build/make/gen_msvs_proj.sh
+++ b/build/make/gen_msvs_proj.sh
@@ -155,8 +155,8 @@ generate_filter() {
tag Tool \
Name="VCCustomBuildTool" \
Description="Assembling \$(InputFileName)" \
- CommandLine="$(eval echo \$asm_${cfg}_cmdline) -o \$(IntDir)$objf" \
- Outputs="\$(IntDir)$objf" \
+ CommandLine="$(eval echo \$asm_${cfg}_cmdline) -o \$(IntDir)\\$objf" \
+ Outputs="\$(IntDir)\\$objf" \
close_tag FileConfiguration
done
@@ -170,7 +170,7 @@ generate_filter() {
tag Tool \
Name="VCCLCompilerTool" \
- ObjectFile="\$(IntDir)$objf" \
+ ObjectFile="\$(IntDir)\\$objf" \
close_tag FileConfiguration
done
diff --git a/examples.mk b/examples.mk
index 0b62df96a..24b5c3788 100644
--- a/examples.mk
+++ b/examples.mk
@@ -15,9 +15,8 @@ LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \
third_party/libyuv/source/scale.c \
third_party/libyuv/source/cpu_id.c
-# List of examples to build. UTILS are files that are taken from the source
-# tree directly, and GEN_EXAMPLES are files that are created from the
-# examples folder.
+# List of examples to build. UTILS are tools meant for distribution
+# while EXAMPLES demonstrate specific portions of the API.
UTILS-$(CONFIG_DECODERS) += vpxdec.c
vpxdec.SRCS += md5_utils.c md5_utils.h
vpxdec.SRCS += vpx_ports/vpx_timer.h
@@ -55,9 +54,6 @@ vpxenc.SRCS += third_party/libmkv/EbmlWriter.h
vpxenc.SRCS += $(LIBYUV_SRCS)
vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
vpxenc.DESCRIPTION = Full featured encoder
-UTILS-$(CONFIG_VP8_ENCODER) += vp8_scalable_patterns.c
-vp8_scalable_patterns.GUID = 0D6A210B-F482-4D6F-8570-4A9C01ACC88C
-vp8_scalable_patterns.DESCRIPTION = Temporal Scalability Encoder
UTILS-$(CONFIG_VP9_ENCODER) += vp9_spatial_scalable_encoder.c
vp9_spatial_scalable_encoder.SRCS += args.c args.h
vp9_spatial_scalable_encoder.SRCS += ivfenc.c ivfenc.h
@@ -74,58 +70,80 @@ endif
#example_xma.GUID = A955FC4A-73F1-44F7-135E-30D84D32F022
#example_xma.DESCRIPTION = External Memory Allocation mode usage
-GEN_EXAMPLES-$(CONFIG_VP8_DECODER) += simple_decoder.c
-simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC
+EXAMPLES-$(CONFIG_ENCODERS) += vpx_temporal_scalable_patterns.c
+vpx_temporal_scalable_patterns.SRCS += ivfenc.c ivfenc.h
+vpx_temporal_scalable_patterns.SRCS += tools_common.c tools_common.h
+vpx_temporal_scalable_patterns.SRCS += video_common.h
+vpx_temporal_scalable_patterns.SRCS += video_writer.h video_writer.c
+vpx_temporal_scalable_patterns.GUID = B18C08F2-A439-4502-A78E-849BE3D60947
+vpx_temporal_scalable_patterns.DESCRIPTION = Temporal Scalability Encoder
+EXAMPLES-$(CONFIG_VP8_DECODER) += simple_decoder.c
+simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC
simple_decoder.SRCS += ivfdec.h ivfdec.c
simple_decoder.SRCS += tools_common.h tools_common.c
-simple_decoder.DESCRIPTION = Simplified decoder loop
-GEN_EXAMPLES-$(CONFIG_VP8_DECODER) += postproc.c
+simple_decoder.SRCS += video_common.h
+simple_decoder.SRCS += video_reader.h video_reader.c
+simple_decoder.DESCRIPTION = Simplified decoder loop
+EXAMPLES-$(CONFIG_VP8_DECODER) += postproc.c
postproc.SRCS += ivfdec.h ivfdec.c
postproc.SRCS += tools_common.h tools_common.c
-postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7
-postproc.DESCRIPTION = Decoder postprocessor control
-GEN_EXAMPLES-$(CONFIG_VP8_DECODER) += decode_to_md5.c
+postproc.SRCS += video_common.h
+postproc.SRCS += video_reader.h video_reader.c
+postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7
+postproc.DESCRIPTION = Decoder postprocessor control
+EXAMPLES-$(CONFIG_VP8_DECODER) += decode_to_md5.c
decode_to_md5.SRCS += md5_utils.h md5_utils.c
decode_to_md5.SRCS += ivfdec.h ivfdec.c
decode_to_md5.SRCS += tools_common.h tools_common.c
-decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42
-decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum
-
-GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += simple_encoder.c
+decode_to_md5.SRCS += video_common.h
+decode_to_md5.SRCS += video_reader.h video_reader.c
+decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42
+decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum
+EXAMPLES-$(CONFIG_VP8_ENCODER) += simple_encoder.c
+simple_encoder.SRCS += ivfenc.h ivfenc.c
+simple_encoder.SRCS += tools_common.h tools_common.c
+simple_encoder.SRCS += video_common.h
+simple_encoder.SRCS += video_writer.h video_writer.c
simple_encoder.GUID = 4607D299-8A71-4D2C-9B1D-071899B6FBFD
simple_encoder.DESCRIPTION = Simplified encoder loop
-GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += twopass_encoder.c
+EXAMPLES-$(CONFIG_VP8_ENCODER) += twopass_encoder.c
+twopass_encoder.SRCS += ivfenc.h ivfenc.c
+twopass_encoder.SRCS += tools_common.h tools_common.c
+twopass_encoder.SRCS += video_common.h
+twopass_encoder.SRCS += video_writer.h video_writer.c
twopass_encoder.GUID = 73494FA6-4AF9-4763-8FBB-265C92402FD8
twopass_encoder.DESCRIPTION = Two-pass encoder loop
-GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += force_keyframe.c
+EXAMPLES-$(CONFIG_VP8_ENCODER) += force_keyframe.c
force_keyframe.GUID = 3C67CADF-029F-4C86-81F5-D6D4F51177F0
force_keyframe.DESCRIPTION = Force generation of keyframes
ifeq ($(CONFIG_DECODERS),yes)
-GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += decode_with_drops.c
-decode_with_drops.SRCS += ivfdec.h ivfdec.c
-decode_with_drops.SRCS += tools_common.h tools_common.c
+EXAMPLES-$(CONFIG_VP8_ENCODER) += decode_with_drops.c
+decode_with_drops.SRCS += ivfdec.h ivfdec.c
+decode_with_drops.SRCS += tools_common.h tools_common.c
+decode_with_drops.SRCS += video_common.h
+decode_with_drops.SRCS += video_reader.h video_reader.c
endif
decode_with_drops.GUID = CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26
decode_with_drops.DESCRIPTION = Drops frames while decoding
ifeq ($(CONFIG_VP8_DECODER),yes)
-GEN_EXAMPLES-$(CONFIG_ERROR_CONCEALMENT) += decode_with_partial_drops.c
+EXAMPLES-$(CONFIG_ERROR_CONCEALMENT) += decode_with_partial_drops.c
endif
decode_with_partial_drops.GUID = 61C2D026-5754-46AC-916F-1343ECC5537E
decode_with_partial_drops.DESCRIPTION = Drops parts of frames while decoding
-GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += error_resilient.c
+EXAMPLES-$(CONFIG_VP8_ENCODER) += error_resilient.c
error_resilient.GUID = DF5837B9-4145-4F92-A031-44E4F832E00C
error_resilient.DESCRIPTION = Error Resiliency Feature
-GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8_set_maps.c
+EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8_set_maps.c
vp8_set_maps.GUID = ECB2D24D-98B8-4015-A465-A4AF3DCC145F
vp8_set_maps.DESCRIPTION = VP8 set active and ROI maps
-GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c
+EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c
vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame
ifeq ($(CONFIG_MULTI_RES_ENCODING),yes)
-GEN_EXAMPLES-$(CONFIG_VP8_DECODER) += vp8_multi_resolution_encoder.c
+EXAMPLES-$(CONFIG_VP8_DECODER) += vp8_multi_resolution_encoder.c
vp8_multi_resolution_encoder.SRCS += $(LIBYUV_SRCS)
vp8_multi_resolution_encoder.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de
vp8_multi_resolution_encoder.DESCRIPTION = VP8 Multiple-resolution Encoding
@@ -171,17 +189,17 @@ INTERNAL_LDFLAGS += $(addprefix -L,$(LIB_PATH))
# Expand list of selected examples to build (as specified above)
UTILS = $(call enabled,UTILS)
-GEN_EXAMPLES = $(call enabled,GEN_EXAMPLES)
-ALL_EXAMPLES = $(UTILS) $(GEN_EXAMPLES)
+EXAMPLES = $(addprefix examples/,$(call enabled,EXAMPLES))
+ALL_EXAMPLES = $(UTILS) $(EXAMPLES)
UTIL_SRCS = $(foreach ex,$(UTILS),$($(ex:.c=).SRCS))
-ALL_SRCS = $(foreach ex,$(ALL_EXAMPLES),$($(ex:.c=).SRCS))
+ALL_SRCS = $(foreach ex,$(ALL_EXAMPLES),$($(notdir $(ex:.c=)).SRCS))
CODEC_EXTRA_LIBS=$(sort $(call enabled,CODEC_EXTRA_LIBS))
# Expand all example sources into a variable containing all sources
-# for that example (not just them main one specified in UTILS/GEN_EXAMPLES)
+# for that example (not just them main one specified in UTILS/EXAMPLES)
# and add this file to the list (for MSVS workspace generation)
-$(foreach ex,$(ALL_EXAMPLES),$(eval $(ex:.c=).SRCS += $(ex) examples.mk))
+$(foreach ex,$(ALL_EXAMPLES),$(eval $(notdir $(ex:.c=)).SRCS += $(ex) examples.mk))
# If this is a universal (fat) binary, then all the subarchitectures have
@@ -218,14 +236,6 @@ $(foreach bin,$(BINS-yes),\
)
-# Rules to generate the GEN_EXAMPLES sources
-.PRECIOUS: %.c
-CLEAN-OBJS += $(GEN_EXAMPLES)
-%.c: examples/%.c
- @echo " [EXAMPLE] $@"
- @cp $< $@
-
-
# The following pairs define a mapping of locations in the distribution
# tree to locations in the source/build trees.
INSTALL_MAPS += src/%.c %.c
@@ -263,8 +273,9 @@ $(1): $($(1:.$(VCPROJ_SFX)=).SRCS) vpx.$(VCPROJ_SFX)
--out=$$@ $$(INTERNAL_CFLAGS) $$(CFLAGS) \
$$(INTERNAL_LDFLAGS) $$(LDFLAGS) -l$$(CODEC_LIB) $$^
endef
-PROJECTS-$(CONFIG_MSVS) += $(ALL_EXAMPLES:.c=.$(VCPROJ_SFX))
+ALL_EXAMPLES_BASENAME := $(notdir $(ALL_EXAMPLES))
+PROJECTS-$(CONFIG_MSVS) += $(ALL_EXAMPLES_BASENAME:.c=.$(VCPROJ_SFX))
INSTALL-BINS-$(CONFIG_MSVS) += $(foreach p,$(VS_PLATFORMS),\
- $(addprefix bin/$(p)/,$(ALL_EXAMPLES:.c=.exe)))
+ $(addprefix bin/$(p)/,$(ALL_EXAMPLES_BASENAME:.c=.exe)))
$(foreach proj,$(call enabled,PROJECTS),\
$(eval $(call vcproj_template,$(proj))))
diff --git a/examples/decode_to_md5.c b/examples/decode_to_md5.c
index bba218209..077513cc7 100644
--- a/examples/decode_to_md5.c
+++ b/examples/decode_to_md5.c
@@ -38,9 +38,9 @@
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
-#include "./ivfdec.h"
#include "./md5_utils.h"
#include "./tools_common.h"
+#include "./video_reader.h"
#include "./vpx_config.h"
static void get_image_md5(const vpx_image_t *img, unsigned char digest[16]) {
@@ -79,41 +79,42 @@ void usage_exit() {
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
+ int frame_cnt = 0;
+ FILE *outfile = NULL;
vpx_codec_ctx_t codec;
- vpx_codec_iface_t *iface;
- int flags = 0, frame_cnt = 0;
- vpx_video_t *video;
+ vpx_codec_iface_t *iface = NULL;
+ VpxVideoReader *reader = NULL;
+ const VpxVideoInfo *info = NULL;
exec_name = argv[0];
if (argc != 3)
- die("Invalid number of arguments");
+ die("Invalid number of arguments.");
- if (!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
+ reader = vpx_video_reader_open(argv[1]);
+ if (!reader)
+ die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
- die("Failed to open %s for writing", argv[2]);
+ die("Failed to open %s for writing.", argv[2]);
- video = vpx_video_open_file(infile);
- if (!video)
- die("%s is not an IVF file.", argv[1]);
+ info = vpx_video_reader_get_info(reader);
- iface = get_codec_interface(vpx_video_get_fourcc(video));
+ iface = get_codec_interface(info->codec_fourcc);
if (!iface)
- die("Unknown FOURCC code.");
+ die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(iface));
- if (vpx_codec_dec_init(&codec, iface, NULL, flags))
+ if (vpx_codec_dec_init(&codec, iface, NULL, 0))
die_codec(&codec, "Failed to initialize decoder");
- while (vpx_video_read_frame(video)) {
+ while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
- const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
+ const unsigned char *frame = vpx_video_reader_get_frame(reader,
+ &frame_size);
if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0))
die_codec(&codec, "Failed to decode frame");
@@ -129,11 +130,10 @@ int main(int argc, char **argv) {
printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec");
+ die_codec(&codec, "Failed to destroy codec.");
- vpx_video_close(video);
+ vpx_video_reader_close(reader);
fclose(outfile);
- fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/examples/decode_with_drops.c b/examples/decode_with_drops.c
index 12686dedd..e8fc0766b 100644
--- a/examples/decode_with_drops.c
+++ b/examples/decode_with_drops.c
@@ -56,14 +56,13 @@
#include <stdlib.h>
#include <string.h>
-#include "./ivfdec.h"
-
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
#include "./tools_common.h"
+#include "./video_reader.h"
#include "./vpx_config.h"
static const char *exec_name;
@@ -74,52 +73,55 @@ void usage_exit() {
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
+ int frame_cnt = 0;
+ FILE *outfile = NULL;
vpx_codec_ctx_t codec;
- vpx_codec_iface_t *iface;
- int flags = 0, frame_cnt = 0;
- vpx_video_t *video;
- int n, m, is_range;
- char *nptr;
+ vpx_codec_iface_t *iface = NULL;
+ VpxVideoReader *reader = NULL;
+ const VpxVideoInfo *info = NULL;
+ int n = 0;
+ int m = 0;
+ int is_range = 0;
+ char *nptr = NULL;
exec_name = argv[0];
if (argc != 4)
- die("Invalid number of arguments");
+ die("Invalid number of arguments.");
- if (!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
+ reader = vpx_video_reader_open(argv[1]);
+ if (!reader)
+ die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
- die("Failed to open %s for writing", argv[2]);
+ die("Failed to open %s for writing.", argv[2]);
n = strtol(argv[3], &nptr, 0);
m = strtol(nptr + 1, NULL, 0);
is_range = (*nptr == '-');
if (!n || !m || (*nptr != '-' && *nptr != '/'))
- die("Couldn't parse pattern %s\n", argv[3]);
+ die("Couldn't parse pattern %s.\n", argv[3]);
- video = vpx_video_open_file(infile);
- if (!video)
- die("%s is not a supported input file.", argv[1]);
+ info = vpx_video_reader_get_info(reader);
- iface = get_codec_interface(vpx_video_get_fourcc(video));
+ iface = get_codec_interface(info->codec_fourcc);
if (!iface)
- die("Unknown FOURCC code.");
+ die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(iface));
- if (vpx_codec_dec_init(&codec, iface, NULL, flags))
- die_codec(&codec, "Failed to initialize decoder");
+ if (vpx_codec_dec_init(&codec, iface, NULL, 0))
+ die_codec(&codec, "Failed to initialize decoder.");
- while (vpx_video_read_frame(video)) {
+ while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
int skip;
- const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
+ const unsigned char *frame = vpx_video_reader_get_frame(reader,
+ &frame_size);
if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0))
- die_codec(&codec, "Failed to decode frame");
+ die_codec(&codec, "Failed to decode frame.");
++frame_cnt;
@@ -140,15 +142,13 @@ int main(int argc, char **argv) {
printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec");
+ die_codec(&codec, "Failed to destroy codec.");
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
- vpx_video_get_width(video), vpx_video_get_height(video), argv[2]);
-
- vpx_video_close(video);
+ info->frame_width, info->frame_height, argv[2]);
+ vpx_video_reader_close(reader);
fclose(outfile);
- fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/examples/postproc.c b/examples/postproc.c
index 4ec2d1f1c..7281f1e3d 100644
--- a/examples/postproc.c
+++ b/examples/postproc.c
@@ -43,14 +43,13 @@
#include <stdlib.h>
#include <string.h>
-#include "./ivfdec.h"
-
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
#include "./tools_common.h"
+#include "./video_reader.h"
#include "./vpx_config.h"
static const char *exec_name;
@@ -61,35 +60,34 @@ void usage_exit() {
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
- vpx_codec_ctx_t codec;
- vpx_codec_iface_t *iface;
int frame_cnt = 0;
- vpx_video_t *video;
+ FILE *outfile = NULL;
+ vpx_codec_ctx_t codec;
vpx_codec_err_t res;
+ vpx_codec_iface_t *iface = NULL;
+ VpxVideoReader *reader = NULL;
+ const VpxVideoInfo *info = NULL;
exec_name = argv[0];
if (argc != 3)
- die("Invalid number of arguments");
+ die("Invalid number of arguments.");
- if (!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
+ reader = vpx_video_reader_open(argv[1]);
+ if (!reader)
+ die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
die("Failed to open %s for writing", argv[2]);
- video = vpx_video_open_file(infile);
- if (!video)
- die("%s is not a supported input file.", argv[1]);
+ info = vpx_video_reader_get_info(reader);
- iface = get_codec_interface(vpx_video_get_fourcc(video));
+ iface = get_codec_interface(info->codec_fourcc);
if (!iface)
- die("Unknown FOURCC code.");
+ die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(iface));
-
res = vpx_codec_dec_init(&codec, iface, NULL, VPX_CODEC_USE_POSTPROC);
if (res == VPX_CODEC_INCAPABLE) {
printf("NOTICE: Postproc not supported.\n");
@@ -97,13 +95,14 @@ int main(int argc, char **argv) {
}
if (res)
- die_codec(&codec, "Failed to initialize decoder");
+ die_codec(&codec, "Failed to initialize decoder.");
- while (vpx_video_read_frame(video)) {
+ while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
- const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
+ const unsigned char *frame = vpx_video_reader_get_frame(reader,
+ &frame_size);
++frame_cnt;
@@ -111,12 +110,12 @@ int main(int argc, char **argv) {
vp8_postproc_cfg_t pp = {0, 0, 0};
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
- die_codec(&codec, "Failed to turn off postproc");
+ die_codec(&codec, "Failed to turn off postproc.");
} else if (frame_cnt % 30 == 16) {
vp8_postproc_cfg_t pp = {VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE,
4, 0};
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
- die_codec(&codec, "Failed to turn on postproc");
+ die_codec(&codec, "Failed to turn on postproc.");
};
// Decode the frame with 15ms deadline
@@ -133,11 +132,10 @@ int main(int argc, char **argv) {
die_codec(&codec, "Failed to destroy codec");
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
- vpx_video_get_width(video), vpx_video_get_height(video), argv[2]);
+ info->frame_width, info->frame_height, argv[2]);
- vpx_video_close(video);
+ vpx_video_reader_close(reader);
fclose(outfile);
- fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/examples/simple_decoder.c b/examples/simple_decoder.c
index 23399f44f..4dc930897 100644
--- a/examples/simple_decoder.c
+++ b/examples/simple_decoder.c
@@ -86,8 +86,8 @@
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
-#include "./ivfdec.h"
#include "./tools_common.h"
+#include "./video_reader.h"
#include "./vpx_config.h"
static const char *exec_name;
@@ -98,43 +98,44 @@ void usage_exit() {
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
+ int frame_cnt = 0;
+ FILE *outfile = NULL;
vpx_codec_ctx_t codec;
- vpx_codec_iface_t *iface;
- int flags = 0, frame_cnt = 0;
- vpx_video_t *video;
+ vpx_codec_iface_t *iface = NULL;
+ VpxVideoReader *reader = NULL;
+ const VpxVideoInfo *info = NULL;
exec_name = argv[0];
if (argc != 3)
- die("Invalid number of arguments");
+ die("Invalid number of arguments.");
- if (!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
+ reader = vpx_video_reader_open(argv[1]);
+ if (!reader)
+ die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
- die("Failed to open %s for writing", argv[2]);
+ die("Failed to open %s for writing.", argv[2]);
- video = vpx_video_open_file(infile);
- if (!video)
- die("%s is not an IVF file.", argv[1]);
+ info = vpx_video_reader_get_info(reader);
- iface = get_codec_interface(vpx_video_get_fourcc(video));
+ iface = get_codec_interface(info->codec_fourcc);
if (!iface)
- die("Unknown FOURCC code.");
+ die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(iface));
- if (vpx_codec_dec_init(&codec, iface, NULL, flags))
- die_codec(&codec, "Failed to initialize decoder");
+ if (vpx_codec_dec_init(&codec, iface, NULL, 0))
+ die_codec(&codec, "Failed to initialize decoder.");
- while (vpx_video_read_frame(video)) {
+ while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
- const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
+ const unsigned char *frame = vpx_video_reader_get_frame(reader,
+ &frame_size);
if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0))
- die_codec(&codec, "Failed to decode frame");
+ die_codec(&codec, "Failed to decode frame.");
while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL) {
vpx_img_write(img, outfile);
@@ -147,12 +148,11 @@ int main(int argc, char **argv) {
die_codec(&codec, "Failed to destroy codec");
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
- vpx_video_get_width(video), vpx_video_get_height(video), argv[2]);
+ info->frame_width, info->frame_height, argv[2]);
- vpx_video_close(video);
+ vpx_video_reader_close(reader);
fclose(outfile);
- fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/examples/simple_encoder.c b/examples/simple_encoder.c
index e64a962ae..50760549a 100644
--- a/examples/simple_encoder.c
+++ b/examples/simple_encoder.c
@@ -83,194 +83,114 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <string.h>
+
#define VPX_CODEC_DISABLE_COMPAT 1
-#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
-#define interface (vpx_codec_vp8_cx())
-#define fourcc 0x30385056
-
-#define IVF_FILE_HDR_SZ (32)
-#define IVF_FRAME_HDR_SZ (12)
-
-static void mem_put_le16(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
-}
-
-static void mem_put_le32(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
- mem[2] = val>>16;
- mem[3] = val>>24;
-}
-
-static void die(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- vprintf(fmt, ap);
- if(fmt[strlen(fmt)-1] != '\n')
- printf("\n");
- exit(EXIT_FAILURE);
-}
-
-static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
- const char *detail = vpx_codec_error_detail(ctx);
-
- printf("%s: %s\n", s, vpx_codec_error(ctx));
- if(detail)
- printf(" %s\n",detail);
- exit(EXIT_FAILURE);
-}
-
-static int read_frame(FILE *f, vpx_image_t *img) {
- size_t nbytes, to_read;
- int res = 1;
-
- to_read = img->w*img->h*3/2;
- nbytes = fread(img->planes[0], 1, to_read, f);
- if(nbytes != to_read) {
- res = 0;
- if(nbytes > 0)
- printf("Warning: Read partial frame. Check your width & height!\n");
- }
- return res;
-}
-
-static void write_ivf_file_header(FILE *outfile,
- const vpx_codec_enc_cfg_t *cfg,
- int frame_cnt) {
- char header[32];
-
- if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
- return;
- header[0] = 'D';
- header[1] = 'K';
- header[2] = 'I';
- header[3] = 'F';
- mem_put_le16(header+4, 0); /* version */
- mem_put_le16(header+6, 32); /* headersize */
- mem_put_le32(header+8, fourcc); /* headersize */
- mem_put_le16(header+12, cfg->g_w); /* width */
- mem_put_le16(header+14, cfg->g_h); /* height */
- mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
- mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
- mem_put_le32(header+24, frame_cnt); /* length */
- mem_put_le32(header+28, 0); /* unused */
-
- (void) fwrite(header, 1, 32, outfile);
-}
-
+#include "vpx/vpx_encoder.h"
-static void write_ivf_frame_header(FILE *outfile,
- const vpx_codec_cx_pkt_t *pkt)
-{
- char header[12];
- vpx_codec_pts_t pts;
+#include "./tools_common.h"
+#include "./video_writer.h"
- if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
- return;
+#define interface (vpx_codec_vp8_cx())
- pts = pkt->data.frame.pts;
- mem_put_le32(header, pkt->data.frame.sz);
- mem_put_le32(header+4, pts&0xFFFFFFFF);
- mem_put_le32(header+8, pts >> 32);
+static const char *exec_name;
- (void) fwrite(header, 1, 12, outfile);
+void usage_exit() {
+ fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name);
+ exit(EXIT_FAILURE);
}
int main(int argc, char **argv) {
- FILE *infile, *outfile;
- vpx_codec_ctx_t codec;
- vpx_codec_enc_cfg_t cfg;
- int frame_cnt = 0;
- vpx_image_t raw;
- vpx_codec_err_t res;
- long width;
- long height;
- int frame_avail;
- int got_data;
- int flags = 0;
-
- /* Open files */
- if(argc!=5)
- die("Usage: %s <width> <height> <infile> <outfile>\n", argv[0]);
- width = strtol(argv[1], NULL, 0);
- height = strtol(argv[2], NULL, 0);
- if(width < 16 || width%2 || height <16 || height%2)
- die("Invalid resolution: %ldx%ld", width, height);
- if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1))
- die("Faile to allocate image", width, height);
- if(!(outfile = fopen(argv[4], "wb")))
- die("Failed to open %s for writing", argv[4]);
-
- printf("Using %s\n",vpx_codec_iface_name(interface));
-
- /* Populate encoder configuration */
- res = vpx_codec_enc_config_default(interface, &cfg, 0);
- if(res) {
- printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
- return EXIT_FAILURE;
+ FILE *infile = NULL;
+ vpx_codec_ctx_t codec;
+ vpx_codec_enc_cfg_t cfg;
+ int frame_count = 0;
+ vpx_image_t raw;
+ vpx_codec_err_t res;
+ VpxVideoInfo info = {0};
+ VpxVideoWriter *writer = NULL;
+ const int fps = 30; // TODO(dkovalev) add command line argument
+ const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument
+
+ exec_name = argv[0];
+
+ if (argc != 5)
+ die("Invalid number of arguments");
+
+ info.codec_fourcc = VP8_FOURCC;
+ info.frame_width = strtol(argv[1], NULL, 0);
+ info.frame_height = strtol(argv[2], NULL, 0);
+ info.time_base.numerator = 1;
+ info.time_base.denominator = fps;
+
+ if (info.frame_width <= 0 ||
+ info.frame_height <= 0 ||
+ (info.frame_width % 2) != 0 ||
+ (info.frame_height % 2) != 0) {
+ die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
+ }
+
+ if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
+ info.frame_height, 1)) {
+ die("Failed to allocate image.");
+ }
+
+ printf("Using %s\n", vpx_codec_iface_name(interface));
+
+ res = vpx_codec_enc_config_default(interface, &cfg, 0);
+ if (res)
+ die_codec(&codec, "Failed to get default codec config.");
+
+ cfg.g_w = info.frame_width;
+ cfg.g_h = info.frame_height;
+ cfg.g_timebase.num = info.time_base.numerator;
+ cfg.g_timebase.den = info.time_base.denominator;
+ cfg.rc_target_bitrate = bitrate;
+
+ writer = vpx_video_writer_open(argv[4], kContainerIVF, &info);
+ if (!writer)
+ die("Failed to open %s for writing.", argv[4]);
+
+ if (!(infile = fopen(argv[3], "rb")))
+ die("Failed to open %s for reading.", argv[3]);
+
+ if (vpx_codec_enc_init(&codec, interface, &cfg, 0))
+ die_codec(&codec, "Failed to initialize encoder");
+
+ while (vpx_img_read(&raw, infile)) {
+ vpx_codec_iter_t iter = NULL;
+ const vpx_codec_cx_pkt_t *pkt = NULL;
+
+ ++frame_count;
+
+ res = vpx_codec_encode(&codec, &raw, frame_count, 1, 0,
+ VPX_DL_GOOD_QUALITY);
+ if (res != VPX_CODEC_OK)
+ die_codec(&codec, "Failed to encode frame");
+
+ while ((pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) {
+ if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
+ const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
+ if (!vpx_video_writer_write_frame(writer,
+ pkt->data.frame.buf,
+ pkt->data.frame.sz,
+ pkt->data.frame.pts))
+ die_codec(&codec, "Failed to write compressed frame.");
+ printf(keyframe ? "K" : ".");
+ fflush(stdout);
+ }
}
+ }
+ printf("\n");
+ fclose(infile);
+ printf("Processed %d frames.\n", frame_count);
- /* Update the default configuration with our settings */
- cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate
- / cfg.g_w / cfg.g_h;
- cfg.g_w = width;
- cfg.g_h = height;
-
- write_ivf_file_header(outfile, &cfg, 0);
-
-
- /* Open input file for this encoding pass */
- if(!(infile = fopen(argv[3], "rb")))
- die("Failed to open %s for reading", argv[3]);
-
- /* Initialize codec */
- if(vpx_codec_enc_init(&codec, interface, &cfg, 0))
- die_codec(&codec, "Failed to initialize encoder");
-
- frame_avail = 1;
- got_data = 0;
- while(frame_avail || got_data) {
- vpx_codec_iter_t iter = NULL;
- const vpx_codec_cx_pkt_t *pkt;
-
- frame_avail = read_frame(infile, &raw);
- if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt,
- 1, flags, VPX_DL_REALTIME))
- die_codec(&codec, "Failed to encode frame");
- got_data = 0;
- while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
- got_data = 1;
- switch(pkt->kind) {
- case VPX_CODEC_CX_FRAME_PKT:
- write_ivf_frame_header(outfile, pkt);
- (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
- outfile);
- break;
- default:
- break;
- }
- printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT
- && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
- fflush(stdout);
- }
- frame_cnt++;
- }
- printf("\n");
- fclose(infile);
+ vpx_img_free(&raw);
+ if (vpx_codec_destroy(&codec))
+ die_codec(&codec, "Failed to destroy codec.");
- printf("Processed %d frames.\n",frame_cnt-1);
- vpx_img_free(&raw);
- if(vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec");
+ vpx_video_writer_close(writer);
- /* Try to rewrite the file header with the actual frame count */
- if(!fseek(outfile, 0, SEEK_SET))
- write_ivf_file_header(outfile, &cfg, frame_cnt-1);
- fclose(outfile);
- return EXIT_SUCCESS;
+ return EXIT_SUCCESS;
}
diff --git a/examples/twopass_encoder.c b/examples/twopass_encoder.c
index b0f0426c6..93b6150a5 100644
--- a/examples/twopass_encoder.c
+++ b/examples/twopass_encoder.c
@@ -50,218 +50,172 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <string.h>
+
#define VPX_CODEC_DISABLE_COMPAT 1
-#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
-#define interface (vpx_codec_vp8_cx())
-#define fourcc 0x30385056
-
-#define IVF_FILE_HDR_SZ (32)
-#define IVF_FRAME_HDR_SZ (12)
-
-static void mem_put_le16(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
-}
-
-static void mem_put_le32(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
- mem[2] = val>>16;
- mem[3] = val>>24;
-}
+#include "vpx/vpx_encoder.h"
-static void die(const char *fmt, ...) {
- va_list ap;
+#include "./tools_common.h"
+#include "./video_writer.h"
- va_start(ap, fmt);
- vprintf(fmt, ap);
- if(fmt[strlen(fmt)-1] != '\n')
- printf("\n");
- exit(EXIT_FAILURE);
-}
+#define interface (vpx_codec_vp8_cx())
-static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
- const char *detail = vpx_codec_error_detail(ctx);
+static const char *exec_name;
- printf("%s: %s\n", s, vpx_codec_error(ctx));
- if(detail)
- printf(" %s\n",detail);
- exit(EXIT_FAILURE);
+void usage_exit() {
+ fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name);
+ exit(EXIT_FAILURE);
}
-static int read_frame(FILE *f, vpx_image_t *img) {
- size_t nbytes, to_read;
- int res = 1;
-
- to_read = img->w*img->h*3/2;
- nbytes = fread(img->planes[0], 1, to_read, f);
- if(nbytes != to_read) {
- res = 0;
- if(nbytes > 0)
- printf("Warning: Read partial frame. Check your width & height!\n");
+static void get_frame_stats(vpx_codec_ctx_t *ctx,
+ const vpx_image_t *img,
+ vpx_codec_pts_t pts,
+ uint64_t duration,
+ vpx_enc_frame_flags_t flags,
+ uint64_t deadline,
+ vpx_fixed_buf_t *stats) {
+ vpx_codec_iter_t iter = NULL;
+ const vpx_codec_cx_pkt_t *pkt = NULL;
+ const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
+ deadline);
+ if (res != VPX_CODEC_OK)
+ die_codec(ctx, "Failed to get frame stats.");
+
+ while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
+ if (pkt->kind == VPX_CODEC_STATS_PKT) {
+ const uint8_t *const pkt_buf = pkt->data.twopass_stats.buf;
+ const size_t pkt_size = pkt->data.twopass_stats.sz;
+ stats->buf = realloc(stats->buf, stats->sz + pkt_size);
+ memcpy((uint8_t *)stats->buf + stats->sz, pkt_buf, pkt_size);
+ stats->sz += pkt_size;
}
- return res;
+ }
}
-static void write_ivf_file_header(FILE *outfile,
- const vpx_codec_enc_cfg_t *cfg,
- int frame_cnt) {
- char header[32];
-
- if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
- return;
- header[0] = 'D';
- header[1] = 'K';
- header[2] = 'I';
- header[3] = 'F';
- mem_put_le16(header+4, 0); /* version */
- mem_put_le16(header+6, 32); /* headersize */
- mem_put_le32(header+8, fourcc); /* headersize */
- mem_put_le16(header+12, cfg->g_w); /* width */
- mem_put_le16(header+14, cfg->g_h); /* height */
- mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
- mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
- mem_put_le32(header+24, frame_cnt); /* length */
- mem_put_le32(header+28, 0); /* unused */
-
- (void) fwrite(header, 1, 32, outfile);
+static void encode_frame(vpx_codec_ctx_t *ctx,
+ const vpx_image_t *img,
+ vpx_codec_pts_t pts,
+ uint64_t duration,
+ vpx_enc_frame_flags_t flags,
+ uint64_t deadline,
+ VpxVideoWriter *writer) {
+ vpx_codec_iter_t iter = NULL;
+ const vpx_codec_cx_pkt_t *pkt = NULL;
+ const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
+ deadline);
+ if (res != VPX_CODEC_OK)
+ die_codec(ctx, "Failed to encode frame.");
+
+ while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
+ if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
+ const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
+
+ if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
+ pkt->data.frame.sz,
+ pkt->data.frame.pts))
+ die_codec(ctx, "Failed to write compressed frame.");
+ printf(keyframe ? "K" : ".");
+ fflush(stdout);
+ }
+ }
}
+int main(int argc, char **argv) {
+ FILE *infile = NULL;
+ VpxVideoWriter *writer = NULL;
+ vpx_codec_ctx_t codec;
+ vpx_codec_enc_cfg_t cfg;
+ vpx_image_t raw;
+ vpx_codec_err_t res;
+ vpx_fixed_buf_t stats = {0};
+ VpxVideoInfo info = {0};
+ int pass;
+ const int fps = 30; // TODO(dkovalev) add command line argument
+ const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument
+
+ if (argc != 5)
+ die("Invalid number of arguments.");
+
+ info.codec_fourcc = VP8_FOURCC;
+ info.time_base.numerator = 1;
+ info.time_base.denominator = fps;
+ info.frame_width = strtol(argv[1], NULL, 0);
+ info.frame_height = strtol(argv[2], NULL, 0);
+
+ if (info.frame_width <= 0 ||
+ info.frame_height <= 0 ||
+ (info.frame_width % 2) != 0 ||
+ (info.frame_height % 2) != 0) {
+ die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
+ }
+
+ if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
+ info.frame_height, 1)) {
+ die("Failed to allocate image", info.frame_width, info.frame_height);
+ }
+
+ writer = vpx_video_writer_open(argv[4], kContainerIVF, &info);
+ if (!writer)
+ die("Failed to open %s for writing", argv[4]);
+
+ printf("Using %s\n", vpx_codec_iface_name(interface));
+
+ res = vpx_codec_enc_config_default(interface, &cfg, 0);
+ if (res)
+ die_codec(&codec, "Failed to get default codec config.");
+
+ cfg.g_w = info.frame_width;
+ cfg.g_h = info.frame_height;
+ cfg.g_timebase.num = info.time_base.numerator;
+ cfg.g_timebase.den = info.time_base.denominator;
+ cfg.rc_target_bitrate = bitrate;
+
+ for (pass = 0; pass < 2; ++pass) {
+ int frame_count = 0;
+
+ if (pass == 0) {
+ cfg.g_pass = VPX_RC_FIRST_PASS;
+ } else {
+ cfg.g_pass = VPX_RC_LAST_PASS;
+ cfg.rc_twopass_stats_in = stats;
+ }
-static void write_ivf_frame_header(FILE *outfile,
- const vpx_codec_cx_pkt_t *pkt)
-{
- char header[12];
- vpx_codec_pts_t pts;
-
- if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
- return;
+ if (!(infile = fopen(argv[3], "rb")))
+ die("Failed to open %s for reading", argv[3]);
- pts = pkt->data.frame.pts;
- mem_put_le32(header, pkt->data.frame.sz);
- mem_put_le32(header+4, pts&0xFFFFFFFF);
- mem_put_le32(header+8, pts >> 32);
+ if (vpx_codec_enc_init(&codec, interface, &cfg, 0))
+ die_codec(&codec, "Failed to initialize encoder");
- (void) fwrite(header, 1, 12, outfile);
-}
+ while (vpx_img_read(&raw, infile)) {
+ ++frame_count;
-int main(int argc, char **argv) {
- FILE *infile, *outfile;
- vpx_codec_ctx_t codec;
- vpx_codec_enc_cfg_t cfg;
- int frame_cnt = 0;
- vpx_image_t raw;
- vpx_codec_err_t res;
- long width;
- long height;
- int frame_avail;
- int got_data;
- int flags = 0;
- int pass;
- vpx_fixed_buf_t stats = {0};
-
- /* Open files */
- if(argc!=5)
- die("Usage: %s <width> <height> <infile> <outfile>\n", argv[0]);
- width = strtol(argv[1], NULL, 0);
- height = strtol(argv[2], NULL, 0);
- if(width < 16 || width%2 || height <16 || height%2)
- die("Invalid resolution: %ldx%ld", width, height);
- if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1))
- die("Faile to allocate image", width, height);
- if(!(outfile = fopen(argv[4], "wb")))
- die("Failed to open %s for writing", argv[4]);
-
- printf("Using %s\n",vpx_codec_iface_name(interface));
-
- /* Populate encoder configuration */
- res = vpx_codec_enc_config_default(interface, &cfg, 0);
- if(res) {
- printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
- return EXIT_FAILURE;
+ if (pass == 0) {
+ get_frame_stats(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
+ &stats);
+ } else {
+ encode_frame(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
+ writer);
+ }
}
- /* Update the default configuration with our settings */
- cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate
- / cfg.g_w / cfg.g_h;
- cfg.g_w = width;
- cfg.g_h = height;
-
- write_ivf_file_header(outfile, &cfg, 0);
-
- for(pass=0; pass<2; pass++) {
- frame_cnt = 0;
-
- if(pass == 0)
- cfg.g_pass = VPX_RC_FIRST_PASS;
- else {
- cfg.g_pass = VPX_RC_LAST_PASS;
- cfg.rc_twopass_stats_in = stats;
- }
-
- /* Open input file for this encoding pass */
- if(!(infile = fopen(argv[3], "rb")))
- die("Failed to open %s for reading", argv[3]);
-
- /* Initialize codec */
- if(vpx_codec_enc_init(&codec, interface, &cfg, 0))
- die_codec(&codec, "Failed to initialize encoder");
-
- frame_avail = 1;
- got_data = 0;
- while(frame_avail || got_data) {
- vpx_codec_iter_t iter = NULL;
- const vpx_codec_cx_pkt_t *pkt;
-
- frame_avail = read_frame(infile, &raw);
- if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt,
- 1, flags, VPX_DL_BEST_QUALITY))
- die_codec(&codec, "Failed to encode frame");
- got_data = 0;
- while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
- got_data = 1;
- switch(pkt->kind) {
- case VPX_CODEC_CX_FRAME_PKT:
- write_ivf_frame_header(outfile, pkt);
- (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
- outfile);
- break;
- case VPX_CODEC_STATS_PKT:
- stats.buf = realloc(stats.buf, stats.sz
- + pkt->data.twopass_stats.sz);
- if(!stats.buf)
- die("Memory reallocation failed.\n");
- memcpy((char*)stats.buf + stats.sz,
- pkt->data.twopass_stats.buf,
- pkt->data.twopass_stats.sz);
- stats.sz += pkt->data.twopass_stats.sz;
- break;
- default:
- break;
- }
- printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT
- && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
- fflush(stdout);
- }
- frame_cnt++;
- }
- printf("\n");
- fclose(infile);
- printf("Pass %d complete.\n", pass+1);
- if(vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec");
+ if (pass == 0) {
+ get_frame_stats(&codec, NULL, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
+ &stats);
+ } else {
+ printf("\n");
}
- printf("Processed %d frames.\n",frame_cnt-1);
- vpx_img_free(&raw);
- free(stats.buf);
+ fclose(infile);
+ printf("Pass %d complete. Processed %d frames.\n", pass + 1, frame_count);
+ if (vpx_codec_destroy(&codec))
+ die_codec(&codec, "Failed to destroy codec.");
+ }
+
+ vpx_img_free(&raw);
+ free(stats.buf);
+
+ vpx_video_writer_close(writer);
- /* Try to rewrite the file header with the actual frame count */
- if(!fseek(outfile, 0, SEEK_SET))
- write_ivf_file_header(outfile, &cfg, frame_cnt-1);
- fclose(outfile);
- return EXIT_SUCCESS;
+ return EXIT_SUCCESS;
}
diff --git a/examples/vp8_set_maps.c b/examples/vp8_set_maps.c
index 242788fd4..4c0e8a0ba 100644
--- a/examples/vp8_set_maps.c
+++ b/examples/vp8_set_maps.c
@@ -201,7 +201,7 @@ int main(int argc, char **argv) {
if(frame_cnt + 1 == 22) {
vpx_roi_map_t roi;
- int i;
+ unsigned int i;
roi.rows = cfg.g_h/16;
roi.cols = cfg.g_w/16;
@@ -232,7 +232,7 @@ int main(int argc, char **argv) {
free(roi.roi_map);
} else if(frame_cnt + 1 == 33) {
vpx_active_map_t active;
- int i;
+ unsigned int i;
active.rows = cfg.g_h/16;
active.cols = cfg.g_w/16;
diff --git a/examples/vpx_temporal_scalable_patterns.c b/examples/vpx_temporal_scalable_patterns.c
new file mode 100644
index 000000000..11d331bd8
--- /dev/null
+++ b/examples/vpx_temporal_scalable_patterns.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2012 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 is an example demonstrating how to implement a multi-layer VP9
+// encoding scheme based on temporal scalability for video applications
+// that benefit from a scalable bitstream.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define VPX_CODEC_DISABLE_COMPAT 1
+#include "vpx/vp8cx.h"
+#include "vpx/vpx_encoder.h"
+
+#include "./tools_common.h"
+#include "./video_writer.h"
+
+static const char *exec_name;
+
+void usage_exit() {
+ exit(EXIT_FAILURE);
+}
+
+static int mode_to_num_layers[12] = {1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3};
+
+// Temporal scaling parameters:
+// NOTE: The 3 prediction frames cannot be used interchangeably due to
+// differences in the way they are handled throughout the code. The
+// frames should be allocated to layers in the order LAST, GF, ARF.
+// Other combinations work, but may produce slightly inferior results.
+static void set_temporal_layer_pattern(int layering_mode,
+ vpx_codec_enc_cfg_t *cfg,
+ int *layer_flags,
+ int *flag_periodicity) {
+ switch (layering_mode) {
+ case 0: {
+ // 1-layer.
+ int ids[1] = {0};
+ cfg->ts_periodicity = 1;
+ *flag_periodicity = 1;
+ cfg->ts_number_layers = 1;
+ cfg->ts_rate_decimator[0] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // Update L only.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ break;
+ }
+ case 1: {
+ // 2-layers, 2-frame period.
+ int ids[2] = {0, 1};
+ cfg->ts_periodicity = 2;
+ *flag_periodicity = 2;
+ cfg->ts_number_layers = 2;
+ cfg->ts_rate_decimator[0] = 2;
+ cfg->ts_rate_decimator[1] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+#if 1
+ // 0=L, 1=GF, Intra-layer prediction enabled.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
+ layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_REF_ARF;
+#else
+ // 0=L, 1=GF, Intra-layer prediction disabled.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
+ layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST;
+#endif
+ break;
+ }
+ case 2: {
+ // 2-layers, 3-frame period.
+ int ids[3] = {0, 1, 1};
+ cfg->ts_periodicity = 3;
+ *flag_periodicity = 3;
+ cfg->ts_number_layers = 2;
+ cfg->ts_rate_decimator[0] = 3;
+ cfg->ts_rate_decimator[1] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF, Intra-layer prediction enabled.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[1] =
+ layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
+ break;
+ }
+ case 3: {
+ // 3-layers, 6-frame period.
+ int ids[6] = {0, 2, 2, 1, 2, 2};
+ cfg->ts_periodicity = 6;
+ *flag_periodicity = 6;
+ cfg->ts_number_layers = 3;
+ cfg->ts_rate_decimator[0] = 6;
+ cfg->ts_rate_decimator[1] = 3;
+ cfg->ts_rate_decimator[2] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_UPD_LAST;
+ layer_flags[1] =
+ layer_flags[2] =
+ layer_flags[4] =
+ layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
+ break;
+ }
+ case 4: {
+ // 3-layers, 4-frame period.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 4;
+ cfg->ts_number_layers = 3;
+ cfg->ts_rate_decimator[0] = 4;
+ cfg->ts_rate_decimator[1] = 2;
+ cfg->ts_rate_decimator[2] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
+ layer_flags[1] =
+ layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ break;
+ }
+ case 5: {
+ // 3-layers, 4-frame period.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 4;
+ cfg->ts_number_layers = 3;
+ cfg->ts_rate_decimator[0] = 4;
+ cfg->ts_rate_decimator[1] = 2;
+ cfg->ts_rate_decimator[2] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, disabled
+ // in layer 2.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[1] =
+ layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ break;
+ }
+ case 6: {
+ // 3-layers, 4-frame period.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 4;
+ cfg->ts_number_layers = 3;
+ cfg->ts_rate_decimator[0] = 4;
+ cfg->ts_rate_decimator[1] = 2;
+ cfg->ts_rate_decimator[2] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[1] =
+ layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
+ break;
+ }
+ case 7: {
+ // NOTE: Probably of academic interest only.
+ // 5-layers, 16-frame period.
+ int ids[16] = {0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4};
+ cfg->ts_periodicity = 16;
+ *flag_periodicity = 16;
+ cfg->ts_number_layers = 5;
+ cfg->ts_rate_decimator[0] = 16;
+ cfg->ts_rate_decimator[1] = 8;
+ cfg->ts_rate_decimator[2] = 4;
+ cfg->ts_rate_decimator[3] = 2;
+ cfg->ts_rate_decimator[4] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ layer_flags[0] = VPX_EFLAG_FORCE_KF;
+ layer_flags[1] =
+ layer_flags[3] =
+ layer_flags[5] =
+ layer_flags[7] =
+ layer_flags[9] =
+ layer_flags[11] =
+ layer_flags[13] =
+ layer_flags[15] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[2] =
+ layer_flags[6] =
+ layer_flags[10] =
+ layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF;
+ layer_flags[4] =
+ layer_flags[12] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF;
+ break;
+ }
+ case 8: {
+ // 2-layers, with sync point at first frame of layer 1.
+ int ids[2] = {0, 1};
+ cfg->ts_periodicity = 2;
+ *flag_periodicity = 8;
+ cfg->ts_number_layers = 2;
+ cfg->ts_rate_decimator[0] = 2;
+ cfg->ts_rate_decimator[1] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF.
+ // ARF is used as predictor for all frames, and is only updated on
+ // key frame. Sync point every 8 frames.
+
+ // Layer 0: predict from L and ARF, update L and G.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ // Layer 1: sync point: predict from L and ARF, and update G.
+ layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ARF;
+ // Layer 0, predict from L and ARF, update L.
+ layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ // Layer 1: predict from L, G and ARF, and update G.
+ layer_flags[3] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ENTROPY;
+ // Layer 0.
+ layer_flags[4] = layer_flags[2];
+ // Layer 1.
+ layer_flags[5] = layer_flags[3];
+ // Layer 0.
+ layer_flags[6] = layer_flags[4];
+ // Layer 1.
+ layer_flags[7] = layer_flags[5];
+ break;
+ }
+ case 9: {
+ // 3-layers: Sync points for layer 1 and 2 every 8 frames.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 8;
+ cfg->ts_number_layers = 3;
+ cfg->ts_rate_decimator[0] = 4;
+ cfg->ts_rate_decimator[1] = 2;
+ cfg->ts_rate_decimator[2] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF, 2=ARF.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
+ layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[3] =
+ layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
+ layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[6] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ARF;
+ layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ENTROPY;
+ break;
+ }
+ case 10: {
+ // 3-layers structure where ARF is used as predictor for all frames,
+ // and is only updated on key frame.
+ // Sync points for layer 1 and 2 every 8 frames.
+
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 8;
+ cfg->ts_number_layers = 3;
+ cfg->ts_rate_decimator[0] = 4;
+ cfg->ts_rate_decimator[1] = 2;
+ cfg->ts_rate_decimator[2] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF, 2=ARF.
+ // Layer 0: predict from L and ARF; update L and G.
+ layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_REF_GF;
+ // Layer 2: sync point: predict from L and ARF; update none.
+ layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ENTROPY;
+ // Layer 1: sync point: predict from L and ARF; update G.
+ layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_UPD_LAST;
+ // Layer 2: predict from L, G, ARF; update none.
+ layer_flags[3] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
+ // Layer 0: predict from L and ARF; update L.
+ layer_flags[4] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_REF_GF;
+ // Layer 2: predict from L, G, ARF; update none.
+ layer_flags[5] = layer_flags[3];
+ // Layer 1: predict from L, G, ARF; update G.
+ layer_flags[6] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
+ // Layer 2: predict from L, G, ARF; update none.
+ layer_flags[7] = layer_flags[3];
+ break;
+ }
+ case 11:
+ default: {
+ // 3-layers structure as in case 10, but no sync/refresh points for
+ // layer 1 and 2.
+ int ids[4] = {0, 2, 1, 2};
+ cfg->ts_periodicity = 4;
+ *flag_periodicity = 8;
+ cfg->ts_number_layers = 3;
+ cfg->ts_rate_decimator[0] = 4;
+ cfg->ts_rate_decimator[1] = 2;
+ cfg->ts_rate_decimator[2] = 1;
+ memcpy(cfg->ts_layer_id, ids, sizeof(ids));
+ // 0=L, 1=GF, 2=ARF.
+ // Layer 0: predict from L and ARF; update L.
+ layer_flags[0] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_REF_GF;
+ layer_flags[4] = layer_flags[0];
+ // Layer 1: predict from L, G, ARF; update G.
+ layer_flags[2] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
+ layer_flags[6] = layer_flags[2];
+ // Layer 2: predict from L, G, ARF; update none.
+ layer_flags[1] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
+ layer_flags[3] = layer_flags[1];
+ layer_flags[5] = layer_flags[1];
+ layer_flags[7] = layer_flags[1];
+ break;
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS];
+ vpx_codec_ctx_t codec;
+ vpx_codec_enc_cfg_t cfg;
+ int frame_cnt = 0;
+ vpx_image_t raw;
+ vpx_codec_err_t res;
+ unsigned int width;
+ unsigned int height;
+ int frame_avail;
+ int got_data;
+ int flags = 0;
+ int i;
+ int pts = 0; // PTS starts at 0.
+ int frame_duration = 1; // 1 timebase tick per frame.
+ int layering_mode = 0;
+ int frames_in_layer[VPX_TS_MAX_LAYERS] = {0};
+ int layer_flags[VPX_TS_MAX_PERIODICITY] = {0};
+ int flag_periodicity = 1;
+ int max_intra_size_pct;
+ vpx_svc_layer_id_t layer_id = {0, 0};
+ char *codec_type;
+ vpx_codec_iface_t *(*interface)(void);
+ unsigned int fourcc;
+ struct VpxInputContext input_ctx = {0};
+
+ exec_name = argv[0];
+ // Check usage and arguments.
+ if (argc < 10) {
+ die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> "
+ "<rate_num> <rate_den> <mode> <Rate_0> ... <Rate_nlayers-1> \n",
+ argv[0]);
+ }
+
+ codec_type = argv[3];
+ if (strncmp(codec_type, "vp9", 3) == 0) {
+#if CONFIG_VP9_ENCODER
+ interface = vpx_codec_vp9_cx;
+ fourcc = VP9_FOURCC;
+#else
+ die("Encoder vp9 selected but not configured");
+#endif
+ } else {
+#if CONFIG_VP8_ENCODER
+ interface = vpx_codec_vp8_cx;
+ fourcc = VP8_FOURCC;
+#else
+ die("Encoder vp8 selected but not configured");
+#endif
+ }
+ printf("Using %s\n", vpx_codec_iface_name(interface()));
+
+ width = strtol(argv[4], NULL, 0);
+ height = strtol(argv[5], NULL, 0);
+ if (width < 16 || width % 2 || height < 16 || height % 2) {
+ die("Invalid resolution: %d x %d", width, height);
+ }
+
+ layering_mode = strtol(argv[8], NULL, 0);
+ if (layering_mode < 0 || layering_mode > 11) {
+ die("Invalid mode (0..11) %s", argv[8]);
+ }
+
+ if (argc != 9 + mode_to_num_layers[layering_mode]) {
+ die("Invalid number of arguments");
+ }
+
+ if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) {
+ die("Failed to allocate image", width, height);
+ }
+
+ // Populate encoder configuration.
+ res = vpx_codec_enc_config_default(interface(), &cfg, 0);
+ if (res) {
+ printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
+ return EXIT_FAILURE;
+ }
+
+ // Update the default configuration with our settings.
+ cfg.g_w = width;
+ cfg.g_h = height;
+
+ // Timebase format e.g. 30fps: numerator=1, demoninator = 30.
+ cfg.g_timebase.num = strtol(argv[6], NULL, 0);
+ cfg.g_timebase.den = strtol(argv[7], NULL, 0);
+
+ for (i = 9; i < 9 + mode_to_num_layers[layering_mode]; ++i) {
+ cfg.ts_target_bitrate[i - 9] = strtol(argv[i], NULL, 0);
+ }
+
+ // Real time parameters.
+ cfg.rc_dropframe_thresh = 0;
+ cfg.rc_end_usage = VPX_CBR;
+ cfg.rc_resize_allowed = 0;
+ cfg.rc_min_quantizer = 2;
+ cfg.rc_max_quantizer = 56;
+ cfg.rc_undershoot_pct = 100;
+ cfg.rc_overshoot_pct = 15;
+ cfg.rc_buf_initial_sz = 500;
+ cfg.rc_buf_optimal_sz = 600;
+ cfg.rc_buf_sz = 1000;
+
+ // Enable error resilient mode.
+ cfg.g_error_resilient = 1;
+ cfg.g_lag_in_frames = 0;
+ cfg.kf_mode = VPX_KF_DISABLED;
+
+ // Disable automatic keyframe placement.
+ cfg.kf_min_dist = cfg.kf_max_dist = 3000;
+
+ // Default setting for bitrate: used in special case of 1 layer (case 0).
+ cfg.rc_target_bitrate = cfg.ts_target_bitrate[0];
+
+ set_temporal_layer_pattern(layering_mode,
+ &cfg,
+ layer_flags,
+ &flag_periodicity);
+
+ // Open input file.
+ input_ctx.filename = argv[1];
+ if (!(input_ctx.file = fopen(input_ctx.filename, "rb"))) {
+ die("Failed to open %s for reading", argv[1]);
+ }
+
+ // Open an output file for each stream.
+ for (i = 0; i < cfg.ts_number_layers; ++i) {
+ char file_name[PATH_MAX];
+ VpxVideoInfo info;
+ info.codec_fourcc = fourcc;
+ info.frame_width = cfg.g_w;
+ info.frame_height = cfg.g_h;
+ info.time_base.numerator = cfg.g_timebase.num;
+ info.time_base.denominator = cfg.g_timebase.den;
+
+ snprintf(file_name, sizeof(file_name), "%s_%d.ivf", argv[2], i);
+ outfile[i] = vpx_video_writer_open(file_name, kContainerIVF, &info);
+ if (!outfile[i])
+ die("Failed to open %s for writing", file_name);
+ }
+ // No spatial layers in this encoder.
+ cfg.ss_number_layers = 1;
+
+ // Initialize codec.
+ if (vpx_codec_enc_init(&codec, interface(), &cfg, 0))
+ die_codec(&codec, "Failed to initialize encoder");
+
+ vpx_codec_control(&codec, VP8E_SET_CPUUSED, -6);
+ vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 1);
+ if (strncmp(codec_type, "vp9", 3) == 0) {
+ vpx_codec_control(&codec, VP8E_SET_CPUUSED, 3);
+ 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");
+ }
+ }
+ vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
+ vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1);
+ max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5)
+ * ((double) cfg.g_timebase.den / cfg.g_timebase.num) / 10.0);
+ vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, max_intra_size_pct);
+
+ frame_avail = 1;
+ while (frame_avail || got_data) {
+ vpx_codec_iter_t iter = NULL;
+ const vpx_codec_cx_pkt_t *pkt;
+ // Update the temporal layer_id. No spatial layers in this test.
+ layer_id.spatial_layer_id = 0;
+ layer_id.temporal_layer_id =
+ cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
+ vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id);
+ flags = layer_flags[frame_cnt % flag_periodicity];
+ frame_avail = !read_yuv_frame(&input_ctx, &raw);
+ if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, 1, flags,
+ VPX_DL_REALTIME)) {
+ die_codec(&codec, "Failed to encode frame");
+ }
+ // Reset KF flag.
+ if (layering_mode != 7) {
+ layer_flags[0] &= ~VPX_EFLAG_FORCE_KF;
+ }
+ got_data = 0;
+ while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
+ got_data = 1;
+ switch (pkt->kind) {
+ case VPX_CODEC_CX_FRAME_PKT:
+ for (i = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
+ i < cfg.ts_number_layers; ++i) {
+ vpx_video_writer_write_frame(outfile[i], pkt->data.frame.buf,
+ pkt->data.frame.sz, pts);
+ ++frames_in_layer[i];
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ ++frame_cnt;
+ pts += frame_duration;
+ }
+ fclose(input_ctx.file);
+ printf("Processed %d frames: \n", frame_cnt - 1);
+ if (vpx_codec_destroy(&codec))
+ die_codec(&codec, "Failed to destroy codec");
+
+ // Try to rewrite the output file headers with the actual frame count.
+ for (i = 0; i < cfg.ts_number_layers; ++i)
+ vpx_video_writer_close(outfile[i]);
+
+ return EXIT_SUCCESS;
+}
diff --git a/ivfdec.c b/ivfdec.c
index b9fec26a4..40394a81a 100644
--- a/ivfdec.c
+++ b/ivfdec.c
@@ -108,68 +108,3 @@ int ivf_read_frame(FILE *infile, uint8_t **buffer,
return 1;
}
-
-struct vpx_video {
- FILE *file;
- unsigned char *buffer;
- size_t buffer_size;
- size_t frame_size;
- unsigned int fourcc;
- int width;
- int height;
-};
-
-vpx_video_t *vpx_video_open_file(FILE *file) {
- char raw_hdr[32];
- vpx_video_t *video;
-
- if (fread(raw_hdr, 1, 32, file) != 32)
- return NULL; // Can't read file header;
-
- if (memcmp(IVF_SIGNATURE, raw_hdr, 4) != 0)
- return NULL; // Wrong IVF signature
-
- if (mem_get_le16(raw_hdr + 4) != 0)
- return NULL; // Wrong IVF version
-
- video = (vpx_video_t *)malloc(sizeof(*video));
- video->file = file;
- video->buffer = NULL;
- video->buffer_size = 0;
- video->frame_size = 0;
- video->fourcc = mem_get_le32(raw_hdr + 8);
- video->width = mem_get_le16(raw_hdr + 12);
- video->height = mem_get_le16(raw_hdr + 14);
- return video;
-}
-
-void vpx_video_close(vpx_video_t *video) {
- if (video) {
- free(video->buffer);
- free(video);
- }
-}
-
-int vpx_video_get_width(vpx_video_t *video) {
- return video->width;
-}
-
-int vpx_video_get_height(vpx_video_t *video) {
- return video->height;
-}
-
-unsigned int vpx_video_get_fourcc(vpx_video_t *video) {
- return video->fourcc;
-}
-
-int vpx_video_read_frame(vpx_video_t *video) {
- return !ivf_read_frame(video->file, &video->buffer, &video->frame_size,
- &video->buffer_size);
-}
-
-const unsigned char *vpx_video_get_frame(vpx_video_t *video, size_t *size) {
- if (size)
- *size = video->frame_size;
-
- return video->buffer;
-}
diff --git a/ivfdec.h b/ivfdec.h
index e960b4aec..dd29cc617 100644
--- a/ivfdec.h
+++ b/ivfdec.h
@@ -21,34 +21,6 @@ int file_is_ivf(struct VpxInputContext *input);
int ivf_read_frame(FILE *infile, uint8_t **buffer,
size_t *bytes_read, size_t *buffer_size);
-// The following code is work in progress. It is going to be in a separate file
-// and support transparent reading of IVF and Y4M formats. Right now only IVF
-// format is supported for simplicity. The main goal the API is to be
-// simple and easy to use in example code (and probably in vpxenc/vpxdec later).
-// All low-level details like memory buffer management are hidden from API
-// users.
-struct vpx_video;
-typedef struct vpx_video vpx_video_t;
-
-// Opens the input file and inspects it to determine file type. Returns an
-// opaque vpx_video_t* upon success, or NULL upon failure.
-vpx_video_t *vpx_video_open_file(FILE *file);
-
-// Frees all resources associated with vpx_video_t returned from
-// vpx_video_open_file() call
-void vpx_video_close(vpx_video_t *video);
-
-int vpx_video_get_width(vpx_video_t *video);
-int vpx_video_get_height(vpx_video_t *video);
-unsigned int vpx_video_get_fourcc(vpx_video_t *video);
-
-// Reads video frame bytes from the file and stores them into internal buffer.
-int vpx_video_read_frame(vpx_video_t *video);
-
-// Returns the pointer to internal memory buffer with frame bytes read from
-// last call to vpx_video_read_frame().
-const unsigned char *vpx_video_get_frame(vpx_video_t *video, size_t *size);
-
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/libs.mk b/libs.mk
index cc40451d4..eac61f289 100644
--- a/libs.mk
+++ b/libs.mk
@@ -57,13 +57,6 @@ CLEAN-OBJS += $$(BUILD_PFX)$(1).h
RTCD += $$(BUILD_PFX)$(1).h
endef
-# x86inc.asm is not compatible with pic 32bit builds. Restrict
-# files which use it to 64bit builds or 32bit without pic
-USE_X86INC = no
-ifeq ($(CONFIG_USE_X86INC),yes)
- USE_X86INC = yes
-endif
-
CODEC_SRCS-yes += CHANGELOG
CODEC_SRCS-yes += libs.mk
@@ -182,6 +175,7 @@ CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc
CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec
INSTALL-LIBS-yes += include/vpx/vpx_codec.h
+INSTALL-LIBS-yes += include/vpx/vpx_frame_buffer.h
INSTALL-LIBS-yes += include/vpx/vpx_image.h
INSTALL-LIBS-yes += include/vpx/vpx_integer.h
INSTALL-LIBS-$(CONFIG_DECODERS) += include/vpx/vpx_decoder.h
diff --git a/test/datarate_test.cc b/test/datarate_test.cc
index db7dfdb53..31b8239d6 100644
--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -200,21 +200,102 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest,
frame_number_ = 0;
first_drop_ = 0;
num_drops_ = 0;
- bits_total_ = 0;
- duration_ = 0.0;
+ // For testing up to 3 layers.
+ for (int i = 0; i < 3; ++i) {
+ bits_total_[i] = 0;
+ }
+ }
+
+ //
+ // Frame flags and layer id for temporal layers.
+ //
+
+ // For two layers, test pattern is:
+ // 1 3
+ // 0 2 .....
+ // For three layers, test pattern is:
+ // 1 3 5 7
+ // 2 6
+ // 0 4 ....
+ // LAST is always update on base/layer 0, GOLDEN is updated on layer 1.
+ // For this 3 layer example, the 2nd enhancement layer (layer 2) does not
+ // update any reference frames.
+ int SetFrameFlags(int frame_num, int num_temp_layers) {
+ int frame_flags = 0;
+ if (num_temp_layers == 2) {
+ if (frame_num % 2 == 0) {
+ // Layer 0: predict from L and ARF, update L.
+ frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ } else {
+ // Layer 1: predict from L, G and ARF, and update G.
+ frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ENTROPY;
+ }
+ } else if (num_temp_layers == 3) {
+ if (frame_num % 4 == 0) {
+ // Layer 0: predict from L and ARF; update L.
+ frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_REF_GF;
+ } else if ((frame_num - 2) % 4 == 0) {
+ // Layer 1: predict from L, G, ARF; update G.
+ frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
+ } else if ((frame_num - 1) % 2 == 0) {
+ // Layer 2: predict from L, G, ARF; update none.
+ frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_UPD_LAST;
+ }
+ }
+ return frame_flags;
+ }
+
+ int SetLayerId(int frame_num, int num_temp_layers) {
+ int layer_id = 0;
+ if (num_temp_layers == 2) {
+ if (frame_num % 2 == 0) {
+ layer_id = 0;
+ } else {
+ layer_id = 1;
+ }
+ } else if (num_temp_layers == 3) {
+ if (frame_num % 4 == 0) {
+ layer_id = 0;
+ } else if ((frame_num - 2) % 4 == 0) {
+ layer_id = 1;
+ } else if ((frame_num - 1) % 2 == 0) {
+ layer_id = 2;
+ }
+ }
+ return layer_id;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
- ::libvpx_test::Encoder *encoder) {
+ ::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
}
+ if (cfg_.ts_number_layers > 1) {
+ if (video->frame() == 1) {
+ encoder->Control(VP9E_SET_SVC, 1);
+ }
+ vpx_svc_layer_id_t layer_id = {0, 0};
+ layer_id.spatial_layer_id = 0;
+ frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
+ layer_id.temporal_layer_id = SetLayerId(video->frame(),
+ cfg_.ts_number_layers);
+ if (video->frame() > 0) {
+ encoder->Control(VP9E_SET_SVC_LAYER_ID, &layer_id);
+ }
+ }
const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0;
}
+
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
+ int layer = SetLayerId(frame_number_, cfg_.ts_number_layers);
+
// Time since last timestamp = duration.
vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
@@ -227,7 +308,12 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest,
<< pkt->data.frame.pts;
const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
- bits_total_ += frame_size_in_bits;
+
+ // Update the total encoded bits. For temporal layers, update the cumulative
+ // encoded bits per layer.
+ for (int i = layer; i < static_cast<int>(cfg_.ts_number_layers); ++i) {
+ bits_total_[i] += frame_size_in_bits;
+ }
// If first drop not set and we have a drop set it to this time.
if (!first_drop_ && duration > 1)
@@ -244,19 +330,22 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest,
}
virtual void EndPassHook(void) {
- if (bits_total_) {
+ for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
+ ++layer) {
duration_ = (last_pts_ + 1) * timebase_;
- // Effective file datarate:
- effective_datarate_ = ((bits_total_) / 1000.0) / duration_;
+ if (bits_total_[layer]) {
+ // Effective file datarate:
+ effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
+ }
}
}
vpx_codec_pts_t last_pts_;
double timebase_;
int frame_number_;
- int64_t bits_total_;
+ int64_t bits_total_[3];
double duration_;
- double effective_datarate_;
+ double effective_datarate_[3];
int set_cpu_used_;
int64_t bits_in_buffer_model_;
vpx_codec_pts_t first_drop_;
@@ -272,6 +361,7 @@ TEST_P(DatarateTestVP9, BasicRateTargeting) {
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
@@ -279,12 +369,10 @@ TEST_P(DatarateTestVP9, BasicRateTargeting) {
cfg_.rc_target_bitrate = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate),
- effective_datarate_ * 0.85)
- << " The datarate for the file exceeds the target by too much!";
- ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate),
- effective_datarate_ * 1.15)
- << " The datarate for the file missed the target!";
+ ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
+ << " The datarate for the file is lower than target by too much!";
+ ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
+ << " The datarate for the file is greater than target by too much!";
}
}
@@ -309,10 +397,10 @@ TEST_P(DatarateTestVP9, BasicRateTargeting444) {
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate),
- effective_datarate_ * 0.85)
+ effective_datarate_[0] * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate),
- effective_datarate_ * 1.15)
+ effective_datarate_[0] * 1.15)
<< " The datarate for the file missed the target!"
<< cfg_.rc_target_bitrate << " "<< effective_datarate_;
}
@@ -334,6 +422,7 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) {
cfg_.rc_max_quantizer = 50;
cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_target_bitrate = 200;
+ cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
@@ -345,10 +434,10 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) {
cfg_.rc_dropframe_thresh = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85)
- << " The datarate for the file is lower than target by too much!";
- ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.15)
- << " The datarate for the file is greater than target by too much!";
+ ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
+ << " The datarate for the file is lower than target by too much!";
+ ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
+ << " The datarate for the file is greater than target by too much!";
ASSERT_LE(first_drop_, last_drop)
<< " The first dropped frame for drop_thresh " << i
<< " > first dropped frame for drop_thresh "
@@ -362,6 +451,84 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) {
}
}
+// Check basic rate targeting for 2 temporal layers.
+TEST_P(DatarateTestVP9, BasicRateTargeting2TemporalLayers) {
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_dropframe_thresh = 1;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+
+ // 2 Temporal layers, no spatial layers: Framerate decimation (2, 1).
+ cfg_.ss_number_layers = 1;
+ cfg_.ts_number_layers = 2;
+ cfg_.ts_rate_decimator[0] = 2;
+ cfg_.ts_rate_decimator[1] = 1;
+
+ ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
+ 30, 1, 0, 200);
+ for (int i = 200; i <= 800; i += 200) {
+ cfg_.rc_target_bitrate = i;
+ ResetModel();
+ // 60-40 bitrate allocation for 2 temporal layers.
+ cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
+ cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
+ ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
+ << " The datarate for the file is lower than target by too much, "
+ "for layer: " << j;
+ ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
+ << " The datarate for the file is greater than target by too much, "
+ "for layer: " << j;
+ }
+ }
+}
+
+// Check basic rate targeting for 3 temporal layers.
+TEST_P(DatarateTestVP9, DISABLED_BasicRateTargeting3TemporalLayers) {
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ // TODO(marpan): For now keep frame dropper off. Need to investigate an
+ // issue (rate-mismatch) that occcurs at speed 3 and low bitrate (200k) when
+ // frame dropper is on.
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+
+ // 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1).
+ cfg_.ss_number_layers = 1;
+ cfg_.ts_number_layers = 3;
+ cfg_.ts_rate_decimator[0] = 4;
+ cfg_.ts_rate_decimator[1] = 2;
+ cfg_.ts_rate_decimator[2] = 1;
+
+ ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
+ 30, 1, 0, 200);
+ for (int i = 200; i <= 800; i += 200) {
+ cfg_.rc_target_bitrate = i;
+ ResetModel();
+ // 40-20-40 bitrate allocation for 3 temporal layers.
+ cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
+ cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
+ cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
+ ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
+ << " The datarate for the file is lower than target by too much, "
+ "for layer: " << j;
+ ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
+ << " The datarate for the file is greater than target by too much, "
+ "for layer: " << j;
+ }
+ }
+}
VP8_INSTANTIATE_TEST_CASE(DatarateTest, ALL_TEST_MODES);
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9,
::testing::Values(::libvpx_test::kOnePassGood),
diff --git a/test/dct16x16_test.cc b/test/dct16x16_test.cc
index ce0431860..8d115fad3 100644
--- a/test/dct16x16_test.cc
+++ b/test/dct16x16_test.cc
@@ -273,7 +273,7 @@ void fdct16x16_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
}
void fht16x16_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
- vp9_short_fht16x16_c(in, out, stride, tx_type);
+ vp9_fht16x16_c(in, out, stride, tx_type);
}
class Trans16x16TestBase {
@@ -507,10 +507,10 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
C, Trans16x16HT,
::testing::Values(
- make_tuple(&vp9_short_fht16x16_c, &vp9_iht16x16_256_add_c, 0),
- make_tuple(&vp9_short_fht16x16_c, &vp9_iht16x16_256_add_c, 1),
- make_tuple(&vp9_short_fht16x16_c, &vp9_iht16x16_256_add_c, 2),
- make_tuple(&vp9_short_fht16x16_c, &vp9_iht16x16_256_add_c, 3)));
+ make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 0),
+ make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 1),
+ make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 2),
+ make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 3)));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(
@@ -521,9 +521,9 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16HT,
::testing::Values(
- make_tuple(&vp9_short_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 0),
- make_tuple(&vp9_short_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 1),
- make_tuple(&vp9_short_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 2),
- make_tuple(&vp9_short_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 3)));
+ make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 0),
+ make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 1),
+ make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 2),
+ make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 3)));
#endif
} // namespace
diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h
index 4dabcd5b4..8017a2a06 100644
--- a/test/encode_test_driver.h
+++ b/test/encode_test_driver.h
@@ -123,6 +123,11 @@ class Encoder {
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
+ void Control(int ctrl_id, struct vpx_svc_layer_id *arg) {
+ const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
+ ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
+ }
+
void set_deadline(unsigned long deadline) {
deadline_ = deadline;
}
diff --git a/test/fdct4x4_test.cc b/test/fdct4x4_test.cc
index 5db5f5cae..dc6668759 100644
--- a/test/fdct4x4_test.cc
+++ b/test/fdct4x4_test.cc
@@ -45,7 +45,7 @@ void fdct4x4_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
}
void fht4x4_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
- vp9_short_fht4x4_c(in, out, stride, tx_type);
+ vp9_fht4x4_c(in, out, stride, tx_type);
}
class Trans4x4TestBase {
@@ -281,10 +281,10 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
C, Trans4x4HT,
::testing::Values(
- make_tuple(&vp9_short_fht4x4_c, &vp9_iht4x4_16_add_c, 0),
- make_tuple(&vp9_short_fht4x4_c, &vp9_iht4x4_16_add_c, 1),
- make_tuple(&vp9_short_fht4x4_c, &vp9_iht4x4_16_add_c, 2),
- make_tuple(&vp9_short_fht4x4_c, &vp9_iht4x4_16_add_c, 3)));
+ make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 0),
+ make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 1),
+ make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 2),
+ make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 3)));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(
@@ -295,10 +295,10 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4HT,
::testing::Values(
- make_tuple(&vp9_short_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 0),
- make_tuple(&vp9_short_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 1),
- make_tuple(&vp9_short_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 2),
- make_tuple(&vp9_short_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 3)));
+ make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 0),
+ make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 1),
+ make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 2),
+ make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 3)));
#endif
} // namespace
diff --git a/test/fdct8x8_test.cc b/test/fdct8x8_test.cc
index beef98055..98aabe6a2 100644
--- a/test/fdct8x8_test.cc
+++ b/test/fdct8x8_test.cc
@@ -44,7 +44,7 @@ void fdct8x8_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
}
void fht8x8_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
- vp9_short_fht8x8_c(in, out, stride, tx_type);
+ vp9_fht8x8_c(in, out, stride, tx_type);
}
class FwdTrans8x8TestBase {
@@ -308,10 +308,10 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
C, FwdTrans8x8HT,
::testing::Values(
- make_tuple(&vp9_short_fht8x8_c, &vp9_iht8x8_64_add_c, 0),
- make_tuple(&vp9_short_fht8x8_c, &vp9_iht8x8_64_add_c, 1),
- make_tuple(&vp9_short_fht8x8_c, &vp9_iht8x8_64_add_c, 2),
- make_tuple(&vp9_short_fht8x8_c, &vp9_iht8x8_64_add_c, 3)));
+ make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0),
+ make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1),
+ make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2),
+ make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3)));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(
@@ -321,9 +321,9 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8HT,
::testing::Values(
- make_tuple(&vp9_short_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 0),
- make_tuple(&vp9_short_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 1),
- make_tuple(&vp9_short_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 2),
- make_tuple(&vp9_short_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 3)));
+ make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 0),
+ make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 1),
+ make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 2),
+ make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 3)));
#endif
} // namespace
diff --git a/third_party/libmkv/Makefile b/third_party/libmkv/Makefile
index b53377b21..71aee2397 100644
--- a/third_party/libmkv/Makefile
+++ b/third_party/libmkv/Makefile
@@ -1,8 +1,9 @@
#Variables
CC=gcc
LINKER=gcc
-FLAGS=
+FLAGS=-g -Wall
+all: testlibmkv
#Build Targets
EbmlWriter.o: EbmlWriter.c EbmlWriter.h
@@ -10,16 +11,15 @@ EbmlWriter.o: EbmlWriter.c EbmlWriter.h
EbmlBufferWriter.o: EbmlBufferWriter.c EbmlBufferWriter.h
$(CC) $(FLAGS) -c EbmlBufferWriter.c
-
-MkvElement.o: MkvElement.c WebMElement.h
- $(CC) $(FLAGS) -c MkvElement.c
-
+
+WebMElement.o: WebMElement.c WebMElement.h
+ $(CC) $(FLAGS) -c WebMElement.c
+
testlibmkv.o: testlibmkv.c
$(CC) $(FLAGS) -c testlibmkv.c
-
-testlibmkv: testlibmkv.o MkvElement.o EbmlBufferWriter.o EbmlWriter.o
- $(LINKER) $(FLAGS) testlibmkv.o MkvElement.o EbmlBufferWriter.o EbmlWriter.o -o testlibmkv
+
+testlibmkv: testlibmkv.o WebMElement.o EbmlBufferWriter.o EbmlWriter.o
+ $(LINKER) $(FLAGS) -o testlibmkv testlibmkv.o WebMElement.o EbmlBufferWriter.o EbmlWriter.o
clean:
rm -rf *.o testlibmkv
- \ No newline at end of file
diff --git a/third_party/libmkv/WebMElement.c b/third_party/libmkv/WebMElement.c
index 2f79a3c6a..6c3670a28 100644
--- a/third_party/libmkv/WebMElement.c
+++ b/third_party/libmkv/WebMElement.c
@@ -11,6 +11,7 @@
#include "EbmlIDs.h"
#include "WebMElement.h"
#include <stdio.h>
+#include "vpx/vpx_integer.h"
#define kVorbisPrivateMaxSize 4000
@@ -43,22 +44,23 @@ void writeSimpleBlock(EbmlGlobal *glob, unsigned char trackNumber, short timeCod
Ebml_Write(glob, data, dataLength);
}
-static UInt64 generateTrackID(unsigned int trackNumber) {
- UInt64 t = time(NULL) * trackNumber;
- UInt64 r = rand();
+static uint64_t generateTrackID(unsigned int trackNumber) {
+ uint64_t t = time(NULL) * trackNumber;
+ uint64_t r = rand();
r = r << 32;
r += rand();
- UInt64 rval = t ^ r;
+ uint64_t rval = t ^ r;
return rval;
}
-void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
- char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
+void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber,
+ int flagLacing, const char *codecId,
+ unsigned int pixelWidth, unsigned int pixelHeight,
double frameRate) {
EbmlLoc start;
Ebml_StartSubElement(glob, &start, TrackEntry);
Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
- UInt64 trackID = generateTrackID(trackNumber);
+ uint64_t trackID = generateTrackID(trackNumber);
Ebml_SerializeUnsigned(glob, TrackUID, trackID);
Ebml_SerializeString(glob, CodecName, "VP8"); // TODO shouldn't be fixed
@@ -74,13 +76,14 @@ void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
}
Ebml_EndSubElement(glob, &start); // Track Entry
}
-void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
- char *codecId, double samplingFrequency, unsigned int channels,
+void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber,
+ int flagLacing, const char *codecId,
+ double samplingFrequency, unsigned int channels,
unsigned char *private, unsigned long privateSize) {
EbmlLoc start;
Ebml_StartSubElement(glob, &start, TrackEntry);
Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
- UInt64 trackID = generateTrackID(trackNumber);
+ uint64_t trackID = generateTrackID(trackNumber);
Ebml_SerializeUnsigned(glob, TrackUID, trackID);
Ebml_SerializeUnsigned(glob, TrackType, 2); // audio is always 2
// I am using defaults for thesed required fields
diff --git a/third_party/libmkv/WebMElement.h b/third_party/libmkv/WebMElement.h
index dd6e50590..0e5ec2036 100644
--- a/third_party/libmkv/WebMElement.h
+++ b/third_party/libmkv/WebMElement.h
@@ -12,19 +12,21 @@
// these are helper functions
void writeHeader(EbmlGlobal *ebml);
-void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration);
+void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo,
+ unsigned long timeCodeScale, double duration);
// this function is a helper only, it assumes a lot of defaults
-void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing,
- char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
+void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber,
+ int flagLacing, const char *codecId,
+ unsigned int pixelWidth, unsigned int pixelHeight,
double frameRate);
-void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
- char *codecId, double samplingFrequency, unsigned int channels,
+void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber,
+ int flagLacing, const char *codecId,
+ double samplingFrequency, unsigned int channels,
unsigned char *private, unsigned long privateSize);
-void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode,
- int isKeyframe, unsigned char lacingFlag, int discardable,
+void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber,
+ short timeCode, int isKeyframe,
+ unsigned char lacingFlag, int discardable,
unsigned char *data, unsigned long dataLength);
-
-
-#endif \ No newline at end of file
+#endif
diff --git a/tools/diff.py b/tools/diff.py
index a42a4dc7c..a96c7db85 100644
--- a/tools/diff.py
+++ b/tools/diff.py
@@ -56,6 +56,9 @@ class DiffHunk(object):
elif line[0] == " ":
self.left.Append(line)
self.right.Append(line)
+ elif line[0] == "\\":
+ # Ignore newline messages from git diff.
+ pass
else:
assert False, ("Unrecognized character at start of diff line "
"%r" % line[0])
diff --git a/tools_common.c b/tools_common.c
index 85bedc99d..53546878b 100644
--- a/tools_common.c
+++ b/tools_common.c
@@ -168,9 +168,31 @@ void vpx_img_write(const vpx_image_t *img, FILE *file) {
const int stride = img->stride[plane];
const int w = plane ? (img->d_w + 1) >> 1 : img->d_w;
const int h = plane ? (img->d_h + 1) >> 1 : img->d_h;
+
for (y = 0; y < h; ++y) {
fwrite(buf, 1, w, file);
buf += stride;
}
}
}
+
+int vpx_img_read(vpx_image_t *img, FILE *file) {
+ int plane;
+
+ for (plane = 0; plane < 3; ++plane) {
+ unsigned char *buf = img->planes[plane];
+ const int stride = img->stride[plane];
+ const int w = plane ? (img->d_w + 1) >> 1 : img->d_w;
+ const int h = plane ? (img->d_h + 1) >> 1 : img->d_h;
+ int y;
+
+ for (y = 0; y < h; ++y) {
+ if (fread(buf, 1, w, file) != w)
+ return 0;
+ buf += stride;
+ }
+ }
+
+ return 1;
+}
+
diff --git a/tools_common.h b/tools_common.h
index 967b7a1fb..0f60c4c3a 100644
--- a/tools_common.h
+++ b/tools_common.h
@@ -129,6 +129,10 @@ vpx_codec_iface_t *get_codec_interface(unsigned int fourcc);
// of vpx_image_t support
void vpx_img_write(const vpx_image_t *img, FILE *file);
+// TODO(dkovalev): move this function to vpx_image.{c, h}, so it will be part
+// of vpx_image_t support
+int vpx_img_read(vpx_image_t *img, FILE *file);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/video_common.h b/video_common.h
new file mode 100644
index 000000000..44b27a839
--- /dev/null
+++ b/video_common.h
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+#ifndef VIDEO_COMMON_H_
+#define VIDEO_COMMON_H_
+
+#include "./tools_common.h"
+
+typedef struct {
+ uint32_t codec_fourcc;
+ int frame_width;
+ int frame_height;
+ struct VpxRational time_base;
+} VpxVideoInfo;
+
+#endif // VIDEO_COMMON_H_
diff --git a/video_reader.c b/video_reader.c
new file mode 100644
index 000000000..4be7483d3
--- /dev/null
+++ b/video_reader.c
@@ -0,0 +1,81 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "./ivfdec.h"
+#include "./video_reader.h"
+
+static const char *const kIVFSignature = "DKIF";
+
+struct VpxVideoReaderStruct {
+ VpxVideoInfo info;
+ FILE *file;
+ uint8_t *buffer;
+ size_t buffer_size;
+ size_t frame_size;
+};
+
+VpxVideoReader *vpx_video_reader_open(const char *filename) {
+ char header[32];
+ VpxVideoReader *reader = NULL;
+ FILE *const file = fopen(filename, "rb");
+ if (!file)
+ return NULL; // Can't open file
+
+ if (fread(header, 1, 32, file) != 32)
+ return NULL; // Can't read file header
+
+ if (memcmp(kIVFSignature, header, 4) != 0)
+ return NULL; // Wrong IVF signature
+
+ if (mem_get_le16(header + 4) != 0)
+ return NULL; // Wrong IVF version
+
+ reader = calloc(1, sizeof(*reader));
+ if (!reader)
+ return NULL; // Can't allocate VpxVideoReader
+
+ reader->file = file;
+ reader->info.codec_fourcc = mem_get_le32(header + 8);
+ reader->info.frame_width = mem_get_le16(header + 12);
+ reader->info.frame_height = mem_get_le16(header + 14);
+ reader->info.time_base.numerator = mem_get_le32(header + 16);
+ reader->info.time_base.denominator = mem_get_le32(header + 20);
+
+ return reader;
+}
+
+void vpx_video_reader_close(VpxVideoReader *reader) {
+ if (reader) {
+ fclose(reader->file);
+ free(reader->buffer);
+ free(reader);
+ }
+}
+
+int vpx_video_reader_read_frame(VpxVideoReader *reader) {
+ return !ivf_read_frame(reader->file, &reader->buffer, &reader->frame_size,
+ &reader->buffer_size);
+}
+
+const uint8_t *vpx_video_reader_get_frame(VpxVideoReader *reader,
+ size_t *size) {
+ if (size)
+ *size = reader->frame_size;
+
+ return reader->buffer;
+}
+
+const VpxVideoInfo *vpx_video_reader_get_info(VpxVideoReader *reader) {
+ return &reader->info;
+}
+
diff --git a/video_reader.h b/video_reader.h
new file mode 100644
index 000000000..a62c6d710
--- /dev/null
+++ b/video_reader.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef VIDEO_READER_H_
+#define VIDEO_READER_H_
+
+#include "./video_common.h"
+
+// The following code is work in progress. It is going to support transparent
+// reading of input files. Right now only IVF format is supported for
+// simplicity. The main goal the API is to be simple and easy to use in example
+// code and in vpxenc/vpxdec later. All low-level details like memory
+// buffer management are hidden from API users.
+struct VpxVideoReaderStruct;
+typedef struct VpxVideoReaderStruct VpxVideoReader;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Opens the input file for reading and inspects it to determine file type.
+// Returns an opaque VpxVideoReader* upon success, or NULL upon failure.
+// Right now only IVF format is supported.
+VpxVideoReader *vpx_video_reader_open(const char *filename);
+
+// Frees all resources associated with VpxVideoReader* returned from
+// vpx_video_reader_open() call.
+void vpx_video_reader_close(VpxVideoReader *reader);
+
+// Reads frame from the file and stores it in internal buffer.
+int vpx_video_reader_read_frame(VpxVideoReader *reader);
+
+// Returns the pointer to memory buffer with frame data read by last call to
+// vpx_video_reader_read_frame().
+const uint8_t *vpx_video_reader_get_frame(VpxVideoReader *reader,
+ size_t *size);
+
+// Fills VpxVideoInfo with information from opened video file.
+const VpxVideoInfo *vpx_video_reader_get_info(VpxVideoReader *reader);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VIDEO_READER_H_
diff --git a/video_writer.c b/video_writer.c
new file mode 100644
index 000000000..3695236bf
--- /dev/null
+++ b/video_writer.c
@@ -0,0 +1,80 @@
+/*
+ * 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 <stdlib.h>
+
+#include "./ivfenc.h"
+#include "./video_writer.h"
+#include "vpx/vpx_encoder.h"
+
+struct VpxVideoWriterStruct {
+ VpxVideoInfo info;
+ FILE *file;
+ int frame_count;
+};
+
+static void write_header(FILE *file, const VpxVideoInfo *info,
+ int frame_count) {
+ struct vpx_codec_enc_cfg cfg;
+ cfg.g_w = info->frame_width;
+ cfg.g_h = info->frame_height;
+ cfg.g_timebase.num = info->time_base.numerator;
+ cfg.g_timebase.den = info->time_base.denominator;
+
+ ivf_write_file_header(file, &cfg, info->codec_fourcc, frame_count);
+}
+
+VpxVideoWriter *vpx_video_writer_open(const char *filename,
+ VpxContainer container,
+ const VpxVideoInfo *info) {
+ if (container == kContainerIVF) {
+ VpxVideoWriter *writer = NULL;
+ FILE *const file = fopen(filename, "wb");
+ if (!file)
+ return NULL;
+
+ writer = malloc(sizeof(*writer));
+ if (!writer)
+ return NULL;
+
+ writer->frame_count = 0;
+ writer->info = *info;
+ writer->file = file;
+
+ write_header(writer->file, info, 0);
+
+ return writer;
+ }
+
+ return NULL;
+}
+
+void vpx_video_writer_close(VpxVideoWriter *writer) {
+ if (writer) {
+ // Rewriting frame header with real frame count
+ rewind(writer->file);
+ write_header(writer->file, &writer->info, writer->frame_count);
+
+ fclose(writer->file);
+ free(writer);
+ }
+}
+
+int vpx_video_writer_write_frame(VpxVideoWriter *writer,
+ const uint8_t *buffer, size_t size,
+ int64_t pts) {
+ ivf_write_frame_header(writer->file, pts, size);
+ if (fwrite(buffer, 1, size, writer->file) != size)
+ return 0;
+
+ ++writer->frame_count;
+
+ return 1;
+}
diff --git a/video_writer.h b/video_writer.h
new file mode 100644
index 000000000..5dbfe52ea
--- /dev/null
+++ b/video_writer.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef VIDEO_WRITER_H_
+#define VIDEO_WRITER_H_
+
+#include "./video_common.h"
+
+typedef enum {
+ kContainerIVF
+} VpxContainer;
+
+struct VpxVideoWriterStruct;
+typedef struct VpxVideoWriterStruct VpxVideoWriter;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Finds and opens writer for specified container format.
+// Returns an opaque VpxVideoWriter* upon success, or NULL upon failure.
+// Right now only IVF format is supported.
+VpxVideoWriter *vpx_video_writer_open(const char *filename,
+ VpxContainer container,
+ const VpxVideoInfo *info);
+
+// Frees all resources associated with VpxVideoWriter* returned from
+// vpx_video_writer_open() call.
+void vpx_video_writer_close(VpxVideoWriter *writer);
+
+// Writes frame bytes to the file.
+int vpx_video_writer_write_frame(VpxVideoWriter *writer,
+ const uint8_t *buffer, size_t size,
+ int64_t pts);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VIDEO_WRITER_H_
diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c
index 968c7f365..afcda9f34 100644
--- a/vp8/encoder/firstpass.c
+++ b/vp8/encoder/firstpass.c
@@ -940,9 +940,9 @@ static int64_t estimate_modemvcost(VP8_COMP *cpi,
/* Crude estimate of overhead cost from modes
* << 9 is the normalization to (bits * 512) used in vp8_bits_per_mb
*/
- mode_cost =((((av_pct_inter - av_pct_motion) * zz_cost) +
- (av_pct_motion * motion_cost) +
- (av_intra * intra_cost)) * cpi->common.MBs) * 512;
+ mode_cost = (int64_t)((((av_pct_inter - av_pct_motion) * zz_cost) +
+ (av_pct_motion * motion_cost) +
+ (av_intra * intra_cost)) * cpi->common.MBs) * 512;
return mv_cost + mode_cost;
}
@@ -2310,7 +2310,7 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
pct_extra = (pct_extra > 20) ? 20 : pct_extra;
cpi->twopass.alt_extra_bits =
- (cpi->twopass.gf_group_bits * pct_extra) / 100;
+ (int)(cpi->twopass.gf_group_bits * pct_extra) / 100;
cpi->twopass.gf_group_bits -= cpi->twopass.alt_extra_bits;
cpi->twopass.alt_extra_bits /=
((cpi->baseline_gf_interval-1)>>1);
@@ -2386,7 +2386,7 @@ static void assign_std_frame_bits(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
target_frame_size = max_bits;
if (target_frame_size > cpi->twopass.gf_group_bits)
- target_frame_size = cpi->twopass.gf_group_bits;
+ target_frame_size = (int)cpi->twopass.gf_group_bits;
}
/* Adjust error and bits remaining */
diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c
index 19e9d2701..ce789e218 100644
--- a/vp8/vp8_cx_iface.c
+++ b/vp8/vp8_cx_iface.c
@@ -414,7 +414,6 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf,
printf("Sharpness: %d\n", oxcf->Sharpness);
printf("cpu_used: %d\n", oxcf->cpu_used);
printf("Mode: %d\n", oxcf->Mode);
- printf("delete_first_pass_file: %d\n", oxcf->delete_first_pass_file);
printf("auto_key: %d\n", oxcf->auto_key);
printf("key_freq: %d\n", oxcf->key_freq);
printf("end_usage: %d\n", oxcf->end_usage);
@@ -751,9 +750,6 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
if (!ctx->cfg.rc_target_bitrate)
return res;
- if (!ctx->cfg.rc_target_bitrate)
- return res;
-
if (img)
res = validate_img(ctx, img);
@@ -1266,7 +1262,6 @@ static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] =
128, /* kf_max_dist */
#if VPX_ENCODER_ABI_VERSION == (1 + VPX_CODEC_ABI_VERSION)
- 1, /* g_delete_first_pass_file */
"vp8.fpf" /* first pass filename */
#endif
VPX_SS_DEFAULT_LAYERS, /* ss_number_layers */
diff --git a/vp8_scalable_patterns.c b/vp8_scalable_patterns.c
deleted file mode 100644
index 06270fecb..000000000
--- a/vp8_scalable_patterns.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * Copyright (c) 2012 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 is an example demonstrating how to implement a multi-layer VP8
- * encoding scheme based on temporal scalability for video applications
- * that benefit from a scalable bitstream.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#define VPX_CODEC_DISABLE_COMPAT 1
-#include "vpx/vpx_encoder.h"
-#include "vpx/vp8cx.h"
-#define interface (vpx_codec_vp8_cx())
-#define fourcc 0x30385056
-
-#define IVF_FILE_HDR_SZ (32)
-#define IVF_FRAME_HDR_SZ (12)
-
-static void mem_put_le16(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
-}
-
-static void mem_put_le32(char *mem, unsigned int val) {
- mem[0] = val;
- mem[1] = val>>8;
- mem[2] = val>>16;
- mem[3] = val>>24;
-}
-
-static void die(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- vprintf(fmt, ap);
- if(fmt[strlen(fmt)-1] != '\n')
- printf("\n");
- exit(EXIT_FAILURE);
-}
-
-static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
- const char *detail = vpx_codec_error_detail(ctx);
-
- printf("%s: %s\n", s, vpx_codec_error(ctx));
- if(detail)
- printf(" %s\n",detail);
- exit(EXIT_FAILURE);
-}
-
-static int read_frame(FILE *f, vpx_image_t *img) {
- size_t nbytes, to_read;
- int res = 1;
-
- to_read = img->w*img->h*3/2;
- nbytes = fread(img->planes[0], 1, to_read, f);
- if(nbytes != to_read) {
- res = 0;
- if(nbytes > 0)
- printf("Warning: Read partial frame. Check your width & height!\n");
- }
- return res;
-}
-
-static void write_ivf_file_header(FILE *outfile,
- const vpx_codec_enc_cfg_t *cfg,
- int frame_cnt) {
- char header[32];
-
- if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
- return;
- header[0] = 'D';
- header[1] = 'K';
- header[2] = 'I';
- header[3] = 'F';
- mem_put_le16(header+4, 0); /* version */
- mem_put_le16(header+6, 32); /* headersize */
- mem_put_le32(header+8, fourcc); /* headersize */
- mem_put_le16(header+12, cfg->g_w); /* width */
- mem_put_le16(header+14, cfg->g_h); /* height */
- mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
- mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
- mem_put_le32(header+24, frame_cnt); /* length */
- mem_put_le32(header+28, 0); /* unused */
-
- (void) fwrite(header, 1, 32, outfile);
-}
-
-
-static void write_ivf_frame_header(FILE *outfile,
- const vpx_codec_cx_pkt_t *pkt)
-{
- char header[12];
- vpx_codec_pts_t pts;
-
- if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
- return;
-
- pts = pkt->data.frame.pts;
- mem_put_le32(header, pkt->data.frame.sz);
- mem_put_le32(header+4, pts&0xFFFFFFFF);
- mem_put_le32(header+8, pts >> 32);
-
- (void) fwrite(header, 1, 12, outfile);
-}
-
-static int mode_to_num_layers[12] = {1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3};
-
-int main(int argc, char **argv) {
- FILE *infile, *outfile[VPX_TS_MAX_LAYERS];
- vpx_codec_ctx_t codec;
- vpx_codec_enc_cfg_t cfg;
- int frame_cnt = 0;
- vpx_image_t raw;
- vpx_codec_err_t res;
- unsigned int width;
- unsigned int height;
- int frame_avail;
- int got_data;
- int flags = 0;
- int i;
- int pts = 0; /* PTS starts at 0 */
- int frame_duration = 1; /* 1 timebase tick per frame */
-
- int layering_mode = 0;
- int frames_in_layer[VPX_TS_MAX_LAYERS] = {0};
- int layer_flags[VPX_TS_MAX_PERIODICITY] = {0};
- int flag_periodicity;
- int max_intra_size_pct;
-
- /* Check usage and arguments */
- if (argc < 9)
- die("Usage: %s <infile> <outfile> <width> <height> <rate_num> "
- " <rate_den> <mode> <Rate_0> ... <Rate_nlayers-1>\n", argv[0]);
-
- width = strtol (argv[3], NULL, 0);
- height = strtol (argv[4], NULL, 0);
- if (width < 16 || width%2 || height <16 || height%2)
- die ("Invalid resolution: %d x %d", width, height);
-
- if (!sscanf(argv[7], "%d", &layering_mode))
- die ("Invalid mode %s", argv[7]);
- if (layering_mode<0 || layering_mode>11)
- die ("Invalid mode (0..11) %s", argv[7]);
-
- if (argc != 8+mode_to_num_layers[layering_mode])
- die ("Invalid number of arguments");
-
- if (!vpx_img_alloc (&raw, VPX_IMG_FMT_I420, width, height, 32))
- die ("Failed to allocate image", width, height);
-
- printf("Using %s\n",vpx_codec_iface_name(interface));
-
- /* Populate encoder configuration */
- res = vpx_codec_enc_config_default(interface, &cfg, 0);
- if(res) {
- printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
- return EXIT_FAILURE;
- }
-
- /* Update the default configuration with our settings */
- cfg.g_w = width;
- cfg.g_h = height;
-
- /* Timebase format e.g. 30fps: numerator=1, demoninator=30 */
- if (!sscanf (argv[5], "%d", &cfg.g_timebase.num ))
- die ("Invalid timebase numerator %s", argv[5]);
- if (!sscanf (argv[6], "%d", &cfg.g_timebase.den ))
- die ("Invalid timebase denominator %s", argv[6]);
-
- for (i=8; i<8+mode_to_num_layers[layering_mode]; i++)
- if (!sscanf(argv[i], "%ud", &cfg.ts_target_bitrate[i-8]))
- die ("Invalid data rate %s", argv[i]);
-
- /* Real time parameters */
- cfg.rc_dropframe_thresh = 0;
- cfg.rc_end_usage = VPX_CBR;
- cfg.rc_resize_allowed = 0;
- cfg.rc_min_quantizer = 2;
- cfg.rc_max_quantizer = 56;
- cfg.rc_undershoot_pct = 100;
- cfg.rc_overshoot_pct = 15;
- cfg.rc_buf_initial_sz = 500;
- cfg.rc_buf_optimal_sz = 600;
- cfg.rc_buf_sz = 1000;
-
- /* Enable error resilient mode */
- cfg.g_error_resilient = 1;
- cfg.g_lag_in_frames = 0;
- cfg.kf_mode = VPX_KF_DISABLED;
-
- /* Disable automatic keyframe placement */
- cfg.kf_min_dist = cfg.kf_max_dist = 3000;
-
- /* Default setting for bitrate: used in special case of 1 layer (case 0). */
- cfg.rc_target_bitrate = cfg.ts_target_bitrate[0];
-
- /* Temporal scaling parameters: */
- /* NOTE: The 3 prediction frames cannot be used interchangeably due to
- * differences in the way they are handled throughout the code. The
- * frames should be allocated to layers in the order LAST, GF, ARF.
- * Other combinations work, but may produce slightly inferior results.
- */
- switch (layering_mode)
- {
- case 0:
- {
- /* 1-layer */
- int ids[1] = {0};
- cfg.ts_number_layers = 1;
- cfg.ts_periodicity = 1;
- cfg.ts_rate_decimator[0] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = cfg.ts_periodicity;
-
- // Update L only.
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- break;
- }
- case 1:
- {
- /* 2-layers, 2-frame period */
- int ids[2] = {0,1};
- cfg.ts_number_layers = 2;
- cfg.ts_periodicity = 2;
- cfg.ts_rate_decimator[0] = 2;
- cfg.ts_rate_decimator[1] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = cfg.ts_periodicity;
-#if 1
- /* 0=L, 1=GF, Intra-layer prediction enabled */
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
- layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_REF_ARF;
-#else
- /* 0=L, 1=GF, Intra-layer prediction disabled */
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
- layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST;
-#endif
- break;
- }
-
- case 2:
- {
- /* 2-layers, 3-frame period */
- int ids[3] = {0,1,1};
- cfg.ts_number_layers = 2;
- cfg.ts_periodicity = 3;
- cfg.ts_rate_decimator[0] = 3;
- cfg.ts_rate_decimator[1] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = cfg.ts_periodicity;
-
- /* 0=L, 1=GF, Intra-layer prediction enabled */
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[1] =
- layer_flags[2] = VP8_EFLAG_NO_REF_GF |
- VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST;
- break;
- }
-
- case 3:
- {
- /* 3-layers, 6-frame period */
- int ids[6] = {0,2,2,1,2,2};
- cfg.ts_number_layers = 3;
- cfg.ts_periodicity = 6;
- cfg.ts_rate_decimator[0] = 6;
- cfg.ts_rate_decimator[1] = 3;
- cfg.ts_rate_decimator[2] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = cfg.ts_periodicity;
-
- /* 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled */
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST;
- layer_flags[1] =
- layer_flags[2] =
- layer_flags[4] =
- layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
- break;
- }
-
- case 4:
- {
- /* 3-layers, 4-frame period */
- int ids[4] = {0,2,1,2};
- cfg.ts_number_layers = 3;
- cfg.ts_periodicity = 4;
- cfg.ts_rate_decimator[0] = 4;
- cfg.ts_rate_decimator[1] = 2;
- cfg.ts_rate_decimator[2] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = cfg.ts_periodicity;
-
- /* 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled */
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST;
- layer_flags[1] =
- layer_flags[3] = VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF;
- break;
- }
-
- case 5:
- {
- /* 3-layers, 4-frame period */
- int ids[4] = {0,2,1,2};
- cfg.ts_number_layers = 3;
- cfg.ts_periodicity = 4;
- cfg.ts_rate_decimator[0] = 4;
- cfg.ts_rate_decimator[1] = 2;
- cfg.ts_rate_decimator[2] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = cfg.ts_periodicity;
-
- /* 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1,
- * disabled in layer 2
- */
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[2] = VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[1] =
- layer_flags[3] = VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF;
- break;
- }
-
- case 6:
- {
- /* 3-layers, 4-frame period */
- int ids[4] = {0,2,1,2};
- cfg.ts_number_layers = 3;
- cfg.ts_periodicity = 4;
- cfg.ts_rate_decimator[0] = 4;
- cfg.ts_rate_decimator[1] = 2;
- cfg.ts_rate_decimator[2] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = cfg.ts_periodicity;
-
- /* 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled */
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[2] = VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[1] =
- layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
- break;
- }
-
- case 7:
- {
- /* NOTE: Probably of academic interest only */
-
- /* 5-layers, 16-frame period */
- int ids[16] = {0,4,3,4,2,4,3,4,1,4,3,4,2,4,3,4};
- cfg.ts_number_layers = 5;
- cfg.ts_periodicity = 16;
- cfg.ts_rate_decimator[0] = 16;
- cfg.ts_rate_decimator[1] = 8;
- cfg.ts_rate_decimator[2] = 4;
- cfg.ts_rate_decimator[3] = 2;
- cfg.ts_rate_decimator[4] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = cfg.ts_periodicity;
-
- layer_flags[0] = VPX_EFLAG_FORCE_KF;
- layer_flags[1] =
- layer_flags[3] =
- layer_flags[5] =
- layer_flags[7] =
- layer_flags[9] =
- layer_flags[11] =
- layer_flags[13] =
- layer_flags[15] = VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF;
- layer_flags[2] =
- layer_flags[6] =
- layer_flags[10] =
- layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF;
- layer_flags[4] =
- layer_flags[12] = VP8_EFLAG_NO_REF_LAST |
- VP8_EFLAG_NO_UPD_ARF;
- layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF;
- break;
- }
-
- case 8:
- {
- /* 2-layers, with sync point at first frame of layer 1. */
- int ids[2] = {0,1};
- cfg.ts_number_layers = 2;
- cfg.ts_periodicity = 2;
- cfg.ts_rate_decimator[0] = 2;
- cfg.ts_rate_decimator[1] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = 8;
-
- /* 0=L, 1=GF */
- // ARF is used as predictor for all frames, and is only updated on
- // key frame. Sync point every 8 frames.
-
- // Layer 0: predict from L and ARF, update L and G.
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_REF_GF |
- VP8_EFLAG_NO_UPD_ARF;
-
- // Layer 1: sync point: predict from L and ARF, and update G.
- layer_flags[1] = VP8_EFLAG_NO_REF_GF |
- VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_UPD_ARF;
-
- // Layer 0, predict from L and ARF, update L.
- layer_flags[2] = VP8_EFLAG_NO_REF_GF |
- VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF;
-
- // Layer 1: predict from L, G and ARF, and update G.
- layer_flags[3] = VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_UPD_ENTROPY;
-
- // Layer 0
- layer_flags[4] = layer_flags[2];
-
- // Layer 1
- layer_flags[5] = layer_flags[3];
-
- // Layer 0
- layer_flags[6] = layer_flags[4];
-
- // Layer 1
- layer_flags[7] = layer_flags[5];
- break;
- }
-
- case 9:
- {
- /* 3-layers */
- // Sync points for layer 1 and 2 every 8 frames.
-
- int ids[4] = {0,2,1,2};
- cfg.ts_number_layers = 3;
- cfg.ts_periodicity = 4;
- cfg.ts_rate_decimator[0] = 4;
- cfg.ts_rate_decimator[1] = 2;
- cfg.ts_rate_decimator[2] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = 8;
-
- /* 0=L, 1=GF, 2=ARF */
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
- layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[3] =
- layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
- layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[6] = VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
- layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_ENTROPY;
- break;
- }
- case 10:
- {
- // 3-layers structure where ARF is used as predictor for all frames,
- // and is only updated on key frame.
- // Sync points for layer 1 and 2 every 8 frames.
-
- int ids[4] = {0,2,1,2};
- cfg.ts_number_layers = 3;
- cfg.ts_periodicity = 4;
- cfg.ts_rate_decimator[0] = 4;
- cfg.ts_rate_decimator[1] = 2;
- cfg.ts_rate_decimator[2] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = 8;
-
- /* 0=L, 1=GF, 2=ARF */
-
- // Layer 0: predict from L and ARF; update L and G.
- layer_flags[0] = VPX_EFLAG_FORCE_KF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_REF_GF;
-
- // Layer 2: sync point: predict from L and ARF; update none.
- layer_flags[1] = VP8_EFLAG_NO_REF_GF |
- VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_UPD_ENTROPY;
-
- // Layer 1: sync point: predict from L and ARF; update G.
- layer_flags[2] = VP8_EFLAG_NO_REF_GF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST;
-
- // Layer 2: predict from L, G, ARF; update none.
- layer_flags[3] = VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_UPD_ENTROPY;
-
- // Layer 0: predict from L and ARF; update L.
- layer_flags[4] = VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_REF_GF;
-
- // Layer 2: predict from L, G, ARF; update none.
- layer_flags[5] = layer_flags[3];
-
- // Layer 1: predict from L, G, ARF; update G.
- layer_flags[6] = VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST;
-
- // Layer 2: predict from L, G, ARF; update none.
- layer_flags[7] = layer_flags[3];
- break;
- }
- case 11:
- default:
- {
- // 3-layers structure as in case 10, but no sync/refresh points for
- // layer 1 and 2.
-
- int ids[4] = {0,2,1,2};
- cfg.ts_number_layers = 3;
- cfg.ts_periodicity = 4;
- cfg.ts_rate_decimator[0] = 4;
- cfg.ts_rate_decimator[1] = 2;
- cfg.ts_rate_decimator[2] = 1;
- memcpy(cfg.ts_layer_id, ids, sizeof(ids));
-
- flag_periodicity = 8;
-
- /* 0=L, 1=GF, 2=ARF */
-
- // Layer 0: predict from L and ARF; update L.
- layer_flags[0] = VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_REF_GF;
- layer_flags[4] = layer_flags[0];
-
- // Layer 1: predict from L, G, ARF; update G.
- layer_flags[2] = VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST;
- layer_flags[6] = layer_flags[2];
-
- // Layer 2: predict from L, G, ARF; update none.
- layer_flags[1] = VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF |
- VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_UPD_ENTROPY;
- layer_flags[3] = layer_flags[1];
- layer_flags[5] = layer_flags[1];
- layer_flags[7] = layer_flags[1];
- break;
- }
- }
-
- /* Open input file */
- if(!(infile = fopen(argv[1], "rb")))
- die("Failed to open %s for reading", argv[1]);
-
- /* Open an output file for each stream */
- for (i=0; i<cfg.ts_number_layers; i++)
- {
- char file_name[512];
- sprintf (file_name, "%s_%d.ivf", argv[2], i);
- if (!(outfile[i] = fopen(file_name, "wb")))
- die("Failed to open %s for writing", file_name);
- write_ivf_file_header(outfile[i], &cfg, 0);
- }
-
- /* Initialize codec */
- if (vpx_codec_enc_init (&codec, interface, &cfg, 0))
- die_codec (&codec, "Failed to initialize encoder");
-
- /* Cap CPU & first I-frame size */
- vpx_codec_control (&codec, VP8E_SET_CPUUSED, -6);
- vpx_codec_control (&codec, VP8E_SET_STATIC_THRESHOLD, 1);
- vpx_codec_control (&codec, VP8E_SET_NOISE_SENSITIVITY, 1);
- vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1);
-
- max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5)
- * ((double) cfg.g_timebase.den / cfg.g_timebase.num)
- / 10.0);
- /* printf ("max_intra_size_pct=%d\n", max_intra_size_pct); */
-
- vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT,
- max_intra_size_pct);
-
- frame_avail = 1;
- while (frame_avail || got_data) {
- vpx_codec_iter_t iter = NULL;
- const vpx_codec_cx_pkt_t *pkt;
-
- flags = layer_flags[frame_cnt % flag_periodicity];
-
- frame_avail = read_frame(infile, &raw);
- if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts,
- 1, flags, VPX_DL_REALTIME))
- die_codec(&codec, "Failed to encode frame");
-
- /* Reset KF flag */
- if (layering_mode != 7)
- layer_flags[0] &= ~VPX_EFLAG_FORCE_KF;
-
- got_data = 0;
- while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
- got_data = 1;
- switch (pkt->kind) {
- case VPX_CODEC_CX_FRAME_PKT:
- for (i=cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
- i<cfg.ts_number_layers; i++)
- {
- write_ivf_frame_header(outfile[i], pkt);
- (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
- outfile[i]);
- frames_in_layer[i]++;
- }
- break;
- default:
- break;
- }
- }
- frame_cnt++;
- pts += frame_duration;
- }
- fclose (infile);
-
- printf ("Processed %d frames.\n",frame_cnt-1);
- if (vpx_codec_destroy(&codec))
- die_codec (&codec, "Failed to destroy codec");
-
- /* Try to rewrite the output file headers with the actual frame count */
- for (i=0; i<cfg.ts_number_layers; i++)
- {
- if (!fseek(outfile[i], 0, SEEK_SET))
- write_ivf_file_header (outfile[i], &cfg, frames_in_layer[i]);
- fclose (outfile[i]);
- }
-
- return EXIT_SUCCESS;
-}
diff --git a/vp9/common/arm/neon/vp9_reconintra_neon.asm b/vp9/common/arm/neon/vp9_reconintra_neon.asm
index 279f678b1..4a49964d5 100644
--- a/vp9/common/arm/neon/vp9_reconintra_neon.asm
+++ b/vp9/common/arm/neon/vp9_reconintra_neon.asm
@@ -349,7 +349,7 @@ loop_h
vdup.u8 d0, r12
; preload 8 left
- vld1.8 d30, [r3]
+ vld1.8 {d30}, [r3]
; Load above 8 pixels
vld1.64 {d2}, [r2]
@@ -422,10 +422,10 @@ loop_h
vdup.u8 q0, r12
; Load above 8 pixels
- vld1.8 q1, [r2]
+ vld1.8 {q1}, [r2]
; preload 8 left into r12
- vld1.8 d18, [r3]!
+ vld1.8 {d18}, [r3]!
; Compute above - ytop_left
vsubl.u8 q2, d2, d0
@@ -492,7 +492,7 @@ loop_16x16_neon
vqshrun.s16 d23, q8, #0
vdup.16 q0, d20[2]
vdup.16 q8, d20[3]
- vld1.8 d18, [r3]! ; preload 8 left into r12
+ vld1.8 {d18}, [r3]! ; preload 8 left into r12
vmovl.u8 q10, d18
vst1.64 {d2,d3}, [r0], r1
vst1.64 {d22,d23}, [r0], r1
@@ -518,11 +518,11 @@ loop_16x16_neon
vdup.u8 q0, r12
; Load above 32 pixels
- vld1.8 q1, [r2]!
- vld1.8 q2, [r2]
+ vld1.8 {q1}, [r2]!
+ vld1.8 {q2}, [r2]
; preload 8 left pixels
- vld1.8 d26, [r3]!
+ vld1.8 {d26}, [r3]!
; Compute above - ytop_left
vsubl.u8 q8, d2, d0
@@ -621,7 +621,7 @@ loop_32x32_neon
vst1.64 {d0-d3}, [r0], r1
vqshrun.s16 d24, q12, #0
vqshrun.s16 d25, q13, #0
- vld1.8 d0, [r3]! ; preload 8 left pixels
+ vld1.8 {d0}, [r3]! ; preload 8 left pixels
vqshrun.s16 d26, q14, #0
vqshrun.s16 d27, q15, #0
vmovl.u8 q3, d0
diff --git a/vp9/common/mips/dspr2/vp9_common_dspr2.h b/vp9/common/mips/dspr2/vp9_common_dspr2.h
index 991d3c2b3..6ebea9f2f 100644
--- a/vp9/common/mips/dspr2/vp9_common_dspr2.h
+++ b/vp9/common/mips/dspr2/vp9_common_dspr2.h
@@ -85,8 +85,8 @@ static INLINE void vp9_prefetch_store_streamed(unsigned char *dst) {
);
}
-void vp9_idct32_1d_cols_add_blk_dspr2(int16_t *input, uint8_t *dest,
- int dest_stride);
+void vp9_idct32_cols_add_blk_dspr2(int16_t *input, uint8_t *dest,
+ int dest_stride);
void vp9_convolve2_horiz_dspr2(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
diff --git a/vp9/common/mips/dspr2/vp9_itrans16_dspr2.c b/vp9/common/mips/dspr2/vp9_itrans16_dspr2.c
index 1b2f5506a..19c582fd1 100644
--- a/vp9/common/mips/dspr2/vp9_itrans16_dspr2.c
+++ b/vp9/common/mips/dspr2/vp9_itrans16_dspr2.c
@@ -19,8 +19,8 @@
#include "vp9/common/mips/dspr2/vp9_common_dspr2.h"
#if HAVE_DSPR2
-static void idct16_1d_rows_dspr2(const int16_t *input, int16_t *output,
- uint32_t no_rows) {
+static void idct16_rows_dspr2(const int16_t *input, int16_t *output,
+ uint32_t no_rows) {
int i;
int step1_0, step1_1, step1_2, step1_3, step1_4, step1_5, step1_6, step1_7;
int step1_10, step1_11, step1_12, step1_13;
@@ -404,8 +404,8 @@ static void idct16_1d_rows_dspr2(const int16_t *input, int16_t *output,
}
}
-static void idct16_1d_cols_add_blk_dspr2(int16_t *input, uint8_t *dest,
- int dest_stride) {
+static void idct16_cols_add_blk_dspr2(int16_t *input, uint8_t *dest,
+ int dest_stride) {
int i;
int step1_0, step1_1, step1_2, step1_3, step1_4, step1_5, step1_6, step1_7;
int step1_8, step1_9, step1_10, step1_11;
@@ -905,13 +905,13 @@ void vp9_idct16x16_256_add_dspr2(const int16_t *input, uint8_t *dest,
);
// First transform rows
- idct16_1d_rows_dspr2(input, out, 16);
+ idct16_rows_dspr2(input, out, 16);
// Then transform columns and add to dest
- idct16_1d_cols_add_blk_dspr2(out, dest, dest_stride);
+ idct16_cols_add_blk_dspr2(out, dest, dest_stride);
}
-static void iadst16_1d(const int16_t *input, int16_t *output) {
+static void iadst16(const int16_t *input, int16_t *output) {
int s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15;
int x0 = input[15];
@@ -1099,16 +1099,16 @@ void vp9_iht16x16_256_add_dspr2(const int16_t *input, uint8_t *dest,
switch (tx_type) {
case DCT_DCT: // DCT in both horizontal and vertical
- idct16_1d_rows_dspr2(input, outptr, 16);
- idct16_1d_cols_add_blk_dspr2(out, dest, pitch);
+ idct16_rows_dspr2(input, outptr, 16);
+ idct16_cols_add_blk_dspr2(out, dest, pitch);
break;
case ADST_DCT: // ADST in vertical, DCT in horizontal
- idct16_1d_rows_dspr2(input, outptr, 16);
+ idct16_rows_dspr2(input, outptr, 16);
outptr = out;
for (i = 0; i < 16; ++i) {
- iadst16_1d(outptr, temp_out);
+ iadst16(outptr, temp_out);
for (j = 0; j < 16; ++j)
dest[j * pitch + i] =
@@ -1125,7 +1125,7 @@ void vp9_iht16x16_256_add_dspr2(const int16_t *input, uint8_t *dest,
/* prefetch row */
vp9_prefetch_load((const uint8_t *)(input + 16));
- iadst16_1d(input, outptr);
+ iadst16(input, outptr);
input += 16;
outptr += 16;
}
@@ -1134,7 +1134,7 @@ void vp9_iht16x16_256_add_dspr2(const int16_t *input, uint8_t *dest,
for (j = 0; j < 16; ++j)
temp_in[j * 16 + i] = out[i * 16 + j];
- idct16_1d_cols_add_blk_dspr2(temp_in, dest, pitch);
+ idct16_cols_add_blk_dspr2(temp_in, dest, pitch);
}
break;
case ADST_ADST: // ADST in both directions
@@ -1145,7 +1145,7 @@ void vp9_iht16x16_256_add_dspr2(const int16_t *input, uint8_t *dest,
/* prefetch row */
vp9_prefetch_load((const uint8_t *)(input + 16));
- iadst16_1d(input, outptr);
+ iadst16(input, outptr);
input += 16;
outptr += 16;
}
@@ -1153,7 +1153,7 @@ void vp9_iht16x16_256_add_dspr2(const int16_t *input, uint8_t *dest,
for (i = 0; i < 16; ++i) {
for (j = 0; j < 16; ++j)
temp_in[j] = out[j * 16 + i];
- iadst16_1d(temp_in, temp_out);
+ iadst16(temp_in, temp_out);
for (j = 0; j < 16; ++j)
dest[j * pitch + i] =
clip_pixel(ROUND_POWER_OF_TWO(temp_out[j], 6)
@@ -1183,7 +1183,7 @@ void vp9_idct16x16_10_add_dspr2(const int16_t *input, uint8_t *dest,
// First transform rows. Since all non-zero dct coefficients are in
// upper-left 4x4 area, we only need to calculate first 4 rows here.
- idct16_1d_rows_dspr2(input, outptr, 4);
+ idct16_rows_dspr2(input, outptr, 4);
outptr += 4;
for (i = 0; i < 6; ++i) {
@@ -1213,7 +1213,7 @@ void vp9_idct16x16_10_add_dspr2(const int16_t *input, uint8_t *dest,
}
// Then transform columns
- idct16_1d_cols_add_blk_dspr2(out, dest, dest_stride);
+ idct16_cols_add_blk_dspr2(out, dest, dest_stride);
}
void vp9_idct16x16_1_add_dspr2(const int16_t *input, uint8_t *dest,
diff --git a/vp9/common/mips/dspr2/vp9_itrans32_cols_dspr2.c b/vp9/common/mips/dspr2/vp9_itrans32_cols_dspr2.c
index 5e92db3d2..132d88ce5 100644
--- a/vp9/common/mips/dspr2/vp9_itrans32_cols_dspr2.c
+++ b/vp9/common/mips/dspr2/vp9_itrans32_cols_dspr2.c
@@ -18,8 +18,8 @@
#include "vp9/common/mips/dspr2/vp9_common_dspr2.h"
#if HAVE_DSPR2
-void vp9_idct32_1d_cols_add_blk_dspr2(int16_t *input, uint8_t *dest,
- int dest_stride) {
+void vp9_idct32_cols_add_blk_dspr2(int16_t *input, uint8_t *dest,
+ int dest_stride) {
int16_t step1_0, step1_1, step1_2, step1_3, step1_4, step1_5, step1_6;
int16_t step1_7, step1_8, step1_9, step1_10, step1_11, step1_12, step1_13;
int16_t step1_14, step1_15, step1_16, step1_17, step1_18, step1_19;
diff --git a/vp9/common/mips/dspr2/vp9_itrans32_dspr2.c b/vp9/common/mips/dspr2/vp9_itrans32_dspr2.c
index bc6759400..74a90b02c 100644
--- a/vp9/common/mips/dspr2/vp9_itrans32_dspr2.c
+++ b/vp9/common/mips/dspr2/vp9_itrans32_dspr2.c
@@ -19,8 +19,8 @@
#include "vp9/common/mips/dspr2/vp9_common_dspr2.h"
#if HAVE_DSPR2
-static void idct32_1d_rows_dspr2(const int16_t *input, int16_t *output,
- uint32_t no_rows) {
+static void idct32_rows_dspr2(const int16_t *input, int16_t *output,
+ uint32_t no_rows) {
int16_t step1_0, step1_1, step1_2, step1_3, step1_4, step1_5, step1_6;
int16_t step1_7, step1_8, step1_9, step1_10, step1_11, step1_12, step1_13;
int16_t step1_14, step1_15, step1_16, step1_17, step1_18, step1_19, step1_20;
@@ -882,10 +882,10 @@ void vp9_idct32x32_1024_add_dspr2(const int16_t *input, uint8_t *dest,
);
// Rows
- idct32_1d_rows_dspr2(input, outptr, 32);
+ idct32_rows_dspr2(input, outptr, 32);
// Columns
- vp9_idct32_1d_cols_add_blk_dspr2(out, dest, dest_stride);
+ vp9_idct32_cols_add_blk_dspr2(out, dest, dest_stride);
}
void vp9_idct32x32_34_add_dspr2(const int16_t *input, uint8_t *dest,
@@ -903,7 +903,7 @@ void vp9_idct32x32_34_add_dspr2(const int16_t *input, uint8_t *dest,
);
// Rows
- idct32_1d_rows_dspr2(input, outptr, 8);
+ idct32_rows_dspr2(input, outptr, 8);
outptr += 8;
__asm__ __volatile__ (
@@ -947,7 +947,7 @@ void vp9_idct32x32_34_add_dspr2(const int16_t *input, uint8_t *dest,
}
// Columns
- vp9_idct32_1d_cols_add_blk_dspr2(out, dest, stride);
+ vp9_idct32_cols_add_blk_dspr2(out, dest, stride);
}
void vp9_idct32x32_1_add_dspr2(const int16_t *input, uint8_t *dest,
diff --git a/vp9/common/mips/dspr2/vp9_itrans4_dspr2.c b/vp9/common/mips/dspr2/vp9_itrans4_dspr2.c
index 5b7aa5e71..1990348b8 100644
--- a/vp9/common/mips/dspr2/vp9_itrans4_dspr2.c
+++ b/vp9/common/mips/dspr2/vp9_itrans4_dspr2.c
@@ -19,7 +19,7 @@
#include "vp9/common/mips/dspr2/vp9_common_dspr2.h"
#if HAVE_DSPR2
-static void vp9_idct4_1d_rows_dspr2(const int16_t *input, int16_t *output) {
+static void vp9_idct4_rows_dspr2(const int16_t *input, int16_t *output) {
int16_t step_0, step_1, step_2, step_3;
int Temp0, Temp1, Temp2, Temp3;
const int const_2_power_13 = 8192;
@@ -104,7 +104,7 @@ static void vp9_idct4_1d_rows_dspr2(const int16_t *input, int16_t *output) {
}
}
-static void vp9_idct4_1d_columns_add_blk_dspr2(int16_t *input, uint8_t *dest,
+static void vp9_idct4_columns_add_blk_dspr2(int16_t *input, uint8_t *dest,
int dest_stride) {
int16_t step_0, step_1, step_2, step_3;
int Temp0, Temp1, Temp2, Temp3;
@@ -240,10 +240,10 @@ void vp9_idct4x4_16_add_dspr2(const int16_t *input, uint8_t *dest,
);
// Rows
- vp9_idct4_1d_rows_dspr2(input, outptr);
+ vp9_idct4_rows_dspr2(input, outptr);
// Columns
- vp9_idct4_1d_columns_add_blk_dspr2(&out[0], dest, dest_stride);
+ vp9_idct4_columns_add_blk_dspr2(&out[0], dest, dest_stride);
}
void vp9_idct4x4_1_add_dspr2(const int16_t *input, uint8_t *dest,
@@ -319,7 +319,7 @@ void vp9_idct4x4_1_add_dspr2(const int16_t *input, uint8_t *dest,
}
}
-static void iadst4_1d_dspr2(const int16_t *input, int16_t *output) {
+static void iadst4_dspr2(const int16_t *input, int16_t *output) {
int s0, s1, s2, s3, s4, s5, s6, s7;
int x0, x1, x2, x3;
@@ -379,16 +379,16 @@ void vp9_iht4x4_16_add_dspr2(const int16_t *input, uint8_t *dest,
switch (tx_type) {
case DCT_DCT: // DCT in both horizontal and vertical
- vp9_idct4_1d_rows_dspr2(input, outptr);
- vp9_idct4_1d_columns_add_blk_dspr2(&out[0], dest, dest_stride);
+ vp9_idct4_rows_dspr2(input, outptr);
+ vp9_idct4_columns_add_blk_dspr2(&out[0], dest, dest_stride);
break;
case ADST_DCT: // ADST in vertical, DCT in horizontal
- vp9_idct4_1d_rows_dspr2(input, outptr);
+ vp9_idct4_rows_dspr2(input, outptr);
outptr = out;
for (i = 0; i < 4; ++i) {
- iadst4_1d_dspr2(outptr, temp_out);
+ iadst4_dspr2(outptr, temp_out);
for (j = 0; j < 4; ++j)
dest[j * dest_stride + i] =
@@ -400,7 +400,7 @@ void vp9_iht4x4_16_add_dspr2(const int16_t *input, uint8_t *dest,
break;
case DCT_ADST: // DCT in vertical, ADST in horizontal
for (i = 0; i < 4; ++i) {
- iadst4_1d_dspr2(input, outptr);
+ iadst4_dspr2(input, outptr);
input += 4;
outptr += 4;
}
@@ -410,11 +410,11 @@ void vp9_iht4x4_16_add_dspr2(const int16_t *input, uint8_t *dest,
temp_in[i * 4 + j] = out[j * 4 + i];
}
}
- vp9_idct4_1d_columns_add_blk_dspr2(&temp_in[0], dest, dest_stride);
+ vp9_idct4_columns_add_blk_dspr2(&temp_in[0], dest, dest_stride);
break;
case ADST_ADST: // ADST in both directions
for (i = 0; i < 4; ++i) {
- iadst4_1d_dspr2(input, outptr);
+ iadst4_dspr2(input, outptr);
input += 4;
outptr += 4;
}
@@ -422,7 +422,7 @@ void vp9_iht4x4_16_add_dspr2(const int16_t *input, uint8_t *dest,
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j)
temp_in[j] = out[j * 4 + i];
- iadst4_1d_dspr2(temp_in, temp_out);
+ iadst4_dspr2(temp_in, temp_out);
for (j = 0; j < 4; ++j)
dest[j * dest_stride + i] =
diff --git a/vp9/common/mips/dspr2/vp9_itrans8_dspr2.c b/vp9/common/mips/dspr2/vp9_itrans8_dspr2.c
index 93a08401d..acccaea6d 100644
--- a/vp9/common/mips/dspr2/vp9_itrans8_dspr2.c
+++ b/vp9/common/mips/dspr2/vp9_itrans8_dspr2.c
@@ -19,8 +19,8 @@
#include "vp9/common/mips/dspr2/vp9_common_dspr2.h"
#if HAVE_DSPR2
-static void idct8_1d_rows_dspr2(const int16_t *input, int16_t *output,
- uint32_t no_rows) {
+static void idct8_rows_dspr2(const int16_t *input, int16_t *output,
+ uint32_t no_rows) {
int step1_0, step1_1, step1_2, step1_3, step1_4, step1_5, step1_6, step1_7;
const int const_2_power_13 = 8192;
int Temp0, Temp1, Temp2, Temp3, Temp4;
@@ -200,8 +200,8 @@ static void idct8_1d_rows_dspr2(const int16_t *input, int16_t *output,
}
}
-static void idct8_1d_columns_add_blk_dspr2(int16_t *input, uint8_t *dest,
- int dest_stride) {
+static void idct8_columns_add_blk_dspr2(int16_t *input, uint8_t *dest,
+ int dest_stride) {
int step1_0, step1_1, step1_2, step1_3, step1_4, step1_5, step1_6, step1_7;
int Temp0, Temp1, Temp2, Temp3;
int i;
@@ -462,13 +462,13 @@ void vp9_idct8x8_64_add_dspr2(const int16_t *input, uint8_t *dest,
);
// First transform rows
- idct8_1d_rows_dspr2(input, outptr, 8);
+ idct8_rows_dspr2(input, outptr, 8);
// Then transform columns and add to dest
- idct8_1d_columns_add_blk_dspr2(&out[0], dest, dest_stride);
+ idct8_columns_add_blk_dspr2(&out[0], dest, dest_stride);
}
-static void iadst8_1d_dspr2(const int16_t *input, int16_t *output) {
+static void iadst8_dspr2(const int16_t *input, int16_t *output) {
int s0, s1, s2, s3, s4, s5, s6, s7;
int x0, x1, x2, x3, x4, x5, x6, x7;
@@ -563,14 +563,14 @@ void vp9_iht8x8_64_add_dspr2(const int16_t *input, uint8_t *dest,
switch (tx_type) {
case DCT_DCT: // DCT in both horizontal and vertical
- idct8_1d_rows_dspr2(input, outptr, 8);
- idct8_1d_columns_add_blk_dspr2(&out[0], dest, dest_stride);
+ idct8_rows_dspr2(input, outptr, 8);
+ idct8_columns_add_blk_dspr2(&out[0], dest, dest_stride);
break;
case ADST_DCT: // ADST in vertical, DCT in horizontal
- idct8_1d_rows_dspr2(input, outptr, 8);
+ idct8_rows_dspr2(input, outptr, 8);
for (i = 0; i < 8; ++i) {
- iadst8_1d_dspr2(&out[i * 8], temp_out);
+ iadst8_dspr2(&out[i * 8], temp_out);
for (j = 0; j < 8; ++j)
dest[j * dest_stride + i] =
@@ -580,7 +580,7 @@ void vp9_iht8x8_64_add_dspr2(const int16_t *input, uint8_t *dest,
break;
case DCT_ADST: // DCT in vertical, ADST in horizontal
for (i = 0; i < 8; ++i) {
- iadst8_1d_dspr2(input, outptr);
+ iadst8_dspr2(input, outptr);
input += 8;
outptr += 8;
}
@@ -590,11 +590,11 @@ void vp9_iht8x8_64_add_dspr2(const int16_t *input, uint8_t *dest,
temp_in[i * 8 + j] = out[j * 8 + i];
}
}
- idct8_1d_columns_add_blk_dspr2(&temp_in[0], dest, dest_stride);
+ idct8_columns_add_blk_dspr2(&temp_in[0], dest, dest_stride);
break;
case ADST_ADST: // ADST in both directions
for (i = 0; i < 8; ++i) {
- iadst8_1d_dspr2(input, outptr);
+ iadst8_dspr2(input, outptr);
input += 8;
outptr += 8;
}
@@ -603,7 +603,7 @@ void vp9_iht8x8_64_add_dspr2(const int16_t *input, uint8_t *dest,
for (j = 0; j < 8; ++j)
temp_in[j] = out[j * 8 + i];
- iadst8_1d_dspr2(temp_in, temp_out);
+ iadst8_dspr2(temp_in, temp_out);
for (j = 0; j < 8; ++j)
dest[j * dest_stride + i] =
@@ -631,7 +631,7 @@ void vp9_idct8x8_10_add_dspr2(const int16_t *input, uint8_t *dest,
);
// First transform rows
- idct8_1d_rows_dspr2(input, outptr, 4);
+ idct8_rows_dspr2(input, outptr, 4);
outptr += 4;
@@ -659,7 +659,7 @@ void vp9_idct8x8_10_add_dspr2(const int16_t *input, uint8_t *dest,
// Then transform columns and add to dest
- idct8_1d_columns_add_blk_dspr2(&out[0], dest, dest_stride);
+ idct8_columns_add_blk_dspr2(&out[0], dest, dest_stride);
}
void vp9_idct8x8_1_add_dspr2(const int16_t *input, uint8_t *dest,
diff --git a/vp9/common/vp9_alloccommon.c b/vp9/common/vp9_alloccommon.c
index e033fbb99..6f771992b 100644
--- a/vp9/common/vp9_alloccommon.c
+++ b/vp9/common/vp9_alloccommon.c
@@ -33,9 +33,16 @@ void vp9_update_mode_info_border(VP9_COMMON *cm, MODE_INFO *mi) {
void vp9_free_frame_buffers(VP9_COMMON *cm) {
int i;
- for (i = 0; i < FRAME_BUFFERS; i++)
+ for (i = 0; i < FRAME_BUFFERS; i++) {
vp9_free_frame_buffer(&cm->frame_bufs[i].buf);
+ if (cm->frame_bufs[i].ref_count > 0 &&
+ cm->frame_bufs[i].raw_frame_buffer.data != NULL) {
+ cm->release_fb_cb(cm->cb_priv, &cm->frame_bufs[i].raw_frame_buffer);
+ cm->frame_bufs[i].ref_count = 0;
+ }
+ }
+
vp9_free_frame_buffer(&cm->post_proc_buffer);
vpx_free(cm->mip);
@@ -85,7 +92,7 @@ int vp9_resize_frame_buffers(VP9_COMMON *cm, int width, int height) {
int mi_size;
if (vp9_realloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y,
- VP9_DEC_BORDER_IN_PIXELS) < 0)
+ VP9_DEC_BORDER_IN_PIXELS, NULL, NULL, NULL) < 0)
goto fail;
set_mb_mi(cm, aligned_width, aligned_height);
@@ -199,6 +206,7 @@ void vp9_create_common(VP9_COMMON *cm) {
void vp9_remove_common(VP9_COMMON *cm) {
vp9_free_frame_buffers(cm);
+ vp9_free_internal_frame_buffers(&cm->int_frame_buffers);
}
void vp9_initialize_common() {
diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h
index 70b8ffa4e..f10a3c8c7 100644
--- a/vp9/common/vp9_blockd.h
+++ b/vp9/common/vp9_blockd.h
@@ -182,7 +182,7 @@ struct macroblockd_plane {
int subsampling_y;
struct buf_2d dst;
struct buf_2d pre[2];
- int16_t *dequant;
+ const int16_t *dequant;
ENTROPY_CONTEXT *above_context;
ENTROPY_CONTEXT *left_context;
};
diff --git a/vp9/common/vp9_convolve.c b/vp9/common/vp9_convolve.c
index 3807ccc87..d30e0b488 100644
--- a/vp9/common/vp9_convolve.c
+++ b/vp9/common/vp9_convolve.c
@@ -145,7 +145,7 @@ static const InterpKernel *get_filter_base(const int16_t *filter) {
}
static int get_filter_offset(const int16_t *f, const InterpKernel *base) {
- return (const InterpKernel *)(intptr_t)f - base;
+ return (int)((const InterpKernel *)(intptr_t)f - base);
}
void vp9_convolve8_horiz_c(const uint8_t *src, ptrdiff_t src_stride,
diff --git a/vp9/common/vp9_entropy.h b/vp9/common/vp9_entropy.h
index e030d92ec..d6b380fd5 100644
--- a/vp9/common/vp9_entropy.h
+++ b/vp9/common/vp9_entropy.h
@@ -119,7 +119,7 @@ static INLINE void reset_skip_context(MACROBLOCKD *xd, BLOCK_SIZE bsize) {
extern DECLARE_ALIGNED(16, const uint8_t, vp9_coefband_trans_8x8plus[1024]);
extern DECLARE_ALIGNED(16, const uint8_t, vp9_coefband_trans_4x4[16]);
-static const uint8_t *get_band_translate(TX_SIZE tx_size) {
+static INLINE const uint8_t *get_band_translate(TX_SIZE tx_size) {
return tx_size == TX_4X4 ? vp9_coefband_trans_4x4
: vp9_coefband_trans_8x8plus;
}
@@ -146,8 +146,8 @@ typedef unsigned int vp9_coeff_count_model[REF_TYPES][COEF_BANDS]
void vp9_model_to_full_probs(const vp9_prob *model, vp9_prob *full);
-static int get_entropy_context(TX_SIZE tx_size, const ENTROPY_CONTEXT *a,
- const ENTROPY_CONTEXT *l) {
+static INLINE int get_entropy_context(TX_SIZE tx_size, const ENTROPY_CONTEXT *a,
+ const ENTROPY_CONTEXT *l) {
ENTROPY_CONTEXT above_ec = 0, left_ec = 0;
switch (tx_size) {
@@ -174,8 +174,8 @@ static int get_entropy_context(TX_SIZE tx_size, const ENTROPY_CONTEXT *a,
return combine_entropy_contexts(above_ec, left_ec);
}
-static const scan_order *get_scan(const MACROBLOCKD *xd, TX_SIZE tx_size,
- PLANE_TYPE type, int block_idx) {
+static const INLINE scan_order *get_scan(const MACROBLOCKD *xd, TX_SIZE tx_size,
+ PLANE_TYPE type, int block_idx) {
const MODE_INFO *const mi = xd->mi_8x8[0];
const MB_MODE_INFO *const mbmi = &mi->mbmi;
diff --git a/vp9/common/vp9_entropymode.c b/vp9/common/vp9_entropymode.c
index 6def3c869..25cba7fbe 100644
--- a/vp9/common/vp9_entropymode.c
+++ b/vp9/common/vp9_entropymode.c
@@ -345,7 +345,7 @@ static int adapt_prob(vp9_prob pre_prob, const unsigned int ct[2]) {
static void adapt_probs(const vp9_tree_index *tree,
const vp9_prob *pre_probs, const unsigned int *counts,
vp9_prob *probs) {
- tree_merge_probs(tree, pre_probs, counts, COUNT_SAT, MAX_UPDATE_FACTOR,
+ vp9_tree_merge_probs(tree, pre_probs, counts, COUNT_SAT, MAX_UPDATE_FACTOR,
probs);
}
diff --git a/vp9/common/vp9_entropymv.c b/vp9/common/vp9_entropymv.c
index 60ae79fdc..e1f5ef7b4 100644
--- a/vp9/common/vp9_entropymv.c
+++ b/vp9/common/vp9_entropymv.c
@@ -192,8 +192,8 @@ static vp9_prob adapt_prob(vp9_prob prep, const unsigned int ct[2]) {
static void adapt_probs(const vp9_tree_index *tree, const vp9_prob *pre_probs,
const unsigned int *counts, vp9_prob *probs) {
- tree_merge_probs(tree, pre_probs, counts, MV_COUNT_SAT, MV_MAX_UPDATE_FACTOR,
- probs);
+ vp9_tree_merge_probs(tree, pre_probs, counts, MV_COUNT_SAT,
+ MV_MAX_UPDATE_FACTOR, probs);
}
void vp9_adapt_mv_probs(VP9_COMMON *cm, int allow_hp) {
diff --git a/vp9/common/vp9_frame_buffers.c b/vp9/common/vp9_frame_buffers.c
new file mode 100644
index 000000000..d903ed695
--- /dev/null
+++ b/vp9/common/vp9_frame_buffers.c
@@ -0,0 +1,84 @@
+/*
+ * 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 <assert.h>
+
+#include "vp9/common/vp9_frame_buffers.h"
+#include "vpx_mem/vpx_mem.h"
+
+int vp9_alloc_internal_frame_buffers(InternalFrameBufferList *list) {
+ assert(list != NULL);
+ vp9_free_internal_frame_buffers(list);
+
+ list->num_internal_frame_buffers =
+ VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
+ list->int_fb = vpx_calloc(list->num_internal_frame_buffers,
+ sizeof(*list->int_fb));
+ return (list->int_fb == NULL);
+}
+
+void vp9_free_internal_frame_buffers(InternalFrameBufferList *list) {
+ int i;
+
+ assert(list != NULL);
+
+ for (i = 0; i < list->num_internal_frame_buffers; ++i) {
+ vpx_free(list->int_fb[i].data);
+ list->int_fb[i].data = NULL;
+ }
+ vpx_free(list->int_fb);
+ list->int_fb = NULL;
+}
+
+int vp9_get_frame_buffer(void *cb_priv, size_t min_size,
+ vpx_codec_frame_buffer_t *fb) {
+ int i;
+ InternalFrameBufferList *const int_fb_list =
+ (InternalFrameBufferList *)cb_priv;
+ if (int_fb_list == NULL || fb == NULL)
+ return -1;
+
+ // Find a free frame buffer.
+ for (i = 0; i < int_fb_list->num_internal_frame_buffers; ++i) {
+ if (!int_fb_list->int_fb[i].in_use)
+ break;
+ }
+
+ if (i == int_fb_list->num_internal_frame_buffers)
+ return -1;
+
+ if (int_fb_list->int_fb[i].size < min_size) {
+ int_fb_list->int_fb[i].data =
+ (uint8_t *)vpx_realloc(int_fb_list->int_fb[i].data, min_size);
+ if (!int_fb_list->int_fb[i].data)
+ return -1;
+
+ int_fb_list->int_fb[i].size = min_size;
+ }
+
+ fb->data = int_fb_list->int_fb[i].data;
+ fb->size = int_fb_list->int_fb[i].size;
+ int_fb_list->int_fb[i].in_use = 1;
+
+ // Set the frame buffer's private data to point at the internal frame buffer.
+ fb->priv = &int_fb_list->int_fb[i];
+ return 0;
+}
+
+int vp9_release_frame_buffer(void *cb_priv, vpx_codec_frame_buffer_t *fb) {
+ InternalFrameBuffer *int_fb;
+ (void)cb_priv;
+ if (fb == NULL)
+ return -1;
+
+ int_fb = (InternalFrameBuffer *)fb->priv;
+ int_fb->in_use = 0;
+ return 0;
+}
diff --git a/vp9/common/vp9_frame_buffers.h b/vp9/common/vp9_frame_buffers.h
new file mode 100644
index 000000000..e2cfe61b6
--- /dev/null
+++ b/vp9/common/vp9_frame_buffers.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef VP9_COMMON_VP9_FRAME_BUFFERS_H_
+#define VP9_COMMON_VP9_FRAME_BUFFERS_H_
+
+#include "vpx/vpx_frame_buffer.h"
+#include "vpx/vpx_integer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct InternalFrameBuffer {
+ uint8_t *data;
+ size_t size;
+ int in_use;
+} InternalFrameBuffer;
+
+typedef struct InternalFrameBufferList {
+ int num_internal_frame_buffers;
+ InternalFrameBuffer *int_fb;
+} InternalFrameBufferList;
+
+// Initializes |list|. Returns 0 on success.
+int vp9_alloc_internal_frame_buffers(InternalFrameBufferList *list);
+
+// Free any data allocated to the frame buffers.
+void vp9_free_internal_frame_buffers(InternalFrameBufferList *list);
+
+// Callback used by libvpx to request an external frame buffer. |cb_priv|
+// Callback private data, which points to an InternalFrameBufferList.
+// |min_size| is the minimum size in bytes needed to decode the next frame.
+// |fb| pointer to the frame buffer.
+int vp9_get_frame_buffer(void *cb_priv, size_t min_size,
+ vpx_codec_frame_buffer_t *fb);
+
+// Callback used by libvpx when there are no references to the frame buffer.
+// |cb_priv| is not used. |fb| pointer to the frame buffer.
+int vp9_release_frame_buffer(void *cb_priv, vpx_codec_frame_buffer_t *fb);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VP9_COMMON_VP9_FRAME_BUFFERS_H_
diff --git a/vp9/common/vp9_mv.h b/vp9/common/vp9_mv.h
index 98fd1d82f..3eb7f9d61 100644
--- a/vp9/common/vp9_mv.h
+++ b/vp9/common/vp9_mv.h
@@ -34,8 +34,8 @@ typedef struct mv32 {
int32_t col;
} MV32;
-static void clamp_mv(MV *mv, int min_col, int max_col,
- int min_row, int max_row) {
+static INLINE void clamp_mv(MV *mv, int min_col, int max_col,
+ int min_row, int max_row) {
mv->col = clamp(mv->col, min_col, max_col);
mv->row = clamp(mv->row, min_row, max_row);
}
diff --git a/vp9/common/vp9_mvref_common.h b/vp9/common/vp9_mvref_common.h
index 0936abfcd..f99952f3c 100644
--- a/vp9/common/vp9_mvref_common.h
+++ b/vp9/common/vp9_mvref_common.h
@@ -48,7 +48,7 @@ void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp,
int_mv *mvlist, int_mv *nearest, int_mv *near);
// TODO(jingning): this mv clamping function should be block size dependent.
-static void clamp_mv2(MV *mv, const MACROBLOCKD *xd) {
+static INLINE void clamp_mv2(MV *mv, const MACROBLOCKD *xd) {
clamp_mv(mv, xd->mb_to_left_edge - LEFT_TOP_MARGIN,
xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
xd->mb_to_top_edge - LEFT_TOP_MARGIN,
diff --git a/vp9/common/vp9_onyx.h b/vp9/common/vp9_onyx.h
index 564e4195f..ac39a98fd 100644
--- a/vp9/common/vp9_onyx.h
+++ b/vp9/common/vp9_onyx.h
@@ -147,8 +147,12 @@ extern "C" {
// END DATARATE CONTROL OPTIONS
// ----------------------------------------------------------------
- // Spatial scalability
- int ss_number_layers;
+ // Spatial and temporal scalability.
+ int ss_number_layers; // Number of spatial layers.
+ int ts_number_layers; // Number of temporal layers.
+ // Bitrate allocation (CBR mode) and framerate factor, for temporal layers.
+ int ts_target_bitrate[VPX_TS_MAX_LAYERS];
+ int ts_rate_decimator[VPX_TS_MAX_LAYERS];
// these parameters aren't to be used in final build don't use!!!
int play_alternate;
diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h
index d92a25b12..97983c596 100644
--- a/vp9/common/vp9_onyxc_int.h
+++ b/vp9/common/vp9_onyxc_int.h
@@ -18,6 +18,7 @@
#include "vp9/common/vp9_entropymv.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_entropymode.h"
+#include "vp9/common/vp9_frame_buffers.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_tile_common.h"
@@ -94,6 +95,7 @@ typedef enum {
typedef struct {
int ref_count;
+ vpx_codec_frame_buffer_t raw_frame_buffer;
YV12_BUFFER_CONFIG buf;
} RefCntBuffer;
@@ -223,13 +225,21 @@ typedef struct VP9Common {
int frame_parallel_decoding_mode;
int log2_tile_cols, log2_tile_rows;
+
+ // Private data associated with the frame buffer callbacks.
+ void *cb_priv;
+ vpx_get_frame_buffer_cb_fn_t get_fb_cb;
+ vpx_release_frame_buffer_cb_fn_t release_fb_cb;
+
+ // Handles memory for the codec.
+ InternalFrameBufferList int_frame_buffers;
} VP9_COMMON;
-static YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) {
+static INLINE YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) {
return &cm->frame_bufs[cm->new_fb_idx].buf;
}
-static int get_free_fb(VP9_COMMON *cm) {
+static INLINE int get_free_fb(VP9_COMMON *cm) {
int i;
for (i = 0; i < FRAME_BUFFERS; i++)
if (cm->frame_bufs[i].ref_count == 0)
@@ -240,7 +250,7 @@ static int get_free_fb(VP9_COMMON *cm) {
return i;
}
-static void ref_cnt_fb(RefCntBuffer *bufs, int *idx, int new_idx) {
+static INLINE void ref_cnt_fb(RefCntBuffer *bufs, int *idx, int new_idx) {
const int ref_index = *idx;
if (ref_index >= 0 && bufs[ref_index].ref_count > 0)
@@ -251,7 +261,7 @@ static void ref_cnt_fb(RefCntBuffer *bufs, int *idx, int new_idx) {
bufs[new_idx].ref_count++;
}
-static int mi_cols_aligned_to_sb(int n_mis) {
+static INLINE int mi_cols_aligned_to_sb(int n_mis) {
return ALIGN_POWER_OF_TWO(n_mis, MI_BLOCK_SIZE_LOG2);
}
@@ -275,10 +285,10 @@ static INLINE void set_skip_context(
}
}
-static void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
- int mi_row, int bh,
- int mi_col, int bw,
- int mi_rows, int mi_cols) {
+static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
+ int mi_row, int bh,
+ int mi_col, int bw,
+ int mi_rows, int mi_cols) {
xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8);
xd->mb_to_bottom_edge = ((mi_rows - bh - mi_row) * MI_SIZE) * 8;
xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8);
diff --git a/vp9/common/vp9_pred_common.c b/vp9/common/vp9_pred_common.c
index 11b6d93c1..487f00cca 100644
--- a/vp9/common/vp9_pred_common.c
+++ b/vp9/common/vp9_pred_common.c
@@ -218,27 +218,25 @@ int vp9_get_pred_context_single_ref_p1(const MACROBLOCKD *xd) {
} else { // inter/inter
const int above_has_second = has_second_ref(above_mbmi);
const int left_has_second = has_second_ref(left_mbmi);
+ const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0];
+ const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1];
+ const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0];
+ const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1];
if (above_has_second && left_has_second) {
- pred_context = 1 + (above_mbmi->ref_frame[0] == LAST_FRAME ||
- above_mbmi->ref_frame[1] == LAST_FRAME ||
- left_mbmi->ref_frame[0] == LAST_FRAME ||
- left_mbmi->ref_frame[1] == LAST_FRAME);
+ pred_context = 1 + (above0 == LAST_FRAME || above1 == LAST_FRAME ||
+ left0 == LAST_FRAME || left1 == LAST_FRAME);
} else if (above_has_second || left_has_second) {
- const MV_REFERENCE_FRAME rfs = !above_has_second ?
- above_mbmi->ref_frame[0] : left_mbmi->ref_frame[0];
- const MV_REFERENCE_FRAME crf1 = above_has_second ?
- above_mbmi->ref_frame[0] : left_mbmi->ref_frame[0];
- const MV_REFERENCE_FRAME crf2 = above_has_second ?
- above_mbmi->ref_frame[1] : left_mbmi->ref_frame[1];
+ const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
+ const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
+ const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
if (rfs == LAST_FRAME)
pred_context = 3 + (crf1 == LAST_FRAME || crf2 == LAST_FRAME);
else
pred_context = (crf1 == LAST_FRAME || crf2 == LAST_FRAME);
} else {
- pred_context = 2 * (above_mbmi->ref_frame[0] == LAST_FRAME) +
- 2 * (left_mbmi->ref_frame[0] == LAST_FRAME);
+ pred_context = 2 * (above0 == LAST_FRAME) + 2 * (left0 == LAST_FRAME);
}
}
} else if (has_above || has_left) { // one edge available
@@ -291,23 +289,23 @@ int vp9_get_pred_context_single_ref_p2(const MACROBLOCKD *xd) {
} else { // inter/inter
const int above_has_second = has_second_ref(above_mbmi);
const int left_has_second = has_second_ref(left_mbmi);
+ const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0];
+ const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1];
+ const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0];
+ const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1];
if (above_has_second && left_has_second) {
- if (above_mbmi->ref_frame[0] == left_mbmi->ref_frame[0] &&
- above_mbmi->ref_frame[1] == left_mbmi->ref_frame[1])
- pred_context = 3 * (above_mbmi->ref_frame[0] == GOLDEN_FRAME ||
- above_mbmi->ref_frame[1] == GOLDEN_FRAME ||
- left_mbmi->ref_frame[0] == GOLDEN_FRAME ||
- left_mbmi->ref_frame[1] == GOLDEN_FRAME);
+ if (above0 == left0 && above1 == left1)
+ pred_context = 3 * (above0 == GOLDEN_FRAME ||
+ above1 == GOLDEN_FRAME ||
+ left0 == GOLDEN_FRAME ||
+ left1 == GOLDEN_FRAME);
else
pred_context = 2;
} else if (above_has_second || left_has_second) {
- const MV_REFERENCE_FRAME rfs = !above_has_second ?
- above_mbmi->ref_frame[0] : left_mbmi->ref_frame[0];
- const MV_REFERENCE_FRAME crf1 = above_has_second ?
- above_mbmi->ref_frame[0] : left_mbmi->ref_frame[0];
- const MV_REFERENCE_FRAME crf2 = above_has_second ?
- above_mbmi->ref_frame[1] : left_mbmi->ref_frame[1];
+ const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
+ const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
+ const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
if (rfs == GOLDEN_FRAME)
pred_context = 3 + (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
@@ -316,17 +314,15 @@ int vp9_get_pred_context_single_ref_p2(const MACROBLOCKD *xd) {
else
pred_context = 1 + 2 * (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
} else {
- if (above_mbmi->ref_frame[0] == LAST_FRAME &&
- left_mbmi->ref_frame[0] == LAST_FRAME) {
+ if (above0 == LAST_FRAME && left0 == LAST_FRAME) {
pred_context = 3;
- } else if (above_mbmi->ref_frame[0] == LAST_FRAME ||
- left_mbmi->ref_frame[0] == LAST_FRAME) {
- const MB_MODE_INFO *edge_mbmi =
- above_mbmi->ref_frame[0] == LAST_FRAME ? left_mbmi : above_mbmi;
- pred_context = 4 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME);
+ } else if (above0 == LAST_FRAME || left0 == LAST_FRAME) {
+ const MV_REFERENCE_FRAME edge0 = (above0 == LAST_FRAME) ? left0
+ : above0;
+ pred_context = 4 * (edge0 == GOLDEN_FRAME);
} else {
- pred_context = 2 * (above_mbmi->ref_frame[0] == GOLDEN_FRAME) +
- 2 * (left_mbmi->ref_frame[0] == GOLDEN_FRAME);
+ pred_context = 2 * (above0 == GOLDEN_FRAME) +
+ 2 * (left0 == GOLDEN_FRAME);
}
}
}
diff --git a/vp9/common/vp9_pred_common.h b/vp9/common/vp9_pred_common.h
index 0acee32f8..33ae5a896 100644
--- a/vp9/common/vp9_pred_common.h
+++ b/vp9/common/vp9_pred_common.h
@@ -98,8 +98,8 @@ static INLINE vp9_prob vp9_get_pred_prob_single_ref_p2(const VP9_COMMON *cm,
int vp9_get_tx_size_context(const MACROBLOCKD *xd);
-static const vp9_prob *get_tx_probs(TX_SIZE max_tx_size, int ctx,
- const struct tx_probs *tx_probs) {
+static INLINE const vp9_prob *get_tx_probs(TX_SIZE max_tx_size, int ctx,
+ const struct tx_probs *tx_probs) {
switch (max_tx_size) {
case TX_8X8:
return tx_probs->p8x8[ctx];
@@ -113,13 +113,14 @@ static const vp9_prob *get_tx_probs(TX_SIZE max_tx_size, int ctx,
}
}
-static const vp9_prob *get_tx_probs2(TX_SIZE max_tx_size, const MACROBLOCKD *xd,
- const struct tx_probs *tx_probs) {
+static INLINE const vp9_prob *get_tx_probs2(TX_SIZE max_tx_size,
+ const MACROBLOCKD *xd,
+ const struct tx_probs *tx_probs) {
return get_tx_probs(max_tx_size, vp9_get_tx_size_context(xd), tx_probs);
}
-static unsigned int *get_tx_counts(TX_SIZE max_tx_size, int ctx,
- struct tx_counts *tx_counts) {
+static INLINE unsigned int *get_tx_counts(TX_SIZE max_tx_size, int ctx,
+ struct tx_counts *tx_counts) {
switch (max_tx_size) {
case TX_8X8:
return tx_counts->p8x8[ctx];
diff --git a/vp9/common/vp9_prob.c b/vp9/common/vp9_prob.c
index 884884e0b..f9bc06ecf 100644
--- a/vp9/common/vp9_prob.c
+++ b/vp9/common/vp9_prob.c
@@ -28,3 +28,34 @@ DECLARE_ALIGNED(16, const uint8_t, vp9_norm[256]) = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
+
+
+static unsigned int tree_merge_probs_impl(unsigned int i,
+ const vp9_tree_index *tree,
+ const vp9_prob *pre_probs,
+ const unsigned int *counts,
+ unsigned int count_sat,
+ unsigned int max_update,
+ vp9_prob *probs) {
+ const int l = tree[i];
+ const unsigned int left_count = (l <= 0)
+ ? counts[-l]
+ : tree_merge_probs_impl(l, tree, pre_probs, counts,
+ count_sat, max_update, probs);
+ const int r = tree[i + 1];
+ const unsigned int right_count = (r <= 0)
+ ? counts[-r]
+ : tree_merge_probs_impl(r, tree, pre_probs, counts,
+ count_sat, max_update, probs);
+ const unsigned int ct[2] = { left_count, right_count };
+ probs[i >> 1] = merge_probs(pre_probs[i >> 1], ct,
+ count_sat, max_update);
+ return left_count + right_count;
+}
+
+void vp9_tree_merge_probs(const vp9_tree_index *tree, const vp9_prob *pre_probs,
+ const unsigned int *counts, unsigned int count_sat,
+ unsigned int max_update_factor, vp9_prob *probs) {
+ tree_merge_probs_impl(0, tree, pre_probs, counts, count_sat,
+ max_update_factor, probs);
+}
diff --git a/vp9/common/vp9_prob.h b/vp9/common/vp9_prob.h
index cc8d8ab38..f36148035 100644
--- a/vp9/common/vp9_prob.h
+++ b/vp9/common/vp9_prob.h
@@ -79,37 +79,10 @@ static INLINE vp9_prob merge_probs(vp9_prob pre_prob,
return weighted_prob(pre_prob, prob, factor);
}
-static unsigned int tree_merge_probs_impl(unsigned int i,
- const vp9_tree_index *tree,
- const vp9_prob *pre_probs,
- const unsigned int *counts,
- unsigned int count_sat,
- unsigned int max_update_factor,
- vp9_prob *probs) {
- const int l = tree[i];
- const unsigned int left_count = (l <= 0)
- ? counts[-l]
- : tree_merge_probs_impl(l, tree, pre_probs, counts,
- count_sat, max_update_factor, probs);
- const int r = tree[i + 1];
- const unsigned int right_count = (r <= 0)
- ? counts[-r]
- : tree_merge_probs_impl(r, tree, pre_probs, counts,
- count_sat, max_update_factor, probs);
- const unsigned int ct[2] = { left_count, right_count };
- probs[i >> 1] = merge_probs(pre_probs[i >> 1], ct,
- count_sat, max_update_factor);
- return left_count + right_count;
-}
+void vp9_tree_merge_probs(const vp9_tree_index *tree, const vp9_prob *pre_probs,
+ const unsigned int *counts, unsigned int count_sat,
+ unsigned int max_update_factor, vp9_prob *probs);
-static void tree_merge_probs(const vp9_tree_index *tree,
- const vp9_prob *pre_probs,
- const unsigned int *counts,
- unsigned int count_sat,
- unsigned int max_update_factor, vp9_prob *probs) {
- tree_merge_probs_impl(0, tree, pre_probs, counts,
- count_sat, max_update_factor, probs);
-}
DECLARE_ALIGNED(16, extern const uint8_t, vp9_norm[256]);
diff --git a/vp9/common/vp9_quant_common.c b/vp9/common/vp9_quant_common.c
index 6dbdb4216..9fef8b1ef 100644
--- a/vp9/common/vp9_quant_common.c
+++ b/vp9/common/vp9_quant_common.c
@@ -130,7 +130,8 @@ int16_t vp9_ac_quant(int qindex, int delta) {
}
-int vp9_get_qindex(struct segmentation *seg, int segment_id, int base_qindex) {
+int vp9_get_qindex(const struct segmentation *seg, int segment_id,
+ int base_qindex) {
if (vp9_segfeature_active(seg, segment_id, SEG_LVL_ALT_Q)) {
const int data = vp9_get_segdata(seg, segment_id, SEG_LVL_ALT_Q);
return seg->abs_delta == SEGMENT_ABSDATA ?
diff --git a/vp9/common/vp9_quant_common.h b/vp9/common/vp9_quant_common.h
index af50e23cd..581104006 100644
--- a/vp9/common/vp9_quant_common.h
+++ b/vp9/common/vp9_quant_common.h
@@ -27,7 +27,8 @@ void vp9_init_quant_tables();
int16_t vp9_dc_quant(int qindex, int delta);
int16_t vp9_ac_quant(int qindex, int delta);
-int vp9_get_qindex(struct segmentation *seg, int segment_id, int base_qindex);
+int vp9_get_qindex(const struct segmentation *seg, int segment_id,
+ int base_qindex);
#ifdef __cplusplus
} // extern "C"
diff --git a/vp9/common/vp9_reconinter.c b/vp9/common/vp9_reconinter.c
index cc70e4cc0..7576e7b6f 100644
--- a/vp9/common/vp9_reconinter.c
+++ b/vp9/common/vp9_reconinter.c
@@ -269,21 +269,15 @@ static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
? (plane == 0 ? mi->bmi[block].as_mv[ref].as_mv
: mi_mv_pred_q4(mi, ref))
: mi->mbmi.mv[ref].as_mv;
-
- // TODO(jkoleszar): This clamping is done in the incorrect place for the
- // scaling case. It needs to be done on the scaled MV, not the pre-scaling
- // MV. Note however that it performs the subsampling aware scaling so
- // that the result is always q4.
- // mv_precision precision is MV_PRECISION_Q4.
- const MV mv_q4 = clamp_mv_to_umv_border_sb(xd, &mv, bw, bh,
- pd->subsampling_x,
- pd->subsampling_y);
-
MV32 scaled_mv;
- int xs, ys, x0, y0, x0_16, y0_16, x1, y1, frame_width,
- frame_height, subpel_x, subpel_y, buf_stride;
+ int xs, ys, x0, y0, x0_16, y0_16, frame_width, frame_height, buf_stride,
+ subpel_x, subpel_y;
uint8_t *ref_frame, *buf_ptr;
const YV12_BUFFER_CONFIG *ref_buf = xd->block_refs[ref]->buf;
+ const MV mv_q4 = {
+ mv.row * (1 << (1 - pd->subsampling_y)),
+ mv.col * (1 << (1 - pd->subsampling_x))
+ };
// Get reference frame pointer, width and height.
if (plane == 0) {
@@ -327,10 +321,6 @@ static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
x0_16 += scaled_mv.col;
y0_16 += scaled_mv.row;
- // Get reference block bottom right coordinate.
- x1 = ((x0_16 + (w - 1) * xs) >> SUBPEL_BITS) + 1;
- y1 = ((y0_16 + (h - 1) * ys) >> SUBPEL_BITS) + 1;
-
// Get reference block pointer.
buf_ptr = ref_frame + y0 * pre_buf->stride + x0;
buf_stride = pre_buf->stride;
@@ -339,6 +329,9 @@ static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
// width/height is not a multiple of 8 pixels.
if (scaled_mv.col || scaled_mv.row ||
(frame_width & 0x7) || (frame_height & 0x7)) {
+ // Get reference block bottom right coordinate.
+ int x1 = ((x0_16 + (w - 1) * xs) >> SUBPEL_BITS) + 1;
+ int y1 = ((y0_16 + (h - 1) * ys) >> SUBPEL_BITS) + 1;
int x_pad = 0, y_pad = 0;
if (subpel_x || (sf->x_step_q4 & SUBPEL_MASK)) {
diff --git a/vp9/common/vp9_reconinter.h b/vp9/common/vp9_reconinter.h
index bf738c28b..dccd60938 100644
--- a/vp9/common/vp9_reconinter.h
+++ b/vp9/common/vp9_reconinter.h
@@ -39,18 +39,18 @@ void vp9_build_inter_predictor(const uint8_t *src, int src_stride,
enum mv_precision precision,
int x, int y);
-static int scaled_buffer_offset(int x_offset, int y_offset, int stride,
- const struct scale_factors *sf) {
+static INLINE int scaled_buffer_offset(int x_offset, int y_offset, int stride,
+ const struct scale_factors *sf) {
const int x = sf ? sf->scale_value_x(x_offset, sf) : x_offset;
const int y = sf ? sf->scale_value_y(y_offset, sf) : y_offset;
return y * stride + x;
}
-static void setup_pred_plane(struct buf_2d *dst,
- uint8_t *src, int stride,
- int mi_row, int mi_col,
- const struct scale_factors *scale,
- int subsampling_x, int subsampling_y) {
+static INLINE void setup_pred_plane(struct buf_2d *dst,
+ uint8_t *src, int stride,
+ int mi_row, int mi_col,
+ const struct scale_factors *scale,
+ int subsampling_x, int subsampling_y) {
const int x = (MI_SIZE * mi_col) >> subsampling_x;
const int y = (MI_SIZE * mi_row) >> subsampling_y;
dst->buf = src + scaled_buffer_offset(x, y, stride, scale);
diff --git a/vp9/common/vp9_rtcd_defs.sh b/vp9/common/vp9_rtcd_defs.sh
index 04a40bd58..7bdd11eb0 100644
--- a/vp9/common/vp9_rtcd_defs.sh
+++ b/vp9/common/vp9_rtcd_defs.sh
@@ -707,14 +707,14 @@ if [ "$CONFIG_INTERNAL_STATS" = "yes" ]; then
fi
# fdct functions
-prototype void vp9_short_fht4x4 "const int16_t *input, int16_t *output, int stride, int tx_type"
-specialize vp9_short_fht4x4 sse2 avx2
+prototype void vp9_fht4x4 "const int16_t *input, int16_t *output, int stride, int tx_type"
+specialize vp9_fht4x4 sse2 avx2
-prototype void vp9_short_fht8x8 "const int16_t *input, int16_t *output, int stride, int tx_type"
-specialize vp9_short_fht8x8 sse2 avx2
+prototype void vp9_fht8x8 "const int16_t *input, int16_t *output, int stride, int tx_type"
+specialize vp9_fht8x8 sse2 avx2
-prototype void vp9_short_fht16x16 "const int16_t *input, int16_t *output, int stride, int tx_type"
-specialize vp9_short_fht16x16 sse2 avx2
+prototype void vp9_fht16x16 "const int16_t *input, int16_t *output, int stride, int tx_type"
+specialize vp9_fht16x16 sse2 avx2
prototype void vp9_fwht4x4 "const int16_t *input, int16_t *output, int stride"
specialize vp9_fwht4x4
diff --git a/vp9/common/vp9_scale.h b/vp9/common/vp9_scale.h
index 90b0d0bf9..a9dda1889 100644
--- a/vp9/common/vp9_scale.h
+++ b/vp9/common/vp9_scale.h
@@ -40,12 +40,12 @@ void vp9_setup_scale_factors_for_frame(struct scale_factors *sf,
int other_w, int other_h,
int this_w, int this_h);
-static int vp9_is_valid_scale(const struct scale_factors *sf) {
+static INLINE int vp9_is_valid_scale(const struct scale_factors *sf) {
return sf->x_scale_fp != REF_INVALID_SCALE &&
sf->y_scale_fp != REF_INVALID_SCALE;
}
-static int vp9_is_scaled(const struct scale_factors *sf) {
+static INLINE int vp9_is_scaled(const struct scale_factors *sf) {
return sf->x_scale_fp != REF_NO_SCALE ||
sf->y_scale_fp != REF_NO_SCALE;
}
diff --git a/vp9/common/vp9_systemdependent.h b/vp9/common/vp9_systemdependent.h
index ee9a4823b..7455abce3 100644
--- a/vp9/common/vp9_systemdependent.h
+++ b/vp9/common/vp9_systemdependent.h
@@ -11,13 +11,17 @@
#ifndef VP9_COMMON_VP9_SYSTEMDEPENDENT_H_
#define VP9_COMMON_VP9_SYSTEMDEPENDENT_H_
-#ifdef __cplusplus
-extern "C" {
+#ifdef _MSC_VER
+# if _MSC_VER > 1310 && (defined(_M_X64) || defined(_M_IX86))
+# include <intrin.h>
+# define USE_MSC_INTRIN
+# endif
+# include <math.h>
+# define snprintf _snprintf
#endif
-#ifdef _MSC_VER
-#include <math.h>
-#define snprintf _snprintf
+#ifdef __cplusplus
+extern "C" {
#endif
#include "./vpx_config.h"
@@ -30,7 +34,7 @@ void vpx_reset_mmx_state(void);
#if defined(_MSC_VER) && _MSC_VER < 1800
// round is not defined in MSVC before VS2013.
-static int round(double x) {
+static INLINE int round(double x) {
if (x < 0)
return (int)ceil(x - 0.5);
else
@@ -44,9 +48,7 @@ static int round(double x) {
static INLINE int get_msb(unsigned int n) {
return 31 ^ __builtin_clz(n);
}
-#elif defined(_MSC_VER) && _MSC_VER > 1310 && \
- (defined(_M_X64) || defined(_M_IX86))
-#include <intrin.h>
+#elif defined(USE_MSC_INTRIN)
#pragma intrinsic(_BitScanReverse)
static INLINE int get_msb(unsigned int n) {
@@ -54,6 +56,7 @@ static INLINE int get_msb(unsigned int n) {
_BitScanReverse(&first_set_bit, n);
return first_set_bit;
}
+#undef USE_MSC_INTRIN
#else
// Returns (int)floor(log2(n)). n must be > 0.
static INLINE int get_msb(unsigned int n) {
diff --git a/vp9/common/x86/vp9_asm_stubs.c b/vp9/common/x86/vp9_asm_stubs.c
index 8ab5fb1bc..60018ea86 100644
--- a/vp9/common/x86/vp9_asm_stubs.c
+++ b/vp9/common/x86/vp9_asm_stubs.c
@@ -16,15 +16,15 @@
typedef void filter8_1dfunction (
const unsigned char *src_ptr,
- const unsigned int src_pitch,
+ const ptrdiff_t src_pitch,
unsigned char *output_ptr,
- unsigned int out_pitch,
+ ptrdiff_t out_pitch,
unsigned int output_height,
const short *filter
);
-#define FUN_CONV_1D(name, step_q4, filter, dir, src_start, avg, opt1, opt2) \
-void vp9_convolve8_##name##_##opt1(const uint8_t *src, ptrdiff_t src_stride, \
+#define FUN_CONV_1D(name, step_q4, filter, dir, src_start, avg, opt) \
+ void vp9_convolve8_##name##_##opt(const uint8_t *src, ptrdiff_t src_stride, \
uint8_t *dst, ptrdiff_t dst_stride, \
const int16_t *filter_x, int x_step_q4, \
const int16_t *filter_y, int y_step_q4, \
@@ -32,50 +32,68 @@ void vp9_convolve8_##name##_##opt1(const uint8_t *src, ptrdiff_t src_stride, \
if (step_q4 == 16 && filter[3] != 128) { \
if (filter[0] || filter[1] || filter[2]) { \
while (w >= 16) { \
- vp9_filter_block1d16_##dir##8_##avg##opt1(src_start, src_stride, \
- dst, dst_stride, \
- h, filter); \
+ vp9_filter_block1d16_##dir##8_##avg##opt(src_start, \
+ src_stride, \
+ dst, \
+ dst_stride, \
+ h, \
+ filter); \
src += 16; \
dst += 16; \
w -= 16; \
} \
while (w >= 8) { \
- vp9_filter_block1d8_##dir##8_##avg##opt1(src_start, src_stride, \
- dst, dst_stride, \
- h, filter); \
+ vp9_filter_block1d8_##dir##8_##avg##opt(src_start, \
+ src_stride, \
+ dst, \
+ dst_stride, \
+ h, \
+ filter); \
src += 8; \
dst += 8; \
w -= 8; \
} \
while (w >= 4) { \
- vp9_filter_block1d4_##dir##8_##avg##opt1(src_start, src_stride, \
- dst, dst_stride, \
- h, filter); \
+ vp9_filter_block1d4_##dir##8_##avg##opt(src_start, \
+ src_stride, \
+ dst, \
+ dst_stride, \
+ h, \
+ filter); \
src += 4; \
dst += 4; \
w -= 4; \
} \
} else { \
while (w >= 16) { \
- vp9_filter_block1d16_##dir##2_##avg##opt2(src, src_stride, \
- dst, dst_stride, \
- h, filter); \
+ vp9_filter_block1d16_##dir##2_##avg##opt(src, \
+ src_stride, \
+ dst, \
+ dst_stride, \
+ h, \
+ filter); \
src += 16; \
dst += 16; \
w -= 16; \
} \
while (w >= 8) { \
- vp9_filter_block1d8_##dir##2_##avg##opt2(src, src_stride, \
- dst, dst_stride, \
- h, filter); \
+ vp9_filter_block1d8_##dir##2_##avg##opt(src, \
+ src_stride, \
+ dst, \
+ dst_stride, \
+ h, \
+ filter); \
src += 8; \
dst += 8; \
w -= 8; \
} \
while (w >= 4) { \
- vp9_filter_block1d4_##dir##2_##avg##opt2(src, src_stride, \
- dst, dst_stride, \
- h, filter); \
+ vp9_filter_block1d4_##dir##2_##avg##opt(src, \
+ src_stride, \
+ dst, \
+ dst_stride, \
+ h, \
+ filter); \
src += 4; \
dst += 4; \
w -= 4; \
@@ -136,18 +154,18 @@ filter8_1dfunction vp9_filter_block1d8_h8_avg_ssse3;
filter8_1dfunction vp9_filter_block1d4_v8_avg_ssse3;
filter8_1dfunction vp9_filter_block1d4_h8_avg_ssse3;
-filter8_1dfunction vp9_filter_block1d16_v2_sse2;
-filter8_1dfunction vp9_filter_block1d16_h2_sse2;
-filter8_1dfunction vp9_filter_block1d8_v2_sse2;
-filter8_1dfunction vp9_filter_block1d8_h2_sse2;
-filter8_1dfunction vp9_filter_block1d4_v2_sse2;
-filter8_1dfunction vp9_filter_block1d4_h2_sse2;
-filter8_1dfunction vp9_filter_block1d16_v2_avg_sse2;
-filter8_1dfunction vp9_filter_block1d16_h2_avg_sse2;
-filter8_1dfunction vp9_filter_block1d8_v2_avg_sse2;
-filter8_1dfunction vp9_filter_block1d8_h2_avg_sse2;
-filter8_1dfunction vp9_filter_block1d4_v2_avg_sse2;
-filter8_1dfunction vp9_filter_block1d4_h2_avg_sse2;
+filter8_1dfunction vp9_filter_block1d16_v2_ssse3;
+filter8_1dfunction vp9_filter_block1d16_h2_ssse3;
+filter8_1dfunction vp9_filter_block1d8_v2_ssse3;
+filter8_1dfunction vp9_filter_block1d8_h2_ssse3;
+filter8_1dfunction vp9_filter_block1d4_v2_ssse3;
+filter8_1dfunction vp9_filter_block1d4_h2_ssse3;
+filter8_1dfunction vp9_filter_block1d16_v2_avg_ssse3;
+filter8_1dfunction vp9_filter_block1d16_h2_avg_ssse3;
+filter8_1dfunction vp9_filter_block1d8_v2_avg_ssse3;
+filter8_1dfunction vp9_filter_block1d8_h2_avg_ssse3;
+filter8_1dfunction vp9_filter_block1d4_v2_avg_ssse3;
+filter8_1dfunction vp9_filter_block1d4_h2_avg_ssse3;
// void vp9_convolve8_horiz_ssse3(const uint8_t *src, ptrdiff_t src_stride,
// uint8_t *dst, ptrdiff_t dst_stride,
@@ -169,11 +187,11 @@ filter8_1dfunction vp9_filter_block1d4_h2_avg_sse2;
// const int16_t *filter_x, int x_step_q4,
// const int16_t *filter_y, int y_step_q4,
// int w, int h);
-FUN_CONV_1D(horiz, x_step_q4, filter_x, h, src, , ssse3, sse2);
-FUN_CONV_1D(vert, y_step_q4, filter_y, v, src - src_stride * 3, , ssse3, sse2);
-FUN_CONV_1D(avg_horiz, x_step_q4, filter_x, h, src, avg_, ssse3, sse2);
+FUN_CONV_1D(horiz, x_step_q4, filter_x, h, src, , ssse3);
+FUN_CONV_1D(vert, y_step_q4, filter_y, v, src - src_stride * 3, , ssse3);
+FUN_CONV_1D(avg_horiz, x_step_q4, filter_x, h, src, avg_, ssse3);
FUN_CONV_1D(avg_vert, y_step_q4, filter_y, v, src - src_stride * 3, avg_,
- ssse3, sse2);
+ ssse3);
// void vp9_convolve8_ssse3(const uint8_t *src, ptrdiff_t src_stride,
// uint8_t *dst, ptrdiff_t dst_stride,
@@ -236,11 +254,10 @@ filter8_1dfunction vp9_filter_block1d4_h2_avg_sse2;
// const int16_t *filter_x, int x_step_q4,
// const int16_t *filter_y, int y_step_q4,
// int w, int h);
-FUN_CONV_1D(horiz, x_step_q4, filter_x, h, src, , sse2, sse2);
-FUN_CONV_1D(vert, y_step_q4, filter_y, v, src - src_stride * 3, , sse2, sse2);
-FUN_CONV_1D(avg_horiz, x_step_q4, filter_x, h, src, avg_, sse2, sse2);
-FUN_CONV_1D(avg_vert, y_step_q4, filter_y, v, src - src_stride * 3, avg_, sse2,
- sse2);
+FUN_CONV_1D(horiz, x_step_q4, filter_x, h, src, , sse2);
+FUN_CONV_1D(vert, y_step_q4, filter_y, v, src - src_stride * 3, , sse2);
+FUN_CONV_1D(avg_horiz, x_step_q4, filter_x, h, src, avg_, sse2);
+FUN_CONV_1D(avg_vert, y_step_q4, filter_y, v, src - src_stride * 3, avg_, sse2);
// void vp9_convolve8_sse2(const uint8_t *src, ptrdiff_t src_stride,
// uint8_t *dst, ptrdiff_t dst_stride,
diff --git a/vp9/common/x86/vp9_subpixel_bilinear_ssse3.asm b/vp9/common/x86/vp9_subpixel_bilinear_ssse3.asm
new file mode 100644
index 000000000..b5e18fe6d
--- /dev/null
+++ b/vp9/common/x86/vp9_subpixel_bilinear_ssse3.asm
@@ -0,0 +1,422 @@
+;
+; 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 "vpx_ports/x86_abi_support.asm"
+
+%macro GET_PARAM_4 0
+ mov rdx, arg(5) ;filter ptr
+ mov rsi, arg(0) ;src_ptr
+ mov rdi, arg(2) ;output_ptr
+ mov rcx, 0x0400040
+
+ movdqa xmm3, [rdx] ;load filters
+ psrldq xmm3, 6
+ packsswb xmm3, xmm3
+ pshuflw xmm3, xmm3, 0b ;k3_k4
+
+ movq xmm2, rcx ;rounding
+ pshufd xmm2, xmm2, 0
+
+ movsxd rax, DWORD PTR arg(1) ;pixels_per_line
+ movsxd rdx, DWORD PTR arg(3) ;out_pitch
+ movsxd rcx, DWORD PTR arg(4) ;output_height
+%endm
+
+%macro APPLY_FILTER_4 1
+ punpcklbw xmm0, xmm1
+ pmaddubsw xmm0, xmm3
+
+ paddsw xmm0, xmm2 ;rounding
+ psraw xmm0, 7 ;shift
+ packuswb xmm0, xmm0 ;pack to byte
+
+%if %1
+ movd xmm1, [rdi]
+ pavgb xmm0, xmm1
+%endif
+ movd [rdi], xmm0
+ lea rsi, [rsi + rax]
+ lea rdi, [rdi + rdx]
+ dec rcx
+%endm
+
+%macro GET_PARAM 0
+ mov rdx, arg(5) ;filter ptr
+ mov rsi, arg(0) ;src_ptr
+ mov rdi, arg(2) ;output_ptr
+ mov rcx, 0x0400040
+
+ movdqa xmm7, [rdx] ;load filters
+ psrldq xmm7, 6
+ packsswb xmm7, xmm7
+ pshuflw xmm7, xmm7, 0b ;k3_k4
+ punpcklwd xmm7, xmm7
+
+ movq xmm6, rcx ;rounding
+ pshufd xmm6, xmm6, 0
+
+ movsxd rax, DWORD PTR arg(1) ;pixels_per_line
+ movsxd rdx, DWORD PTR arg(3) ;out_pitch
+ movsxd rcx, DWORD PTR arg(4) ;output_height
+%endm
+
+%macro APPLY_FILTER_8 1
+ punpcklbw xmm0, xmm1
+ pmaddubsw xmm0, xmm7
+
+ paddsw xmm0, xmm6 ;rounding
+ psraw xmm0, 7 ;shift
+ packuswb xmm0, xmm0 ;pack back to byte
+
+%if %1
+ movq xmm1, [rdi]
+ pavgb xmm0, xmm1
+%endif
+ movq [rdi], xmm0 ;store the result
+
+ lea rsi, [rsi + rax]
+ lea rdi, [rdi + rdx]
+ dec rcx
+%endm
+
+%macro APPLY_FILTER_16 1
+ punpcklbw xmm0, xmm1
+ punpckhbw xmm2, xmm1
+ pmaddubsw xmm0, xmm7
+ pmaddubsw xmm2, xmm7
+
+ paddsw xmm0, xmm6 ;rounding
+ paddsw xmm2, xmm6
+ psraw xmm0, 7 ;shift
+ psraw xmm2, 7
+ packuswb xmm0, xmm2 ;pack back to byte
+
+%if %1
+ movdqu xmm1, [rdi]
+ pavgb xmm0, xmm1
+%endif
+ movdqu [rdi], xmm0 ;store the result
+
+ lea rsi, [rsi + rax]
+ lea rdi, [rdi + rdx]
+ dec rcx
+%endm
+
+global sym(vp9_filter_block1d4_v2_ssse3) PRIVATE
+sym(vp9_filter_block1d4_v2_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM_4
+.loop:
+ movd xmm0, [rsi] ;load src
+ movd xmm1, [rsi + rax]
+
+ APPLY_FILTER_4 0
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d8_v2_ssse3) PRIVATE
+sym(vp9_filter_block1d8_v2_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ SAVE_XMM 7
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM
+.loop:
+ movq xmm0, [rsi] ;0
+ movq xmm1, [rsi + rax] ;1
+
+ APPLY_FILTER_8 0
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ RESTORE_XMM
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d16_v2_ssse3) PRIVATE
+sym(vp9_filter_block1d16_v2_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ SAVE_XMM 7
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM
+.loop:
+ movdqu xmm0, [rsi] ;0
+ movdqu xmm1, [rsi + rax] ;1
+ movdqa xmm2, xmm0
+
+ APPLY_FILTER_16 0
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ RESTORE_XMM
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d4_v2_avg_ssse3) PRIVATE
+sym(vp9_filter_block1d4_v2_avg_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM_4
+.loop:
+ movd xmm0, [rsi] ;load src
+ movd xmm1, [rsi + rax]
+
+ APPLY_FILTER_4 1
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d8_v2_avg_ssse3) PRIVATE
+sym(vp9_filter_block1d8_v2_avg_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ SAVE_XMM 7
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM
+.loop:
+ movq xmm0, [rsi] ;0
+ movq xmm1, [rsi + rax] ;1
+
+ APPLY_FILTER_8 1
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ RESTORE_XMM
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d16_v2_avg_ssse3) PRIVATE
+sym(vp9_filter_block1d16_v2_avg_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ SAVE_XMM 7
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM
+.loop:
+ movdqu xmm0, [rsi] ;0
+ movdqu xmm1, [rsi + rax] ;1
+ movdqa xmm2, xmm0
+
+ APPLY_FILTER_16 1
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ RESTORE_XMM
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d4_h2_ssse3) PRIVATE
+sym(vp9_filter_block1d4_h2_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM_4
+.loop:
+ movdqu xmm0, [rsi] ;load src
+ movdqa xmm1, xmm0
+ psrldq xmm1, 1
+
+ APPLY_FILTER_4 0
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d8_h2_ssse3) PRIVATE
+sym(vp9_filter_block1d8_h2_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ SAVE_XMM 7
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM
+.loop:
+ movdqu xmm0, [rsi] ;load src
+ movdqa xmm1, xmm0
+ psrldq xmm1, 1
+
+ APPLY_FILTER_8 0
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ RESTORE_XMM
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d16_h2_ssse3) PRIVATE
+sym(vp9_filter_block1d16_h2_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ SAVE_XMM 7
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM
+.loop:
+ movdqu xmm0, [rsi] ;load src
+ movdqu xmm1, [rsi + 1]
+ movdqa xmm2, xmm0
+
+ APPLY_FILTER_16 0
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ RESTORE_XMM
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d4_h2_avg_ssse3) PRIVATE
+sym(vp9_filter_block1d4_h2_avg_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM_4
+.loop:
+ movdqu xmm0, [rsi] ;load src
+ movdqa xmm1, xmm0
+ psrldq xmm1, 1
+
+ APPLY_FILTER_4 1
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d8_h2_avg_ssse3) PRIVATE
+sym(vp9_filter_block1d8_h2_avg_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ SAVE_XMM 7
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM
+.loop:
+ movdqu xmm0, [rsi] ;load src
+ movdqa xmm1, xmm0
+ psrldq xmm1, 1
+
+ APPLY_FILTER_8 1
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ RESTORE_XMM
+ UNSHADOW_ARGS
+ pop rbp
+ ret
+
+global sym(vp9_filter_block1d16_h2_avg_ssse3) PRIVATE
+sym(vp9_filter_block1d16_h2_avg_ssse3):
+ push rbp
+ mov rbp, rsp
+ SHADOW_ARGS_TO_STACK 6
+ SAVE_XMM 7
+ push rsi
+ push rdi
+ ; end prolog
+
+ GET_PARAM
+.loop:
+ movdqu xmm0, [rsi] ;load src
+ movdqu xmm1, [rsi + 1]
+ movdqa xmm2, xmm0
+
+ APPLY_FILTER_16 1
+ jnz .loop
+
+ ; begin epilog
+ pop rdi
+ pop rsi
+ RESTORE_XMM
+ UNSHADOW_ARGS
+ pop rbp
+ ret
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c
index 93ef7503f..d37afa5bc 100644
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -691,9 +691,14 @@ static void apply_frame_size(VP9D_COMP *pbi, int width, int height) {
vp9_update_frame_size(cm);
}
- vp9_realloc_frame_buffer(get_frame_new_buffer(cm), cm->width, cm->height,
- cm->subsampling_x, cm->subsampling_y,
- VP9_DEC_BORDER_IN_PIXELS);
+ if (vp9_realloc_frame_buffer(
+ get_frame_new_buffer(cm), cm->width, cm->height,
+ cm->subsampling_x, cm->subsampling_y, VP9_DEC_BORDER_IN_PIXELS,
+ &cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer, cm->get_fb_cb,
+ cm->cb_priv)) {
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to allocate frame buffer");
+ }
}
static void setup_frame_size(VP9D_COMP *pbi,
@@ -1114,7 +1119,7 @@ static size_t read_uncompressed_header(VP9D_COMP *pbi,
cm->show_existing_frame = vp9_rb_read_bit(rb);
if (cm->show_existing_frame) {
// Show an existing frame directly.
- int frame_to_show = cm->ref_frame_map[vp9_rb_read_literal(rb, 3)];
+ const int frame_to_show = cm->ref_frame_map[vp9_rb_read_literal(rb, 3)];
ref_cnt_fb(cm->frame_bufs, &cm->new_fb_idx, frame_to_show);
pbi->refresh_frame_flags = 0;
cm->lf.filter_level = 0;
diff --git a/vp9/decoder/vp9_dthread.c b/vp9/decoder/vp9_dthread.c
index 128b9f8af..542732aa0 100644
--- a/vp9/decoder/vp9_dthread.c
+++ b/vp9/decoder/vp9_dthread.c
@@ -220,11 +220,13 @@ void vp9_loop_filter_alloc(VP9_COMMON *cm, VP9LfSync *lf_sync, int rows,
CHECK_MEM_ERROR(cm, lf_sync->mutex_,
vpx_malloc(sizeof(*lf_sync->mutex_) * rows));
+ for (i = 0; i < rows; ++i) {
+ pthread_mutex_init(&lf_sync->mutex_[i], NULL);
+ }
+
CHECK_MEM_ERROR(cm, lf_sync->cond_,
vpx_malloc(sizeof(*lf_sync->cond_) * rows));
-
for (i = 0; i < rows; ++i) {
- pthread_mutex_init(&lf_sync->mutex_[i], NULL);
pthread_cond_init(&lf_sync->cond_[i], NULL);
}
#endif // CONFIG_MULTITHREAD
@@ -242,18 +244,29 @@ void vp9_loop_filter_dealloc(VP9LfSync *lf_sync, int rows) {
if (lf_sync != NULL) {
int i;
- for (i = 0; i < rows; ++i) {
- pthread_mutex_destroy(&lf_sync->mutex_[i]);
- pthread_cond_destroy(&lf_sync->cond_[i]);
+ if (lf_sync->mutex_ != NULL) {
+ for (i = 0; i < rows; ++i) {
+ pthread_mutex_destroy(&lf_sync->mutex_[i]);
+ }
+ vpx_free(lf_sync->mutex_);
+ }
+ if (lf_sync->cond_ != NULL) {
+ for (i = 0; i < rows; ++i) {
+ pthread_cond_destroy(&lf_sync->cond_[i]);
+ }
+ vpx_free(lf_sync->cond_);
}
- vpx_free(lf_sync->mutex_);
- vpx_free(lf_sync->cond_);
vpx_free(lf_sync->cur_sb_col);
+ // clear the structure as the source of this call may be a resize in which
+ // case this call will be followed by an _alloc() which may fail.
+ vpx_memset(lf_sync, 0, sizeof(*lf_sync));
}
#else
(void)rows;
- if (lf_sync != NULL)
+ if (lf_sync != NULL) {
vpx_free(lf_sync->cur_sb_col);
+ vpx_memset(lf_sync, 0, sizeof(*lf_sync));
+ }
#endif // CONFIG_MULTITHREAD
}
diff --git a/vp9/decoder/vp9_onyxd_if.c b/vp9/decoder/vp9_onyxd_if.c
index 803d536ba..fd3488355 100644
--- a/vp9/decoder/vp9_onyxd_if.c
+++ b/vp9/decoder/vp9_onyxd_if.c
@@ -290,9 +290,14 @@ static void swap_frame_buffers(VP9D_COMP *pbi) {
VP9_COMMON *const cm = &pbi->common;
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
- if (mask & 1)
+ if (mask & 1) {
+ const int old_idx = cm->ref_frame_map[ref_index];
ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[ref_index],
cm->new_fb_idx);
+ if (old_idx >= 0 && cm->frame_bufs[old_idx].ref_count == 0)
+ cm->release_fb_cb(cm->cb_priv,
+ &cm->frame_bufs[old_idx].raw_frame_buffer);
+ }
++ref_index;
}
diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
index dc64a107c..c8f334f4b 100644
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -33,11 +33,6 @@
#include "vp9/encoder/vp9_tokenize.h"
#include "vp9/encoder/vp9_write_bit_buffer.h"
-
-#if defined(SECTIONBITS_OUTPUT)
-unsigned __int64 Sectionbits[500];
-#endif
-
#ifdef ENTROPY_STATS
vp9_coeff_stats tree_update_hist[TX_SIZES][PLANE_TYPES];
extern unsigned int active_section;
diff --git a/vp9/encoder/vp9_dct.c b/vp9/encoder/vp9_dct.c
index a840b480a..a9d168cc8 100644
--- a/vp9/encoder/vp9_dct.c
+++ b/vp9/encoder/vp9_dct.c
@@ -18,8 +18,6 @@
#include "vp9/common/vp9_idct.h"
#include "vp9/common/vp9_systemdependent.h"
-#include "vp9/encoder/vp9_dct.h"
-
static INLINE int fdct_round_shift(int input) {
int rv = ROUND_POWER_OF_TWO(input, DCT_CONST_BITS);
assert(INT16_MIN <= rv && rv <= INT16_MAX);
@@ -157,32 +155,36 @@ static const transform_2d FHT_4[] = {
{ fadst4, fadst4 } // ADST_ADST = 3
};
-void vp9_short_fht4x4_c(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
- int16_t out[4 * 4];
- int16_t *outptr = &out[0];
- int i, j;
- int16_t temp_in[4], temp_out[4];
- const transform_2d ht = FHT_4[tx_type];
+void vp9_fht4x4_c(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
+ if (tx_type == DCT_DCT) {
+ vp9_fdct4x4_c(input, output, stride);
+ } else {
+ int16_t out[4 * 4];
+ int16_t *outptr = &out[0];
+ int i, j;
+ int16_t temp_in[4], temp_out[4];
+ const transform_2d ht = FHT_4[tx_type];
- // Columns
- for (i = 0; i < 4; ++i) {
- for (j = 0; j < 4; ++j)
- temp_in[j] = input[j * stride + i] * 16;
- if (i == 0 && temp_in[0])
- temp_in[0] += 1;
- ht.cols(temp_in, temp_out);
- for (j = 0; j < 4; ++j)
- outptr[j * 4 + i] = temp_out[j];
- }
+ // Columns
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 4; ++j)
+ temp_in[j] = input[j * stride + i] * 16;
+ if (i == 0 && temp_in[0])
+ temp_in[0] += 1;
+ ht.cols(temp_in, temp_out);
+ for (j = 0; j < 4; ++j)
+ outptr[j * 4 + i] = temp_out[j];
+ }
- // Rows
- for (i = 0; i < 4; ++i) {
- for (j = 0; j < 4; ++j)
- temp_in[j] = out[j + i * 4];
- ht.rows(temp_in, temp_out);
- for (j = 0; j < 4; ++j)
- output[j + i * 4] = (temp_out[j] + 1) >> 2;
+ // Rows
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 4; ++j)
+ temp_in[j] = out[j + i * 4];
+ ht.rows(temp_in, temp_out);
+ for (j = 0; j < 4; ++j)
+ output[j + i * 4] = (temp_out[j] + 1) >> 2;
+ }
}
}
@@ -565,30 +567,34 @@ static const transform_2d FHT_8[] = {
{ fadst8, fadst8 } // ADST_ADST = 3
};
-void vp9_short_fht8x8_c(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
- int16_t out[64];
- int16_t *outptr = &out[0];
- int i, j;
- int16_t temp_in[8], temp_out[8];
- const transform_2d ht = FHT_8[tx_type];
-
- // Columns
- for (i = 0; i < 8; ++i) {
- for (j = 0; j < 8; ++j)
- temp_in[j] = input[j * stride + i] * 4;
- ht.cols(temp_in, temp_out);
- for (j = 0; j < 8; ++j)
- outptr[j * 8 + i] = temp_out[j];
- }
+void vp9_fht8x8_c(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
+ if (tx_type == DCT_DCT) {
+ vp9_fdct8x8_c(input, output, stride);
+ } else {
+ int16_t out[64];
+ int16_t *outptr = &out[0];
+ int i, j;
+ int16_t temp_in[8], temp_out[8];
+ const transform_2d ht = FHT_8[tx_type];
+
+ // Columns
+ for (i = 0; i < 8; ++i) {
+ for (j = 0; j < 8; ++j)
+ temp_in[j] = input[j * stride + i] * 4;
+ ht.cols(temp_in, temp_out);
+ for (j = 0; j < 8; ++j)
+ outptr[j * 8 + i] = temp_out[j];
+ }
- // Rows
- for (i = 0; i < 8; ++i) {
- for (j = 0; j < 8; ++j)
- temp_in[j] = out[j + i * 8];
- ht.rows(temp_in, temp_out);
- for (j = 0; j < 8; ++j)
- output[j + i * 8] = (temp_out[j] + (temp_out[j] < 0)) >> 1;
+ // Rows
+ for (i = 0; i < 8; ++i) {
+ for (j = 0; j < 8; ++j)
+ temp_in[j] = out[j + i * 8];
+ ht.rows(temp_in, temp_out);
+ for (j = 0; j < 8; ++j)
+ output[j + i * 8] = (temp_out[j] + (temp_out[j] < 0)) >> 1;
+ }
}
}
@@ -958,31 +964,34 @@ static const transform_2d FHT_16[] = {
{ fadst16, fadst16 } // ADST_ADST = 3
};
-void vp9_short_fht16x16_c(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
- int16_t out[256];
- int16_t *outptr = &out[0];
- int i, j;
- int16_t temp_in[16], temp_out[16];
- const transform_2d ht = FHT_16[tx_type];
-
- // Columns
- for (i = 0; i < 16; ++i) {
- for (j = 0; j < 16; ++j)
- temp_in[j] = input[j * stride + i] * 4;
- ht.cols(temp_in, temp_out);
- for (j = 0; j < 16; ++j)
- outptr[j * 16 + i] = (temp_out[j] + 1 + (temp_out[j] < 0)) >> 2;
-// outptr[j * 16 + i] = (temp_out[j] + 1 + (temp_out[j] > 0)) >> 2;
- }
+void vp9_fht16x16_c(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
+ if (tx_type == DCT_DCT) {
+ vp9_fdct16x16_c(input, output, stride);
+ } else {
+ int16_t out[256];
+ int16_t *outptr = &out[0];
+ int i, j;
+ int16_t temp_in[16], temp_out[16];
+ const transform_2d ht = FHT_16[tx_type];
+
+ // Columns
+ for (i = 0; i < 16; ++i) {
+ for (j = 0; j < 16; ++j)
+ temp_in[j] = input[j * stride + i] * 4;
+ ht.cols(temp_in, temp_out);
+ for (j = 0; j < 16; ++j)
+ outptr[j * 16 + i] = (temp_out[j] + 1 + (temp_out[j] < 0)) >> 2;
+ }
- // Rows
- for (i = 0; i < 16; ++i) {
- for (j = 0; j < 16; ++j)
- temp_in[j] = out[j + i * 16];
- ht.rows(temp_in, temp_out);
- for (j = 0; j < 16; ++j)
- output[j + i * 16] = temp_out[j];
+ // Rows
+ for (i = 0; i < 16; ++i) {
+ for (j = 0; j < 16; ++j)
+ temp_in[j] = out[j + i * 16];
+ ht.rows(temp_in, temp_out);
+ for (j = 0; j < 16; ++j)
+ output[j + i * 16] = temp_out[j];
+ }
}
}
@@ -1375,27 +1384,3 @@ void vp9_fdct32x32_rd_c(const int16_t *input, int16_t *out, int stride) {
out[j + i * 32] = temp_out[j];
}
}
-
-void vp9_fht4x4(TX_TYPE tx_type, const int16_t *input, int16_t *output,
- int stride) {
- if (tx_type == DCT_DCT)
- vp9_fdct4x4(input, output, stride);
- else
- vp9_short_fht4x4(input, output, stride, tx_type);
-}
-
-void vp9_fht8x8(TX_TYPE tx_type, const int16_t *input, int16_t *output,
- int stride) {
- if (tx_type == DCT_DCT)
- vp9_fdct8x8(input, output, stride);
- else
- vp9_short_fht8x8(input, output, stride, tx_type);
-}
-
-void vp9_fht16x16(TX_TYPE tx_type, const int16_t *input, int16_t *output,
- int stride) {
- if (tx_type == DCT_DCT)
- vp9_fdct16x16(input, output, stride);
- else
- vp9_short_fht16x16(input, output, stride, tx_type);
-}
diff --git a/vp9/encoder/vp9_dct.h b/vp9/encoder/vp9_dct.h
deleted file mode 100644
index cf5f001a9..000000000
--- a/vp9/encoder/vp9_dct.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-
-#ifndef VP9_ENCODER_VP9_DCT_H_
-#define VP9_ENCODER_VP9_DCT_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void vp9_fht4x4(TX_TYPE tx_type, const int16_t *input, int16_t *output,
- int stride);
-
-void vp9_fht8x8(TX_TYPE tx_type, const int16_t *input, int16_t *output,
- int stride);
-
-void vp9_fht16x16(TX_TYPE tx_type, const int16_t *input, int16_t *output,
- int stride);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // VP9_ENCODER_VP9_DCT_H_
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 7fb5a03ba..0022ef3b4 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -40,8 +40,6 @@
#include "vp9/encoder/vp9_tokenize.h"
#include "vp9/encoder/vp9_vaq.h"
-#define DBG_PRNT_SEGMAP 0
-
static INLINE uint8_t *get_sb_index(MACROBLOCK *x, BLOCK_SIZE subsize) {
switch (subsize) {
case BLOCK_64X64:
@@ -321,7 +319,7 @@ static void build_activity_map(VP9_COMP *cpi) {
}
// Macroblock activity masking
-void vp9_activity_masking(VP9_COMP *cpi, MACROBLOCK *x) {
+static void activity_masking(VP9_COMP *cpi, MACROBLOCK *x) {
#if USE_ACT_INDEX
x->rdmult += *(x->mb_activity_ptr) * (x->rdmult >> 2);
x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
@@ -493,24 +491,26 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
} else {
// Note how often each mode chosen as best
cpi->mode_chosen_counts[mb_mode_index]++;
- if (is_inter_block(mbmi) &&
- (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV)) {
- int_mv best_mv[2];
- for (i = 0; i < 1 + has_second_ref(mbmi); ++i)
- best_mv[i].as_int = mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_int;
- vp9_update_mv_count(cpi, x, best_mv);
- }
- if (cm->interp_filter == SWITCHABLE && is_inter_mode(mbmi->mode)) {
- const int ctx = vp9_get_pred_context_switchable_interp(xd);
- ++cm->counts.switchable_interp[ctx][mbmi->interp_filter];
+ if (is_inter_block(mbmi)) {
+ if (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV) {
+ int_mv best_mv[2];
+ for (i = 0; i < 1 + has_second_ref(mbmi); ++i)
+ best_mv[i].as_int = mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_int;
+ vp9_update_mv_count(cpi, x, best_mv);
+ }
+
+ if (cm->interp_filter == SWITCHABLE) {
+ const int ctx = vp9_get_pred_context_switchable_interp(xd);
+ ++cm->counts.switchable_interp[ctx][mbmi->interp_filter];
+ }
}
cpi->rd_comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff;
cpi->rd_comp_pred_diff[COMPOUND_REFERENCE] += ctx->comp_pred_diff;
cpi->rd_comp_pred_diff[REFERENCE_MODE_SELECT] += ctx->hybrid_pred_diff;
- for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++)
+ for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i)
cpi->rd_filter_diff[i] += ctx->best_filter_diff[i];
}
}
@@ -613,7 +613,7 @@ static void set_offsets(VP9_COMP *cpi, const TileInfo *const tile,
x->encode_breakout = cpi->segment_encode_breakout[mbmi->segment_id];
} else {
mbmi->segment_id = 0;
- x->encode_breakout = cpi->oxcf.encode_breakout;
+ x->encode_breakout = cpi->encode_breakout;
}
}
@@ -673,7 +673,7 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, const TileInfo *const tile,
}
if (cpi->oxcf.tuning == VP8_TUNE_SSIM)
- vp9_activity_masking(cpi, x);
+ activity_masking(cpi, x);
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
vp9_clear_system_state(); // __asm emms;
@@ -713,36 +713,40 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, const TileInfo *const tile,
static void update_stats(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
- MACROBLOCK *const x = &cpi->mb;
- MACROBLOCKD *const xd = &x->e_mbd;
- MODE_INFO *mi = xd->mi_8x8[0];
- MB_MODE_INFO *const mbmi = &mi->mbmi;
+ const MACROBLOCK *const x = &cpi->mb;
+ const MACROBLOCKD *const xd = &x->e_mbd;
+ const MODE_INFO *const mi = xd->mi_8x8[0];
+ const MB_MODE_INFO *const mbmi = &mi->mbmi;
if (!frame_is_intra_only(cm)) {
const int seg_ref_active = vp9_segfeature_active(&cm->seg, mbmi->segment_id,
SEG_LVL_REF_FRAME);
+ if (!seg_ref_active) {
+ FRAME_COUNTS *const counts = &cm->counts;
+ const int inter_block = is_inter_block(mbmi);
- if (!seg_ref_active)
- cm->counts.intra_inter[vp9_get_intra_inter_context(xd)]
- [is_inter_block(mbmi)]++;
-
- // If the segment reference feature is enabled we have only a single
- // reference frame allowed for the segment so exclude it from
- // the reference frame counts used to work out probabilities.
- if (is_inter_block(mbmi) && !seg_ref_active) {
- if (cm->reference_mode == REFERENCE_MODE_SELECT)
- cm->counts.comp_inter[vp9_get_reference_mode_context(cm, xd)]
- [has_second_ref(mbmi)]++;
-
- if (has_second_ref(mbmi)) {
- cm->counts.comp_ref[vp9_get_pred_context_comp_ref_p(cm, xd)]
- [mbmi->ref_frame[0] == GOLDEN_FRAME]++;
- } else {
- cm->counts.single_ref[vp9_get_pred_context_single_ref_p1(xd)][0]
- [mbmi->ref_frame[0] != LAST_FRAME]++;
- if (mbmi->ref_frame[0] != LAST_FRAME)
- cm->counts.single_ref[vp9_get_pred_context_single_ref_p2(xd)][1]
- [mbmi->ref_frame[0] != GOLDEN_FRAME]++;
+ counts->intra_inter[vp9_get_intra_inter_context(xd)][inter_block]++;
+
+ // If the segment reference feature is enabled we have only a single
+ // reference frame allowed for the segment so exclude it from
+ // the reference frame counts used to work out probabilities.
+ if (inter_block) {
+ const MV_REFERENCE_FRAME ref0 = mbmi->ref_frame[0];
+
+ if (cm->reference_mode == REFERENCE_MODE_SELECT)
+ counts->comp_inter[vp9_get_reference_mode_context(cm, xd)]
+ [has_second_ref(mbmi)]++;
+
+ if (has_second_ref(mbmi)) {
+ counts->comp_ref[vp9_get_pred_context_comp_ref_p(cm, xd)]
+ [ref0 == GOLDEN_FRAME]++;
+ } else {
+ counts->single_ref[vp9_get_pred_context_single_ref_p1(xd)][0]
+ [ref0 != LAST_FRAME]++;
+ if (ref0 != LAST_FRAME)
+ counts->single_ref[vp9_get_pred_context_single_ref_p2(xd)][1]
+ [ref0 != GOLDEN_FRAME]++;
+ }
}
}
}
@@ -1074,17 +1078,18 @@ static void update_state_rt(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
} else {
// Note how often each mode chosen as best
cpi->mode_chosen_counts[mb_mode_index]++;
- if (is_inter_block(mbmi) &&
- (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV)) {
- int_mv best_mv[2];
- for (i = 0; i < 1 + has_second_ref(mbmi); ++i)
- best_mv[i].as_int = mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_int;
- vp9_update_mv_count(cpi, x, best_mv);
- }
+ if (is_inter_block(mbmi)) {
+ if (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV) {
+ int_mv best_mv[2];
+ for (i = 0; i < 1 + has_second_ref(mbmi); ++i)
+ best_mv[i].as_int = mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_int;
+ vp9_update_mv_count(cpi, x, best_mv);
+ }
- if (cm->interp_filter == SWITCHABLE && is_inter_mode(mbmi->mode)) {
- const int ctx = vp9_get_pred_context_switchable_interp(xd);
- ++cm->counts.switchable_interp[ctx][mbmi->interp_filter];
+ if (cm->interp_filter == SWITCHABLE) {
+ const int ctx = vp9_get_pred_context_switchable_interp(xd);
+ ++cm->counts.switchable_interp[ctx][mbmi->interp_filter];
+ }
}
}
}
@@ -1595,30 +1600,14 @@ static void compute_fast_motion_search_level(VP9_COMP *cpi, BLOCK_SIZE bsize) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
- // Only use 8x8 result for non HD videos.
- // int use_8x8 = (MIN(cpi->common.width, cpi->common.height) < 720) ? 1 : 0;
- int use_8x8 = 1;
-
- if (cm->frame_type && !cpi->rc.is_src_frame_alt_ref &&
- ((use_8x8 && bsize == BLOCK_16X16) ||
- bsize == BLOCK_32X32 || bsize == BLOCK_64X64)) {
- int ref0 = 0, ref1 = 0, ref2 = 0, ref3 = 0;
- PICK_MODE_CONTEXT *block_context = NULL;
-
- if (bsize == BLOCK_16X16) {
- block_context = x->sb8x8_context[x->sb_index][x->mb_index];
- } else if (bsize == BLOCK_32X32) {
- block_context = x->mb_context[x->sb_index];
- } else if (bsize == BLOCK_64X64) {
- block_context = x->sb32_context;
- }
-
- if (block_context) {
- ref0 = block_context[0].mic.mbmi.ref_frame[0];
- ref1 = block_context[1].mic.mbmi.ref_frame[0];
- ref2 = block_context[2].mic.mbmi.ref_frame[0];
- ref3 = block_context[3].mic.mbmi.ref_frame[0];
- }
+ if (cm->frame_type == INTER_FRAME &&
+ !cpi->rc.is_src_frame_alt_ref &&
+ (bsize == BLOCK_16X16 || bsize == BLOCK_32X32 || bsize == BLOCK_64X64)) {
+ const PICK_MODE_CONTEXT *block_context = get_block_context(x, bsize);
+ const int ref0 = block_context[0].mic.mbmi.ref_frame[0];
+ const int ref1 = block_context[1].mic.mbmi.ref_frame[0];
+ const int ref2 = block_context[2].mic.mbmi.ref_frame[0];
+ const int ref3 = block_context[3].mic.mbmi.ref_frame[0];
// Currently, only consider 4 inter reference frames.
if (ref0 && ref1 && ref2 && ref3) {
@@ -2183,118 +2172,6 @@ static void switch_tx_mode(VP9_COMP *cpi) {
cpi->common.tx_mode = ALLOW_32X32;
}
-static void encode_frame_internal(VP9_COMP *cpi) {
- int mi_row;
- MACROBLOCK *const x = &cpi->mb;
- VP9_COMMON *const cm = &cpi->common;
- MACROBLOCKD *const xd = &x->e_mbd;
-
-// fprintf(stderr, "encode_frame_internal frame %d (%d) type %d\n",
-// cpi->common.current_video_frame, cpi->common.show_frame,
-// cm->frame_type);
-
-// debug output
-#if DBG_PRNT_SEGMAP
- {
- FILE *statsfile;
- statsfile = fopen("segmap2.stt", "a");
- fprintf(statsfile, "\n");
- fclose(statsfile);
- }
-#endif
-
- vp9_zero(cm->counts.switchable_interp);
- vp9_zero(cpi->tx_stepdown_count);
-
- xd->mi_8x8 = cm->mi_grid_visible;
- // required for vp9_frame_init_quantizer
- xd->mi_8x8[0] = cm->mi;
-
- xd->last_mi = cm->prev_mi;
-
- vp9_zero(cm->counts.mv);
- vp9_zero(cpi->coef_counts);
- vp9_zero(cm->counts.eob_branch);
-
- cpi->mb.e_mbd.lossless = cm->base_qindex == 0 && cm->y_dc_delta_q == 0
- && cm->uv_dc_delta_q == 0 && cm->uv_ac_delta_q == 0;
- switch_lossless_mode(cpi, cpi->mb.e_mbd.lossless);
-
- vp9_frame_init_quantizer(cpi);
-
- vp9_initialize_rd_consts(cpi);
- vp9_initialize_me_consts(cpi, cm->base_qindex);
- switch_tx_mode(cpi);
-
- if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
- // Initialize encode frame context.
- init_encode_frame_mb_context(cpi);
-
- // Build a frame level activity map
- build_activity_map(cpi);
- }
-
- // Re-initialize encode frame context.
- init_encode_frame_mb_context(cpi);
-
- vp9_zero(cpi->rd_comp_pred_diff);
- vp9_zero(cpi->rd_filter_diff);
- vp9_zero(cpi->rd_tx_select_diff);
- vp9_zero(cpi->rd_tx_select_threshes);
-
- set_prev_mi(cm);
-
- {
- struct vpx_usec_timer emr_timer;
- vpx_usec_timer_start(&emr_timer);
-
- {
- // Take tiles into account and give start/end MB
- int tile_col, tile_row;
- TOKENEXTRA *tp = cpi->tok;
- const int tile_cols = 1 << cm->log2_tile_cols;
- const int tile_rows = 1 << cm->log2_tile_rows;
-
- for (tile_row = 0; tile_row < tile_rows; tile_row++) {
- for (tile_col = 0; tile_col < tile_cols; tile_col++) {
- TileInfo tile;
- TOKENEXTRA *tp_old = tp;
-
- // For each row of SBs in the frame
- vp9_tile_init(&tile, cm, tile_row, tile_col);
- for (mi_row = tile.mi_row_start;
- mi_row < tile.mi_row_end; mi_row += 8)
- encode_sb_row(cpi, &tile, mi_row, &tp);
-
- cpi->tok_count[tile_row][tile_col] = (unsigned int)(tp - tp_old);
- assert(tp - cpi->tok <= get_token_alloc(cm->mb_rows, cm->mb_cols));
- }
- }
- }
-
- vpx_usec_timer_mark(&emr_timer);
- cpi->time_encode_sb_row += vpx_usec_timer_elapsed(&emr_timer);
- }
-
- if (cpi->sf.skip_encode_sb) {
- int j;
- unsigned int intra_count = 0, inter_count = 0;
- for (j = 0; j < INTRA_INTER_CONTEXTS; ++j) {
- intra_count += cm->counts.intra_inter[j][0];
- inter_count += cm->counts.intra_inter[j][1];
- }
- cpi->sf.skip_encode_frame = ((intra_count << 2) < inter_count);
- cpi->sf.skip_encode_frame &= (cm->frame_type != KEY_FRAME);
- cpi->sf.skip_encode_frame &= cm->show_frame;
- } else {
- cpi->sf.skip_encode_frame = 0;
- }
-
-#if 0
- // Keep record of the total distortion this time around for future use
- cpi->last_frame_distortion = cpi->frame_distortion;
-#endif
-}
static int check_dual_ref_flags(VP9_COMP *cpi) {
const int ref_flags = cpi->ref_frame_flags;
@@ -2584,28 +2461,18 @@ static void encode_rtc_sb_row(VP9_COMP *cpi, const TileInfo *const tile,
&dummy_rate, &dummy_dist, 1);
}
}
+// end RTC play code
-
-static void encode_rtc_frame_internal(VP9_COMP *cpi) {
+static void encode_frame_internal(VP9_COMP *cpi) {
int mi_row;
- MACROBLOCK * const x = &cpi->mb;
- VP9_COMMON * const cm = &cpi->common;
- MACROBLOCKD * const xd = &x->e_mbd;
+ MACROBLOCK *const x = &cpi->mb;
+ VP9_COMMON *const cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
// fprintf(stderr, "encode_frame_internal frame %d (%d) type %d\n",
// cpi->common.current_video_frame, cpi->common.show_frame,
// cm->frame_type);
-// debug output
-#if DBG_PRNT_SEGMAP
- {
- FILE *statsfile;
- statsfile = fopen("segmap2.stt", "a");
- fprintf(statsfile, "\n");
- fclose(statsfile);
- }
-#endif
-
vp9_zero(cm->counts.switchable_interp);
vp9_zero(cpi->tx_stepdown_count);
@@ -2615,7 +2482,7 @@ static void encode_rtc_frame_internal(VP9_COMP *cpi) {
xd->last_mi = cm->prev_mi;
- vp9_zero(cpi->common.counts.mv);
+ vp9_zero(cm->counts.mv);
vp9_zero(cpi->coef_counts);
vp9_zero(cm->counts.eob_branch);
@@ -2628,7 +2495,6 @@ static void encode_rtc_frame_internal(VP9_COMP *cpi) {
vp9_initialize_rd_consts(cpi);
vp9_initialize_me_consts(cpi, cm->base_qindex);
switch_tx_mode(cpi);
- cpi->sf.always_this_block_size = BLOCK_16X16;
if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
// Initialize encode frame context.
@@ -2667,9 +2533,12 @@ static void encode_rtc_frame_internal(VP9_COMP *cpi) {
// For each row of SBs in the frame
vp9_tile_init(&tile, cm, tile_row, tile_col);
for (mi_row = tile.mi_row_start;
- mi_row < tile.mi_row_end; mi_row += 8)
- encode_rtc_sb_row(cpi, &tile, mi_row, &tp);
-
+ mi_row < tile.mi_row_end; mi_row += 8) {
+ if (cpi->sf.use_pick_mode)
+ encode_rtc_sb_row(cpi, &tile, mi_row, &tp);
+ else
+ encode_sb_row(cpi, &tile, mi_row, &tp);
+ }
cpi->tok_count[tile_row][tile_col] = (unsigned int)(tp - tp_old);
assert(tp - cpi->tok <= get_token_alloc(cm->mb_rows, cm->mb_cols));
}
@@ -2699,8 +2568,6 @@ static void encode_rtc_frame_internal(VP9_COMP *cpi) {
cpi->last_frame_distortion = cpi->frame_distortion;
#endif
}
-// end RTC play code
-
void vp9_encode_frame(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
@@ -2725,7 +2592,7 @@ void vp9_encode_frame(VP9_COMP *cpi) {
}
}
- if (cpi->sf.RD) {
+ if (cpi->sf.frame_parameter_update) {
int i;
REFERENCE_MODE reference_mode;
/*
@@ -2775,10 +2642,7 @@ void vp9_encode_frame(VP9_COMP *cpi) {
select_tx_mode(cpi);
cm->reference_mode = reference_mode;
- if (cpi->sf.super_fast_rtc)
- encode_rtc_frame_internal(cpi);
- else
- encode_frame_internal(cpi);
+ encode_frame_internal(cpi);
for (i = 0; i < REFERENCE_MODES; ++i) {
const int diff = (int) (cpi->rd_comp_pred_diff[i] / cm->MBs);
@@ -2858,10 +2722,7 @@ void vp9_encode_frame(VP9_COMP *cpi) {
} else {
// Force the usage of the BILINEAR interp_filter.
cm->interp_filter = BILINEAR;
- if (cpi->sf.super_fast_rtc)
- encode_rtc_frame_internal(cpi);
- else
- encode_frame_internal(cpi);
+ encode_frame_internal(cpi);
}
}
@@ -2938,7 +2799,7 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
const int mi_height = num_8x8_blocks_high_lookup[bsize];
x->skip_recode = !x->select_txfm_size && mbmi->sb_type >= BLOCK_8X8 &&
(cpi->oxcf.aq_mode != COMPLEXITY_AQ) &&
- !cpi->sf.super_fast_rtc;
+ !cpi->sf.use_pick_mode;
x->skip_optimize = ctx->is_coded;
ctx->is_coded = 1;
x->use_lp32x32fdct = cpi->sf.use_lp32x32fdct;
diff --git a/vp9/encoder/vp9_encodemb.c b/vp9/encoder/vp9_encodemb.c
index 376a899e0..2c6535164 100644
--- a/vp9/encoder/vp9_encodemb.c
+++ b/vp9/encoder/vp9_encodemb.c
@@ -19,12 +19,22 @@
#include "vp9/common/vp9_reconintra.h"
#include "vp9/common/vp9_systemdependent.h"
-#include "vp9/encoder/vp9_dct.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_rdopt.h"
#include "vp9/encoder/vp9_tokenize.h"
+struct optimize_ctx {
+ ENTROPY_CONTEXT ta[MAX_MB_PLANE][16];
+ ENTROPY_CONTEXT tl[MAX_MB_PLANE][16];
+};
+
+struct encode_b_args {
+ MACROBLOCK *x;
+ struct optimize_ctx *ctx;
+ unsigned char *skip_coeff;
+};
+
void vp9_subtract_block_c(int rows, int cols,
int16_t *diff_ptr, ptrdiff_t diff_stride,
const uint8_t *src_ptr, ptrdiff_t src_stride,
@@ -338,11 +348,9 @@ static void optimize_init_b(int plane, BLOCK_SIZE bsize,
pd->above_context, pd->left_context,
num_4x4_w, num_4x4_h);
}
-void vp9_xform_quant(int plane, int block, BLOCK_SIZE plane_bsize,
- TX_SIZE tx_size, void *arg) {
- struct encode_b_args* const args = arg;
- MACROBLOCK* const x = args->x;
- MACROBLOCKD* const xd = &x->e_mbd;
+void vp9_xform_quant(MACROBLOCK *x, int plane, int block,
+ BLOCK_SIZE plane_bsize, TX_SIZE tx_size) {
+ MACROBLOCKD *const xd = &x->e_mbd;
struct macroblock_plane *const p = &x->plane[plane];
struct macroblockd_plane *const pd = &xd->plane[plane];
int16_t *coeff = BLOCK_OFFSET(p->coeff, block);
@@ -421,7 +429,7 @@ static void encode_block(int plane, int block, BLOCK_SIZE plane_bsize,
}
if (!x->skip_recode)
- vp9_xform_quant(plane, block, plane_bsize, tx_size, arg);
+ vp9_xform_quant(x, plane, block, plane_bsize, tx_size);
if (x->optimize && (!x->skip_recode || !x->skip_optimize)) {
vp9_optimize_b(plane, block, plane_bsize, tx_size, x, ctx);
@@ -469,7 +477,7 @@ static void encode_block_pass1(int plane, int block, BLOCK_SIZE plane_bsize,
txfrm_block_to_raster_xy(plane_bsize, tx_size, block, &i, &j);
dst = &pd->dst.buf[4 * j * pd->dst.stride + 4 * i];
- vp9_xform_quant(plane, block, plane_bsize, tx_size, arg);
+ vp9_xform_quant(x, plane, block, plane_bsize, tx_size);
if (p->eobs[block] == 0)
return;
@@ -509,8 +517,8 @@ void vp9_encode_sb(MACROBLOCK *x, BLOCK_SIZE bsize) {
vp9_foreach_transformed_block(xd, bsize, encode_block, &arg);
}
-void vp9_encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize,
- TX_SIZE tx_size, void *arg) {
+static void encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize,
+ TX_SIZE tx_size, void *arg) {
struct encode_b_args* const args = arg;
MACROBLOCK *const x = args->x;
MACROBLOCKD *const xd = &x->e_mbd;
@@ -571,7 +579,7 @@ void vp9_encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize,
if (!x->skip_recode) {
vp9_subtract_block(16, 16, src_diff, diff_stride,
src, p->src.stride, dst, pd->dst.stride);
- vp9_fht16x16(tx_type, src_diff, coeff, diff_stride);
+ vp9_fht16x16(src_diff, coeff, diff_stride, tx_type);
vp9_quantize_b(coeff, 256, x->skip_block, p->zbin, p->round,
p->quant, p->quant_shift, qcoeff, dqcoeff,
pd->dequant, p->zbin_extra, eob, scan_order->scan,
@@ -591,7 +599,7 @@ void vp9_encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize,
if (!x->skip_recode) {
vp9_subtract_block(8, 8, src_diff, diff_stride,
src, p->src.stride, dst, pd->dst.stride);
- vp9_fht8x8(tx_type, src_diff, coeff, diff_stride);
+ vp9_fht8x8(src_diff, coeff, diff_stride, tx_type);
vp9_quantize_b(coeff, 64, x->skip_block, p->zbin, p->round, p->quant,
p->quant_shift, qcoeff, dqcoeff,
pd->dequant, p->zbin_extra, eob, scan_order->scan,
@@ -617,7 +625,7 @@ void vp9_encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize,
vp9_subtract_block(4, 4, src_diff, diff_stride,
src, p->src.stride, dst, pd->dst.stride);
if (tx_type != DCT_DCT)
- vp9_short_fht4x4(src_diff, coeff, diff_stride, tx_type);
+ vp9_fht4x4(src_diff, coeff, diff_stride, tx_type);
else
x->fwd_txm4x4(src_diff, coeff, diff_stride);
vp9_quantize_b(coeff, 16, x->skip_block, p->zbin, p->round, p->quant,
@@ -643,21 +651,25 @@ void vp9_encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize,
*(args->skip_coeff) = 0;
}
+void vp9_encode_block_intra(MACROBLOCK *x, int plane, int block,
+ BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
+ unsigned char *skip_coeff) {
+ struct encode_b_args arg = {x, NULL, skip_coeff};
+ encode_block_intra(plane, block, plane_bsize, tx_size, &arg);
+}
+
+
void vp9_encode_intra_block_y(MACROBLOCK *x, BLOCK_SIZE bsize) {
- MACROBLOCKD* const xd = &x->e_mbd;
- struct optimize_ctx ctx;
- MB_MODE_INFO *mbmi = &xd->mi_8x8[0]->mbmi;
- struct encode_b_args arg = {x, &ctx, &mbmi->skip_coeff};
+ const MACROBLOCKD *const xd = &x->e_mbd;
+ struct encode_b_args arg = {x, NULL, &xd->mi_8x8[0]->mbmi.skip_coeff};
- vp9_foreach_transformed_block_in_plane(xd, bsize, 0, vp9_encode_block_intra,
- &arg);
+ vp9_foreach_transformed_block_in_plane(xd, bsize, 0, encode_block_intra,
+ &arg);
}
void vp9_encode_intra_block_uv(MACROBLOCK *x, BLOCK_SIZE bsize) {
- MACROBLOCKD* const xd = &x->e_mbd;
- struct optimize_ctx ctx;
- MB_MODE_INFO *mbmi = &xd->mi_8x8[0]->mbmi;
- struct encode_b_args arg = {x, &ctx, &mbmi->skip_coeff};
- vp9_foreach_transformed_block_uv(xd, bsize, vp9_encode_block_intra, &arg);
+ const MACROBLOCKD *const xd = &x->e_mbd;
+ struct encode_b_args arg = {x, NULL, &xd->mi_8x8[0]->mbmi.skip_coeff};
+ vp9_foreach_transformed_block_uv(xd, bsize, encode_block_intra, &arg);
}
int vp9_encode_intra(MACROBLOCK *x, int use_16x16_pred) {
diff --git a/vp9/encoder/vp9_encodemb.h b/vp9/encoder/vp9_encodemb.h
index 9f6c9f069..cd7c46b58 100644
--- a/vp9/encoder/vp9_encodemb.h
+++ b/vp9/encoder/vp9_encodemb.h
@@ -20,29 +20,19 @@
extern "C" {
#endif
-struct optimize_ctx {
- ENTROPY_CONTEXT ta[MAX_MB_PLANE][16];
- ENTROPY_CONTEXT tl[MAX_MB_PLANE][16];
-};
-
-struct encode_b_args {
- MACROBLOCK *x;
- struct optimize_ctx *ctx;
- unsigned char *skip_coeff;
-};
-
void vp9_encode_sb(MACROBLOCK *x, BLOCK_SIZE bsize);
void vp9_encode_sby(MACROBLOCK *x, BLOCK_SIZE bsize);
-void vp9_xform_quant(int plane, int block, BLOCK_SIZE plane_bsize,
- TX_SIZE tx_size, void *arg);
+void vp9_xform_quant(MACROBLOCK *x, int plane, int block,
+ BLOCK_SIZE plane_bsize, TX_SIZE tx_size);
void vp9_subtract_sby(MACROBLOCK *x, BLOCK_SIZE bsize);
void vp9_subtract_sbuv(MACROBLOCK *x, BLOCK_SIZE bsize);
void vp9_subtract_sb(MACROBLOCK *x, BLOCK_SIZE bsize);
-void vp9_encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize,
- TX_SIZE tx_size, void *arg);
+void vp9_encode_block_intra(MACROBLOCK *x, int plane, int block,
+ BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
+ unsigned char *skip_coeff);
void vp9_encode_intra_block_y(MACROBLOCK *x, BLOCK_SIZE bsize);
void vp9_encode_intra_block_uv(MACROBLOCK *x, BLOCK_SIZE bsize);
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index 153046440..3e04c2faf 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -49,8 +49,9 @@
#define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x) - 0.000001 : (x) + 0.000001)
-#define MIN_BOOST 300
-#define KEY_FRAME_BOOST 2000
+#define MIN_KF_BOOST 300
+
+#define DISABLE_RC_LONG_TERM_MEM 0
static void swap_yv12(YV12_BUFFER_CONFIG *a, YV12_BUFFER_CONFIG *b) {
YV12_BUFFER_CONFIG temp = *a;
@@ -132,9 +133,9 @@ static int input_stats(struct twopass_rc *p, FIRSTPASS_STATS *fps) {
return 1;
}
-static void output_stats(const VP9_COMP *cpi,
+static void output_stats(const VP9_COMP *cpi,
struct vpx_codec_pkt_list *pktlist,
- FIRSTPASS_STATS *stats) {
+ FIRSTPASS_STATS *stats) {
struct vpx_codec_cx_pkt pkt;
pkt.kind = VPX_CODEC_STATS_PKT;
pkt.data.twopass_stats.buf = stats;
@@ -265,9 +266,9 @@ static void avg_stats(FIRSTPASS_STATS *section) {
// Calculate a modified Error used in distributing bits between easier and
// harder frames.
-static double calculate_modified_err(VP9_COMP *cpi,
- FIRSTPASS_STATS *this_frame) {
- struct twopass_rc *const twopass = &cpi->twopass;
+static double calculate_modified_err(const VP9_COMP *cpi,
+ const FIRSTPASS_STATS *this_frame) {
+ const struct twopass_rc *const twopass = &cpi->twopass;
const FIRSTPASS_STATS *const stats = &twopass->total_stats;
const double av_err = stats->ssim_weighted_pred_err / stats->count;
double modified_error = av_err * pow(this_frame->ssim_weighted_pred_err /
@@ -336,7 +337,7 @@ static double simple_weight(const YV12_BUFFER_CONFIG *buf) {
}
// This function returns the maximum target rate per frame.
-static int frame_max_bits(VP9_COMP *cpi) {
+static int frame_max_bits(const VP9_COMP *cpi) {
int64_t max_bits =
((int64_t)cpi->rc.av_per_frame_bandwidth *
(int64_t)cpi->oxcf.two_pass_vbrmax_section) / 100;
@@ -468,7 +469,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
TileInfo tile;
struct macroblock_plane *const p = x->plane;
struct macroblockd_plane *const pd = xd->plane;
- PICK_MODE_CONTEXT *ctx = &x->sb64_context;
+ const PICK_MODE_CONTEXT *ctx = &x->sb64_context;
int i;
int recon_yoffset, recon_uvoffset;
@@ -901,12 +902,12 @@ static double calc_correction_factor(double err_per_mb,
return fclamp(pow(error_term, power_term), 0.05, 5.0);
}
-static int estimate_max_q(VP9_COMP *cpi, FIRSTPASS_STATS *fpstats,
- int section_target_bandwitdh) {
+int vp9_twopass_worst_quality(VP9_COMP *cpi, FIRSTPASS_STATS *fpstats,
+ int section_target_bandwitdh) {
int q;
const int num_mbs = cpi->common.MBs;
int target_norm_bits_per_mb;
- RATE_CONTROL *const rc = &cpi->rc;
+ const RATE_CONTROL *const rc = &cpi->rc;
const double section_err = fpstats->coded_error / fpstats->count;
const double err_per_mb = section_err / num_mbs;
@@ -936,58 +937,6 @@ static int estimate_max_q(VP9_COMP *cpi, FIRSTPASS_STATS *fpstats,
return q;
}
-// For cq mode estimate a cq level that matches the observed
-// complexity and data rate.
-static int estimate_cq(VP9_COMP *cpi,
- FIRSTPASS_STATS *fpstats,
- int section_target_bandwitdh) {
- int q;
- int num_mbs = cpi->common.MBs;
- int target_norm_bits_per_mb;
-
- double section_err = (fpstats->coded_error / fpstats->count);
- double err_per_mb = section_err / num_mbs;
- double err_correction_factor;
- double clip_iiratio;
- double clip_iifactor;
-
- target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20))
- ? (512 * section_target_bandwitdh) / num_mbs
- : 512 * (section_target_bandwitdh / num_mbs);
-
-
- // II ratio correction factor for clip as a whole
- clip_iiratio = cpi->twopass.total_stats.intra_error /
- DOUBLE_DIVIDE_CHECK(cpi->twopass.total_stats.coded_error);
- clip_iifactor = 1.0 - ((clip_iiratio - 10.0) * 0.025);
- if (clip_iifactor < 0.80)
- clip_iifactor = 0.80;
-
- // Try and pick a Q that can encode the content at the given rate.
- for (q = 0; q < MAXQ; q++) {
- int bits_per_mb_at_this_q;
-
- // Error per MB based correction factor
- err_correction_factor =
- calc_correction_factor(err_per_mb, 100.0, 0.5, 0.90, q) * clip_iifactor;
-
- bits_per_mb_at_this_q =
- vp9_rc_bits_per_mb(INTER_FRAME, q, err_correction_factor);
-
- if (bits_per_mb_at_this_q <= target_norm_bits_per_mb)
- break;
- }
-
- // Clip value to range "best allowed to (worst allowed - 1)"
- q = select_cq_level(q);
- if (q >= cpi->rc.worst_quality)
- q = cpi->rc.worst_quality - 1;
- if (q < cpi->rc.best_quality)
- q = cpi->rc.best_quality;
-
- return q;
-}
-
extern void vp9_new_framerate(VP9_COMP *cpi, double framerate);
void vp9_init_second_pass(VP9_COMP *cpi) {
@@ -1091,12 +1040,10 @@ static double get_prediction_decay_rate(const VP9_COMMON *cm,
// Function to test for a condition where a complex transition is followed
// by a static section. For example in slide shows where there is a fade
// between slides. This is to help with more optimal kf and gf positioning.
-static int detect_transition_to_still(
- VP9_COMP *cpi,
- int frame_interval,
- int still_interval,
- double loop_decay_rate,
- double last_decay_rate) {
+static int detect_transition_to_still(VP9_COMP *cpi, int frame_interval,
+ int still_interval,
+ double loop_decay_rate,
+ double last_decay_rate) {
int trans_to_still = 0;
// Break clause to detect very still sections after motion
@@ -1464,7 +1411,7 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
double mv_in_out_accumulator = 0.0;
double abs_mv_in_out_accumulator = 0.0;
double mv_ratio_accumulator_thresh;
- int max_bits = frame_max_bits(cpi); // Max for a single frame
+ const int max_bits = frame_max_bits(cpi); // Max for a single frame
unsigned int allow_alt_ref = cpi->oxcf.play_alternate &&
cpi->oxcf.lag_in_frames;
@@ -1689,27 +1636,23 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
#endif
// Calculate the bits to be allocated to the group as a whole
- if ((cpi->twopass.kf_group_bits > 0) &&
- (cpi->twopass.kf_group_error_left > 0)) {
- cpi->twopass.gf_group_bits =
- (int64_t)(cpi->twopass.kf_group_bits *
+ if (twopass->kf_group_bits > 0 && twopass->kf_group_error_left > 0) {
+ twopass->gf_group_bits = (int64_t)(cpi->twopass.kf_group_bits *
(gf_group_err / cpi->twopass.kf_group_error_left));
} else {
- cpi->twopass.gf_group_bits = 0;
+ twopass->gf_group_bits = 0;
}
- cpi->twopass.gf_group_bits =
- (cpi->twopass.gf_group_bits < 0)
- ? 0
- : (cpi->twopass.gf_group_bits > cpi->twopass.kf_group_bits)
- ? cpi->twopass.kf_group_bits : cpi->twopass.gf_group_bits;
+ twopass->gf_group_bits = (twopass->gf_group_bits < 0) ?
+ 0 : (twopass->gf_group_bits > twopass->kf_group_bits) ?
+ twopass->kf_group_bits : twopass->gf_group_bits;
// Clip cpi->twopass.gf_group_bits based on user supplied data rate
// variability limit (cpi->oxcf.two_pass_vbrmax_section)
- if (cpi->twopass.gf_group_bits > (int64_t)max_bits * rc->baseline_gf_interval)
- cpi->twopass.gf_group_bits = (int64_t)max_bits * rc->baseline_gf_interval;
+ if (twopass->gf_group_bits > (int64_t)max_bits * rc->baseline_gf_interval)
+ twopass->gf_group_bits = (int64_t)max_bits * rc->baseline_gf_interval;
// Reset the file position
- reset_fpf_position(&cpi->twopass, start_pos);
+ reset_fpf_position(twopass, start_pos);
// Assign bits to the arf or gf.
for (i = 0; i <= (rc->source_alt_ref_pending &&
@@ -1737,17 +1680,17 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
// Calculate the number of bits to be spent on the gf or arf based on
// the boost number
- gf_bits = (int)((double)boost * (cpi->twopass.gf_group_bits /
- (double)allocation_chunks));
+ gf_bits = (int)((double)boost * (twopass->gf_group_bits /
+ (double)allocation_chunks));
// If the frame that is to be boosted is simpler than the average for
// the gf/arf group then use an alternative calculation
// based on the error score of the frame itself
if (rc->baseline_gf_interval < 1 ||
mod_frame_err < gf_group_err / (double)rc->baseline_gf_interval) {
- double alt_gf_grp_bits = (double)cpi->twopass.kf_group_bits *
+ double alt_gf_grp_bits = (double)twopass->kf_group_bits *
(mod_frame_err * (double)rc->baseline_gf_interval) /
- DOUBLE_DIVIDE_CHECK(cpi->twopass.kf_group_error_left);
+ DOUBLE_DIVIDE_CHECK(twopass->kf_group_error_left);
int alt_gf_bits = (int)((double)boost * (alt_gf_grp_bits /
(double)allocation_chunks));
@@ -1758,9 +1701,9 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
// If it is harder than other frames in the group make sure it at
// least receives an allocation in keeping with its relative error
// score, otherwise it may be worse off than an "un-boosted" frame.
- int alt_gf_bits = (int)((double)cpi->twopass.kf_group_bits *
+ int alt_gf_bits = (int)((double)twopass->kf_group_bits *
mod_frame_err /
- DOUBLE_DIVIDE_CHECK(cpi->twopass.kf_group_error_left));
+ DOUBLE_DIVIDE_CHECK(twopass->kf_group_error_left));
if (alt_gf_bits > gf_bits)
gf_bits = alt_gf_bits;
@@ -1771,23 +1714,23 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
gf_bits = 0;
if (i == 0) {
- cpi->twopass.gf_bits = gf_bits;
+ twopass->gf_bits = gf_bits;
}
if (i == 1 ||
(!rc->source_alt_ref_pending &&
- (cpi->common.frame_type != KEY_FRAME))) {
+ cpi->common.frame_type != KEY_FRAME)) {
// Per frame bit target for this frame
- rc->per_frame_bandwidth = gf_bits;
+ vp9_rc_set_frame_target(cpi, gf_bits);
}
}
{
// Adjust KF group bits and error remaining
- cpi->twopass.kf_group_error_left -= (int64_t)gf_group_err;
- cpi->twopass.kf_group_bits -= cpi->twopass.gf_group_bits;
+ twopass->kf_group_error_left -= (int64_t)gf_group_err;
+ twopass->kf_group_bits -= twopass->gf_group_bits;
- if (cpi->twopass.kf_group_bits < 0)
- cpi->twopass.kf_group_bits = 0;
+ if (twopass->kf_group_bits < 0)
+ twopass->kf_group_bits = 0;
// If this is an arf update we want to remove the score for the
// overlay frame at the end which will usually be very cheap to code.
@@ -1796,18 +1739,18 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
// For normal GFs remove the score for the GF itself unless this is
// also a key frame in which case it has already been accounted for.
if (rc->source_alt_ref_pending) {
- cpi->twopass.gf_group_error_left = (int64_t)gf_group_err - mod_frame_err;
+ twopass->gf_group_error_left = (int64_t)gf_group_err - mod_frame_err;
} else if (cpi->common.frame_type != KEY_FRAME) {
- cpi->twopass.gf_group_error_left = (int64_t)(gf_group_err
+ twopass->gf_group_error_left = (int64_t)(gf_group_err
- gf_first_frame_err);
} else {
- cpi->twopass.gf_group_error_left = (int64_t)gf_group_err;
+ twopass->gf_group_error_left = (int64_t)gf_group_err;
}
- cpi->twopass.gf_group_bits -= cpi->twopass.gf_bits;
+ twopass->gf_group_bits -= twopass->gf_bits;
- if (cpi->twopass.gf_group_bits < 0)
- cpi->twopass.gf_group_bits = 0;
+ if (twopass->gf_group_bits < 0)
+ twopass->gf_group_bits = 0;
// This condition could fail if there are two kfs very close together
// despite (MIN_GF_INTERVAL) and would cause a divide by 0 in the
@@ -1816,12 +1759,10 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
const int boost = rc->source_alt_ref_pending ? b_boost : rc->gfu_boost;
if (boost >= 150) {
- int alt_extra_bits;
- int pct_extra = (boost - 100) / 50;
- pct_extra = (pct_extra > 20) ? 20 : pct_extra;
-
- alt_extra_bits = (int)((cpi->twopass.gf_group_bits * pct_extra) / 100);
- cpi->twopass.gf_group_bits -= alt_extra_bits;
+ const int pct_extra = MIN(20, (boost - 100) / 50);
+ const int alt_extra_bits = (int)((twopass->gf_group_bits * pct_extra) /
+ 100);
+ twopass->gf_group_bits -= alt_extra_bits;
}
}
}
@@ -1830,20 +1771,20 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
FIRSTPASS_STATS sectionstats;
zero_stats(&sectionstats);
- reset_fpf_position(&cpi->twopass, start_pos);
+ reset_fpf_position(twopass, start_pos);
for (i = 0; i < rc->baseline_gf_interval; i++) {
- input_stats(&cpi->twopass, &next_frame);
+ input_stats(twopass, &next_frame);
accumulate_stats(&sectionstats, &next_frame);
}
avg_stats(&sectionstats);
- cpi->twopass.section_intra_rating = (int)
+ twopass->section_intra_rating = (int)
(sectionstats.intra_error /
DOUBLE_DIVIDE_CHECK(sectionstats.coded_error));
- reset_fpf_position(&cpi->twopass, start_pos);
+ reset_fpf_position(twopass, start_pos);
}
}
@@ -1879,18 +1820,13 @@ static void assign_std_frame_bits(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
cpi->twopass.gf_group_bits = 0;
// Per frame bit target for this frame.
- cpi->rc.per_frame_bandwidth = target_frame_size;
-}
-
-static int test_for_kf_one_pass(VP9_COMP *cpi) {
- // Placeholder function for auto key frame
- return 0;
+ vp9_rc_set_frame_target(cpi, target_frame_size);
}
static int test_candidate_kf(VP9_COMP *cpi,
- FIRSTPASS_STATS *last_frame,
- FIRSTPASS_STATS *this_frame,
- FIRSTPASS_STATS *next_frame) {
+ const FIRSTPASS_STATS *last_frame,
+ const FIRSTPASS_STATS *this_frame,
+ const FIRSTPASS_STATS *next_frame) {
int is_viable_kf = 0;
// Does the frame satisfy the primary criteria of a key frame
@@ -2222,8 +2158,8 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
if (kf_boost < (rc->frames_to_key * 3))
kf_boost = (rc->frames_to_key * 3);
- if (kf_boost < MIN_BOOST)
- kf_boost = MIN_BOOST;
+ if (kf_boost < MIN_KF_BOOST)
+ kf_boost = MIN_KF_BOOST;
// Make a note of baseline boost and the zero motion
// accumulator value for use elsewhere.
@@ -2287,13 +2223,9 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
twopass->kf_bits = alt_kf_bits;
}
}
-
twopass->kf_group_bits -= twopass->kf_bits;
-
- // Peer frame bit target for this frame
- rc->per_frame_bandwidth = twopass->kf_bits;
- // Convert to a per second bitrate
- cpi->target_bandwidth = (int)(twopass->kf_bits * cpi->output_framerate);
+ // Per frame bit target for this frame.
+ vp9_rc_set_frame_target(cpi, twopass->kf_bits);
}
// Note the total error score of the kf group minus the key frame itself
@@ -2305,73 +2237,7 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
twopass->modified_error_left -= kf_group_err;
}
-void vp9_get_svc_params(VP9_COMP *cpi) {
- VP9_COMMON *const cm = &cpi->common;
- if ((cm->current_video_frame == 0) ||
- (cm->frame_flags & FRAMEFLAGS_KEY) ||
- (cpi->oxcf.auto_key && (cpi->rc.frames_since_key %
- cpi->key_frame_frequency == 0))) {
- cm->frame_type = KEY_FRAME;
- cpi->rc.source_alt_ref_active = 0;
- } else {
- cm->frame_type = INTER_FRAME;
- }
- cpi->rc.frames_till_gf_update_due = INT_MAX;
- cpi->rc.baseline_gf_interval = INT_MAX;
-}
-
-// Use this macro to turn on/off use of alt-refs in one-pass mode.
-#define USE_ALTREF_FOR_ONE_PASS 1
-
-void vp9_get_one_pass_params(VP9_COMP *cpi) {
- VP9_COMMON *const cm = &cpi->common;
- if (!cpi->refresh_alt_ref_frame &&
- (cm->current_video_frame == 0 ||
- cm->frame_flags & FRAMEFLAGS_KEY ||
- cpi->rc.frames_to_key == 0 ||
- (cpi->oxcf.auto_key && test_for_kf_one_pass(cpi)))) {
- cm->frame_type = KEY_FRAME;
- cpi->rc.this_key_frame_forced = cm->current_video_frame != 0 &&
- cpi->rc.frames_to_key == 0;
- cpi->rc.frames_to_key = cpi->key_frame_frequency;
- cpi->rc.kf_boost = KEY_FRAME_BOOST;
- cpi->rc.source_alt_ref_active = 0;
- } else {
- cm->frame_type = INTER_FRAME;
- }
- if (cpi->rc.frames_till_gf_update_due == 0) {
- cpi->rc.baseline_gf_interval = DEFAULT_GF_INTERVAL;
- cpi->rc.frames_till_gf_update_due = cpi->rc.baseline_gf_interval;
- // NOTE: frames_till_gf_update_due must be <= frames_to_key.
- if (cpi->rc.frames_till_gf_update_due > cpi->rc.frames_to_key)
- cpi->rc.frames_till_gf_update_due = cpi->rc.frames_to_key;
- cpi->refresh_golden_frame = 1;
- cpi->rc.source_alt_ref_pending = USE_ALTREF_FOR_ONE_PASS;
- cpi->rc.gfu_boost = 1000;
- }
-}
-
-void vp9_get_one_pass_cbr_params(VP9_COMP *cpi) {
- VP9_COMMON *const cm = &cpi->common;
- if ((cm->current_video_frame == 0 ||
- cm->frame_flags & FRAMEFLAGS_KEY ||
- cpi->rc.frames_to_key == 0 ||
- (cpi->oxcf.auto_key && test_for_kf_one_pass(cpi)))) {
- cm->frame_type = KEY_FRAME;
- cpi->rc.this_key_frame_forced = cm->current_video_frame != 0 &&
- cpi->rc.frames_to_key == 0;
- cpi->rc.frames_to_key = cpi->key_frame_frequency;
- cpi->rc.kf_boost = KEY_FRAME_BOOST;
- cpi->rc.source_alt_ref_active = 0;
- } else {
- cm->frame_type = INTER_FRAME;
- }
- // Don't use gf_update by default in CBR mode.
- cpi->rc.frames_till_gf_update_due = INT_MAX;
- cpi->rc.baseline_gf_interval = INT_MAX;
-}
-
-void vp9_get_first_pass_params(VP9_COMP *cpi) {
+void vp9_rc_get_first_pass_params(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
if (!cpi->refresh_alt_ref_frame &&
(cm->current_video_frame == 0 ||
@@ -2384,7 +2250,7 @@ void vp9_get_first_pass_params(VP9_COMP *cpi) {
cpi->rc.frames_to_key = INT_MAX;
}
-void vp9_get_second_pass_params(VP9_COMP *cpi) {
+void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
struct twopass_rc *const twopass = &cpi->twopass;
@@ -2395,28 +2261,28 @@ void vp9_get_second_pass_params(VP9_COMP *cpi) {
double this_frame_intra_error;
double this_frame_coded_error;
+ int target;
if (!twopass->stats_in)
return;
if (cpi->refresh_alt_ref_frame) {
cm->frame_type = INTER_FRAME;
- rc->per_frame_bandwidth = twopass->gf_bits;
+ vp9_rc_set_frame_target(cpi, twopass->gf_bits);
return;
}
vp9_clear_system_state();
if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
- rc->active_worst_quality = cpi->oxcf.cq_level;
+ twopass->active_worst_quality = cpi->oxcf.cq_level;
} else if (cm->current_video_frame == 0) {
// Special case code for first frame.
const int section_target_bandwidth = (int)(twopass->bits_left /
- frames_left);
- const int tmp_q = estimate_max_q(cpi, &twopass->total_left_stats,
- section_target_bandwidth);
-
- rc->active_worst_quality = tmp_q;
+ frames_left);
+ const int tmp_q = vp9_twopass_worst_quality(cpi, &twopass->total_left_stats,
+ section_target_bandwidth);
+ twopass->active_worst_quality = tmp_q;
rc->ni_av_qi = tmp_q;
rc->avg_q = vp9_convert_qindex_to_q(tmp_q);
@@ -2461,11 +2327,11 @@ void vp9_get_second_pass_params(VP9_COMP *cpi) {
if (twopass->gf_zeromotion_pct > 995) {
// As long as max_thresh for encode breakout is small enough, it is ok
- // to enable it for no-show frame, i.e. set enable_encode_breakout to 2.
+ // to enable it for show frame, i.e. set allow_encode_breakout to 2.
if (!cm->show_frame)
- cpi->enable_encode_breakout = 0;
+ cpi->allow_encode_breakout = ENCODE_BREAKOUT_DISABLED;
else
- cpi->enable_encode_breakout = 2;
+ cpi->allow_encode_breakout = ENCODE_BREAKOUT_LIMITED;
}
rc->frames_till_gf_update_due = rc->baseline_gf_interval;
@@ -2488,11 +2354,11 @@ void vp9_get_second_pass_params(VP9_COMP *cpi) {
}
}
- // Set nominal per second bandwidth for this frame
- cpi->target_bandwidth = (int)(rc->per_frame_bandwidth *
- cpi->output_framerate);
- if (cpi->target_bandwidth < 0)
- cpi->target_bandwidth = 0;
+ if (cpi->common.frame_type == KEY_FRAME)
+ target = vp9_rc_clamp_iframe_target_size(cpi, rc->this_frame_target);
+ else
+ target = vp9_rc_clamp_pframe_target_size(cpi, rc->this_frame_target);
+ vp9_rc_set_frame_target(cpi, target);
// Update the total stats remaining structure
subtract_stats(&twopass->total_left_stats, &this_frame);
@@ -2503,5 +2369,18 @@ void vp9_twopass_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) {
cpi->twopass.bits_left -= cpi->rc.this_frame_target;
#else
cpi->twopass.bits_left -= 8 * bytes_used;
+ // Update bits left to the kf and gf groups to account for overshoot or
+ // undershoot on these frames
+ if (cm->frame_type == KEY_FRAME) {
+ cpi->twopass.kf_group_bits += cpi->rc.this_frame_target -
+ cpi->rc.projected_frame_size;
+
+ cpi->twopass.kf_group_bits = MAX(cpi->twopass.kf_group_bits, 0);
+ } else if (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame) {
+ cpi->twopass.gf_group_bits += cpi->rc.this_frame_target -
+ cpi->rc.projected_frame_size;
+
+ cpi->twopass.gf_group_bits = MAX(cpi->twopass.gf_group_bits, 0);
+ }
#endif
}
diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h
index ca5b10080..83e337b6d 100644
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -10,25 +10,92 @@
#ifndef VP9_ENCODER_VP9_FIRSTPASS_H_
#define VP9_ENCODER_VP9_FIRSTPASS_H_
-#include "vp9/encoder/vp9_onyx_int.h"
#ifdef __cplusplus
extern "C" {
#endif
-void vp9_init_first_pass(VP9_COMP *cpi);
-void vp9_first_pass(VP9_COMP *cpi);
-void vp9_end_first_pass(VP9_COMP *cpi);
+typedef struct {
+ double frame;
+ double intra_error;
+ double coded_error;
+ double sr_coded_error;
+ double ssim_weighted_pred_err;
+ double pcnt_inter;
+ double pcnt_motion;
+ double pcnt_second_ref;
+ double pcnt_neutral;
+ double MVr;
+ double mvr_abs;
+ double MVc;
+ double mvc_abs;
+ double MVrv;
+ double MVcv;
+ double mv_in_out_count;
+ double new_mv_count;
+ double duration;
+ double count;
+} FIRSTPASS_STATS;
-void vp9_init_second_pass(VP9_COMP *cpi);
-void vp9_get_second_pass_params(VP9_COMP *cpi);
-void vp9_end_second_pass(VP9_COMP *cpi);
+struct twopass_rc {
+ unsigned int section_intra_rating;
+ unsigned int next_iiratio;
+ unsigned int this_iiratio;
+ FIRSTPASS_STATS total_stats;
+ FIRSTPASS_STATS this_frame_stats;
+ FIRSTPASS_STATS *stats_in, *stats_in_end, *stats_in_start;
+ FIRSTPASS_STATS total_left_stats;
+ int first_pass_done;
+ int64_t bits_left;
+ int64_t clip_bits_total;
+ double avg_iiratio;
+ double modified_error_min;
+ double modified_error_max;
+ double modified_error_total;
+ double modified_error_left;
+ double kf_intra_err_min;
+ double gf_intra_err_min;
+ int static_scene_max_gf_interval;
+ int kf_bits;
+ // Remaining error from uncoded frames in a gf group. Two pass use only
+ int64_t gf_group_error_left;
-void vp9_get_first_pass_params(VP9_COMP *cpi);
-void vp9_get_one_pass_params(VP9_COMP *cpi);
-void vp9_get_one_pass_cbr_params(VP9_COMP *cpi);
-void vp9_get_svc_params(VP9_COMP *cpi);
+ // Projected total bits available for a key frame group of frames
+ int64_t kf_group_bits;
+ // Error score of frames still to be coded in kf group
+ int64_t kf_group_error_left;
+
+ // Projected Bits available for a group of frames including 1 GF or ARF
+ int64_t gf_group_bits;
+ // Bits for the golden frame or ARF - 2 pass only
+ int gf_bits;
+ int alt_extra_bits;
+
+ int sr_update_lag;
+
+ int kf_zeromotion_pct;
+ int gf_zeromotion_pct;
+
+ int active_worst_quality;
+};
+
+struct VP9_COMP;
+
+void vp9_init_first_pass(struct VP9_COMP *cpi);
+void vp9_rc_get_first_pass_params(struct VP9_COMP *cpi);
+void vp9_first_pass(struct VP9_COMP *cpi);
+void vp9_end_first_pass(struct VP9_COMP *cpi);
+
+void vp9_init_second_pass(struct VP9_COMP *cpi);
+void vp9_rc_get_second_pass_params(struct VP9_COMP *cpi);
+void vp9_end_second_pass(struct VP9_COMP *cpi);
+int vp9_twopass_worst_quality(struct VP9_COMP *cpi, FIRSTPASS_STATS *fpstats,
+ int section_target_bandwitdh);
+
+// Post encode update of the rate control parameters for 2-pass
+void vp9_twopass_postencode_update(struct VP9_COMP *cpi,
+ uint64_t bytes_used);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/vp9/encoder/vp9_lookahead.c b/vp9/encoder/vp9_lookahead.c
index e6e59c05a..4b642e2b6 100644
--- a/vp9/encoder/vp9_lookahead.c
+++ b/vp9/encoder/vp9_lookahead.c
@@ -11,9 +11,12 @@
#include <stdlib.h>
#include "./vpx_config.h"
+
#include "vp9/common/vp9_common.h"
+
#include "vp9/encoder/vp9_extend.h"
#include "vp9/encoder/vp9_lookahead.h"
+#include "vp9/encoder/vp9_onyx_int.h"
struct lookahead_ctx {
unsigned int max_sz; /* Absolute size of the queue */
diff --git a/vp9/encoder/vp9_mbgraph.h b/vp9/encoder/vp9_mbgraph.h
index 79dd2bc95..bc2a7048f 100644
--- a/vp9/encoder/vp9_mbgraph.h
+++ b/vp9/encoder/vp9_mbgraph.h
@@ -15,7 +15,23 @@
extern "C" {
#endif
-void vp9_update_mbgraph_stats(VP9_COMP *cpi);
+typedef struct {
+ struct {
+ int err;
+ union {
+ int_mv mv;
+ MB_PREDICTION_MODE mode;
+ } m;
+ } ref[MAX_REF_FRAMES];
+} MBGRAPH_MB_STATS;
+
+typedef struct {
+ MBGRAPH_MB_STATS *mb_stats;
+} MBGRAPH_FRAME_STATS;
+
+struct VP9_COMP;
+
+void vp9_update_mbgraph_stats(struct VP9_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
diff --git a/vp9/encoder/vp9_mcomp.c b/vp9/encoder/vp9_mcomp.c
index ec9934a30..198e11cc2 100644
--- a/vp9/encoder/vp9_mcomp.c
+++ b/vp9/encoder/vp9_mcomp.c
@@ -466,7 +466,6 @@ int vp9_find_best_sub_pixel_comp_tree(const MACROBLOCK *x,
#undef PRE
#undef DIST
#undef CHECK_BETTER
-#undef SP
static INLINE int check_bounds(const MACROBLOCK *x, int row, int col,
int range) {
@@ -476,11 +475,9 @@ static INLINE int check_bounds(const MACROBLOCK *x, int row, int col,
((col + range) <= x->mv_col_max);
}
-static INLINE int check_point(const MACROBLOCK *x, const MV *mv) {
- return (mv->col < x->mv_col_min) |
- (mv->col > x->mv_col_max) |
- (mv->row < x->mv_row_min) |
- (mv->row > x->mv_row_max);
+static INLINE int is_mv_in(const MACROBLOCK *x, const MV *mv) {
+ return (mv->col >= x->mv_col_min) && (mv->col <= x->mv_col_max) &&
+ (mv->row >= x->mv_row_min) && (mv->row <= x->mv_row_max);
}
#define CHECK_BETTER \
@@ -496,11 +493,6 @@ static INLINE int check_point(const MACROBLOCK *x, const MV *mv) {
}\
}
-#define get_next_chkpts(list, i, n) \
- list[0] = ((i) == 0 ? (n) - 1 : (i) - 1); \
- list[1] = (i); \
- list[2] = ((i) == (n) - 1 ? 0 : (i) + 1);
-
#define MAX_PATTERN_SCALES 11
#define MAX_PATTERN_CANDIDATES 8 // max number of canddiates per scale
#define PATTERN_CANDIDATES_REF 3 // number of refinement candidates
@@ -578,7 +570,7 @@ static int vp9_pattern_search(const MACROBLOCK *x,
for (i = 0; i < num_candidates[t]; i++) {
this_mv.row = br + candidates[t][i].row;
this_mv.col = bc + candidates[t][i].col;
- if (check_point(x, &this_mv))
+ if (!is_mv_in(x, &this_mv))
continue;
this_offset = base_offset + (this_mv.row * in_what_stride) +
this_mv.col;
@@ -622,7 +614,7 @@ static int vp9_pattern_search(const MACROBLOCK *x,
for (i = 0; i < num_candidates[s]; i++) {
this_mv.row = br + candidates[s][i].row;
this_mv.col = bc + candidates[s][i].col;
- if (check_point(x, &this_mv))
+ if (!is_mv_in(x, &this_mv))
continue;
this_offset = base_offset + (this_mv.row * in_what_stride) +
this_mv.col;
@@ -644,7 +636,10 @@ static int vp9_pattern_search(const MACROBLOCK *x,
do {
int next_chkpts_indices[PATTERN_CANDIDATES_REF];
best_site = -1;
- get_next_chkpts(next_chkpts_indices, k, num_candidates[s]);
+ next_chkpts_indices[0] = (k == 0) ? num_candidates[s] - 1 : k - 1;
+ next_chkpts_indices[1] = k;
+ next_chkpts_indices[2] = (k == num_candidates[s] - 1) ? 0 : k + 1;
+
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;
@@ -659,7 +654,7 @@ static int vp9_pattern_search(const MACROBLOCK *x,
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;
- if (check_point(x, &this_mv))
+ if (!is_mv_in(x, &this_mv))
continue;
this_offset = base_offset + (this_mv.row * (in_what_stride)) +
this_mv.col;
@@ -698,7 +693,7 @@ static int vp9_pattern_search(const MACROBLOCK *x,
for (i = 0; i < 4; i++) {
this_mv.row = br + neighbors[i].row;
this_mv.col = bc + neighbors[i].col;
- if (check_point(x, &this_mv))
+ if (!is_mv_in(x, &this_mv))
continue;
this_offset = base_offset + this_mv.row * in_what_stride +
this_mv.col;
@@ -1688,10 +1683,7 @@ int vp9_refining_search_sad_c(const MACROBLOCK *x,
this_mv.row = ref_mv->row + neighbors[j].row;
this_mv.col = ref_mv->col + neighbors[j].col;
- if ((this_mv.col > x->mv_col_min) &&
- (this_mv.col < x->mv_col_max) &&
- (this_mv.row > x->mv_row_min) &&
- (this_mv.row < x->mv_row_max)) {
+ if (is_mv_in(x, &this_mv)) {
const uint8_t *check_here = &in_what[this_mv.row * in_what_stride +
this_mv.col];
thissad = fn_ptr->sdf(what, what_stride, check_here, in_what_stride,
@@ -1878,10 +1870,7 @@ int vp9_refining_search_8p_c(const MACROBLOCK *x,
this_mv.row = ref_mv->row + neighbors[j].row;
this_mv.col = ref_mv->col + neighbors[j].col;
- if ((this_mv.col > x->mv_col_min) &&
- (this_mv.col < x->mv_col_max) &&
- (this_mv.row > x->mv_row_min) &&
- (this_mv.row < x->mv_row_max)) {
+ if (is_mv_in(x, &this_mv)) {
const uint8_t *check_here = &in_what[this_mv.row * in_what_stride +
this_mv.col];
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c
index a9b0718c8..88cf73c57 100644
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -93,16 +93,7 @@ FILE *kf_list;
FILE *keyfile;
#endif
-#ifdef SPEEDSTATS
-unsigned int frames_at_speed[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0};
-#endif
-
-#if defined(SECTIONBITS_OUTPUT)
-extern unsigned __int64 Sectionbits[500];
-#endif
-
-extern void vp9_init_quantizer(VP9_COMP *cpi);
+void vp9_init_quantizer(VP9_COMP *cpi);
static const double in_frame_q_adj_ratio[MAX_SEGMENTS] =
{1.0, 1.5, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0};
@@ -581,7 +572,7 @@ static void set_good_speed_feature(VP9_COMMON *cm,
int speed) {
int i;
sf->adaptive_rd_thresh = 1;
- sf->recode_loop = (speed < 1);
+ sf->recode_loop = ((speed < 1) ? ALLOW_RECODE : ALLOW_RECODE_KFMAXBW);
if (speed == 1) {
sf->use_square_partition_only = !frame_is_intra_only(cm);
sf->less_rectangular_check = 1;
@@ -599,7 +590,7 @@ static void set_good_speed_feature(VP9_COMMON *cm,
sf->adaptive_pred_interp_filter = 1;
sf->auto_mv_step_size = 1;
sf->adaptive_rd_thresh = 2;
- sf->recode_loop = 2;
+ sf->recode_loop = ALLOW_RECODE_KFARFGF;
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
@@ -635,7 +626,7 @@ static void set_good_speed_feature(VP9_COMMON *cm,
sf->last_partitioning_redo_frequency = 3;
sf->adaptive_rd_thresh = 2;
- sf->recode_loop = 2;
+ sf->recode_loop = ALLOW_RECODE_KFARFGF;
sf->use_lp32x32fdct = 1;
sf->mode_skip_start = 11;
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V;
@@ -752,7 +743,9 @@ static void set_rt_speed_feature(VP9_COMMON *cm,
int speed) {
sf->static_segmentation = 0;
sf->adaptive_rd_thresh = 1;
- sf->recode_loop = (speed < 1);
+ sf->recode_loop = ((speed < 1) ? ALLOW_RECODE : ALLOW_RECODE_KFMAXBW);
+ sf->encode_breakout_thresh = 1;
+
if (speed == 1) {
sf->use_square_partition_only = !frame_is_intra_only(cm);
sf->less_rectangular_check = 1;
@@ -770,10 +763,11 @@ static void set_rt_speed_feature(VP9_COMMON *cm,
sf->adaptive_pred_interp_filter = 1;
sf->auto_mv_step_size = 1;
sf->adaptive_rd_thresh = 2;
- sf->recode_loop = 2;
+ sf->recode_loop = ALLOW_RECODE_KFARFGF;
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
+ sf->encode_breakout_thresh = 8;
}
if (speed >= 2) {
sf->use_square_partition_only = !frame_is_intra_only(cm);
@@ -806,13 +800,14 @@ static void set_rt_speed_feature(VP9_COMMON *cm,
sf->last_partitioning_redo_frequency = 3;
sf->adaptive_rd_thresh = 2;
- sf->recode_loop = 2;
+ sf->recode_loop = ALLOW_RECODE_KFARFGF;
sf->use_lp32x32fdct = 1;
sf->mode_skip_start = 11;
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_y_mode_mask[TX_16X16] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
+ sf->encode_breakout_thresh = 200;
}
if (speed >= 3) {
sf->use_square_partition_only = 1;
@@ -835,13 +830,17 @@ static void set_rt_speed_feature(VP9_COMMON *cm,
sf->use_fast_coef_updates = 2;
sf->adaptive_rd_thresh = 4;
sf->mode_skip_start = 6;
+ sf->encode_breakout_thresh = 400;
}
if (speed >= 4) {
sf->optimize_coefficients = 0;
+ sf->disable_split_mask = DISABLE_ALL_SPLIT;
+ sf->use_fast_lpf_pick = 2;
+ sf->encode_breakout_thresh = 700;
}
if (speed >= 5) {
int i;
- sf->disable_split_mask = DISABLE_ALL_SPLIT;
+ sf->adaptive_rd_thresh = 5;
sf->auto_min_max_partition_size = frame_is_intra_only(cm) ?
RELAXED_NEIGHBORING_MIN_MAX : STRICT_NEIGHBORING_MIN_MAX;
sf->subpel_force_stop = 1;
@@ -849,11 +848,13 @@ static void set_rt_speed_feature(VP9_COMMON *cm,
sf->intra_y_mode_mask[i] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[i] = INTRA_DC_ONLY;
}
- sf->use_fast_lpf_pick = 2;
- sf->RD = 0;
+ sf->frame_parameter_update = 0;
+ sf->encode_breakout_thresh = 1000;
}
if (speed >= 6) {
- sf->super_fast_rtc = 1;
+ sf->always_this_block_size = BLOCK_16X16;
+ sf->use_pick_mode = 1;
+ sf->encode_breakout_thresh = 1000;
}
}
@@ -871,9 +872,9 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
cpi->mode_chosen_counts[i] = 0;
// best quality defaults
- sf->RD = 1;
+ sf->frame_parameter_update = 1;
sf->search_method = NSTEP;
- sf->recode_loop = 1;
+ sf->recode_loop = ALLOW_RECODE;
sf->subpel_search_method = SUBPEL_TREE;
sf->subpel_iters_per_step = 2;
sf->subpel_force_stop = 0;
@@ -912,7 +913,8 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
sf->use_fast_coef_updates = 0;
sf->using_small_partition_info = 0;
sf->mode_skip_start = MAX_MODES; // Mode index at which mode skip mask set
- sf->super_fast_rtc = 0;
+ sf->use_pick_mode = 0;
+ sf->encode_breakout_thresh = 0;
switch (cpi->oxcf.mode) {
case MODE_BESTQUALITY:
@@ -941,7 +943,7 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
// No recode for 1 pass.
if (cpi->pass == 0) {
- sf->recode_loop = 0;
+ sf->recode_loop = DISALLOW_RECODE;
sf->optimize_coefficients = 0;
}
@@ -957,9 +959,9 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
cpi->mb.optimize = cpi->sf.optimize_coefficients == 1 && cpi->pass != 1;
-#ifdef SPEEDSTATS
- frames_at_speed[cpi->speed]++;
-#endif
+ if (cpi->encode_breakout && cpi->oxcf.mode == MODE_REALTIME &&
+ sf->encode_breakout_thresh > cpi->encode_breakout)
+ cpi->encode_breakout = sf->encode_breakout_thresh;
}
static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
@@ -975,7 +977,7 @@ static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
cpi->oxcf.width, cpi->oxcf.height,
cm->subsampling_x, cm->subsampling_y,
- VP9_ENC_BORDER_IN_PIXELS))
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate altref buffer");
}
@@ -1043,14 +1045,14 @@ static void update_frame_size(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9_ENC_BORDER_IN_PIXELS))
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate last frame buffer");
if (vp9_realloc_frame_buffer(&cpi->scaled_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9_ENC_BORDER_IN_PIXELS))
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate scaled source buffer");
@@ -1107,8 +1109,6 @@ void vp9_new_framerate(VP9_COMP *cpi, double framerate) {
cpi->oxcf.framerate = framerate;
cpi->output_framerate = cpi->oxcf.framerate;
- cpi->rc.per_frame_bandwidth = (int)(cpi->oxcf.target_bandwidth
- / cpi->output_framerate);
cpi->rc.av_per_frame_bandwidth = (int)(cpi->oxcf.target_bandwidth
/ cpi->output_framerate);
cpi->rc.min_frame_bandwidth = (int)(cpi->rc.av_per_frame_bandwidth *
@@ -1158,6 +1158,121 @@ static int64_t rescale(int val, int64_t num, int denom) {
return (llval * llnum / llden);
}
+// Initialize layer context data from init_config().
+static void init_layer_context(VP9_COMP *const cpi) {
+ const VP9_CONFIG *const oxcf = &cpi->oxcf;
+ int temporal_layer = 0;
+ cpi->svc.spatial_layer_id = 0;
+ cpi->svc.temporal_layer_id = 0;
+ for (temporal_layer = 0; temporal_layer < cpi->svc.number_temporal_layers;
+ ++temporal_layer) {
+ LAYER_CONTEXT *const lc = &cpi->svc.layer_context[temporal_layer];
+ RATE_CONTROL *const lrc = &lc->rc;
+ lrc->avg_frame_qindex[INTER_FRAME] = q_trans[oxcf->worst_allowed_q];
+ lrc->last_q[INTER_FRAME] = q_trans[oxcf->worst_allowed_q];
+ lrc->ni_av_qi = q_trans[oxcf->worst_allowed_q];
+ lrc->total_actual_bits = 0;
+ lrc->total_target_vs_actual = 0;
+ lrc->ni_tot_qi = 0;
+ lrc->tot_q = 0.0;
+ lrc->avg_q = 0.0;
+ lrc->ni_frames = 0;
+ lrc->decimation_count = 0;
+ lrc->decimation_factor = 0;
+ lrc->rate_correction_factor = 1.0;
+ lrc->key_frame_rate_correction_factor = 1.0;
+ lc->target_bandwidth = oxcf->ts_target_bitrate[temporal_layer] *
+ 1000;
+ lrc->buffer_level = rescale((int)(oxcf->starting_buffer_level),
+ lc->target_bandwidth, 1000);
+ lrc->bits_off_target = lrc->buffer_level;
+ }
+}
+
+// Update the layer context from a change_config() call.
+static void update_layer_context_change_config(VP9_COMP *const cpi,
+ const int target_bandwidth) {
+ const VP9_CONFIG *const oxcf = &cpi->oxcf;
+ const RATE_CONTROL *const rc = &cpi->rc;
+ int temporal_layer = 0;
+ float bitrate_alloc = 1.0;
+ for (temporal_layer = 0; temporal_layer < cpi->svc.number_temporal_layers;
+ ++temporal_layer) {
+ LAYER_CONTEXT *const lc = &cpi->svc.layer_context[temporal_layer];
+ RATE_CONTROL *const lrc = &lc->rc;
+ lc->target_bandwidth = oxcf->ts_target_bitrate[temporal_layer] * 1000;
+ bitrate_alloc = (float)lc->target_bandwidth / (float)target_bandwidth;
+ // Update buffer-related quantities.
+ lc->starting_buffer_level = oxcf->starting_buffer_level * bitrate_alloc;
+ lc->optimal_buffer_level = oxcf->optimal_buffer_level * bitrate_alloc;
+ lc->maximum_buffer_size = oxcf->maximum_buffer_size * bitrate_alloc;
+ lrc->bits_off_target = MIN(lrc->bits_off_target, lc->maximum_buffer_size);
+ lrc->buffer_level = MIN(lrc->buffer_level, lc->maximum_buffer_size);
+ // Update framerate-related quantities.
+ lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[temporal_layer];
+ lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
+ lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
+ // Update qp-related quantities.
+ lrc->worst_quality = rc->worst_quality;
+ lrc->best_quality = rc->best_quality;
+ }
+}
+
+// Prior to encoding the frame, update framerate-related quantities
+// for the current layer.
+static void update_layer_framerate(VP9_COMP *const cpi) {
+ int temporal_layer = cpi->svc.temporal_layer_id;
+ const VP9_CONFIG *const oxcf = &cpi->oxcf;
+ LAYER_CONTEXT *const lc = &cpi->svc.layer_context[temporal_layer];
+ RATE_CONTROL *const lrc = &lc->rc;
+ lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[temporal_layer];
+ lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
+ lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth;
+ // Update the average layer frame size (non-cumulative per-frame-bw).
+ if (temporal_layer == 0) {
+ lc->avg_frame_size = lrc->av_per_frame_bandwidth;
+ } else {
+ double prev_layer_framerate = oxcf->framerate /
+ oxcf->ts_rate_decimator[temporal_layer - 1];
+ int prev_layer_target_bandwidth =
+ oxcf->ts_target_bitrate[temporal_layer - 1] * 1000;
+ lc->avg_frame_size =
+ (int)(lc->target_bandwidth - prev_layer_target_bandwidth) /
+ (lc->framerate - prev_layer_framerate);
+ }
+}
+
+// Prior to encoding the frame, set the layer context, for the current layer
+// to be encoded, to the cpi struct.
+static void restore_layer_context(VP9_COMP *const cpi) {
+ int temporal_layer = cpi->svc.temporal_layer_id;
+ LAYER_CONTEXT *lc = &cpi->svc.layer_context[temporal_layer];
+ int frame_since_key = cpi->rc.frames_since_key;
+ int frame_to_key = cpi->rc.frames_to_key;
+ cpi->rc = lc->rc;
+ cpi->oxcf.target_bandwidth = lc->target_bandwidth;
+ cpi->oxcf.starting_buffer_level = lc->starting_buffer_level;
+ cpi->oxcf.optimal_buffer_level = lc->optimal_buffer_level;
+ cpi->oxcf.maximum_buffer_size = lc->maximum_buffer_size;
+ cpi->output_framerate = lc->framerate;
+ // 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).
+ cpi->rc.frames_since_key = frame_since_key;
+ cpi->rc.frames_to_key = frame_to_key;
+}
+
+// Save the layer context after encoding the frame.
+static void save_layer_context(VP9_COMP *const cpi) {
+ int temporal_layer = cpi->svc.temporal_layer_id;
+ LAYER_CONTEXT *lc = &cpi->svc.layer_context[temporal_layer];
+ lc->rc = cpi->rc;
+ lc->target_bandwidth = cpi->oxcf.target_bandwidth;
+ lc->starting_buffer_level = cpi->oxcf.starting_buffer_level;
+ lc->optimal_buffer_level = cpi->oxcf.optimal_buffer_level;
+ lc->maximum_buffer_size = cpi->oxcf.maximum_buffer_size;
+ lc->framerate = cpi->output_framerate;
+}
+
static void set_tile_limits(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
@@ -1184,12 +1299,20 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cm->subsampling_y = 0;
vp9_alloc_compressor_data(cpi);
+ // Spatial scalability.
+ cpi->svc.number_spatial_layers = oxcf->ss_number_layers;
+ // Temporal scalability.
+ cpi->svc.number_temporal_layers = oxcf->ts_number_layers;
+
+ if (cpi->svc.number_temporal_layers > 1 &&
+ cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ init_layer_context(cpi);
+ }
+
// change includes all joint functionality
vp9_change_config(ptr, oxcf);
// Initialize active best and worst q and average q values.
- cpi->rc.active_worst_quality = cpi->oxcf.worst_allowed_q;
-
if (cpi->pass == 0 && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
cpi->rc.avg_frame_qindex[0] = cpi->oxcf.worst_allowed_q;
cpi->rc.avg_frame_qindex[1] = cpi->oxcf.worst_allowed_q;
@@ -1224,9 +1347,6 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cpi->gld_fb_idx = 1;
cpi->alt_fb_idx = 2;
- cpi->current_layer = 0;
- cpi->use_svc = 0;
-
set_tile_limits(cpi);
cpi->fixed_divide[0] = 0;
@@ -1234,7 +1354,6 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cpi->fixed_divide[i] = 0x80000 / i;
}
-
void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
VP9_COMP *cpi = (VP9_COMP *)(ptr);
VP9_COMMON *const cm = &cpi->common;
@@ -1298,6 +1417,7 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
for (i = 0; i < MAX_SEGMENTS; i++)
cpi->segment_encode_breakout[i] = cpi->oxcf.encode_breakout;
}
+ cpi->encode_breakout = cpi->oxcf.encode_breakout;
// local file playback mode == really big buffer
if (cpi->oxcf.end_usage == USAGE_LOCAL_FILE_PLAYBACK) {
@@ -1326,10 +1446,10 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cpi->oxcf.target_bandwidth, 1000);
// Under a configuration change, where maximum_buffer_size may change,
// keep buffer level clipped to the maximum allowed buffer size.
- if (cpi->rc.bits_off_target > cpi->oxcf.maximum_buffer_size) {
- cpi->rc.bits_off_target = cpi->oxcf.maximum_buffer_size;
- cpi->rc.buffer_level = cpi->rc.bits_off_target;
- }
+ cpi->rc.bits_off_target = MIN(cpi->rc.bits_off_target,
+ cpi->oxcf.maximum_buffer_size);
+ cpi->rc.buffer_level = MIN(cpi->rc.buffer_level,
+ cpi->oxcf.maximum_buffer_size);
// Set up frame rate and related parameters rate control values.
vp9_new_framerate(cpi, cpi->oxcf.framerate);
@@ -1339,16 +1459,11 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cpi->rc.best_quality = cpi->oxcf.best_allowed_q;
// active values should only be modified if out of new range
- cpi->rc.active_worst_quality = clamp(cpi->rc.active_worst_quality,
- cpi->rc.best_quality,
- cpi->rc.worst_quality);
cpi->cq_target_quality = cpi->oxcf.cq_level;
cm->interp_filter = DEFAULT_INTERP_FILTER;
- cpi->target_bandwidth = cpi->oxcf.target_bandwidth;
-
cm->display_width = cpi->oxcf.width;
cm->display_height = cpi->oxcf.height;
@@ -1366,6 +1481,11 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
}
update_frame_size(cpi);
+ if (cpi->svc.number_temporal_layers > 1 &&
+ cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ update_layer_context_change_config(cpi, cpi->oxcf.target_bandwidth);
+ }
+
cpi->speed = cpi->oxcf.cpu_used;
if (cpi->oxcf.lag_in_frames == 0) {
@@ -1589,6 +1709,8 @@ VP9_PTR vp9_create_compressor(VP9_CONFIG *oxcf) {
vp9_create_common(cm);
+ cpi->use_svc = 0;
+
init_config((VP9_PTR)cpi, oxcf);
init_pick_mode_context(cpi);
@@ -1604,9 +1726,6 @@ VP9_PTR vp9_create_compressor(VP9_CONFIG *oxcf) {
cpi->alt_is_last = 0;
cpi->gold_is_alt = 0;
- // Spatial scalability
- cpi->number_spatial_layers = oxcf->ss_number_layers;
-
// Create the encoder segmentation map and set all entries to 0
CHECK_MEM_ERROR(cm, cpi->segmentation_map,
vpx_calloc(cm->mi_rows * cm->mi_cols, 1));
@@ -1632,11 +1751,6 @@ VP9_PTR vp9_create_compressor(VP9_CONFIG *oxcf) {
sizeof(*cpi->mbgraph_stats[i].mb_stats), 1));
}
-#ifdef ENTROPY_STATS
- if (cpi->pass != 1)
- init_context_counters();
-#endif
-
/*Initialize the feed-forward activity masking.*/
cpi->activity_avg = 90 << 12;
cpi->key_frame_frequency = cpi->oxcf.key_freq;
@@ -1741,7 +1855,7 @@ VP9_PTR vp9_create_compressor(VP9_CONFIG *oxcf) {
cpi->output_pkt_list = oxcf->output_pkt_list;
- cpi->enable_encode_breakout = 1;
+ cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
if (cpi->pass == 1) {
vp9_init_first_pass(cpi);
@@ -1967,21 +2081,6 @@ void vp9_remove_compressor(VP9_PTR *ptr) {
}
#endif
-#if defined(SECTIONBITS_OUTPUT)
-
- if (0) {
- int i;
- FILE *f = fopen("tokenbits.stt", "a");
-
- for (i = 0; i < 28; i++)
- fprintf(f, "%8d", (int)(Sectionbits[i] / 256));
-
- fprintf(f, "\n");
- fclose(f);
- }
-
-#endif
-
#if 0
{
printf("\n_pick_loop_filter_level:%d\n", cpi->time_pick_lpf / 1000);
@@ -2448,34 +2547,33 @@ static double compute_edge_pixel_proportion(YV12_BUFFER_CONFIG *frame) {
// Function to test for conditions that indicate we should loop
// back and recode a frame.
-static int recode_loop_test(VP9_COMP *cpi,
+static int recode_loop_test(const VP9_COMP *cpi,
int high_limit, int low_limit,
int q, int maxq, int minq) {
+ const VP9_COMMON *const cm = &cpi->common;
+ const RATE_CONTROL *const rc = &cpi->rc;
int force_recode = 0;
- VP9_COMMON *cm = &cpi->common;
// Special case trap if maximum allowed frame size exceeded.
- if (cpi->rc.projected_frame_size > cpi->rc.max_frame_bandwidth) {
+ if (rc->projected_frame_size > rc->max_frame_bandwidth) {
force_recode = 1;
// Is frame recode allowed.
// Yes if either recode mode 1 is selected or mode 2 is selected
// and the frame is a key frame, golden frame or alt_ref_frame
- } else if ((cpi->sf.recode_loop == 1) ||
- ((cpi->sf.recode_loop == 2) &&
- ((cm->frame_type == KEY_FRAME) ||
- cpi->refresh_golden_frame ||
- cpi->refresh_alt_ref_frame))) {
+ } else if ((cpi->sf.recode_loop == ALLOW_RECODE) ||
+ ((cpi->sf.recode_loop == ALLOW_RECODE_KFARFGF) &&
+ (cm->frame_type == KEY_FRAME ||
+ cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame))) {
// General over and under shoot tests
- if (((cpi->rc.projected_frame_size > high_limit) && (q < maxq)) ||
- ((cpi->rc.projected_frame_size < low_limit) && (q > minq))) {
+ if ((rc->projected_frame_size > high_limit && q < maxq) ||
+ (rc->projected_frame_size < low_limit && q > minq)) {
force_recode = 1;
} else if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) {
// Deal with frame undershoot and whether or not we are
// below the automatically set cq level.
if (q > cpi->cq_target_quality &&
- cpi->rc.projected_frame_size <
- ((cpi->rc.this_frame_target * 7) >> 3)) {
+ rc->projected_frame_size < ((rc->this_frame_target * 7) >> 3)) {
force_recode = 1;
}
}
@@ -2583,7 +2681,7 @@ static void scale_references(VP9_COMP *cpi) {
vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9_ENC_BORDER_IN_PIXELS);
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf);
cpi->scaled_ref_idx[ref_frame - 1] = new_fb;
} else {
@@ -2636,7 +2734,7 @@ static void output_frame_level_debug_stats(VP9_COMP *cpi) {
if (cpi->twopass.total_left_stats.coded_error != 0.0)
fprintf(f, "%10u %10d %10d %10d %10d %10d "
"%10"PRId64" %10"PRId64" %10d "
- "%7.2lf %7.2lf %7.2lf %7.2lf %7.2lf %7.2lf"
+ "%7.2lf %7.2lf %7.2lf %7.2lf %7.2lf"
"%6d %6d %5d %5d %5d "
"%10"PRId64" %10.3lf"
"%10lf %8u %10d %10d %10d\n",
@@ -2649,7 +2747,7 @@ static void output_frame_level_debug_stats(VP9_COMP *cpi) {
cpi->rc.total_actual_bits, cm->base_qindex,
vp9_convert_qindex_to_q(cm->base_qindex),
(double)vp9_dc_quant(cm->base_qindex, 0) / 4.0,
- vp9_convert_qindex_to_q(cpi->rc.active_worst_quality), cpi->rc.avg_q,
+ cpi->rc.avg_q,
vp9_convert_qindex_to_q(cpi->rc.ni_av_qi),
vp9_convert_qindex_to_q(cpi->cq_target_quality),
cpi->refresh_last_frame, cpi->refresh_golden_frame,
@@ -2683,25 +2781,67 @@ static void output_frame_level_debug_stats(VP9_COMP *cpi) {
}
#endif
+static void encode_without_recode_loop(VP9_COMP *cpi,
+ size_t *size,
+ uint8_t *dest,
+ int q) {
+ VP9_COMMON *const cm = &cpi->common;
+ vp9_clear_system_state(); // __asm emms;
+ vp9_set_quantizer(cpi, q);
+
+ // Set up entropy context depending on frame type. The decoder mandates
+ // the use of the default context, index 0, for keyframes and inter
+ // frames where the error_resilient_mode or intra_only flag is set. For
+ // other inter-frames the encoder currently uses only two contexts;
+ // context 1 for ALTREF frames and context 0 for the others.
+ if (cm->frame_type == KEY_FRAME) {
+ vp9_setup_key_frame(cpi);
+ } else {
+ if (!cm->intra_only && !cm->error_resilient_mode) {
+ cpi->common.frame_context_idx = cpi->refresh_alt_ref_frame;
+ }
+ vp9_setup_inter_frame(cpi);
+ }
+ // Variance adaptive and in frame q adjustment experiments are mutually
+ // exclusive.
+ if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
+ vp9_vaq_frame_setup(cpi);
+ } else if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) {
+ setup_in_frame_q_adj(cpi);
+ }
+ // transform / motion compensation build reconstruction frame
+ vp9_encode_frame(cpi);
+
+ // Update the skip mb flag probabilities based on the distribution
+ // seen in the last encoder iteration.
+ // update_base_skip_probs(cpi);
+ vp9_clear_system_state(); // __asm emms;
+}
+
static void encode_with_recode_loop(VP9_COMP *cpi,
size_t *size,
uint8_t *dest,
- int *q,
+ int q,
int bottom_index,
- int top_index,
- int frame_over_shoot_limit,
- int frame_under_shoot_limit) {
+ int top_index) {
VP9_COMMON *const cm = &cpi->common;
int loop_count = 0;
int loop = 0;
int overshoot_seen = 0;
int undershoot_seen = 0;
int q_low = bottom_index, q_high = top_index;
+ int frame_over_shoot_limit;
+ int frame_under_shoot_limit;
+
+ // Decide frame size bounds
+ vp9_rc_compute_frame_size_bounds(cpi, cpi->rc.this_frame_target,
+ &frame_under_shoot_limit,
+ &frame_over_shoot_limit);
do {
vp9_clear_system_state(); // __asm emms;
- vp9_set_quantizer(cpi, *q);
+ vp9_set_quantizer(cpi, q);
if (loop_count == 0) {
// Set up entropy context depending on frame type. The decoder mandates
@@ -2728,7 +2868,6 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
}
// transform / motion compensation build reconstruction frame
-
vp9_encode_frame(cpi);
// Update the skip mb flag probabilities based on the distribution
@@ -2740,10 +2879,10 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
// Dummy pack of the bitstream using up to date stats to get an
// accurate estimate of output frame size to determine if we need
// to recode.
- if (cpi->sf.recode_loop != 0) {
+ if (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF) {
vp9_save_coding_context(cpi);
cpi->dummy_packing = 1;
- if (!cpi->sf.super_fast_rtc)
+ if (!cpi->sf.use_pick_mode)
vp9_pack_bitstream(cpi, dest, size);
cpi->rc.projected_frame_size = (*size) << 3;
@@ -2759,7 +2898,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
if ((cm->frame_type == KEY_FRAME) &&
cpi->rc.this_key_frame_forced &&
(cpi->rc.projected_frame_size < cpi->rc.max_frame_bandwidth)) {
- int last_q = *q;
+ int last_q = q;
int kf_err = vp9_calc_ss_err(cpi->Source, get_frame_new_buffer(cm));
int high_err_target = cpi->ambient_err;
@@ -2775,32 +2914,32 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
(kf_err > low_err_target &&
cpi->rc.projected_frame_size <= frame_under_shoot_limit)) {
// Lower q_high
- q_high = *q > q_low ? *q - 1 : q_low;
+ q_high = q > q_low ? q - 1 : q_low;
// Adjust Q
- *q = ((*q) * high_err_target) / kf_err;
- *q = MIN((*q), (q_high + q_low) >> 1);
+ q = (q * high_err_target) / kf_err;
+ q = MIN(q, (q_high + q_low) >> 1);
} else if (kf_err < low_err_target &&
cpi->rc.projected_frame_size >= frame_under_shoot_limit) {
// The key frame is much better than the previous frame
// Raise q_low
- q_low = *q < q_high ? *q + 1 : q_high;
+ q_low = q < q_high ? q + 1 : q_high;
// Adjust Q
- *q = ((*q) * low_err_target) / kf_err;
- *q = MIN((*q), (q_high + q_low + 1) >> 1);
+ q = (q * low_err_target) / kf_err;
+ q = MIN(q, (q_high + q_low + 1) >> 1);
}
// Clamp Q to upper and lower limits:
- *q = clamp(*q, q_low, q_high);
+ q = clamp(q, q_low, q_high);
- loop = *q != last_q;
+ loop = q != last_q;
} else if (recode_loop_test(
cpi, frame_over_shoot_limit, frame_under_shoot_limit,
- *q, MAX(q_high, top_index), bottom_index)) {
+ q, MAX(q_high, top_index), bottom_index)) {
// Is the projected frame size out of range and are we allowed
// to attempt to recode.
- int last_q = *q;
+ int last_q = q;
int retries = 0;
// Frame size out of permitted range:
@@ -2813,23 +2952,23 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
q_high = cpi->rc.worst_quality;
// Raise Qlow as to at least the current value
- q_low = *q < q_high ? *q + 1 : q_high;
+ q_low = q < q_high ? q + 1 : q_high;
if (undershoot_seen || loop_count > 1) {
// Update rate_correction_factor unless
vp9_rc_update_rate_correction_factors(cpi, 1);
- *q = (q_high + q_low + 1) / 2;
+ q = (q_high + q_low + 1) / 2;
} else {
// Update rate_correction_factor unless
vp9_rc_update_rate_correction_factors(cpi, 0);
- *q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target,
+ q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target,
bottom_index, MAX(q_high, top_index));
- while (*q < q_low && retries < 10) {
+ while (q < q_low && retries < 10) {
vp9_rc_update_rate_correction_factors(cpi, 0);
- *q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target,
+ q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target,
bottom_index, MAX(q_high, top_index));
retries++;
}
@@ -2838,27 +2977,27 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
overshoot_seen = 1;
} else {
// Frame is too small
- q_high = *q > q_low ? *q - 1 : q_low;
+ q_high = q > q_low ? q - 1 : q_low;
if (overshoot_seen || loop_count > 1) {
vp9_rc_update_rate_correction_factors(cpi, 1);
- *q = (q_high + q_low) / 2;
+ q = (q_high + q_low) / 2;
} else {
vp9_rc_update_rate_correction_factors(cpi, 0);
- *q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target,
+ q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target,
bottom_index, top_index);
// Special case reset for qlow for constrained quality.
// This should only trigger where there is very substantial
// undershoot on a frame and the auto cq level is above
// the user passsed in value.
if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY &&
- *q < q_low) {
- q_low = *q;
+ q < q_low) {
+ q_low = q;
}
- while (*q > q_high && retries < 10) {
+ while (q > q_high && retries < 10) {
vp9_rc_update_rate_correction_factors(cpi, 0);
- *q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target,
+ q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target,
bottom_index, top_index);
retries++;
}
@@ -2868,9 +3007,9 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
}
// Clamp Q to upper and lower limits:
- *q = clamp(*q, q_low, q_high);
+ q = clamp(q, q_low, q_high);
- loop = *q != last_q;
+ loop = q != last_q;
} else {
loop = 0;
}
@@ -2943,20 +3082,18 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
VP9_COMMON *const cm = &cpi->common;
TX_SIZE t;
int q;
- int frame_over_shoot_limit;
- int frame_under_shoot_limit;
int top_index;
int bottom_index;
SPEED_FEATURES *const sf = &cpi->sf;
- unsigned int max_mv_def = MIN(cpi->common.width, cpi->common.height);
+ unsigned int max_mv_def = MIN(cm->width, cm->height);
struct segmentation *const seg = &cm->seg;
set_ext_overrides(cpi);
/* Scale the source buffer, if required. */
- if (cm->mi_cols * 8 != cpi->un_scaled_source->y_width ||
- cm->mi_rows * 8 != cpi->un_scaled_source->y_height) {
+ if (cm->mi_cols * MI_SIZE != cpi->un_scaled_source->y_width ||
+ cm->mi_rows * MI_SIZE != cpi->un_scaled_source->y_height) {
scale_and_extend_frame_nonnormative(cpi->un_scaled_source,
&cpi->scaled_source);
cpi->Source = &cpi->scaled_source;
@@ -2965,12 +3102,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
}
scale_references(cpi);
- // Clear down mmx registers to allow floating point in what follows.
vp9_clear_system_state();
- // Clear zbin over-quant value and mode boost values.
- cpi->zbin_mode_boost = 0;
-
// Enable or disable mode based tweaking of the zbin.
// For 2 pass only used where GF/ARF prediction quality
// is above a threshold.
@@ -2978,7 +3111,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
cpi->zbin_mode_boost_enabled = 0;
// Current default encoder behavior for the altref sign bias.
- cpi->common.ref_frame_sign_bias[ALTREF_FRAME] = cpi->rc.source_alt_ref_active;
+ cm->ref_frame_sign_bias[ALTREF_FRAME] = cpi->rc.source_alt_ref_active;
// Set default state for segment based loop filter update flags.
cm->lf.mode_ref_delta_update = 0;
@@ -2987,7 +3120,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
cpi->mv_step_param = vp9_init_search_range(cpi, max_mv_def);
// Initialize cpi->max_mv_magnitude and cpi->mv_step_param if appropriate.
if (sf->auto_mv_step_size) {
- if (frame_is_intra_only(&cpi->common)) {
+ if (frame_is_intra_only(cm)) {
// Initialize max_mv_magnitude for use in the first INTER frame
// after a key/intra-only frame.
cpi->max_mv_magnitude = max_mv_def;
@@ -2996,8 +3129,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
// Allow mv_steps to correspond to twice the max mv magnitude found
// in the previous frame, capped by the default max_mv_magnitude based
// on resolution.
- cpi->mv_step_param = vp9_init_search_range(
- cpi, MIN(max_mv_def, 2 * cpi->max_mv_magnitude));
+ cpi->mv_step_param = vp9_init_search_range(cpi, MIN(max_mv_def, 2 *
+ cpi->max_mv_magnitude));
cpi->max_mv_magnitude = 0;
}
}
@@ -3034,21 +3167,17 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
// static regions if indicated.
// Only allowed in second pass of two pass (as requires lagged coding)
// and if the relevant speed feature flag is set.
- if ((cpi->pass == 2) && (cpi->sf.static_segmentation)) {
+ if (cpi->pass == 2 && cpi->sf.static_segmentation)
configure_static_seg_features(cpi);
- }
// For 1 pass CBR, check if we are dropping this frame.
// Never drop on key frame.
if (cpi->pass == 0 &&
cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER &&
cm->frame_type != KEY_FRAME) {
- if (vp9_drop_frame(cpi)) {
- // Update buffer level with zero size, update frame counters, and return.
- vp9_update_buffer_level(cpi, 0);
- cm->last_frame_type = cm->frame_type;
+ if (vp9_rc_drop_frame(cpi)) {
vp9_rc_postencode_update_drop_frame(cpi);
- cm->current_video_frame++;
+ ++cm->current_video_frame;
return;
}
}
@@ -3086,29 +3215,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
vp9_write_yuv_frame(cpi->Source);
#endif
- // Decide how big to make the frame.
- vp9_rc_pick_frame_size_target(cpi);
-
- // Decide frame size bounds
- vp9_rc_compute_frame_size_bounds(cpi, cpi->rc.this_frame_target,
- &frame_under_shoot_limit,
- &frame_over_shoot_limit);
-
// Decide q and q bounds.
- q = vp9_rc_pick_q_and_adjust_q_bounds(cpi,
- &bottom_index,
- &top_index);
-
- // JBB : This is realtime mode. In real time mode the first frame
- // should be larger. Q of 0 is disabled because we force tx size to be
- // 16x16...
- if (cpi->sf.super_fast_rtc) {
- if (cpi->common.current_video_frame == 0)
- q /= 3;
-
- if (q == 0)
- q++;
- }
+ q = vp9_rc_pick_q_and_bounds(cpi, &bottom_index, &top_index);
if (!frame_is_intra_only(cm)) {
cm->interp_filter = DEFAULT_INTERP_FILTER;
@@ -3116,14 +3224,11 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
set_high_precision_mv(cpi, (q < HIGH_PRECISION_MV_QTHRESH));
}
- encode_with_recode_loop(cpi,
- size,
- dest,
- &q,
- bottom_index,
- top_index,
- frame_over_shoot_limit,
- frame_under_shoot_limit);
+ if (cpi->sf.recode_loop == DISALLOW_RECODE) {
+ encode_without_recode_loop(cpi, size, dest, q);
+ } else {
+ encode_with_recode_loop(cpi, size, dest, q, bottom_index, top_index);
+ }
// Special case code to reduce pulsing when key frames are forced at a
// fixed interval. Note the reconstruction error if it is the frame before
@@ -3170,41 +3275,30 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
update_reference_frames(cpi);
for (t = TX_4X4; t <= TX_32X32; t++)
- full_to_model_counts(cpi->common.counts.coef[t],
- cpi->coef_counts[t]);
- if (!cpi->common.error_resilient_mode &&
- !cpi->common.frame_parallel_decoding_mode) {
- vp9_adapt_coef_probs(&cpi->common);
- }
-
- if (!frame_is_intra_only(&cpi->common)) {
- if (!cpi->common.error_resilient_mode &&
- !cpi->common.frame_parallel_decoding_mode) {
- vp9_adapt_mode_probs(&cpi->common);
- vp9_adapt_mv_probs(&cpi->common, cpi->common.allow_high_precision_mv);
- }
- }
+ full_to_model_counts(cm->counts.coef[t], cpi->coef_counts[t]);
-#ifdef ENTROPY_STATS
- vp9_update_mode_context_stats(cpi);
-#endif
+ if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode)
+ vp9_adapt_coef_probs(cm);
- /* Move storing frame_type out of the above loop since it is also
- * needed in motion search besides loopfilter */
- cm->last_frame_type = cm->frame_type;
+ if (!frame_is_intra_only(cm)) {
+ if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode) {
+ vp9_adapt_mode_probs(cm);
+ vp9_adapt_mv_probs(cm, cm->allow_high_precision_mv);
+ }
+ }
#if 0
output_frame_level_debug_stats(cpi);
#endif
if (cpi->refresh_golden_frame == 1)
- cm->frame_flags = cm->frame_flags | FRAMEFLAGS_GOLDEN;
+ cm->frame_flags |= FRAMEFLAGS_GOLDEN;
else
- cm->frame_flags = cm->frame_flags&~FRAMEFLAGS_GOLDEN;
+ cm->frame_flags &= ~FRAMEFLAGS_GOLDEN;
if (cpi->refresh_alt_ref_frame == 1)
- cm->frame_flags = cm->frame_flags | FRAMEFLAGS_ALTREF;
+ cm->frame_flags |= FRAMEFLAGS_ALTREF;
else
- cm->frame_flags = cm->frame_flags&~FRAMEFLAGS_ALTREF;
+ cm->frame_flags &= ~FRAMEFLAGS_ALTREF;
get_ref_frame_flags(cpi);
@@ -3253,6 +3347,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
// reset to normal state now that we are done.
if (!cm->show_existing_frame)
cm->last_show_frame = cm->show_frame;
+
if (cm->show_frame) {
// current mip will be the prev_mip for the next frame
MODE_INFO *temp = cm->prev_mip;
@@ -3273,6 +3368,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
// update not a real frame
++cm->current_video_frame;
}
+
// restore prev_mi
cm->prev_mi = cm->prev_mip + cm->mode_info_stride + 1;
cm->prev_mi_grid_visible = cm->prev_mi_grid_base + cm->mode_info_stride + 1;
@@ -3280,16 +3376,16 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
static void SvcEncode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
unsigned int *frame_flags) {
- vp9_get_svc_params(cpi);
+ vp9_rc_get_svc_params(cpi);
encode_frame_to_data_rate(cpi, size, dest, frame_flags);
}
static void Pass0Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
unsigned int *frame_flags) {
if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
- vp9_get_one_pass_cbr_params(cpi);
+ vp9_rc_get_one_pass_cbr_params(cpi);
} else {
- vp9_get_one_pass_params(cpi);
+ vp9_rc_get_one_pass_vbr_params(cpi);
}
encode_frame_to_data_rate(cpi, size, dest, frame_flags);
}
@@ -3300,16 +3396,16 @@ static void Pass1Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
(void) dest;
(void) frame_flags;
- vp9_get_first_pass_params(cpi);
+ vp9_rc_get_first_pass_params(cpi);
vp9_set_quantizer(cpi, find_fp_qindex());
vp9_first_pass(cpi);
}
static void Pass2Encode(VP9_COMP *cpi, size_t *size,
uint8_t *dest, unsigned int *frame_flags) {
- cpi->enable_encode_breakout = 1;
+ cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
- vp9_get_second_pass_params(cpi);
+ vp9_rc_get_second_pass_params(cpi);
encode_frame_to_data_rate(cpi, size, dest, frame_flags);
vp9_twopass_postencode_update(cpi, *size);
@@ -3558,6 +3654,12 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
adjust_frame_rate(cpi);
}
+ if (cpi->svc.number_temporal_layers > 1 &&
+ cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ update_layer_framerate(cpi);
+ restore_layer_context(cpi);
+ }
+
// start with a 0 size frame
*size = 0;
@@ -3587,7 +3689,7 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
vp9_realloc_frame_buffer(get_frame_new_buffer(cm),
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9_ENC_BORDER_IN_PIXELS);
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
@@ -3633,6 +3735,12 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
cpi->droppable = !frame_is_reference(cpi);
}
+ // Save layer specific state.
+ if (cpi->svc.number_temporal_layers > 1 &&
+ cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ save_layer_context(cpi);
+ }
+
vpx_usec_timer_mark(&cmptimer);
cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer);
diff --git a/vp9/encoder/vp9_onyx_int.h b/vp9/encoder/vp9_onyx_int.h
index d928312b6..88a041984 100644
--- a/vp9/encoder/vp9_onyx_int.h
+++ b/vp9/encoder/vp9_onyx_int.h
@@ -23,7 +23,9 @@
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/encoder/vp9_encodemb.h"
+#include "vp9/encoder/vp9_firstpass.h"
#include "vp9/encoder/vp9_lookahead.h"
+#include "vp9/encoder/vp9_mbgraph.h"
#include "vp9/encoder/vp9_mcomp.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_ratectrl.h"
@@ -35,17 +37,17 @@
extern "C" {
#endif
-#define DISABLE_RC_LONG_TERM_MEM 0
// #define MODE_TEST_HIT_STATS
-// #define SPEEDSTATS 1
#if CONFIG_MULTIPLE_ARF
// Set MIN_GF_INTERVAL to 1 for the full decomposition.
#define MIN_GF_INTERVAL 2
#else
#define MIN_GF_INTERVAL 4
#endif
-#define DEFAULT_GF_INTERVAL 7
+#define DEFAULT_GF_INTERVAL 10
+#define DEFAULT_KF_BOOST 2000
+#define DEFAULT_GF_BOOST 2000
#define KEY_FRAME_CONTEXT 5
@@ -78,42 +80,6 @@ typedef struct {
FRAME_CONTEXT fc;
} CODING_CONTEXT;
-typedef struct {
- double frame;
- double intra_error;
- double coded_error;
- double sr_coded_error;
- double ssim_weighted_pred_err;
- double pcnt_inter;
- double pcnt_motion;
- double pcnt_second_ref;
- double pcnt_neutral;
- double MVr;
- double mvr_abs;
- double MVc;
- double mvc_abs;
- double MVrv;
- double MVcv;
- double mv_in_out_count;
- double new_mv_count;
- double duration;
- double count;
-} FIRSTPASS_STATS;
-
-typedef struct {
- struct {
- int err;
- union {
- int_mv mv;
- MB_PREDICTION_MODE mode;
- } m;
- } ref[MAX_REF_FRAMES];
-} MBGRAPH_MB_STATS;
-
-typedef struct {
- MBGRAPH_MB_STATS *mb_stats;
-} MBGRAPH_FRAME_STATS;
-
// This enumerator type needs to be kept aligned with the mode order in
// const MODE_DEFINITION vp9_mode_order[MAX_MODES] used in the rd code.
typedef enum {
@@ -231,18 +197,34 @@ typedef enum {
LAST_FRAME_PARTITION_ALL = 2
} LAST_FRAME_PARTITION_METHOD;
+typedef enum {
+ // No recode.
+ DISALLOW_RECODE = 0,
+ // Allow recode for KF and exceeding maximum frame bandwidth.
+ ALLOW_RECODE_KFMAXBW = 1,
+ // Allow recode only for KF/ARF/GF frames.
+ ALLOW_RECODE_KFARFGF = 2,
+ // Allow recode for all frames based on bitrate constraints.
+ ALLOW_RECODE = 3,
+} RECODE_LOOP_TYPE;
+
+typedef enum {
+ // encode_breakout is disabled.
+ ENCODE_BREAKOUT_DISABLED = 0,
+ // encode_breakout is enabled.
+ ENCODE_BREAKOUT_ENABLED = 1,
+ // encode_breakout is enabled with small max_thresh limit.
+ ENCODE_BREAKOUT_LIMITED = 2
+} ENCODE_BREAKOUT_TYPE;
+
typedef struct {
- // This flag refers to whether or not to perform rd optimization.
- int RD;
+ // Frame level coding parameter update
+ int frame_parameter_update;
// Motion search method (Diamond, NSTEP, Hex, Big Diamond, Square, etc).
SEARCH_METHODS search_method;
- // Recode_loop can be:
- // 0 means we only encode a frame once
- // 1 means we can re-encode based on bitrate constraints on any frame
- // 2 means we can only recode gold, alt, and key frames.
- int recode_loop;
+ RECODE_LOOP_TYPE recode_loop;
// Subpel_search_method can only be subpel_tree which does a subpixel
// logarithmic search that keeps stepping at 1/2 pixel units until
@@ -417,10 +399,24 @@ typedef struct {
// by only looking at counts from 1/2 the bands.
int use_fast_coef_updates; // 0: 2-loop, 1: 1-loop, 2: 1-loop reduced
- // This flag control the use of the new super fast rtc mode
- int super_fast_rtc;
+ // This flag controls the use of non-RD mode decision.
+ int use_pick_mode;
+
+ // This variable sets the encode_breakout threshold. Currently, it is only
+ // enabled in real time mode.
+ int encode_breakout_thresh;
} SPEED_FEATURES;
+typedef struct {
+ RATE_CONTROL rc;
+ int target_bandwidth;
+ int64_t starting_buffer_level;
+ int64_t optimal_buffer_level;
+ int64_t maximum_buffer_size;
+ double framerate;
+ int avg_frame_size;
+} LAYER_CONTEXT;
+
typedef struct VP9_COMP {
DECLARE_ALIGNED(16, int16_t, y_quant[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, y_quant_shift[QINDEX_RANGE][8]);
@@ -465,9 +461,6 @@ typedef struct VP9_COMP {
int gld_fb_idx;
int alt_fb_idx;
- int current_layer;
- int use_svc;
-
#if CONFIG_MULTIPLE_ARF
int alt_ref_fb_idx[REF_FRAMES - 3];
#endif
@@ -543,7 +536,6 @@ typedef struct VP9_COMP {
vp9_coeff_probs_model frame_coef_probs[TX_SIZES][PLANE_TYPES];
vp9_coeff_stats frame_branch_ct[TX_SIZES][PLANE_TYPES];
- int64_t target_bandwidth;
struct vpx_codec_pkt_list *output_pkt_list;
MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS];
@@ -567,6 +559,13 @@ typedef struct VP9_COMP {
unsigned int max_mv_magnitude;
int mv_step_param;
+ // Default value is 1. From first pass stats, encode_breakout may be disabled.
+ ENCODE_BREAKOUT_TYPE allow_encode_breakout;
+
+ // Get threshold from external input. In real time mode, it can be
+ // overwritten according to encoding speed.
+ int encode_breakout;
+
unsigned char *segmentation_map;
// segment threashold for encode breakout
@@ -588,46 +587,7 @@ typedef struct VP9_COMP {
uint64_t time_pick_lpf;
uint64_t time_encode_sb_row;
- struct twopass_rc {
- unsigned int section_intra_rating;
- unsigned int next_iiratio;
- unsigned int this_iiratio;
- FIRSTPASS_STATS total_stats;
- FIRSTPASS_STATS this_frame_stats;
- FIRSTPASS_STATS *stats_in, *stats_in_end, *stats_in_start;
- FIRSTPASS_STATS total_left_stats;
- int first_pass_done;
- int64_t bits_left;
- int64_t clip_bits_total;
- double avg_iiratio;
- double modified_error_min;
- double modified_error_max;
- double modified_error_total;
- double modified_error_left;
- double kf_intra_err_min;
- double gf_intra_err_min;
- int static_scene_max_gf_interval;
- int kf_bits;
- // Remaining error from uncoded frames in a gf group. Two pass use only
- int64_t gf_group_error_left;
-
- // Projected total bits available for a key frame group of frames
- int64_t kf_group_bits;
-
- // Error score of frames still to be coded in kf group
- int64_t kf_group_error_left;
-
- // Projected Bits available for a group of frames including 1 GF or ARF
- int64_t gf_group_bits;
- // Bits for the golden frame or ARF - 2 pass only
- int gf_bits;
- int alt_extra_bits;
-
- int sr_update_lag;
-
- int kf_zeromotion_pct;
- int gf_zeromotion_pct;
- } twopass;
+ struct twopass_rc twopass;
YV12_BUFFER_CONFIG alt_ref_buffer;
YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS];
@@ -684,9 +644,17 @@ typedef struct VP9_COMP {
int initial_width;
int initial_height;
- int number_spatial_layers;
- int enable_encode_breakout; // Default value is 1. From first pass stats,
- // encode_breakout may be disabled.
+ int use_svc;
+
+ struct svc {
+ int spatial_layer_id;
+ int temporal_layer_id;
+ int number_spatial_layers;
+ int number_temporal_layers;
+ // Layer context used for rate control in CBR mode, only defined for
+ // temporal layers for now.
+ LAYER_CONTEXT layer_context[VPX_TS_MAX_LAYERS];
+ } svc;
#if CONFIG_MULTIPLE_ARF
// ARF tracking variables.
@@ -741,8 +709,6 @@ void vp9_encode_frame(VP9_COMP *cpi);
void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t *size);
-void vp9_activity_masking(VP9_COMP *cpi, MACROBLOCK *x);
-
void vp9_set_speed_features(VP9_COMP *cpi);
int vp9_calc_ss_err(const YV12_BUFFER_CONFIG *source,
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index 1aaa4162b..512b6bf18 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -170,6 +170,10 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
mbmi->ref_frame[1] = NONE;
mbmi->tx_size = MIN(max_txsize_lookup[bsize],
tx_mode_to_biggest_tx_size[cpi->common.tx_mode]);
+ mbmi->interp_filter = cpi->common.interp_filter == SWITCHABLE ?
+ EIGHTTAP : cpi->common.interp_filter;
+ mbmi->skip_coeff = 0;
+ mbmi->segment_id = 0;
for (ref_frame = LAST_FRAME; ref_frame <= LAST_FRAME ; ++ref_frame) {
x->pred_mv_sad[ref_frame] = INT_MAX;
@@ -219,15 +223,7 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
mbmi->ref_frame[0] = ref_frame;
mbmi->mv[0].as_int = frame_mv[this_mode][ref_frame].as_int;
xd->mi_8x8[0]->bmi[0].as_mv[0].as_int = mbmi->mv[0].as_int;
- mbmi->interp_filter = cpi->common.interp_filter == SWITCHABLE ?
- EIGHTTAP : cpi->common.interp_filter;
-
- mbmi->ref_frame[1] = INTRA_FRAME;
- mbmi->tx_size = max_txsize_lookup[bsize];
mbmi->uv_mode = this_mode;
- mbmi->skip_coeff = 0;
- mbmi->sb_type = bsize;
- mbmi->segment_id = 0;
}
}
}
diff --git a/vp9/encoder/vp9_quantize.c b/vp9/encoder/vp9_quantize.c
index a2eea1cd7..862573f3f 100644
--- a/vp9/encoder/vp9_quantize.c
+++ b/vp9/encoder/vp9_quantize.c
@@ -79,55 +79,47 @@ void vp9_quantize_b_32x32_c(const int16_t *coeff_ptr, intptr_t n_coeffs,
const int16_t *dequant_ptr,
int zbin_oq_value, uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
- int i, rc, eob;
- int zbins[2], nzbins[2];
- int x, y, z, sz;
+ const int zbins[2] = { ROUND_POWER_OF_TWO(zbin_ptr[0] + zbin_oq_value, 1),
+ ROUND_POWER_OF_TWO(zbin_ptr[1] + zbin_oq_value, 1) };
+ const int nzbins[2] = {zbins[0] * -1, zbins[1] * -1};
+
int idx = 0;
int idx_arr[1024];
+ int i, eob = -1;
- vpx_memset(qcoeff_ptr, 0, n_coeffs*sizeof(int16_t));
- vpx_memset(dqcoeff_ptr, 0, n_coeffs*sizeof(int16_t));
-
- eob = -1;
-
- // Base ZBIN
- zbins[0] = ROUND_POWER_OF_TWO(zbin_ptr[0] + zbin_oq_value, 1);
- zbins[1] = ROUND_POWER_OF_TWO(zbin_ptr[1] + zbin_oq_value, 1);
- nzbins[0] = zbins[0] * -1;
- nzbins[1] = zbins[1] * -1;
+ vpx_memset(qcoeff_ptr, 0, n_coeffs * sizeof(int16_t));
+ vpx_memset(dqcoeff_ptr, 0, n_coeffs * sizeof(int16_t));
if (!skip_block) {
// Pre-scan pass
for (i = 0; i < n_coeffs; i++) {
- rc = scan[i];
- z = coeff_ptr[rc];
+ const int rc = scan[i];
+ const int coeff = coeff_ptr[rc];
// If the coefficient is out of the base ZBIN range, keep it for
// quantization.
- if (z >= zbins[rc != 0] || z <= nzbins[rc != 0])
+ if (coeff >= zbins[rc != 0] || coeff <= nzbins[rc != 0])
idx_arr[idx++] = i;
}
// Quantization pass: only process the coefficients selected in
// pre-scan pass. Note: idx can be zero.
for (i = 0; i < idx; i++) {
- rc = scan[idx_arr[i]];
-
- z = coeff_ptr[rc];
- sz = (z >> 31); // sign of z
- x = (z ^ sz) - sz; // x = abs(z)
-
- x += ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1);
- x = clamp(x, INT16_MIN, INT16_MAX);
- y = ((((x * quant_ptr[rc != 0]) >> 16) + x) *
- quant_shift_ptr[rc != 0]) >> 15; // quantize (x)
-
- x = (y ^ sz) - sz; // get the sign back
- qcoeff_ptr[rc] = x; // write to destination
- dqcoeff_ptr[rc] = x * dequant_ptr[rc != 0] / 2; // dequantized value
-
- if (y)
- eob = idx_arr[i]; // last nonzero coeffs
+ const int rc = scan[idx_arr[i]];
+ const int coeff = coeff_ptr[rc];
+ const int coeff_sign = (coeff >> 31);
+ int tmp;
+ int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
+ abs_coeff += ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1);
+ abs_coeff = clamp(abs_coeff, INT16_MIN, INT16_MAX);
+ tmp = ((((abs_coeff * quant_ptr[rc != 0]) >> 16) + abs_coeff) *
+ quant_shift_ptr[rc != 0]) >> 15;
+
+ qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
+ dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 2;
+
+ if (tmp)
+ eob = idx_arr[i];
}
}
*eob_ptr = eob + 1;
@@ -136,8 +128,8 @@ void vp9_quantize_b_32x32_c(const int16_t *coeff_ptr, intptr_t n_coeffs,
void vp9_regular_quantize_b_4x4(MACROBLOCK *x, int plane, int block,
const int16_t *scan, const int16_t *iscan) {
MACROBLOCKD *const xd = &x->e_mbd;
- struct macroblock_plane* p = &x->plane[plane];
- struct macroblockd_plane* pd = &xd->plane[plane];
+ struct macroblock_plane *p = &x->plane[plane];
+ struct macroblockd_plane *pd = &xd->plane[plane];
vp9_quantize_b(BLOCK_OFFSET(p->coeff, block),
16, x->skip_block,
@@ -223,38 +215,30 @@ void vp9_init_quantizer(VP9_COMP *cpi) {
}
void vp9_mb_init_quantizer(VP9_COMP *cpi, MACROBLOCK *x) {
- int i;
- VP9_COMMON *const cm = &cpi->common;
+ const VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *xd = &x->e_mbd;
- int zbin_extra;
- int segment_id = xd->mi_8x8[0]->mbmi.segment_id;
- const int qindex = vp9_get_qindex(&cpi->common.seg, segment_id,
- cpi->common.base_qindex);
-
- int rdmult = vp9_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q);
+ const int segment_id = xd->mi_8x8[0]->mbmi.segment_id;
+ const int qindex = vp9_get_qindex(&cm->seg, segment_id, cm->base_qindex);
+ const int rdmult = vp9_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q);
+ const int zbin = cpi->zbin_mode_boost + x->act_zbin_adj;
+ int i;
// Y
- zbin_extra = (cpi->common.y_dequant[qindex][1] *
- (cpi->zbin_mode_boost + x->act_zbin_adj)) >> 7;
-
x->plane[0].quant = cpi->y_quant[qindex];
x->plane[0].quant_shift = cpi->y_quant_shift[qindex];
x->plane[0].zbin = cpi->y_zbin[qindex];
x->plane[0].round = cpi->y_round[qindex];
- x->plane[0].zbin_extra = (int16_t)zbin_extra;
- x->e_mbd.plane[0].dequant = cpi->common.y_dequant[qindex];
+ x->plane[0].zbin_extra = (int16_t)((cm->y_dequant[qindex][1] * zbin) >> 7);
+ xd->plane[0].dequant = cm->y_dequant[qindex];
// UV
- zbin_extra = (cpi->common.uv_dequant[qindex][1] *
- (cpi->zbin_mode_boost + x->act_zbin_adj)) >> 7;
-
for (i = 1; i < 3; i++) {
x->plane[i].quant = cpi->uv_quant[qindex];
x->plane[i].quant_shift = cpi->uv_quant_shift[qindex];
x->plane[i].zbin = cpi->uv_zbin[qindex];
x->plane[i].round = cpi->uv_round[qindex];
- x->plane[i].zbin_extra = (int16_t)zbin_extra;
- x->e_mbd.plane[i].dequant = cpi->common.uv_dequant[qindex];
+ x->plane[i].zbin_extra = (int16_t)((cm->uv_dequant[qindex][1] * zbin) >> 7);
+ xd->plane[i].dequant = cm->uv_dequant[qindex];
}
#if CONFIG_ALPHA
@@ -263,18 +247,14 @@ void vp9_mb_init_quantizer(VP9_COMP *cpi, MACROBLOCK *x) {
x->plane[3].zbin = cpi->a_zbin[qindex];
x->plane[3].round = cpi->a_round[qindex];
x->plane[3].zbin_extra = (int16_t)zbin_extra;
- x->e_mbd.plane[3].dequant = cpi->common.a_dequant[qindex];
+ xd->plane[3].dequant = cm->a_dequant[qindex];
#endif
- x->skip_block = vp9_segfeature_active(&cpi->common.seg, segment_id,
- SEG_LVL_SKIP);
-
- /* save this macroblock QIndex for vp9_update_zbin_extra() */
+ x->skip_block = vp9_segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP);
x->q_index = qindex;
- /* R/D setup */
- cpi->mb.errorperbit = rdmult >> 6;
- cpi->mb.errorperbit += (cpi->mb.errorperbit == 0);
+ x->errorperbit = rdmult >> 6;
+ x->errorperbit += (x->errorperbit == 0);
vp9_initialize_me_consts(cpi, x->q_index);
}
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index 701557238..9afa0647d 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -209,51 +209,60 @@ static int estimate_bits_at_q(int frame_kind, int q, int mbs,
: (bpm * mbs) >> BPER_MB_NORMBITS;
}
-
-static void calc_iframe_target_size(VP9_COMP *cpi) {
- const VP9_CONFIG *oxcf = &cpi->oxcf;
- RATE_CONTROL *const rc = &cpi->rc;
- int target;
-
- vp9_clear_system_state(); // __asm emms;
-
- // For 1-pass.
- if (cpi->pass == 0 && oxcf->end_usage == USAGE_STREAM_FROM_SERVER) {
- if (cpi->common.current_video_frame == 0) {
- target = oxcf->starting_buffer_level / 2;
- } else {
- // TODO(marpan): Add in adjustment based on Q.
- // If this keyframe was forced, use a more recent Q estimate.
- // int Q = (cpi->common.frame_flags & FRAMEFLAGS_KEY) ?
- // cpi->rc.avg_frame_qindex : cpi->rc.ni_av_qi;
- int initial_boost = 32;
- // Boost depends somewhat on frame rate.
- int kf_boost = MAX(initial_boost, (int)(2 * cpi->output_framerate - 16));
- // Adjustment up based on q: need to fix.
- // kf_boost = kf_boost * kfboost_qadjust(Q) / 100;
- // Frame separation adjustment (down).
- if (rc->frames_since_key < cpi->output_framerate / 2) {
- kf_boost = (int)(kf_boost * rc->frames_since_key /
- (cpi->output_framerate / 2));
- }
- kf_boost = (kf_boost < 16) ? 16 : kf_boost;
- target = ((16 + kf_boost) * rc->per_frame_bandwidth) >> 4;
- }
- rc->active_worst_quality = rc->worst_quality;
- } else {
- target = rc->per_frame_bandwidth;
+int vp9_rc_clamp_pframe_target_size(const VP9_COMP *const cpi, int target) {
+ const RATE_CONTROL *rc = &cpi->rc;
+ const int min_frame_target = MAX(rc->min_frame_bandwidth,
+ rc->av_per_frame_bandwidth >> 5);
+ if (target < min_frame_target)
+ target = min_frame_target;
+ if (cpi->refresh_golden_frame && rc->is_src_frame_alt_ref) {
+ // If there is an active ARF at this location use the minimum
+ // bits on this frame even if it is a constructed arf.
+ // The active maximum quantizer insures that an appropriate
+ // number of bits will be spent if needed for constructed ARFs.
+ target = min_frame_target;
}
+ // Clip the frame target to the maximum allowed value.
+ if (target > rc->max_frame_bandwidth)
+ target = rc->max_frame_bandwidth;
+ return target;
+}
+int vp9_rc_clamp_iframe_target_size(const VP9_COMP *const cpi, int target) {
+ const RATE_CONTROL *rc = &cpi->rc;
+ const VP9_CONFIG *oxcf = &cpi->oxcf;
if (oxcf->rc_max_intra_bitrate_pct) {
- const int max_rate = rc->per_frame_bandwidth *
+ const int max_rate = rc->av_per_frame_bandwidth *
oxcf->rc_max_intra_bitrate_pct / 100;
target = MIN(target, max_rate);
}
- rc->this_frame_target = target;
+ if (target > rc->max_frame_bandwidth)
+ target = rc->max_frame_bandwidth;
+ return target;
+}
+
+
+// Update the buffer level for higher layers, given the encoded current layer.
+static void update_layer_buffer_level(VP9_COMP *const cpi,
+ int encoded_frame_size) {
+ int temporal_layer = 0;
+ int current_temporal_layer = cpi->svc.temporal_layer_id;
+ for (temporal_layer = current_temporal_layer + 1;
+ temporal_layer < cpi->svc.number_temporal_layers; ++temporal_layer) {
+ LAYER_CONTEXT *lc = &cpi->svc.layer_context[temporal_layer];
+ RATE_CONTROL *lrc = &lc->rc;
+ int bits_off_for_this_layer = (int)(lc->target_bandwidth / lc->framerate -
+ encoded_frame_size);
+ lrc->bits_off_target += bits_off_for_this_layer;
+
+ // Clip buffer level to maximum buffer size for the layer.
+ lrc->bits_off_target = MIN(lrc->bits_off_target, lc->maximum_buffer_size);
+ lrc->buffer_level = lrc->bits_off_target;
+ }
}
// Update the buffer level: leaky bucket model.
-void vp9_update_buffer_level(VP9_COMP *cpi, int encoded_frame_size) {
+static void update_buffer_level(VP9_COMP *cpi, int encoded_frame_size) {
const VP9_COMMON *const cm = &cpi->common;
const VP9_CONFIG *oxcf = &cpi->oxcf;
RATE_CONTROL *const rc = &cpi->rc;
@@ -266,14 +275,18 @@ void vp9_update_buffer_level(VP9_COMP *cpi, int encoded_frame_size) {
}
// Clip the buffer level to the maximum specified buffer size.
- rc->buffer_level = MIN(rc->bits_off_target, oxcf->maximum_buffer_size);
+ rc->bits_off_target = MIN(rc->bits_off_target, oxcf->maximum_buffer_size);
+ rc->buffer_level = rc->bits_off_target;
+
+ if (cpi->use_svc && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ update_layer_buffer_level(cpi, encoded_frame_size);
+ }
}
-int vp9_drop_frame(VP9_COMP *cpi) {
+int vp9_rc_drop_frame(VP9_COMP *cpi) {
const VP9_CONFIG *oxcf = &cpi->oxcf;
RATE_CONTROL *const rc = &cpi->rc;
-
if (!oxcf->drop_frames_water_mark) {
return 0;
} else {
@@ -284,7 +297,7 @@ int vp9_drop_frame(VP9_COMP *cpi) {
// If buffer is below drop_mark, for now just drop every other frame
// (starting with the next frame) until it increases back over drop_mark.
int drop_mark = (int)(oxcf->drop_frames_water_mark *
- oxcf->optimal_buffer_level / 100);
+ oxcf->optimal_buffer_level / 100);
if ((rc->buffer_level > drop_mark) &&
(rc->decimation_factor > 0)) {
--rc->decimation_factor;
@@ -308,127 +321,12 @@ int vp9_drop_frame(VP9_COMP *cpi) {
}
}
-// Adjust active_worst_quality level based on buffer level.
-static int adjust_active_worst_quality_from_buffer_level(const VP9_CONFIG *oxcf,
- const RATE_CONTROL *rc) {
- // Adjust active_worst_quality: If buffer is above the optimal/target level,
- // bring active_worst_quality down depending on fullness over buffer.
- // If buffer is below the optimal level, let the active_worst_quality go from
- // ambient Q (at buffer = optimal level) to worst_quality level
- // (at buffer = critical level).
-
- int active_worst_quality = rc->active_worst_quality;
- // Maximum limit for down adjustment, ~20%.
- int max_adjustment_down = active_worst_quality / 5;
- // Buffer level below which we push active_worst to worst_quality.
- int critical_level = oxcf->optimal_buffer_level >> 2;
- int adjustment = 0;
- int buff_lvl_step = 0;
- if (rc->buffer_level > oxcf->optimal_buffer_level) {
- // Adjust down.
- if (max_adjustment_down) {
- buff_lvl_step = (int)((oxcf->maximum_buffer_size -
- oxcf->optimal_buffer_level) / max_adjustment_down);
- if (buff_lvl_step)
- adjustment = (int)((rc->buffer_level - oxcf->optimal_buffer_level) /
- buff_lvl_step);
- active_worst_quality -= adjustment;
- }
- } else if (rc->buffer_level > critical_level) {
- // Adjust up from ambient Q.
- if (critical_level) {
- buff_lvl_step = (oxcf->optimal_buffer_level - critical_level);
- if (buff_lvl_step) {
- adjustment = (rc->worst_quality - rc->avg_frame_qindex[INTER_FRAME]) *
- (oxcf->optimal_buffer_level - rc->buffer_level) /
- buff_lvl_step;
- }
- active_worst_quality = rc->avg_frame_qindex[INTER_FRAME] + adjustment;
- }
- } else {
- // Set to worst_quality if buffer is below critical level.
- active_worst_quality = rc->worst_quality;
- }
- return active_worst_quality;
-}
-
-// Adjust target frame size with respect to the buffering constraints:
-static int target_size_from_buffer_level(const VP9_CONFIG *oxcf,
- const RATE_CONTROL *rc) {
- int target = rc->this_frame_target;
- const int64_t diff = oxcf->optimal_buffer_level - rc->buffer_level;
- const int one_pct_bits = 1 + oxcf->optimal_buffer_level / 100;
-
- if (diff > 0) {
- // Lower the target bandwidth for this frame.
- const int pct_low = MIN(diff / one_pct_bits, oxcf->under_shoot_pct);
- target -= (target * pct_low) / 200;
- } else if (diff < 0) {
- // Increase the target bandwidth for this frame.
- const int pct_high = MIN(-diff / one_pct_bits, oxcf->over_shoot_pct);
- target += (target * pct_high) / 200;
- }
-
- return target;
-}
-
-static void calc_pframe_target_size(VP9_COMP *const cpi) {
- RATE_CONTROL *const rc = &cpi->rc;
- const VP9_CONFIG *const oxcf = &cpi->oxcf;
- int min_frame_target;
- rc->this_frame_target = rc->per_frame_bandwidth;
-
- if (cpi->pass == 0 && oxcf->end_usage == USAGE_STREAM_FROM_SERVER) {
- // Need to decide how low min_frame_target should be for 1-pass CBR.
- // For now, use: cpi->rc.av_per_frame_bandwidth / 16:
- min_frame_target = MAX(rc->av_per_frame_bandwidth >> 4,
- FRAME_OVERHEAD_BITS);
- rc->this_frame_target = target_size_from_buffer_level(oxcf, rc);
- // Adjust qp-max based on buffer level.
- rc->active_worst_quality =
- adjust_active_worst_quality_from_buffer_level(oxcf, rc);
-
- if (rc->this_frame_target < min_frame_target)
- rc->this_frame_target = min_frame_target;
- return;
- }
-
- // Check that the total sum of adjustments is not above the maximum allowed.
- // That is, having allowed for the KF and GF penalties, we have not pushed
- // the current inter-frame target too low. If the adjustment we apply here is
- // not capable of recovering all the extra bits we have spent in the KF or GF,
- // then the remainder will have to be recovered over a longer time span via
- // other buffer / rate control mechanisms.
- min_frame_target = MAX(rc->min_frame_bandwidth,
- rc->av_per_frame_bandwidth >> 5);
-
- if (rc->this_frame_target < min_frame_target)
- rc->this_frame_target = min_frame_target;
-
- // Adjust target frame size for Golden Frames:
- if (cpi->refresh_golden_frame) {
- // If we are using alternate ref instead of gf then do not apply the boost
- // It will instead be applied to the altref update
- // Jims modified boost
- if (!rc->source_alt_ref_active) {
- // The spend on the GF is defined in the two pass code
- // for two pass encodes
- rc->this_frame_target = rc->per_frame_bandwidth;
- } else {
- // If there is an active ARF at this location use the minimum
- // bits on this frame even if it is a constructed arf.
- // The active maximum quantizer insures that an appropriate
- // number of bits will be spent if needed for constructed ARFs.
- rc->this_frame_target = 0;
- }
- }
-}
-
static double get_rate_correction_factor(const VP9_COMP *cpi) {
if (cpi->common.frame_type == KEY_FRAME) {
return cpi->rc.key_frame_rate_correction_factor;
} else {
- if (cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame)
+ if ((cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) &&
+ !(cpi->use_svc && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER))
return cpi->rc.gf_rate_correction_factor;
else
return cpi->rc.rate_correction_factor;
@@ -439,7 +337,8 @@ static void set_rate_correction_factor(VP9_COMP *cpi, double factor) {
if (cpi->common.frame_type == KEY_FRAME) {
cpi->rc.key_frame_rate_correction_factor = factor;
} else {
- if (cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame)
+ if ((cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) &&
+ !(cpi->use_svc && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER))
cpi->rc.gf_rate_correction_factor = factor;
else
cpi->rc.rate_correction_factor = factor;
@@ -463,7 +362,6 @@ void vp9_rc_update_rate_correction_factors(VP9_COMP *cpi, int damp_var) {
projected_size_based_on_q = estimate_bits_at_q(cpi->common.frame_type, q,
cpi->common.MBs,
rate_correction_factor);
-
// Work out a size correction factor.
if (projected_size_based_on_q > 0)
correction_factor = (100 * cpi->rc.projected_frame_size) /
@@ -562,13 +460,206 @@ static int get_active_quality(int q, int gfu_boost, int low, int high,
}
}
-int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi,
- int *bottom_index, int *top_index) {
+static int calc_active_worst_quality_one_pass_vbr(const VP9_COMP *cpi) {
+ int active_worst_quality;
+ if (cpi->common.frame_type == KEY_FRAME) {
+ if (cpi->common.current_video_frame == 0) {
+ active_worst_quality = cpi->rc.worst_quality;
+ } else {
+ // Choose active worst quality twice as large as the last q.
+ active_worst_quality = cpi->rc.last_q[KEY_FRAME] * 2;
+ }
+ } else if (!cpi->rc.is_src_frame_alt_ref &&
+ (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
+ if (cpi->common.current_video_frame == 1) {
+ active_worst_quality = cpi->rc.last_q[KEY_FRAME] * 5 / 4;
+ } else {
+ // Choose active worst quality twice as large as the last q.
+ active_worst_quality = cpi->rc.last_q[INTER_FRAME];
+ }
+ } else {
+ if (cpi->common.current_video_frame == 1) {
+ active_worst_quality = cpi->rc.last_q[KEY_FRAME] * 2;
+ } else {
+ // Choose active worst quality twice as large as the last q.
+ active_worst_quality = cpi->rc.last_q[INTER_FRAME] * 2;
+ }
+ }
+ if (active_worst_quality > cpi->rc.worst_quality)
+ active_worst_quality = cpi->rc.worst_quality;
+ return active_worst_quality;
+}
+
+// Adjust active_worst_quality level based on buffer level.
+static int calc_active_worst_quality_one_pass_cbr(const VP9_COMP *cpi) {
+ // Adjust active_worst_quality: If buffer is above the optimal/target level,
+ // bring active_worst_quality down depending on fullness of buffer.
+ // If buffer is below the optimal level, let the active_worst_quality go from
+ // ambient Q (at buffer = optimal level) to worst_quality level
+ // (at buffer = critical level).
+ const VP9_CONFIG *oxcf = &cpi->oxcf;
+ const RATE_CONTROL *rc = &cpi->rc;
+ // int active_worst_quality = rc->active_worst_quality;
+ // Maximum limit for down adjustment, ~20%.
+ // Buffer level below which we push active_worst to worst_quality.
+ int critical_level = oxcf->optimal_buffer_level >> 2;
+ int adjustment = 0;
+ int buff_lvl_step = 0;
+ int active_worst_quality;
+ if (cpi->common.frame_type == KEY_FRAME)
+ return rc->worst_quality;
+ if (cpi->common.current_video_frame > 1)
+ active_worst_quality = MIN(rc->worst_quality,
+ rc->avg_frame_qindex[INTER_FRAME] * 5 / 4);
+ else
+ active_worst_quality = MIN(rc->worst_quality,
+ rc->avg_frame_qindex[KEY_FRAME] * 3 / 2);
+ if (rc->buffer_level > oxcf->optimal_buffer_level) {
+ // Adjust down.
+ int max_adjustment_down = active_worst_quality / 3;
+ if (max_adjustment_down) {
+ buff_lvl_step = (int)((oxcf->maximum_buffer_size -
+ oxcf->optimal_buffer_level) / max_adjustment_down);
+ if (buff_lvl_step)
+ adjustment = (int)((rc->buffer_level - oxcf->optimal_buffer_level) /
+ buff_lvl_step);
+ active_worst_quality -= adjustment;
+ }
+ } else if (rc->buffer_level > critical_level) {
+ // Adjust up from ambient Q.
+ if (critical_level) {
+ buff_lvl_step = (oxcf->optimal_buffer_level - critical_level);
+ if (buff_lvl_step) {
+ adjustment = (rc->worst_quality - rc->avg_frame_qindex[INTER_FRAME]) *
+ (oxcf->optimal_buffer_level - rc->buffer_level) /
+ buff_lvl_step;
+ }
+ active_worst_quality = rc->avg_frame_qindex[INTER_FRAME] + adjustment;
+ }
+ } else {
+ // Set to worst_quality if buffer is below critical level.
+ active_worst_quality = rc->worst_quality;
+ }
+ return active_worst_quality;
+}
+
+static int rc_pick_q_and_bounds_one_pass_cbr(const VP9_COMP *cpi,
+ int *bottom_index,
+ int *top_index) {
+ const VP9_COMMON *const cm = &cpi->common;
+ const RATE_CONTROL *const rc = &cpi->rc;
+ int active_best_quality;
+ int active_worst_quality = calc_active_worst_quality_one_pass_cbr(cpi);
+ int q;
+
+ if (frame_is_intra_only(cm)) {
+ active_best_quality = rc->best_quality;
+ // Handle the special case for key frames forced when we have75 reached
+ // the maximum key frame interval. Here force the Q to a range
+ // based on the ambient Q to reduce the risk of popping.
+ if (rc->this_key_frame_forced) {
+ int qindex = rc->last_boosted_qindex;
+ double last_boosted_q = vp9_convert_qindex_to_q(qindex);
+ int delta_qindex = vp9_compute_qdelta(cpi, last_boosted_q,
+ (last_boosted_q * 0.75));
+ active_best_quality = MAX(qindex + delta_qindex, rc->best_quality);
+ } else if (cm->current_video_frame > 0) {
+ // not first frame of one pass and kf_boost is set
+ double q_adj_factor = 1.0;
+ double q_val;
+
+ active_best_quality = get_active_quality(rc->avg_frame_qindex[KEY_FRAME],
+ rc->kf_boost,
+ kf_low, kf_high,
+ kf_low_motion_minq,
+ kf_high_motion_minq);
+
+ // Allow somewhat lower kf minq with small image formats.
+ if ((cm->width * cm->height) <= (352 * 288)) {
+ q_adj_factor -= 0.25;
+ }
+
+ // Convert the adjustment factor to a qindex delta
+ // on active_best_quality.
+ q_val = vp9_convert_qindex_to_q(active_best_quality);
+ active_best_quality += vp9_compute_qdelta(cpi, q_val, q_val *
+ q_adj_factor);
+ }
+ } else if (!rc->is_src_frame_alt_ref &&
+ (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
+ // Use the lower of active_worst_quality and recent
+ // average Q as basis for GF/ARF best Q limit unless last frame was
+ // a key frame.
+ if (rc->frames_since_key > 1 &&
+ rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) {
+ q = rc->avg_frame_qindex[INTER_FRAME];
+ } else {
+ q = active_worst_quality;
+ }
+ active_best_quality = get_active_quality(
+ q, rc->gfu_boost, gf_low, gf_high,
+ gf_low_motion_minq, gf_high_motion_minq);
+ } else {
+ // Use the lower of active_worst_quality and recent/average Q.
+ if (cm->current_video_frame > 1) {
+ if (rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality)
+ active_best_quality = inter_minq[rc->avg_frame_qindex[INTER_FRAME]];
+ else
+ active_best_quality = inter_minq[active_worst_quality];
+ } else {
+ if (rc->avg_frame_qindex[KEY_FRAME] < active_worst_quality)
+ active_best_quality = inter_minq[rc->avg_frame_qindex[KEY_FRAME]];
+ else
+ active_best_quality = inter_minq[active_worst_quality];
+ }
+ }
+
+ // Clip the active best and worst quality values to limits
+ active_best_quality = clamp(active_best_quality,
+ rc->best_quality, rc->worst_quality);
+ active_worst_quality = clamp(active_worst_quality,
+ active_best_quality, rc->worst_quality);
+
+ *top_index = active_worst_quality;
+ *bottom_index = active_best_quality;
+
+#if LIMIT_QRANGE_FOR_ALTREF_AND_KEY
+ // Limit Q range for the adaptive loop.
+ if (cm->frame_type == KEY_FRAME && !rc->this_key_frame_forced) {
+ if (!(cm->current_video_frame == 0))
+ *top_index = (active_worst_quality + active_best_quality * 3) / 4;
+ }
+#endif
+ // Special case code to try and match quality with forced key frames
+ if (cm->frame_type == KEY_FRAME && rc->this_key_frame_forced) {
+ q = rc->last_boosted_qindex;
+ } else {
+ q = vp9_rc_regulate_q(cpi, rc->this_frame_target,
+ active_best_quality, active_worst_quality);
+ if (q > *top_index) {
+ // Special case when we are targeting the max allowed rate
+ if (cpi->rc.this_frame_target >= cpi->rc.max_frame_bandwidth)
+ *top_index = q;
+ else
+ q = *top_index;
+ }
+ }
+ assert(*top_index <= rc->worst_quality &&
+ *top_index >= rc->best_quality);
+ assert(*bottom_index <= rc->worst_quality &&
+ *bottom_index >= rc->best_quality);
+ assert(q <= rc->worst_quality && q >= rc->best_quality);
+ return q;
+}
+
+static int rc_pick_q_and_bounds_one_pass_vbr(const VP9_COMP *cpi,
+ int *bottom_index,
+ int *top_index) {
const VP9_COMMON *const cm = &cpi->common;
const RATE_CONTROL *const rc = &cpi->rc;
const VP9_CONFIG *const oxcf = &cpi->oxcf;
int active_best_quality;
- int active_worst_quality = rc->active_worst_quality;
+ int active_worst_quality = calc_active_worst_quality_one_pass_vbr(cpi);
int q;
if (frame_is_intra_only(cm)) {
@@ -583,12 +674,194 @@ int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi,
int delta_qindex = vp9_compute_qdelta(cpi, last_boosted_q,
(last_boosted_q * 0.75));
active_best_quality = MAX(qindex + delta_qindex, rc->best_quality);
- } else if (!(cpi->pass == 0 && cm->current_video_frame == 0)) {
+ } else if (cm->current_video_frame > 0) {
// not first frame of one pass and kf_boost is set
double q_adj_factor = 1.0;
double q_val;
- // Baseline value derived from cpi->active_worst_quality and kf boost
+ active_best_quality = get_active_quality(rc->avg_frame_qindex[KEY_FRAME],
+ rc->kf_boost,
+ kf_low, kf_high,
+ kf_low_motion_minq,
+ kf_high_motion_minq);
+
+ // Allow somewhat lower kf minq with small image formats.
+ if ((cm->width * cm->height) <= (352 * 288)) {
+ q_adj_factor -= 0.25;
+ }
+
+ // Convert the adjustment factor to a qindex delta
+ // on active_best_quality.
+ q_val = vp9_convert_qindex_to_q(active_best_quality);
+ active_best_quality += vp9_compute_qdelta(cpi, q_val, q_val *
+ q_adj_factor);
+ }
+#else
+ double current_q;
+ // Force the KF quantizer to be 30% of the active_worst_quality.
+ current_q = vp9_convert_qindex_to_q(active_worst_quality);
+ active_best_quality = active_worst_quality
+ + vp9_compute_qdelta(cpi, current_q, current_q * 0.3);
+#endif
+ } else if (!rc->is_src_frame_alt_ref &&
+ (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
+ // Use the lower of active_worst_quality and recent
+ // average Q as basis for GF/ARF best Q limit unless last frame was
+ // a key frame.
+ if (rc->frames_since_key > 1 &&
+ rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) {
+ q = rc->avg_frame_qindex[INTER_FRAME];
+ } else {
+ q = rc->avg_frame_qindex[KEY_FRAME];
+ }
+ // For constrained quality dont allow Q less than the cq level
+ if (oxcf->end_usage == USAGE_CONSTRAINED_QUALITY) {
+ if (q < cpi->cq_target_quality)
+ q = cpi->cq_target_quality;
+ if (rc->frames_since_key > 1) {
+ active_best_quality = get_active_quality(q, rc->gfu_boost,
+ gf_low, gf_high,
+ afq_low_motion_minq,
+ afq_high_motion_minq);
+ } else {
+ active_best_quality = get_active_quality(q, rc->gfu_boost,
+ gf_low, gf_high,
+ gf_low_motion_minq,
+ gf_high_motion_minq);
+ }
+ // Constrained quality use slightly lower active best.
+ active_best_quality = active_best_quality * 15 / 16;
+
+ } else if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
+ if (!cpi->refresh_alt_ref_frame) {
+ active_best_quality = cpi->cq_target_quality;
+ } else {
+ if (rc->frames_since_key > 1) {
+ active_best_quality = get_active_quality(
+ q, rc->gfu_boost, gf_low, gf_high,
+ afq_low_motion_minq, afq_high_motion_minq);
+ } else {
+ active_best_quality = get_active_quality(
+ q, rc->gfu_boost, gf_low, gf_high,
+ gf_low_motion_minq, gf_high_motion_minq);
+ }
+ }
+ } else {
+ active_best_quality = get_active_quality(
+ q, rc->gfu_boost, gf_low, gf_high,
+ gf_low_motion_minq, gf_high_motion_minq);
+ }
+ } else {
+ if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
+ active_best_quality = cpi->cq_target_quality;
+ } else {
+ // Use the lower of active_worst_quality and recent/average Q.
+ if (cm->current_video_frame > 1)
+ active_best_quality = inter_minq[rc->avg_frame_qindex[INTER_FRAME]];
+ else
+ active_best_quality = inter_minq[rc->avg_frame_qindex[KEY_FRAME]];
+ // For the constrained quality mode we don't want
+ // q to fall below the cq level.
+ if ((oxcf->end_usage == USAGE_CONSTRAINED_QUALITY) &&
+ (active_best_quality < cpi->cq_target_quality)) {
+ // If we are strongly undershooting the target rate in the last
+ // frames then use the user passed in cq value not the auto
+ // cq value.
+ if (rc->rolling_actual_bits < rc->min_frame_bandwidth)
+ active_best_quality = oxcf->cq_level;
+ else
+ active_best_quality = cpi->cq_target_quality;
+ }
+ }
+ }
+
+ // Clip the active best and worst quality values to limits
+ active_best_quality = clamp(active_best_quality,
+ rc->best_quality, rc->worst_quality);
+ active_worst_quality = clamp(active_worst_quality,
+ active_best_quality, rc->worst_quality);
+
+ *top_index = active_worst_quality;
+ *bottom_index = active_best_quality;
+
+#if LIMIT_QRANGE_FOR_ALTREF_AND_KEY
+ // Limit Q range for the adaptive loop.
+ if (cm->frame_type == KEY_FRAME && !rc->this_key_frame_forced) {
+ if (!(cm->current_video_frame == 0))
+ *top_index = (active_worst_quality + active_best_quality * 3) / 4;
+ } else if (!rc->is_src_frame_alt_ref &&
+ (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
+ *top_index = (active_worst_quality + active_best_quality) / 2;
+ }
+#endif
+ if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
+ q = active_best_quality;
+ // Special case code to try and match quality with forced key frames
+ } else if ((cm->frame_type == KEY_FRAME) && rc->this_key_frame_forced) {
+ q = rc->last_boosted_qindex;
+ } else {
+ q = vp9_rc_regulate_q(cpi, rc->this_frame_target,
+ active_best_quality, active_worst_quality);
+ if (q > *top_index) {
+ // Special case when we are targeting the max allowed rate
+ if (cpi->rc.this_frame_target >= cpi->rc.max_frame_bandwidth)
+ *top_index = q;
+ else
+ q = *top_index;
+ }
+ }
+#if CONFIG_MULTIPLE_ARF
+ // Force the quantizer determined by the coding order pattern.
+ if (cpi->multi_arf_enabled && (cm->frame_type != KEY_FRAME) &&
+ cpi->oxcf.end_usage != USAGE_CONSTANT_QUALITY) {
+ double new_q;
+ double current_q = vp9_convert_qindex_to_q(active_worst_quality);
+ int level = cpi->this_frame_weight;
+ assert(level >= 0);
+ new_q = current_q * (1.0 - (0.2 * (cpi->max_arf_level - level)));
+ q = active_worst_quality +
+ vp9_compute_qdelta(cpi, current_q, new_q);
+
+ *bottom_index = q;
+ *top_index = q;
+ printf("frame:%d q:%d\n", cm->current_video_frame, q);
+ }
+#endif
+ assert(*top_index <= rc->worst_quality &&
+ *top_index >= rc->best_quality);
+ assert(*bottom_index <= rc->worst_quality &&
+ *bottom_index >= rc->best_quality);
+ assert(q <= rc->worst_quality && q >= rc->best_quality);
+ return q;
+}
+
+static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi,
+ int *bottom_index,
+ int *top_index) {
+ const VP9_COMMON *const cm = &cpi->common;
+ const RATE_CONTROL *const rc = &cpi->rc;
+ const VP9_CONFIG *const oxcf = &cpi->oxcf;
+ int active_best_quality;
+ int active_worst_quality = cpi->twopass.active_worst_quality;
+ int q;
+
+ if (frame_is_intra_only(cm)) {
+ active_best_quality = rc->best_quality;
+#if !CONFIG_MULTIPLE_ARF
+ // Handle the special case for key frames forced when we have75 reached
+ // the maximum key frame interval. Here force the Q to a range
+ // based on the ambient Q to reduce the risk of popping.
+ if (rc->this_key_frame_forced) {
+ int qindex = rc->last_boosted_qindex;
+ double last_boosted_q = vp9_convert_qindex_to_q(qindex);
+ int delta_qindex = vp9_compute_qdelta(cpi, last_boosted_q,
+ (last_boosted_q * 0.75));
+ active_best_quality = MAX(qindex + delta_qindex, rc->best_quality);
+ } else {
+ // Not forced keyframe.
+ double q_adj_factor = 1.0;
+ double q_val;
+ // Baseline value derived from cpi->active_worst_quality and kf boost.
active_best_quality = get_active_quality(active_worst_quality,
rc->kf_boost,
kf_low, kf_high,
@@ -618,7 +891,6 @@ int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi,
#endif
} else if (!rc->is_src_frame_alt_ref &&
(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
-
// Use the lower of active_worst_quality and recent
// average Q as basis for GF/ARF best Q limit unless last frame was
// a key frame.
@@ -669,13 +941,7 @@ int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi,
if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
active_best_quality = cpi->cq_target_quality;
} else {
- if (cpi->pass == 0 &&
- rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality)
- // 1-pass: for now, use the average Q for the active_best, if its lower
- // than active_worst.
- active_best_quality = inter_minq[rc->avg_frame_qindex[INTER_FRAME]];
- else
- active_best_quality = inter_minq[active_worst_quality];
+ active_best_quality = inter_minq[active_worst_quality];
// For the constrained quality mode we don't want
// q to fall below the cq level.
@@ -692,7 +958,7 @@ int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi,
}
}
- // Clip the active best and worst quality values to limits
+ // Clip the active best and worst quality values to limits.
if (active_worst_quality > rc->worst_quality)
active_worst_quality = rc->worst_quality;
@@ -711,8 +977,7 @@ int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi,
#if LIMIT_QRANGE_FOR_ALTREF_AND_KEY
// Limit Q range for the adaptive loop.
if (cm->frame_type == KEY_FRAME && !rc->this_key_frame_forced) {
- if (!(cpi->pass == 0 && cm->current_video_frame == 0))
- *top_index = (active_worst_quality + active_best_quality * 3) / 4;
+ *top_index = (active_worst_quality + active_best_quality * 3) / 4;
} else if (!rc->is_src_frame_alt_ref &&
(oxcf->end_usage != USAGE_STREAM_FROM_SERVER) &&
(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
@@ -722,14 +987,14 @@ int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi,
if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
q = active_best_quality;
- // Special case code to try and match quality with forced key frames
+ // Special case code to try and match quality with forced key frames.
} else if ((cm->frame_type == KEY_FRAME) && rc->this_key_frame_forced) {
q = rc->last_boosted_qindex;
} else {
q = vp9_rc_regulate_q(cpi, rc->this_frame_target,
active_best_quality, active_worst_quality);
if (q > *top_index) {
- // Special case when we are targeting the max allowed rate
+ // Special case when we are targeting the max allowed rate.
if (cpi->rc.this_frame_target >= cpi->rc.max_frame_bandwidth)
*top_index = q;
else
@@ -761,6 +1026,35 @@ int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi,
return q;
}
+int vp9_rc_pick_q_and_bounds(const VP9_COMP *cpi,
+ int *bottom_index,
+ int *top_index) {
+ int q;
+ if (cpi->pass == 0) {
+ if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)
+ q = rc_pick_q_and_bounds_one_pass_cbr(cpi, bottom_index, top_index);
+ else
+ q = rc_pick_q_and_bounds_one_pass_vbr(cpi, bottom_index, top_index);
+ } else {
+ q = rc_pick_q_and_bounds_two_pass(cpi, bottom_index, top_index);
+ }
+
+ // JBB : This is realtime mode. In real time mode the first frame
+ // should be larger. Q of 0 is disabled because we force tx size to be
+ // 16x16...
+ if (cpi->sf.use_pick_mode) {
+ if (cpi->common.current_video_frame == 0)
+ q /= 3;
+ if (q == 0)
+ q++;
+ if (q < *bottom_index)
+ *bottom_index = q;
+ else if (q > *top_index)
+ *top_index = q;
+ }
+ return q;
+}
+
void vp9_rc_compute_frame_size_bounds(const VP9_COMP *cpi,
int this_frame_target,
int *frame_under_shoot_limit,
@@ -804,24 +1098,14 @@ void vp9_rc_compute_frame_size_bounds(const VP9_COMP *cpi,
}
}
-// return of 0 means drop frame
-int vp9_rc_pick_frame_size_target(VP9_COMP *cpi) {
+void vp9_rc_set_frame_target(VP9_COMP *cpi, int target) {
const VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
- if (cm->frame_type == KEY_FRAME)
- calc_iframe_target_size(cpi);
- else
- calc_pframe_target_size(cpi);
-
- // Clip the frame target to the maximum allowed value.
- if (rc->this_frame_target > rc->max_frame_bandwidth)
- rc->this_frame_target = rc->max_frame_bandwidth;
-
+ rc->this_frame_target = target;
// Target rate per SB64 (including partial SB64s.
rc->sb64_target_rate = ((int64_t)rc->this_frame_target * 64 * 64) /
(cm->width * cm->height);
- return 1;
}
static void update_alt_ref_frame_stats(VP9_COMP *cpi) {
@@ -865,11 +1149,14 @@ static void update_golden_frame_stats(VP9_COMP *cpi) {
void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) {
VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
+
+ cm->last_frame_type = cm->frame_type;
// Update rate control heuristics
rc->projected_frame_size = (bytes_used << 3);
// Post encode loop adjustment of Q prediction.
- vp9_rc_update_rate_correction_factors(cpi, (cpi->sf.recode_loop ||
+ vp9_rc_update_rate_correction_factors(
+ cpi, (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF ||
cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ? 2 : 0);
// Keep a record of last Q and ambient average Q.
@@ -878,7 +1165,8 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) {
rc->avg_frame_qindex[KEY_FRAME] = ROUND_POWER_OF_TWO(
3 * rc->avg_frame_qindex[KEY_FRAME] + cm->base_qindex, 2);
} else if (!rc->is_src_frame_alt_ref &&
- (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
+ (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame) &&
+ !(cpi->use_svc && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) {
rc->last_q[2] = cm->base_qindex;
rc->avg_frame_qindex[2] = ROUND_POWER_OF_TWO(
3 * rc->avg_frame_qindex[2] + cm->base_qindex, 2);
@@ -907,7 +1195,7 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) {
rc->last_boosted_qindex = cm->base_qindex;
}
- vp9_update_buffer_level(cpi, rc->projected_frame_size);
+ update_buffer_level(cpi, rc->projected_frame_size);
// Rolling monitors of whether we are over or underspending used to help
// regulate min and Max Q in two pass.
@@ -929,22 +1217,6 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) {
rc->total_target_vs_actual += (rc->this_frame_target -
rc->projected_frame_size);
-#ifndef DISABLE_RC_LONG_TERM_MEM
- // Update bits left to the kf and gf groups to account for overshoot or
- // undershoot on these frames
- if (cm->frame_type == KEY_FRAME) {
- cpi->twopass.kf_group_bits += cpi->rc.this_frame_target -
- cpi->rc.projected_frame_size;
-
- cpi->twopass.kf_group_bits = MAX(cpi->twopass.kf_group_bits, 0);
- } else if (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame) {
- cpi->twopass.gf_group_bits += cpi->rc.this_frame_target -
- cpi->rc.projected_frame_size;
-
- cpi->twopass.gf_group_bits = MAX(cpi->twopass.gf_group_bits, 0);
- }
-#endif
-
if (cpi->oxcf.play_alternate && cpi->refresh_alt_ref_frame &&
(cm->frame_type != KEY_FRAME))
// Update the alternate reference frame stats as appropriate.
@@ -962,6 +1234,168 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) {
}
void vp9_rc_postencode_update_drop_frame(VP9_COMP *cpi) {
+ // Update buffer level with zero size, update frame counters, and return.
+ update_buffer_level(cpi, 0);
+ cpi->common.last_frame_type = cpi->common.frame_type;
cpi->rc.frames_since_key++;
cpi->rc.frames_to_key--;
}
+
+static int test_for_kf_one_pass(VP9_COMP *cpi) {
+ // Placeholder function for auto key frame
+ return 0;
+}
+// Use this macro to turn on/off use of alt-refs in one-pass mode.
+#define USE_ALTREF_FOR_ONE_PASS 1
+
+static int calc_pframe_target_size_one_pass_vbr(const VP9_COMP *const cpi) {
+ static const int af_ratio = 10;
+ const RATE_CONTROL *rc = &cpi->rc;
+ int target;
+#if USE_ALTREF_FOR_ONE_PASS
+ target = (!rc->is_src_frame_alt_ref &&
+ (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) ?
+ (rc->av_per_frame_bandwidth * cpi->rc.baseline_gf_interval * af_ratio) /
+ (cpi->rc.baseline_gf_interval + af_ratio - 1) :
+ (rc->av_per_frame_bandwidth * cpi->rc.baseline_gf_interval) /
+ (cpi->rc.baseline_gf_interval + af_ratio - 1);
+#else
+ target = rc->av_per_frame_bandwidth;
+#endif
+ return vp9_rc_clamp_pframe_target_size(cpi, target);
+}
+
+static int calc_iframe_target_size_one_pass_vbr(const VP9_COMP *const cpi) {
+ static const int kf_ratio = 25;
+ const RATE_CONTROL *rc = &cpi->rc;
+ int target = rc->av_per_frame_bandwidth * kf_ratio;
+ return vp9_rc_clamp_iframe_target_size(cpi, target);
+}
+
+void vp9_rc_get_one_pass_vbr_params(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ RATE_CONTROL *const rc = &cpi->rc;
+ int target;
+ if (!cpi->refresh_alt_ref_frame &&
+ (cm->current_video_frame == 0 ||
+ cm->frame_flags & FRAMEFLAGS_KEY ||
+ rc->frames_to_key == 0 ||
+ (cpi->oxcf.auto_key && test_for_kf_one_pass(cpi)))) {
+ cm->frame_type = KEY_FRAME;
+ rc->this_key_frame_forced = cm->current_video_frame != 0 &&
+ rc->frames_to_key == 0;
+ rc->frames_to_key = cpi->key_frame_frequency;
+ rc->kf_boost = DEFAULT_KF_BOOST;
+ rc->source_alt_ref_active = 0;
+ } else {
+ cm->frame_type = INTER_FRAME;
+ }
+ if (rc->frames_till_gf_update_due == 0) {
+ rc->baseline_gf_interval = DEFAULT_GF_INTERVAL;
+ rc->frames_till_gf_update_due = rc->baseline_gf_interval;
+ // NOTE: frames_till_gf_update_due must be <= frames_to_key.
+ if (rc->frames_till_gf_update_due > rc->frames_to_key)
+ rc->frames_till_gf_update_due = rc->frames_to_key;
+ cpi->refresh_golden_frame = 1;
+ rc->source_alt_ref_pending = USE_ALTREF_FOR_ONE_PASS;
+ rc->gfu_boost = DEFAULT_GF_BOOST;
+ }
+ if (cm->frame_type == KEY_FRAME)
+ target = calc_iframe_target_size_one_pass_vbr(cpi);
+ else
+ target = calc_pframe_target_size_one_pass_vbr(cpi);
+ vp9_rc_set_frame_target(cpi, target);
+}
+
+static int calc_pframe_target_size_one_pass_cbr(const VP9_COMP *cpi) {
+ const VP9_CONFIG *oxcf = &cpi->oxcf;
+ const RATE_CONTROL *rc = &cpi->rc;
+ const int64_t diff = oxcf->optimal_buffer_level - rc->buffer_level;
+ const int one_pct_bits = 1 + oxcf->optimal_buffer_level / 100;
+ int min_frame_target = MAX(rc->av_per_frame_bandwidth >> 4,
+ FRAME_OVERHEAD_BITS);
+ int target = rc->av_per_frame_bandwidth;
+ if (cpi->use_svc && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ // Note that for layers, av_per_frame_bandwidth is the cumulative
+ // per-frame-bandwidth. For the target size of this frame, use the
+ // layer average frame size (i.e., non-cumulative per-frame-bw).
+ int current_temporal_layer = cpi->svc.temporal_layer_id;
+ const LAYER_CONTEXT *lc = &cpi->svc.layer_context[current_temporal_layer];
+ target = lc->avg_frame_size;
+ min_frame_target = MAX(lc->avg_frame_size >> 4, FRAME_OVERHEAD_BITS);
+ }
+ if (diff > 0) {
+ // Lower the target bandwidth for this frame.
+ const int pct_low = MIN(diff / one_pct_bits, oxcf->under_shoot_pct);
+ target -= (target * pct_low) / 200;
+ } else if (diff < 0) {
+ // Increase the target bandwidth for this frame.
+ const int pct_high = MIN(-diff / one_pct_bits, oxcf->over_shoot_pct);
+ target += (target * pct_high) / 200;
+ }
+ return MAX(min_frame_target, target);
+}
+
+static int calc_iframe_target_size_one_pass_cbr(const VP9_COMP *cpi) {
+ const RATE_CONTROL *rc = &cpi->rc;
+
+ if (cpi->common.current_video_frame == 0) {
+ return cpi->oxcf.starting_buffer_level / 2;
+ } else {
+ const int initial_boost = 32;
+ int kf_boost = MAX(initial_boost, (int)(2 * cpi->output_framerate - 16));
+ if (rc->frames_since_key < cpi->output_framerate / 2) {
+ kf_boost = (int)(kf_boost * rc->frames_since_key /
+ (cpi->output_framerate / 2));
+ }
+ return ((16 + kf_boost) * rc->av_per_frame_bandwidth) >> 4;
+ }
+}
+
+void vp9_rc_get_svc_params(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ int target = cpi->rc.av_per_frame_bandwidth;
+ if ((cm->current_video_frame == 0) ||
+ (cm->frame_flags & FRAMEFLAGS_KEY) ||
+ (cpi->oxcf.auto_key && (cpi->rc.frames_since_key %
+ cpi->key_frame_frequency == 0))) {
+ cm->frame_type = KEY_FRAME;
+ cpi->rc.source_alt_ref_active = 0;
+ if (cpi->pass == 0 && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ target = calc_iframe_target_size_one_pass_cbr(cpi);
+ }
+ } else {
+ cm->frame_type = INTER_FRAME;
+ if (cpi->pass == 0 && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ target = calc_pframe_target_size_one_pass_cbr(cpi);
+ }
+ }
+ vp9_rc_set_frame_target(cpi, target);
+ cpi->rc.frames_till_gf_update_due = INT_MAX;
+ cpi->rc.baseline_gf_interval = INT_MAX;
+}
+
+void vp9_rc_get_one_pass_cbr_params(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ RATE_CONTROL *const rc = &cpi->rc;
+ int target;
+ if ((cm->current_video_frame == 0 ||
+ cm->frame_flags & FRAMEFLAGS_KEY ||
+ rc->frames_to_key == 0 ||
+ (cpi->oxcf.auto_key && test_for_kf_one_pass(cpi)))) {
+ cm->frame_type = KEY_FRAME;
+ rc->this_key_frame_forced = cm->current_video_frame != 0 &&
+ rc->frames_to_key == 0;
+ rc->frames_to_key = cpi->key_frame_frequency;
+ rc->kf_boost = DEFAULT_KF_BOOST;
+ rc->source_alt_ref_active = 0;
+ target = calc_iframe_target_size_one_pass_cbr(cpi);
+ } else {
+ cm->frame_type = INTER_FRAME;
+ target = calc_pframe_target_size_one_pass_cbr(cpi);
+ }
+ vp9_rc_set_frame_target(cpi, target);
+ // Don't use gf_update by default in CBR mode.
+ rc->frames_till_gf_update_due = INT_MAX;
+ rc->baseline_gf_interval = INT_MAX;
+}
diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h
index eba4b7a92..551b6c327 100644
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -46,7 +46,6 @@ typedef struct {
unsigned int source_alt_ref_active;
unsigned int is_src_frame_alt_ref;
- int per_frame_bandwidth; // Current section per frame bandwidth target
int av_per_frame_bandwidth; // Average frame size target for clip
int min_frame_bandwidth; // Minimum allocation used for any frame
int max_frame_bandwidth; // Maximum burst rate allowed for a frame.
@@ -74,7 +73,6 @@ typedef struct {
int total_target_vs_actual; // debug stats
int worst_quality;
- int active_worst_quality;
int best_quality;
// int active_best_quality;
} RATE_CONTROL;
@@ -89,50 +87,79 @@ void vp9_setup_inter_frame(struct VP9_COMP *cpi);
double vp9_convert_qindex_to_q(int qindex);
-// Updates rate correction factors
-void vp9_rc_update_rate_correction_factors(struct VP9_COMP *cpi, int damp_var);
-
// initialize luts for minq
void vp9_rc_init_minq_luts(void);
-// return of 0 means drop frame
-// Changes only rc.this_frame_target and rc.sb64_rate_target
-int vp9_rc_pick_frame_size_target(struct VP9_COMP *cpi);
+// Generally at the high level, the following flow is expected
+// to be enforced for rate control:
+// First call per frame, one of:
+// vp9_rc_get_one_pass_vbr_params()
+// vp9_rc_get_one_pass_cbr_params()
+// vp9_rc_get_svc_params()
+// vp9_rc_get_first_pass_params()
+// vp9_rc_get_second_pass_params()
+// depending on the usage to set the rate control encode parameters desired.
+//
+// Then, call encode_frame_to_data_rate() to perform the
+// actual encode. This function will in turn call encode_frame()
+// one or more times, followed by one of:
+// vp9_rc_postencode_update()
+// vp9_rc_postencode_update_drop_frame()
+//
+// The majority of rate control parameters are only expected
+// to be set in the vp9_rc_get_..._params() functions and
+// updated during the vp9_rc_postencode_update...() functions.
+// The only exceptions are vp9_rc_drop_frame() and
+// vp9_rc_update_rate_correction_factors() functions.
+
+// Functions to set parameters for encoding before the actual
+// encode_frame_to_data_rate() function.
+void vp9_rc_get_one_pass_vbr_params(struct VP9_COMP *cpi);
+void vp9_rc_get_one_pass_cbr_params(struct VP9_COMP *cpi);
+void vp9_rc_get_svc_params(struct VP9_COMP *cpi);
+
+// Post encode update of the rate control parameters based
+// on bytes used
+void vp9_rc_postencode_update(struct VP9_COMP *cpi,
+ uint64_t bytes_used);
+// Post encode update of the rate control parameters for dropped frames
+void vp9_rc_postencode_update_drop_frame(struct VP9_COMP *cpi);
+
+// Updates rate correction factors
+// Changes only the rate correction factors in the rate control structure.
+void vp9_rc_update_rate_correction_factors(struct VP9_COMP *cpi, int damp_var);
+// Decide if we should drop this frame: For 1-pass CBR.
+// Changes only the decimation count in the rate control structure
+int vp9_rc_drop_frame(struct VP9_COMP *cpi);
+
+// Computes frame size bounds.
void vp9_rc_compute_frame_size_bounds(const struct VP9_COMP *cpi,
int this_frame_target,
int *frame_under_shoot_limit,
int *frame_over_shoot_limit);
// Picks q and q bounds given the target for bits
-int vp9_rc_pick_q_and_adjust_q_bounds(const struct VP9_COMP *cpi,
- int *bottom_index,
- int *top_index);
+int vp9_rc_pick_q_and_bounds(const struct VP9_COMP *cpi,
+ int *bottom_index,
+ int *top_index);
// Estimates q to achieve a target bits per frame
int vp9_rc_regulate_q(const struct VP9_COMP *cpi, int target_bits_per_frame,
int active_best_quality, int active_worst_quality);
-// Post encode update of the rate control parameters based
-// on bytes used
-void vp9_rc_postencode_update(struct VP9_COMP *cpi,
- uint64_t bytes_used);
-// for dropped frames
-void vp9_rc_postencode_update_drop_frame(struct VP9_COMP *cpi);
-
-// estimates bits per mb for a given qindex and correction factor
+// Estimates bits per mb for a given qindex and correction factor.
int vp9_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex,
double correction_factor);
-// Post encode update of the rate control parameters for 2-pass
-void vp9_twopass_postencode_update(struct VP9_COMP *cpi,
- uint64_t bytes_used);
-
-// Decide if we should drop this frame: For 1-pass CBR.
-int vp9_drop_frame(struct VP9_COMP *cpi);
-
-// Update the buffer level.
-void vp9_update_buffer_level(struct VP9_COMP *cpi, int encoded_frame_size);
+// Clamping utilities for bitrate targets for iframes and pframes.
+int vp9_rc_clamp_iframe_target_size(const struct VP9_COMP *const cpi,
+ int target);
+int vp9_rc_clamp_pframe_target_size(const struct VP9_COMP *const cpi,
+ int target);
+// Utility to set frame_target into the RATE_CONTROL structure
+// This function is called only from the vp9_rc_get_..._params() functions.
+void vp9_rc_set_frame_target(struct VP9_COMP *cpi, int target);
#ifdef __cplusplus
} // extern "C"
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index e5230feb4..cae7884fd 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -285,7 +285,8 @@ void vp9_initialize_rd_consts(VP9_COMP *cpi) {
cpi->RDDIV = RDDIV_BITS; // in bits (to multiply D by 128)
cpi->RDMULT = vp9_compute_rd_mult(cpi, qindex);
- x->errorperbit = cpi->RDMULT / RD_MULT_EPB_RATIO + (x->errorperbit == 0);
+ x->errorperbit = cpi->RDMULT / RD_MULT_EPB_RATIO;
+ x->errorperbit += (x->errorperbit == 0);
vp9_set_speed_features(cpi);
@@ -296,7 +297,7 @@ void vp9_initialize_rd_consts(VP9_COMP *cpi) {
fill_token_costs(x->token_costs, cm->fc.coef_probs);
- if (!cpi->sf.super_fast_rtc) {
+ if (!cpi->sf.use_pick_mode) {
for (i = 0; i < PARTITION_CONTEXTS; i++)
vp9_cost_tokens(x->partition_cost[i], get_partition_probs(cm, i),
vp9_partition_tree);
@@ -443,7 +444,7 @@ static void model_rd_for_sb(VP9_COMP *cpi, BLOCK_SIZE bsize,
if (i == 0)
x->pred_sse[ref] = sse;
- if (cpi->sf.super_fast_rtc) {
+ if (cpi->sf.use_pick_mode) {
dist_sum += (int)sse;
} else {
int rate;
@@ -643,17 +644,16 @@ static void block_rd_txfm(int plane, int block, BLOCK_SIZE plane_bsize,
MACROBLOCK *const x = args->x;
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *mbmi = &xd->mi_8x8[0]->mbmi;
- struct encode_b_args encode_args = {x, NULL, &mbmi->skip_coeff};
-
int64_t rd1, rd2, rd;
if (args->skip)
return;
- if (!is_inter_block(&xd->mi_8x8[0]->mbmi))
- vp9_encode_block_intra(plane, block, plane_bsize, tx_size, &encode_args);
+ if (!is_inter_block(mbmi))
+ vp9_encode_block_intra(x, plane, block, plane_bsize, tx_size,
+ &mbmi->skip_coeff);
else
- vp9_xform_quant(plane, block, plane_bsize, tx_size, &encode_args);
+ vp9_xform_quant(x, plane, block, plane_bsize, tx_size);
dist_block(plane, block, tx_size, args);
rate_block(plane, block, plane_bsize, tx_size, args);
@@ -1064,7 +1064,7 @@ static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int ib,
so = &vp9_scan_orders[TX_4X4][tx_type];
if (tx_type != DCT_DCT)
- vp9_short_fht4x4(src_diff, coeff, 8, tx_type);
+ vp9_fht4x4(src_diff, coeff, 8, tx_type);
else
x->fwd_txm4x4(src_diff, coeff, 8);
@@ -1645,14 +1645,15 @@ static void rd_check_segment_txsize(VP9_COMP *cpi, MACROBLOCK *x,
BEST_SEG_INFO *bsi_buf, int filter_idx,
int_mv seg_mvs[4][MAX_REF_FRAMES],
int mi_row, int mi_col) {
- int i, br = 0, idx, idy;
+ int k, br = 0, idx, idy;
int64_t bd = 0, block_sse = 0;
MB_PREDICTION_MODE this_mode;
+ MACROBLOCKD *xd = &x->e_mbd;
VP9_COMMON *cm = &cpi->common;
- MODE_INFO *mi = x->e_mbd.mi_8x8[0];
+ MODE_INFO *mi = xd->mi_8x8[0];
MB_MODE_INFO *const mbmi = &mi->mbmi;
struct macroblock_plane *const p = &x->plane[0];
- struct macroblockd_plane *const pd = &x->e_mbd.plane[0];
+ struct macroblockd_plane *const pd = &xd->plane[0];
const int label_count = 4;
int64_t this_segment_rd = 0;
int label_mv_thresh;
@@ -1660,7 +1661,7 @@ static void rd_check_segment_txsize(VP9_COMP *cpi, MACROBLOCK *x,
const BLOCK_SIZE bsize = mbmi->sb_type;
const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize];
const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize];
- vp9_variance_fn_ptr_t *v_fn_ptr;
+ vp9_variance_fn_ptr_t *v_fn_ptr = &cpi->fn_ptr[bsize];
ENTROPY_CONTEXT t_above[2], t_left[2];
BEST_SEG_INFO *bsi = bsi_buf + filter_idx;
int mode_idx;
@@ -1670,8 +1671,6 @@ static void rd_check_segment_txsize(VP9_COMP *cpi, MACROBLOCK *x,
vpx_memcpy(t_above, pd->above_context, sizeof(t_above));
vpx_memcpy(t_left, pd->left_context, sizeof(t_left));
- v_fn_ptr = &cpi->fn_ptr[bsize];
-
// 64 makes this threshold really big effectively
// making it so that we very rarely check mvs on
// segments. setting this to 1 would make mv thresh
@@ -1687,20 +1686,17 @@ static void rd_check_segment_txsize(VP9_COMP *cpi, MACROBLOCK *x,
int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES];
MB_PREDICTION_MODE mode_selected = ZEROMV;
int64_t best_rd = INT64_MAX;
- i = idy * 2 + idx;
-
- frame_mv[ZEROMV][mbmi->ref_frame[0]].as_int = 0;
- vp9_append_sub8x8_mvs_for_idx(cm, &x->e_mbd, tile,
- i, 0, mi_row, mi_col,
- &frame_mv[NEARESTMV][mbmi->ref_frame[0]],
- &frame_mv[NEARMV][mbmi->ref_frame[0]]);
- if (has_second_rf) {
- frame_mv[ZEROMV][mbmi->ref_frame[1]].as_int = 0;
- vp9_append_sub8x8_mvs_for_idx(cm, &x->e_mbd, tile,
- i, 1, mi_row, mi_col,
- &frame_mv[NEARESTMV][mbmi->ref_frame[1]],
- &frame_mv[NEARMV][mbmi->ref_frame[1]]);
+ const int i = idy * 2 + idx;
+ int ref;
+
+ for (ref = 0; ref < 1 + has_second_rf; ++ref) {
+ const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref];
+ frame_mv[ZEROMV][frame].as_int = 0;
+ vp9_append_sub8x8_mvs_for_idx(cm, xd, tile, i, ref, mi_row, mi_col,
+ &frame_mv[NEARESTMV][frame],
+ &frame_mv[NEARMV][frame]);
}
+
// search for the best motion vector on this segment
for (this_mode = NEARESTMV; this_mode <= NEWMV; ++this_mode) {
const struct buf_2d orig_src = x->plane[0].src;
@@ -2042,8 +2038,8 @@ static void rd_check_segment_txsize(VP9_COMP *cpi, MACROBLOCK *x,
bsi->sse = block_sse;
// update the coding decisions
- for (i = 0; i < 4; ++i)
- bsi->modes[i] = mi->bmi[i].as_mode;
+ for (k = 0; k < 4; ++k)
+ bsi->modes[k] = mi->bmi[k].as_mode;
}
static int64_t rd_pick_best_mbsegmentation(VP9_COMP *cpi, MACROBLOCK *x,
@@ -2910,33 +2906,26 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
if (cm->interp_filter == SWITCHABLE)
*rate2 += get_switchable_rate(x);
- if (!is_comp_pred && cpi->enable_encode_breakout) {
+ if (!is_comp_pred) {
if (cpi->active_map_enabled && x->active_ptr[0] == 0)
x->skip = 1;
- else if (x->encode_breakout) {
+ else if (cpi->allow_encode_breakout && x->encode_breakout) {
const BLOCK_SIZE y_size = get_plane_block_size(bsize, &xd->plane[0]);
const BLOCK_SIZE uv_size = get_plane_block_size(bsize, &xd->plane[1]);
unsigned int var, sse;
// Skipping threshold for ac.
unsigned int thresh_ac;
- // The encode_breakout input
- unsigned int encode_breakout = x->encode_breakout << 4;
- unsigned int max_thresh = 36000;
-
+ // Set a maximum for threshold to avoid big PSNR loss in low bitrate case.
// Use extreme low threshold for static frames to limit skipping.
- if (cpi->enable_encode_breakout == 2)
- max_thresh = 128;
+ const unsigned int max_thresh = (cpi->allow_encode_breakout ==
+ ENCODE_BREAKOUT_LIMITED) ? 128 : 36000;
+ // The encode_breakout input
+ const unsigned int min_thresh = ((x->encode_breakout << 4) > max_thresh) ?
+ max_thresh : (x->encode_breakout << 4);
// Calculate threshold according to dequant value.
thresh_ac = (xd->plane[0].dequant[1] * xd->plane[0].dequant[1]) / 9;
-
- // Use encode_breakout input if it is bigger than internal threshold.
- if (thresh_ac < encode_breakout)
- thresh_ac = encode_breakout;
-
- // Set a maximum for threshold to avoid big PSNR loss in low bitrate case.
- if (thresh_ac > max_thresh)
- thresh_ac = max_thresh;
+ thresh_ac = clamp(thresh_ac, min_thresh, max_thresh);
var = cpi->fn_ptr[y_size].vf(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].dst.buf,
diff --git a/vp9/encoder/vp9_sad_c.c b/vp9/encoder/vp9_sad.c
index 58c5df47e..58c5df47e 100644
--- a/vp9/encoder/vp9_sad_c.c
+++ b/vp9/encoder/vp9_sad.c
diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c
index e822e4c64..ca11dda1e 100644
--- a/vp9/encoder/vp9_temporal_filter.c
+++ b/vp9/encoder/vp9_temporal_filter.c
@@ -134,17 +134,16 @@ static int temporal_filter_find_matching_mb_c(VP9_COMP *cpi,
int sadpb = x->sadperbit16;
int bestsme = INT_MAX;
- int_mv best_ref_mv1;
- int_mv best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */
- int_mv *ref_mv;
+ MV best_ref_mv1 = {0, 0};
+ MV best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */
+ MV *ref_mv = &x->e_mbd.mi_8x8[0]->bmi[0].as_mv[0].as_mv;
// Save input state
struct buf_2d src = x->plane[0].src;
struct buf_2d pre = xd->plane[0].pre[0];
- best_ref_mv1.as_int = 0;
- best_ref_mv1_full.as_mv.col = best_ref_mv1.as_mv.col >> 3;
- best_ref_mv1_full.as_mv.row = best_ref_mv1.as_mv.row >> 3;
+ best_ref_mv1_full.col = best_ref_mv1.col >> 3;
+ best_ref_mv1_full.row = best_ref_mv1.row >> 3;
// Setup frame pointers
x->plane[0].src.buf = arf_frame_buf;
@@ -161,11 +160,9 @@ static int temporal_filter_find_matching_mb_c(VP9_COMP *cpi,
/*cpi->sf.search_method == HEX*/
// Ignore mv costing by sending NULL pointer instead of cost arrays
- ref_mv = &x->e_mbd.mi_8x8[0]->bmi[0].as_mv[0];
- bestsme = vp9_hex_search(x, &best_ref_mv1_full.as_mv,
- step_param, sadpb, 1,
+ bestsme = vp9_hex_search(x, &best_ref_mv1_full, step_param, sadpb, 1,
&cpi->fn_ptr[BLOCK_16X16],
- 0, &best_ref_mv1.as_mv, &ref_mv->as_mv);
+ 0, &best_ref_mv1, ref_mv);
#if ALT_REF_SUBPEL_ENABLED
// Try sub-pixel MC?
@@ -174,8 +171,8 @@ static int temporal_filter_find_matching_mb_c(VP9_COMP *cpi,
int distortion;
unsigned int sse;
// Ignore mv costing by sending NULL pointer instead of cost array
- bestsme = cpi->find_fractional_mv_step(x, &ref_mv->as_mv,
- &best_ref_mv1.as_mv,
+ bestsme = cpi->find_fractional_mv_step(x, ref_mv,
+ &best_ref_mv1,
cpi->common.allow_high_precision_mv,
x->errorperbit,
&cpi->fn_ptr[BLOCK_16X16],
@@ -523,11 +520,16 @@ void vp9_configure_arnr_filter(VP9_COMP *cpi,
cpi->active_arnr_frames = frames_bwd + 1 + frames_fwd;
// Adjust the strength based on active max q
- q = ((int)vp9_convert_qindex_to_q(cpi->rc.active_worst_quality) >> 1);
- if (q > 8) {
+ if (cpi->common.current_video_frame > 1)
+ q = ((int)vp9_convert_qindex_to_q(
+ cpi->rc.avg_frame_qindex[INTER_FRAME]));
+ else
+ q = ((int)vp9_convert_qindex_to_q(
+ cpi->rc.avg_frame_qindex[KEY_FRAME]));
+ if (q > 16) {
cpi->active_arnr_strength = cpi->oxcf.arnr_strength;
} else {
- cpi->active_arnr_strength = cpi->oxcf.arnr_strength - (8 - q);
+ cpi->active_arnr_strength = cpi->oxcf.arnr_strength - ((16 - q) / 2);
if (cpi->active_arnr_strength < 0)
cpi->active_arnr_strength = 0;
}
diff --git a/vp9/encoder/vp9_variance_c.c b/vp9/encoder/vp9_variance.c
index 8bc385089..8bc385089 100644
--- a/vp9/encoder/vp9_variance_c.c
+++ b/vp9/encoder/vp9_variance.c
diff --git a/vp9/encoder/vp9_writer.c b/vp9/encoder/vp9_writer.c
index 3d13d07b6..fda1b390e 100644
--- a/vp9/encoder/vp9_writer.c
+++ b/vp9/encoder/vp9_writer.c
@@ -12,11 +12,6 @@
#include "vp9/encoder/vp9_writer.h"
#include "vp9/common/vp9_entropy.h"
-#if defined(SECTIONBITS_OUTPUT)
-unsigned __int64 Sectionbits[500];
-
-#endif
-
#ifdef ENTROPY_STATS
unsigned int active_section = 0;
#endif
diff --git a/vp9/encoder/vp9_writer.h b/vp9/encoder/vp9_writer.h
index 62f555c99..defeec377 100644
--- a/vp9/encoder/vp9_writer.h
+++ b/vp9/encoder/vp9_writer.h
@@ -44,17 +44,6 @@ static void vp9_write(vp9_writer *br, int bit, int probability) {
unsigned int lowvalue = br->lowvalue;
register unsigned int shift;
-#ifdef ENTROPY_STATS
-#if defined(SECTIONBITS_OUTPUT)
-
- if (bit)
- Sectionbits[active_section] += vp9_prob_cost[255 - probability];
- else
- Sectionbits[active_section] += vp9_prob_cost[probability];
-
-#endif
-#endif
-
split = 1 + (((range - 1) * probability) >> 8);
range = split;
diff --git a/vp9/encoder/x86/vp9_dct_avx2.c b/vp9/encoder/x86/vp9_dct_avx2.c
index ea031fb07..2b82d9750 100644
--- a/vp9/encoder/x86/vp9_dct_avx2.c
+++ b/vp9/encoder/x86/vp9_dct_avx2.c
@@ -244,32 +244,36 @@ void fadst4_avx2(__m128i *in) {
transpose_4x4_avx2(in);
}
-void vp9_short_fht4x4_avx2(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
+void vp9_fht4x4_avx2(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
__m128i in[4];
- load_buffer_4x4_avx2(input, in, stride);
+
switch (tx_type) {
- case 0: // DCT_DCT
- fdct4_avx2(in);
- fdct4_avx2(in);
+ case DCT_DCT:
+ vp9_fdct4x4_avx2(input, output, stride);
break;
- case 1: // ADST_DCT
+ case ADST_DCT:
+ load_buffer_4x4_avx2(input, in, stride);
fadst4_avx2(in);
fdct4_avx2(in);
+ write_buffer_4x4_avx2(output, in);
break;
- case 2: // DCT_ADST
+ case DCT_ADST:
+ load_buffer_4x4_avx2(input, in, stride);
fdct4_avx2(in);
fadst4_avx2(in);
+ write_buffer_4x4_avx2(output, in);
break;
- case 3: // ADST_ADST
+ case ADST_ADST:
+ load_buffer_4x4_avx2(input, in, stride);
fadst4_avx2(in);
fadst4_avx2(in);
+ write_buffer_4x4_avx2(output, in);
break;
default:
assert(0);
break;
}
- write_buffer_4x4_avx2(output, in);
}
void vp9_fdct8x8_avx2(const int16_t *input, int16_t *output, int stride) {
@@ -1028,33 +1032,39 @@ void fadst8_avx2(__m128i *in) {
array_transpose_8x8_avx2(in, in);
}
-void vp9_short_fht8x8_avx2(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
+void vp9_fht8x8_avx2(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
__m128i in[8];
- load_buffer_8x8_avx2(input, in, stride);
+
switch (tx_type) {
- case 0: // DCT_DCT
- fdct8_avx2(in);
- fdct8_avx2(in);
+ case DCT_DCT:
+ vp9_fdct8x8_avx2(input, output, stride);
break;
- case 1: // ADST_DCT
+ case ADST_DCT:
+ load_buffer_8x8_avx2(input, in, stride);
fadst8_avx2(in);
fdct8_avx2(in);
+ right_shift_8x8_avx2(in, 1);
+ write_buffer_8x8_avx2(output, in, 8);
break;
- case 2: // DCT_ADST
+ case DCT_ADST:
+ load_buffer_8x8_avx2(input, in, stride);
fdct8_avx2(in);
fadst8_avx2(in);
+ right_shift_8x8_avx2(in, 1);
+ write_buffer_8x8_avx2(output, in, 8);
break;
- case 3: // ADST_ADST
+ case ADST_ADST:
+ load_buffer_8x8_avx2(input, in, stride);
fadst8_avx2(in);
fadst8_avx2(in);
+ right_shift_8x8_avx2(in, 1);
+ write_buffer_8x8_avx2(output, in, 8);
break;
default:
assert(0);
break;
}
- right_shift_8x8_avx2(in, 1);
- write_buffer_8x8_avx2(output, in, 8);
}
void vp9_fdct16x16_avx2(const int16_t *input, int16_t *output, int stride) {
@@ -2534,36 +2544,39 @@ void fadst16_avx2(__m128i *in0, __m128i *in1) {
array_transpose_16x16_avx2(in0, in1);
}
-void vp9_short_fht16x16_avx2(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
+void vp9_fht16x16_avx2(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
__m128i in0[16], in1[16];
- load_buffer_16x16_avx2(input, in0, in1, stride);
+
switch (tx_type) {
- case 0: // DCT_DCT
- fdct16_avx2(in0, in1);
- right_shift_16x16_avx2(in0, in1);
- fdct16_avx2(in0, in1);
+ case DCT_DCT:
+ vp9_fdct16x16_avx2(input, output, stride);
break;
- case 1: // ADST_DCT
+ case ADST_DCT:
+ load_buffer_16x16_avx2(input, in0, in1, stride);
fadst16_avx2(in0, in1);
right_shift_16x16_avx2(in0, in1);
fdct16_avx2(in0, in1);
+ write_buffer_16x16_avx2(output, in0, in1, 16);
break;
- case 2: // DCT_ADST
+ case DCT_ADST:
+ load_buffer_16x16_avx2(input, in0, in1, stride);
fdct16_avx2(in0, in1);
right_shift_16x16_avx2(in0, in1);
fadst16_avx2(in0, in1);
+ write_buffer_16x16_avx2(output, in0, in1, 16);
break;
- case 3: // ADST_ADST
+ case ADST_ADST:
+ load_buffer_16x16_avx2(input, in0, in1, stride);
fadst16_avx2(in0, in1);
right_shift_16x16_avx2(in0, in1);
fadst16_avx2(in0, in1);
+ write_buffer_16x16_avx2(output, in0, in1, 16);
break;
default:
assert(0);
break;
}
- write_buffer_16x16_avx2(output, in0, in1, 16);
}
#define FDCT32x32_2D_AVX2 vp9_fdct32x32_rd_avx2
diff --git a/vp9/encoder/x86/vp9_dct_sse2.c b/vp9/encoder/x86/vp9_dct_sse2.c
index c876cc273..852cf8667 100644
--- a/vp9/encoder/x86/vp9_dct_sse2.c
+++ b/vp9/encoder/x86/vp9_dct_sse2.c
@@ -242,32 +242,36 @@ void fadst4_sse2(__m128i *in) {
transpose_4x4(in);
}
-void vp9_short_fht4x4_sse2(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
+void vp9_fht4x4_sse2(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
__m128i in[4];
- load_buffer_4x4(input, in, stride);
+
switch (tx_type) {
- case 0: // DCT_DCT
- fdct4_sse2(in);
- fdct4_sse2(in);
+ case DCT_DCT:
+ vp9_fdct4x4_sse2(input, output, stride);
break;
- case 1: // ADST_DCT
+ case ADST_DCT:
+ load_buffer_4x4(input, in, stride);
fadst4_sse2(in);
fdct4_sse2(in);
+ write_buffer_4x4(output, in);
break;
- case 2: // DCT_ADST
+ case DCT_ADST:
+ load_buffer_4x4(input, in, stride);
fdct4_sse2(in);
fadst4_sse2(in);
+ write_buffer_4x4(output, in);
break;
- case 3: // ADST_ADST
+ case ADST_ADST:
+ load_buffer_4x4(input, in, stride);
fadst4_sse2(in);
fadst4_sse2(in);
+ write_buffer_4x4(output, in);
break;
- default:
- assert(0);
- break;
+ default:
+ assert(0);
+ break;
}
- write_buffer_4x4(output, in);
}
void vp9_fdct8x8_sse2(const int16_t *input, int16_t *output, int stride) {
@@ -1026,33 +1030,39 @@ void fadst8_sse2(__m128i *in) {
array_transpose_8x8(in, in);
}
-void vp9_short_fht8x8_sse2(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
+void vp9_fht8x8_sse2(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
__m128i in[8];
- load_buffer_8x8(input, in, stride);
+
switch (tx_type) {
- case 0: // DCT_DCT
- fdct8_sse2(in);
- fdct8_sse2(in);
+ case DCT_DCT:
+ vp9_fdct8x8_sse2(input, output, stride);
break;
- case 1: // ADST_DCT
+ case ADST_DCT:
+ load_buffer_8x8(input, in, stride);
fadst8_sse2(in);
fdct8_sse2(in);
+ right_shift_8x8(in, 1);
+ write_buffer_8x8(output, in, 8);
break;
- case 2: // DCT_ADST
+ case DCT_ADST:
+ load_buffer_8x8(input, in, stride);
fdct8_sse2(in);
fadst8_sse2(in);
+ right_shift_8x8(in, 1);
+ write_buffer_8x8(output, in, 8);
break;
- case 3: // ADST_ADST
+ case ADST_ADST:
+ load_buffer_8x8(input, in, stride);
fadst8_sse2(in);
fadst8_sse2(in);
+ right_shift_8x8(in, 1);
+ write_buffer_8x8(output, in, 8);
break;
default:
assert(0);
break;
}
- right_shift_8x8(in, 1);
- write_buffer_8x8(output, in, 8);
}
void vp9_fdct16x16_sse2(const int16_t *input, int16_t *output, int stride) {
@@ -2532,36 +2542,39 @@ void fadst16_sse2(__m128i *in0, __m128i *in1) {
array_transpose_16x16(in0, in1);
}
-void vp9_short_fht16x16_sse2(const int16_t *input, int16_t *output,
- int stride, int tx_type) {
+void vp9_fht16x16_sse2(const int16_t *input, int16_t *output,
+ int stride, int tx_type) {
__m128i in0[16], in1[16];
- load_buffer_16x16(input, in0, in1, stride);
+
switch (tx_type) {
- case 0: // DCT_DCT
- fdct16_sse2(in0, in1);
- right_shift_16x16(in0, in1);
- fdct16_sse2(in0, in1);
+ case DCT_DCT:
+ vp9_fdct16x16_sse2(input, output, stride);
break;
- case 1: // ADST_DCT
+ case ADST_DCT:
+ load_buffer_16x16(input, in0, in1, stride);
fadst16_sse2(in0, in1);
right_shift_16x16(in0, in1);
fdct16_sse2(in0, in1);
+ write_buffer_16x16(output, in0, in1, 16);
break;
- case 2: // DCT_ADST
+ case DCT_ADST:
+ load_buffer_16x16(input, in0, in1, stride);
fdct16_sse2(in0, in1);
right_shift_16x16(in0, in1);
fadst16_sse2(in0, in1);
+ write_buffer_16x16(output, in0, in1, 16);
break;
- case 3: // ADST_ADST
+ case ADST_ADST:
+ load_buffer_16x16(input, in0, in1, stride);
fadst16_sse2(in0, in1);
right_shift_16x16(in0, in1);
fadst16_sse2(in0, in1);
+ write_buffer_16x16(output, in0, in1, 16);
break;
default:
assert(0);
break;
}
- write_buffer_16x16(output, in0, in1, 16);
}
#define FDCT32x32_2D vp9_fdct32x32_rd_sse2
diff --git a/vp9/encoder/x86/vp9_quantize_ssse3.asm b/vp9/encoder/x86/vp9_quantize_ssse3.asm
index db306603b..48ccef8cc 100644
--- a/vp9/encoder/x86/vp9_quantize_ssse3.asm
+++ b/vp9/encoder/x86/vp9_quantize_ssse3.asm
@@ -188,7 +188,8 @@ cglobal quantize_%1, 0, %2, 15, coeff, ncoeff, skip, zbin, round, quant, \
pmaxsw m8, m7
pshuflw m7, m8, 0x1
pmaxsw m8, m7
- pextrw [r2], m8, 0
+ pextrw r6, m8, 0
+ mov [r2], r6
RET
; skip-block, i.e. just write all zeroes
@@ -214,5 +215,5 @@ cglobal quantize_%1, 0, %2, 15, coeff, ncoeff, skip, zbin, round, quant, \
%endmacro
INIT_XMM ssse3
-QUANTIZE_FN b, 6
+QUANTIZE_FN b, 7
QUANTIZE_FN b_32x32, 7
diff --git a/vp9/vp9_common.mk b/vp9/vp9_common.mk
index c691411bf..85e83b834 100644
--- a/vp9/vp9_common.mk
+++ b/vp9/vp9_common.mk
@@ -23,6 +23,8 @@ VP9_COMMON_SRCS-yes += common/vp9_entropymode.c
VP9_COMMON_SRCS-yes += common/vp9_entropymv.c
VP9_COMMON_SRCS-yes += common/vp9_filter.c
VP9_COMMON_SRCS-yes += common/vp9_filter.h
+VP9_COMMON_SRCS-yes += common/vp9_frame_buffers.c
+VP9_COMMON_SRCS-yes += common/vp9_frame_buffers.h
VP9_COMMON_SRCS-yes += common/generic/vp9_systemdependent.c
VP9_COMMON_SRCS-yes += common/vp9_idct.c
VP9_COMMON_SRCS-yes += common/vp9_alloccommon.h
@@ -76,12 +78,13 @@ VP9_COMMON_SRCS-$(HAVE_MMX) += common/x86/vp9_loopfilter_mmx.asm
VP9_COMMON_SRCS-$(HAVE_SSE2) += common/x86/vp9_subpixel_8t_sse2.asm
VP9_COMMON_SRCS-$(HAVE_SSE2) += common/x86/vp9_subpixel_bilinear_sse2.asm
VP9_COMMON_SRCS-$(HAVE_SSSE3) += common/x86/vp9_subpixel_8t_ssse3.asm
+VP9_COMMON_SRCS-$(HAVE_SSSE3) += common/x86/vp9_subpixel_bilinear_ssse3.asm
ifeq ($(CONFIG_VP9_POSTPROC),yes)
VP9_COMMON_SRCS-$(HAVE_MMX) += common/x86/vp9_postproc_mmx.asm
VP9_COMMON_SRCS-$(HAVE_SSE2) += common/x86/vp9_postproc_sse2.asm
endif
-ifeq ($(USE_X86INC),yes)
+ifeq ($(CONFIG_USE_X86INC),yes)
VP9_COMMON_SRCS-$(HAVE_SSE2) += common/x86/vp9_copy_sse2.asm
VP9_COMMON_SRCS-$(HAVE_SSE2) += common/x86/vp9_intrapred_sse2.asm
VP9_COMMON_SRCS-$(HAVE_SSSE3) += common/x86/vp9_intrapred_ssse3.asm
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index 6b181710e..ece6d5280 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -175,6 +175,23 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
RANGE_CHECK(cfg, ss_number_layers, 1,
VPX_SS_MAX_LAYERS); /*Spatial layers max */
+
+ RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
+ if (cfg->ts_number_layers > 1) {
+ int i;
+ for (i = 1; i < cfg->ts_number_layers; ++i) {
+ if (cfg->ts_target_bitrate[i] < cfg->ts_target_bitrate[i-1]) {
+ ERROR("ts_target_bitrate entries are not increasing");
+ }
+ }
+ RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers-1], 1, 1);
+ for (i = cfg->ts_number_layers-2; i > 0; --i) {
+ if (cfg->ts_rate_decimator[i-1] != 2*cfg->ts_rate_decimator[i]) {
+ ERROR("ts_rate_decimator factors are not powers of 2");
+ }
+ }
+ }
+
/* VP8 does not support a lower bound on the keyframe interval in
* automatic keyframe placement mode.
*/
@@ -279,14 +296,11 @@ static vpx_codec_err_t set_vp9e_config(VP9_CONFIG *oxcf,
oxcf->lag_in_frames = cfg.g_lag_in_frames;
}
- // VBR only supported for now.
- // CBR code has been deprectated for experimental phase.
- // CQ mode not yet tested
- oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;
+ oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;
if (cfg.rc_end_usage == VPX_CQ)
- oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
+ oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
else if (cfg.rc_end_usage == VPX_Q)
- oxcf->end_usage = USAGE_CONSTANT_QUALITY;
+ oxcf->end_usage = USAGE_CONSTANT_QUALITY;
else if (cfg.rc_end_usage == VPX_CBR)
oxcf->end_usage = USAGE_STREAM_FROM_SERVER;
@@ -316,9 +330,6 @@ static vpx_codec_err_t set_vp9e_config(VP9_CONFIG *oxcf,
// oxcf->kf_min_dist = cfg.kf_min_dis;
oxcf->key_freq = cfg.kf_max_dist;
- // oxcf->delete_first_pass_file = cfg.g_delete_firstpassfile;
- // strcpy(oxcf->first_pass_file, cfg.g_firstpass_file);
-
oxcf->cpu_used = vp8_cfg.cpu_used;
oxcf->encode_breakout = vp8_cfg.static_thresh;
oxcf->play_alternate = vp8_cfg.enable_auto_alt_ref;
@@ -345,6 +356,19 @@ static vpx_codec_err_t set_vp9e_config(VP9_CONFIG *oxcf,
oxcf->aq_mode = vp8_cfg.aq_mode;
oxcf->ss_number_layers = cfg.ss_number_layers;
+
+ oxcf->ts_number_layers = cfg.ts_number_layers;
+
+ if (oxcf->ts_number_layers > 1) {
+ memcpy(oxcf->ts_target_bitrate, cfg.ts_target_bitrate,
+ sizeof(cfg.ts_target_bitrate));
+ memcpy(oxcf->ts_rate_decimator, cfg.ts_rate_decimator,
+ sizeof(cfg.ts_rate_decimator));
+ } else if (oxcf->ts_number_layers == 1) {
+ oxcf->ts_target_bitrate[0] = oxcf->target_bandwidth;
+ oxcf->ts_rate_decimator[0] = 1;
+ }
+
/*
printf("Current VP9 Settings: \n");
printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
@@ -352,7 +376,6 @@ static vpx_codec_err_t set_vp9e_config(VP9_CONFIG *oxcf,
printf("sharpness: %d\n", oxcf->sharpness);
printf("cpu_used: %d\n", oxcf->cpu_used);
printf("Mode: %d\n", oxcf->mode);
- // printf("delete_first_pass_file: %d\n", oxcf->delete_first_pass_file);
printf("auto_key: %d\n", oxcf->auto_key);
printf("key_freq: %d\n", oxcf->key_freq);
printf("end_usage: %d\n", oxcf->end_usage);
@@ -862,10 +885,9 @@ static const vpx_codec_cx_pkt_t *vp9e_get_cxdata(vpx_codec_alg_priv_t *ctx,
static vpx_codec_err_t vp9e_set_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
- vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
+ vpx_ref_frame_t *frame = va_arg(args, vpx_ref_frame_t *);
- if (data) {
- vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
+ if (frame != NULL) {
YV12_BUFFER_CONFIG sd;
image2yuvconfig(&frame->img, &sd);
@@ -880,10 +902,9 @@ static vpx_codec_err_t vp9e_set_reference(vpx_codec_alg_priv_t *ctx,
static vpx_codec_err_t vp9e_copy_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
- vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
+ vpx_ref_frame_t *frame = va_arg(args, vpx_ref_frame_t *);
- if (data) {
- vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
+ if (frame != NULL) {
YV12_BUFFER_CONFIG sd;
image2yuvconfig(&frame->img, &sd);
@@ -898,13 +919,13 @@ static vpx_codec_err_t vp9e_copy_reference(vpx_codec_alg_priv_t *ctx,
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
- vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);
+ vp9_ref_frame_t *frame = va_arg(args, vp9_ref_frame_t *);
- if (data) {
+ if (frame != NULL) {
YV12_BUFFER_CONFIG* fb;
- vp9_get_reference_enc(ctx->cpi, data->idx, &fb);
- yuvconfig2image(&data->img, fb, NULL);
+ vp9_get_reference_enc(ctx->cpi, frame->idx, &fb);
+ yuvconfig2image(&frame->img, fb, NULL);
return VPX_CODEC_OK;
} else {
return VPX_CODEC_INVALID_PARAM;
@@ -915,11 +936,11 @@ static vpx_codec_err_t vp9e_set_previewpp(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
#if CONFIG_VP9_POSTPROC
- vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
+ vp8_postproc_cfg_t *config = va_arg(args, vp8_postproc_cfg_t *);
(void)ctr_id;
- if (data) {
- ctx->preview_ppcfg = *((vp8_postproc_cfg_t *)data);
+ if (config != NULL) {
+ ctx->preview_ppcfg = *config;
return VPX_CODEC_OK;
} else {
return VPX_CODEC_INVALID_PARAM;
@@ -993,14 +1014,13 @@ static vpx_codec_err_t vp9e_set_activemap(vpx_codec_alg_priv_t *ctx,
static vpx_codec_err_t vp9e_set_scalemode(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
- vpx_scaling_mode_t *data = va_arg(args, vpx_scaling_mode_t *);
+ vpx_scaling_mode_t *scalemode = va_arg(args, vpx_scaling_mode_t *);
- if (data) {
+ if (scalemode != NULL) {
int res;
- vpx_scaling_mode_t scalemode = *(vpx_scaling_mode_t *)data;
res = vp9_set_internal_size(ctx->cpi,
- (VPX_SCALING)scalemode.h_scaling_mode,
- (VPX_SCALING)scalemode.v_scaling_mode);
+ (VPX_SCALING)scalemode->h_scaling_mode,
+ (VPX_SCALING)scalemode->v_scaling_mode);
if (!res) {
return VPX_CODEC_OK;
@@ -1016,32 +1036,54 @@ static vpx_codec_err_t vp9e_set_svc(vpx_codec_alg_priv_t *ctx, int ctr_id,
va_list args) {
int data = va_arg(args, int);
vp9_set_svc(ctx->cpi, data);
+ // CBR mode for SVC with both temporal and spatial layers not yet supported.
+ if (data == 1 &&
+ ctx->cfg.rc_end_usage == VPX_CBR &&
+ ctx->cfg.ss_number_layers > 1 &&
+ ctx->cfg.ts_number_layers > 1) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
+ return VPX_CODEC_OK;
+}
+
+static vpx_codec_err_t vp9e_set_svc_layer_id(vpx_codec_alg_priv_t *ctx,
+ int ctr_id,
+ va_list args) {
+ vpx_svc_layer_id_t *data = va_arg(args, vpx_svc_layer_id_t *);
+ VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
+ cpi->svc.spatial_layer_id = data->spatial_layer_id;
+ cpi->svc.temporal_layer_id = data->temporal_layer_id;
+ // Checks on valid layer_id input.
+ if (cpi->svc.temporal_layer_id < 0 ||
+ cpi->svc.temporal_layer_id >= ctx->cfg.ts_number_layers) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
+ if (cpi->svc.spatial_layer_id < 0 ||
+ cpi->svc.spatial_layer_id >= ctx->cfg.ss_number_layers) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
return VPX_CODEC_OK;
}
static vpx_codec_err_t vp9e_set_svc_parameters(vpx_codec_alg_priv_t *ctx,
int ctr_id, va_list args) {
- vpx_svc_parameters_t *data = va_arg(args, vpx_svc_parameters_t *);
VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
- vpx_svc_parameters_t params;
+ vpx_svc_parameters_t *params = va_arg(args, vpx_svc_parameters_t *);
- if (data == NULL) {
- return VPX_CODEC_INVALID_PARAM;
- }
+ if (params == NULL) return VPX_CODEC_INVALID_PARAM;
- params = *(vpx_svc_parameters_t *)data;
+ cpi->svc.spatial_layer_id = params->spatial_layer;
+ cpi->svc.temporal_layer_id = params->temporal_layer;
- cpi->current_layer = params.layer;
- cpi->lst_fb_idx = params.lst_fb_idx;
- cpi->gld_fb_idx = params.gld_fb_idx;
- cpi->alt_fb_idx = params.alt_fb_idx;
+ cpi->lst_fb_idx = params->lst_fb_idx;
+ cpi->gld_fb_idx = params->gld_fb_idx;
+ cpi->alt_fb_idx = params->alt_fb_idx;
- if (vp9_set_size_literal(ctx->cpi, params.width, params.height) != 0) {
+ if (vp9_set_size_literal(ctx->cpi, params->width, params->height) != 0)
return VPX_CODEC_INVALID_PARAM;
- }
- ctx->cfg.rc_max_quantizer = params.max_quantizer;
- ctx->cfg.rc_min_quantizer = params.min_quantizer;
+ ctx->cfg.rc_max_quantizer = params->max_quantizer;
+ ctx->cfg.rc_min_quantizer = params->min_quantizer;
set_vp9e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg);
vp9_change_config(ctx->cpi, &ctx->oxcf);
@@ -1080,6 +1122,7 @@ static vpx_codec_ctrl_fn_map_t vp9e_ctf_maps[] = {
{VP9_GET_REFERENCE, get_reference},
{VP9E_SET_SVC, vp9e_set_svc},
{VP9E_SET_SVC_PARAMETERS, vp9e_set_svc_parameters},
+ {VP9E_SET_SVC_LAYER_ID, vp9e_set_svc_layer_id},
{ -1, NULL},
};
@@ -1130,9 +1173,12 @@ static vpx_codec_enc_cfg_map_t vp9e_usage_cfg_map[] = {
9999, /* kf_max_dist */
VPX_SS_DEFAULT_LAYERS, /* ss_number_layers */
-
+ 1, /* ts_number_layers */
+ {0}, /* ts_target_bitrate */
+ {0}, /* ts_rate_decimator */
+ 0, /* ts_periodicity */
+ {0}, /* ts_layer_id */
#if VPX_ENCODER_ABI_VERSION == (1 + VPX_CODEC_ABI_VERSION)
- 1, /* g_delete_first_pass_file */
"vp8.fpf" /* first pass filename */
#endif
}
diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c
index 92c6cd20c..881a7d152 100644
--- a/vp9/vp9_dx_iface.c
+++ b/vp9/vp9_dx_iface.c
@@ -15,6 +15,7 @@
#include "vpx/vp8dx.h"
#include "vpx/internal/vpx_codec_internal.h"
#include "./vpx_version.h"
+#include "vp9/common/vp9_frame_buffers.h"
#include "vp9/decoder/vp9_onyxd.h"
#include "vp9/decoder/vp9_onyxd_int.h"
#include "vp9/decoder/vp9_read_bit_buffer.h"
@@ -148,7 +149,9 @@ static vpx_codec_err_t vp9_peek_si(const uint8_t *data, unsigned int data_sz,
{
struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
const int frame_marker = vp9_rb_read_literal(&rb, 2);
- const int version = vp9_rb_read_bit(&rb) | (vp9_rb_read_bit(&rb) << 1);
+ const int version = vp9_rb_read_bit(&rb);
+ (void) vp9_rb_read_bit(&rb); // unused version bit
+
if (frame_marker != VP9_FRAME_MARKER)
return VPX_CODEC_UNSUP_BITSTREAM;
#if CONFIG_NON420
@@ -291,10 +294,22 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
ctx->postproc_cfg.noise_level = 0;
}
- if (!optr)
+ if (!optr) {
res = VPX_CODEC_ERROR;
- else
+ } else {
+ VP9D_COMP *const pbi = (VP9D_COMP*)optr;
+ VP9_COMMON *const cm = &pbi->common;
+
+ cm->get_fb_cb = vp9_get_frame_buffer;
+ cm->release_fb_cb = vp9_release_frame_buffer;
+
+ 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;
diff --git a/vp9/vp9cx.mk b/vp9/vp9cx.mk
index 63003b9c2..c0d973b4f 100644
--- a/vp9/vp9cx.mk
+++ b/vp9/vp9cx.mk
@@ -19,7 +19,6 @@ VP9_CX_SRCS-yes += vp9_cx_iface.c
VP9_CX_SRCS-yes += encoder/vp9_bitstream.c
VP9_CX_SRCS-yes += encoder/vp9_dct.c
-VP9_CX_SRCS-yes += encoder/vp9_dct.h
VP9_CX_SRCS-yes += encoder/vp9_encodeframe.c
VP9_CX_SRCS-yes += encoder/vp9_encodeframe.h
VP9_CX_SRCS-yes += encoder/vp9_encodemb.c
@@ -56,7 +55,7 @@ VP9_CX_SRCS-yes += encoder/vp9_quantize.c
VP9_CX_SRCS-yes += encoder/vp9_ratectrl.c
VP9_CX_SRCS-yes += encoder/vp9_rdopt.c
VP9_CX_SRCS-yes += encoder/vp9_pickmode.c
-VP9_CX_SRCS-yes += encoder/vp9_sad_c.c
+VP9_CX_SRCS-yes += encoder/vp9_sad.c
VP9_CX_SRCS-yes += encoder/vp9_segmentation.c
VP9_CX_SRCS-yes += encoder/vp9_segmentation.h
VP9_CX_SRCS-yes += encoder/vp9_subexp.c
@@ -66,7 +65,7 @@ VP9_CX_SRCS-yes += encoder/vp9_resize.h
VP9_CX_SRCS-$(CONFIG_INTERNAL_STATS) += encoder/vp9_ssim.c
VP9_CX_SRCS-yes += encoder/vp9_tokenize.c
VP9_CX_SRCS-yes += encoder/vp9_treewriter.c
-VP9_CX_SRCS-yes += encoder/vp9_variance_c.c
+VP9_CX_SRCS-yes += encoder/vp9_variance.c
VP9_CX_SRCS-yes += encoder/vp9_vaq.c
VP9_CX_SRCS-yes += encoder/vp9_vaq.h
ifeq ($(CONFIG_VP9_POSTPROC),yes)
@@ -90,7 +89,7 @@ VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_subpel_variance_impl_sse2.asm
VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_temporal_filter_apply_sse2.asm
VP9_CX_SRCS-$(HAVE_SSE3) += encoder/x86/vp9_sad_sse3.asm
-ifeq ($(USE_X86INC),yes)
+ifeq ($(CONFIG_USE_X86INC),yes)
VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_error_sse2.asm
VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_sad_sse2.asm
VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_subtract_sse2.asm
diff --git a/vpx/src/svc_encodeframe.c b/vpx/src/svc_encodeframe.c
index 810e881c8..4f5ba6f20 100644
--- a/vpx/src/svc_encodeframe.c
+++ b/vpx/src/svc_encodeframe.c
@@ -95,7 +95,8 @@ struct LayerData {
// create LayerData from encoder output
static struct LayerData *ld_create(void *buf, size_t size) {
- struct LayerData *const layer_data = malloc(sizeof(*layer_data));
+ struct LayerData *const layer_data =
+ (struct LayerData *)malloc(sizeof(*layer_data));
if (layer_data == NULL) {
return NULL;
}
@@ -201,18 +202,18 @@ static void sf_create_index(struct Superframe *sf) {
static SvcInternal *get_svc_internal(SvcContext *svc_ctx) {
if (svc_ctx == NULL) return NULL;
if (svc_ctx->internal == NULL) {
- SvcInternal *const si = malloc(sizeof(*si));
+ SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si));
if (si != NULL) {
memset(si, 0, sizeof(*si));
}
svc_ctx->internal = si;
}
- return svc_ctx->internal;
+ return (SvcInternal *)svc_ctx->internal;
}
static const SvcInternal *get_const_svc_internal(const SvcContext *svc_ctx) {
if (svc_ctx == NULL) return NULL;
- return svc_ctx->internal;
+ return (const SvcInternal *)svc_ctx->internal;
}
static void svc_log_reset(SvcContext *svc_ctx) {
@@ -272,7 +273,7 @@ static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
char *save_ptr;
int found = 0;
int i, q;
- int res = VPX_CODEC_OK;
+ vpx_codec_err_t res = VPX_CODEC_OK;
SvcInternal *const si = get_svc_internal(svc_ctx);
if (quantizer_values == NULL || strlen(quantizer_values) == 0) {
@@ -322,7 +323,7 @@ static vpx_codec_err_t parse_scale_factors(SvcContext *svc_ctx,
int found = 0;
int i;
int64_t num, den;
- int res = VPX_CODEC_OK;
+ vpx_codec_err_t res = VPX_CODEC_OK;
SvcInternal *const si = get_svc_internal(svc_ctx);
if (scale_factors == NULL || strlen(scale_factors) == 0) {
@@ -381,7 +382,7 @@ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
char *option_name;
char *option_value;
char *input_ptr;
- int res = VPX_CODEC_OK;
+ vpx_codec_err_t res = VPX_CODEC_OK;
if (options == NULL) return VPX_CODEC_OK;
input_string = strdup(options);
@@ -499,6 +500,7 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
// modify encoder configuration
enc_cfg->ss_number_layers = si->layers;
+ enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder.
enc_cfg->kf_mode = VPX_KF_DISABLED;
enc_cfg->g_pass = VPX_RC_ONE_PASS;
// Lag in frames not currently supported
@@ -691,7 +693,8 @@ static void set_svc_parameters(SvcContext *svc_ctx,
SvcInternal *const si = get_svc_internal(svc_ctx);
memset(&svc_params, 0, sizeof(svc_params));
- svc_params.layer = si->layer;
+ svc_params.temporal_layer = 0;
+ svc_params.spatial_layer = si->layer;
svc_params.flags = si->enc_frame_flags;
layer = si->layer;
@@ -817,7 +820,7 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size);
if (layer_data == NULL) {
svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n");
- return 0;
+ return VPX_CODEC_OK;
}
ld_list_add(&cx_layer_list, layer_data);
@@ -862,7 +865,7 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
si->buffer_size = si->frame_size;
}
// copy layer data into packet
- ld_list_copy_to_buffer(cx_layer_list, si->buffer);
+ ld_list_copy_to_buffer(cx_layer_list, (uint8_t *)si->buffer);
ld_list_free(cx_layer_list);
diff --git a/vpx/src/vpx_encoder.c b/vpx/src/vpx_encoder.c
index 778ed2f0e..23742c8e8 100644
--- a/vpx/src/vpx_encoder.c
+++ b/vpx/src/vpx_encoder.c
@@ -70,7 +70,7 @@ vpx_codec_err_t vpx_codec_enc_init_multi_ver(vpx_codec_ctx_t *ctx,
vpx_codec_flags_t flags,
vpx_rational_t *dsf,
int ver) {
- vpx_codec_err_t res = 0;
+ vpx_codec_err_t res = VPX_CODEC_OK;
if (ver != VPX_ENCODER_ABI_VERSION)
res = VPX_CODEC_ABI_MISMATCH;
@@ -207,7 +207,7 @@ vpx_codec_err_t vpx_codec_encode(vpx_codec_ctx_t *ctx,
unsigned long duration,
vpx_enc_frame_flags_t flags,
unsigned long deadline) {
- vpx_codec_err_t res = 0;
+ vpx_codec_err_t res = VPX_CODEC_OK;
if (!ctx || (img && !duration))
res = VPX_CODEC_INVALID_PARAM;
diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h
index 829490f73..d0ac1afc8 100644
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -194,7 +194,8 @@ enum vp8e_enc_control_id {
VP9E_SET_AQ_MODE,
VP9E_SET_SVC,
- VP9E_SET_SVC_PARAMETERS
+ VP9E_SET_SVC_PARAMETERS,
+ VP9E_SET_SVC_LAYER_ID
};
/*!\brief vpx 1-D scaling mode
@@ -285,7 +286,8 @@ typedef enum {
typedef struct vpx_svc_parameters {
unsigned int width; /**< width of current spatial layer */
unsigned int height; /**< height of current spatial layer */
- int layer; /**< current layer number - 0 = base */
+ int spatial_layer; /**< current spatial layer number - 0 = base */
+ int temporal_layer; /**< current temporal layer number - 0 = base */
int flags; /**< encode frame flags */
int max_quantizer; /**< max quantizer for current layer */
int min_quantizer; /**< min quantizer for current layer */
@@ -295,6 +297,11 @@ typedef struct vpx_svc_parameters {
int alt_fb_idx; /**< alt reference frame frame buffer index */
} vpx_svc_parameters_t;
+typedef struct vpx_svc_layer_id {
+ int spatial_layer_id;
+ int temporal_layer_id;
+} vpx_svc_layer_id_t;
+
/*!\brief VP8 encoder control function parameter type
*
* Defines the data types that VP8E control functions take. Note that
@@ -316,6 +323,7 @@ VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *)
VPX_CTRL_USE_TYPE(VP9E_SET_SVC, int)
VPX_CTRL_USE_TYPE(VP9E_SET_SVC_PARAMETERS, vpx_svc_parameters_t *)
+VPX_CTRL_USE_TYPE(VP9E_SET_SVC_LAYER_ID, vpx_svc_layer_id_t *)
VPX_CTRL_USE_TYPE(VP8E_SET_CPUUSED, int)
VPX_CTRL_USE_TYPE(VP8E_SET_ENABLEAUTOALTREF, unsigned int)
diff --git a/vpx/vpx_codec.mk b/vpx/vpx_codec.mk
index 549c24908..111c87e53 100644
--- a/vpx/vpx_codec.mk
+++ b/vpx/vpx_codec.mk
@@ -26,6 +26,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_frame_buffer.h
API_DOC_SRCS-yes += vpx_image.h
API_SRCS-yes += src/vpx_decoder.c
@@ -37,5 +38,6 @@ API_SRCS-yes += src/vpx_codec.c
API_SRCS-yes += src/vpx_image.c
API_SRCS-yes += vpx_codec.h
API_SRCS-yes += vpx_codec.mk
+API_SRCS-yes += vpx_frame_buffer.h
API_SRCS-yes += vpx_image.h
API_SRCS-$(BUILD_LIBVPX) += vpx_integer.h
diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h
index 347388551..1d9f0c9b7 100644
--- a/vpx/vpx_encoder.h
+++ b/vpx/vpx_encoder.h
@@ -604,47 +604,48 @@ extern "C" {
* Spatial scalability settings (ss)
*/
- /*!\brief Number of coding layers (spatial)
+ /*!\brief Number of spatial coding layers.
*
- * This value specifies the number of coding layers to be used.
+ * This value specifies the number of spatial coding layers to be used.
*/
unsigned int ss_number_layers;
- /*!\brief Number of coding layers
+ /*!\brief Number of temporal coding layers.
*
- * This value specifies the number of coding layers to be used.
+ * This value specifies the number of temporal layers to be used.
*/
unsigned int ts_number_layers;
- /*!\brief Target bitrate for each layer
+ /*!\brief Target bitrate for each temporal layer.
*
- * These values specify the target coding bitrate for each coding layer.
+ * These values specify the target coding bitrate to be used for each
+ * temporal layer.
*/
unsigned int ts_target_bitrate[VPX_TS_MAX_LAYERS];
- /*!\brief Frame rate decimation factor for each layer
+ /*!\brief Frame rate decimation factor for each temporal layer.
*
* These values specify the frame rate decimation factors to apply
- * to each layer.
+ * to each temporal layer.
*/
unsigned int ts_rate_decimator[VPX_TS_MAX_LAYERS];
- /*!\brief Length of the sequence defining frame layer membership
+ /*!\brief Length of the sequence defining frame temporal layer membership.
*
* This value specifies the length of the sequence that defines the
- * membership of frames to layers. For example, if ts_periodicity=8 then
- * frames are assigned to coding layers with a repeated sequence of
- * length 8.
- */
+ * membership of frames to temporal layers. For example, if the
+ * ts_periodicity = 8, then the frames are assigned to coding layers with a
+ * repeated sequence of length 8.
+ */
unsigned int ts_periodicity;
- /*!\brief Template defining the membership of frames to coding layers
+ /*!\brief Template defining the membership of frames to temporal layers.
*
- * This array defines the membership of frames to coding layers. For a
- * 2-layer encoding that assigns even numbered frames to one layer (0)
- * and odd numbered frames to a second layer (1) with ts_periodicity=8,
- * then ts_layer_id = (0,1,0,1,0,1,0,1).
- */
+ * This array defines the membership of frames to temporal coding layers.
+ * For a 2-layer encoding that assigns even numbered frames to one temporal
+ * layer (0) and odd numbered frames to a second temporal layer (1) with
+ * ts_periodicity=8, then ts_layer_id = (0,1,0,1,0,1,0,1).
+ */
unsigned int ts_layer_id[VPX_TS_MAX_PERIODICITY];
} vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */
diff --git a/vpx/vpx_frame_buffer.h b/vpx/vpx_frame_buffer.h
new file mode 100644
index 000000000..b5489b41b
--- /dev/null
+++ b/vpx/vpx_frame_buffer.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef VPX_VPX_FRAME_BUFFER_H_
+#define VPX_VPX_FRAME_BUFFER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "./vpx_integer.h"
+
+/*!\brief The maximum number of work buffers used by libvpx.
+ */
+#define VPX_MAXIMUM_WORK_BUFFERS 1
+
+/*!\brief The maximum number of reference buffers that a VP9 encoder may use.
+ */
+#define VP9_MAXIMUM_REF_BUFFERS 8
+
+/*!\brief External frame buffer
+ *
+ * This structure holds allocated frame buffers used by the decoder.
+ */
+typedef struct vpx_codec_frame_buffer {
+ uint8_t *data; /**< Pointer to the data buffer */
+ size_t size; /**< Size of data in bytes */
+ void *priv; /**< Frame's private data */
+} vpx_codec_frame_buffer_t;
+
+/*!\brief get frame buffer callback prototype
+ *
+ * This callback is invoked by the decoder to retrieve data for the frame
+ * buffer in order for the decode call to complete. The callback must
+ * allocate at least min_size in bytes and assign it to fb->data. Then the
+ * callback must set fb->size to the allocated size. The application does not
+ * need to align the allocated data. The callback is triggered when the
+ * decoder needs a frame buffer to decode a compressed image into. This
+ * function may be called more than once for every call to vpx_codec_decode.
+ * The application may set fb->priv to some data which will be passed
+ * back in the ximage and the release function call. On success the callback
+ * must return 0. Any failure the callback must return a value less than 0.
+ *
+ * \param[in] priv Callback's private data
+ * \param[in] new_size Size in bytes needed by the buffer
+ * \param[in,out] fb Pointer to vpx_codec_frame_buffer_t
+ */
+typedef int (*vpx_get_frame_buffer_cb_fn_t)(
+ void *priv, size_t min_size, vpx_codec_frame_buffer_t *fb);
+
+/*!\brief release frame buffer callback prototype
+ *
+ * This callback is invoked by the decoder when the frame buffer is not
+ * referenced by any other buffers. On success the callback must return 0.
+ * Any failure the callback must return a value less than 0.
+ *
+ * \param[in] priv Callback's private data
+ * \param[in] fb Pointer to vpx_codec_frame_buffer_t
+ */
+typedef int (*vpx_release_frame_buffer_cb_fn_t)(
+ void *priv, vpx_codec_frame_buffer_t *fb);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VPX_VPX_FRAME_BUFFER_H_
diff --git a/vpx/vpx_integer.h b/vpx/vpx_integer.h
index dfa361ba3..258618bbd 100644
--- a/vpx/vpx_integer.h
+++ b/vpx/vpx_integer.h
@@ -48,7 +48,7 @@ typedef size_t uintptr_t;
#endif
/* VS2010 defines stdint.h, but not inttypes.h */
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && _MSC_VER < 1800
#define PRId64 "I64d"
#else
#include <inttypes.h>
diff --git a/vpx_scale/generic/yv12config.c b/vpx_scale/generic/yv12config.c
index 693125a0f..ab0a30a4d 100644
--- a/vpx_scale/generic/yv12config.c
+++ b/vpx_scale/generic/yv12config.c
@@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <assert.h>
+
#include "./vpx_config.h"
#include "vpx_scale/yv12config.h"
#include "vpx_mem/vpx_mem.h"
@@ -19,10 +21,17 @@
/****************************************************************************
*
****************************************************************************/
+#define yv12_align_addr(addr, align) \
+ (void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align))
+
int
vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
if (ybf) {
- vpx_free(ybf->buffer_alloc);
+ // If libvpx is using frame buffer callbacks then buffer_alloc_sz must
+ // not be set.
+ if (ybf->buffer_alloc_sz > 0) {
+ vpx_free(ybf->buffer_alloc);
+ }
/* buffer_alloc isn't accessed by most functions. Rather y_buffer,
u_buffer and v_buffer point to buffer_alloc and are used. Clear out
@@ -108,7 +117,9 @@ int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
if (ybf) {
- vpx_free(ybf->buffer_alloc);
+ if (ybf->buffer_alloc_sz > 0) {
+ vpx_free(ybf->buffer_alloc);
+ }
/* buffer_alloc isn't accessed by most functions. Rather y_buffer,
u_buffer and v_buffer point to buffer_alloc and are used. Clear out
@@ -123,7 +134,10 @@ int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height,
- int ss_x, int ss_y, int border) {
+ int ss_x, int ss_y, int border,
+ vpx_codec_frame_buffer_t *fb,
+ vpx_get_frame_buffer_cb_fn_t cb,
+ void *cb_priv) {
if (ybf) {
const int aligned_width = (width + 7) & ~7;
const int aligned_height = (height + 7) & ~7;
@@ -148,7 +162,26 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
#else
const int frame_size = yplane_size + 2 * uvplane_size;
#endif
- if (frame_size > ybf->buffer_alloc_sz) {
+ if (cb != NULL) {
+ const int align_addr_extra_size = 31;
+ const size_t external_frame_size = frame_size + align_addr_extra_size;
+
+ assert(fb != NULL);
+
+ // Allocation to hold larger frame, or first allocation.
+ if (cb(cb_priv, external_frame_size, fb) < 0)
+ return -1;
+
+ if (fb->data == NULL || fb->size < external_frame_size)
+ return -1;
+
+ // This memset is needed for fixing valgrind error from C loop filter
+ // due to access uninitialized memory in frame border. It could be
+ // removed if border is totally removed.
+ vpx_memset(fb->data, 0, fb->size);
+
+ ybf->buffer_alloc = yv12_align_addr(fb->data, 32);
+ } else if (frame_size > ybf->buffer_alloc_sz) {
// Allocation to hold larger frame, or first allocation.
if (ybf->buffer_alloc)
vpx_free(ybf->buffer_alloc);
@@ -159,14 +192,11 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
ybf->buffer_alloc_sz = frame_size;
// This memset is needed for fixing valgrind error from C loop filter
- // due to access uninitialized memory in frame boarder. It could be
+ // due to access uninitialized memory in frame border. It could be
// removed if border is totally removed.
vpx_memset(ybf->buffer_alloc, 0, ybf->buffer_alloc_sz);
}
- if (ybf->buffer_alloc_sz < frame_size)
- return -1;
-
/* Only support allocating buffers that have a border that's a multiple
* of 32. The border restriction is required to get 16-byte alignment of
* the start of the chroma rows without introducing an arbitrary gap
@@ -214,7 +244,8 @@ int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int ss_x, int ss_y, int border) {
if (ybf) {
vp9_free_frame_buffer(ybf);
- return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border);
+ return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border,
+ NULL, NULL, NULL);
}
return -2;
}
diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h
index 8f39eb769..525f3a00d 100644
--- a/vpx_scale/yv12config.h
+++ b/vpx_scale/yv12config.h
@@ -15,6 +15,7 @@
extern "C" {
#endif
+#include "vpx/vpx_frame_buffer.h"
#include "vpx/vpx_integer.h"
#define VP8BORDERINPIXELS 32
@@ -65,9 +66,19 @@ extern "C" {
int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, int ss_x, int ss_y,
int border);
+
+ // Updates the yv12 buffer config with the frame buffer. If cb is not
+ // NULL, then libvpx is using the frame buffer callbacks to handle memory.
+ // If cb is not NULL, libvpx will call cb with minimum size in bytes needed
+ // to decode the current frame. If cb is NULL, libvpx will allocate memory
+ // internally to decode the current frame. Returns 0 on success. Returns < 0
+ // on failure.
int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, int ss_x, int ss_y,
- int border);
+ int border,
+ vpx_codec_frame_buffer_t *fb,
+ vpx_get_frame_buffer_cb_fn_t cb,
+ void *cb_priv);
int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf);
#ifdef __cplusplus
diff --git a/vpxdec.c b/vpxdec.c
index 6d5ca2469..98d1550a5 100644
--- a/vpxdec.c
+++ b/vpxdec.c
@@ -187,8 +187,8 @@ static int raw_read_frame(FILE *infile, uint8_t **buffer,
if (!feof(infile))
warn("Failed to read RAW frame size\n");
} else {
- const int kCorruptFrameThreshold = 256 * 1024 * 1024;
- const int kFrameTooSmallThreshold = 256 * 1024;
+ const size_t kCorruptFrameThreshold = 256 * 1024 * 1024;
+ const size_t kFrameTooSmallThreshold = 256 * 1024;
frame_size = mem_get_le32(raw_hdr);
if (frame_size > kCorruptFrameThreshold) {
diff --git a/vpxenc.c b/vpxenc.c
index cf3831cfc..5e36fd9ad 100644
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -27,6 +27,7 @@
#include "third_party/libyuv/include/libyuv/scale.h"
#include "./args.h"
#include "./ivfenc.h"
+#include "./tools_common.h"
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
#include "vpx/vp8cx.h"
@@ -35,7 +36,7 @@
#include "vpx/vp8dx.h"
#endif
-#include "./tools_common.h"
+#include "vpx/vpx_integer.h"
#include "vpx_ports/mem_ops.h"
#include "vpx_ports/vpx_timer.h"
#include "./rate_hist.h"
@@ -1352,7 +1353,7 @@ static void get_cx_data(struct stream_state *stream,
#if CONFIG_DECODERS
if (global->test_decode != TEST_DECODE_OFF && !stream->mismatch_seen) {
vpx_codec_decode(&stream->decoder, pkt->data.frame.buf,
- pkt->data.frame.sz, NULL, 0);
+ (unsigned int)pkt->data.frame.sz, NULL, 0);
if (stream->decoder.err) {
warn_or_exit_on_error(&stream->decoder,
global->test_decode == TEST_DECODE_FATAL,
@@ -1475,7 +1476,9 @@ static void test_decode(struct stream_state *stream,
static void print_time(const char *label, int64_t etl) {
- int hours, mins, secs;
+ int64_t hours;
+ int64_t mins;
+ int64_t secs;
if (etl >= 0) {
hours = etl / 3600;
@@ -1484,7 +1487,7 @@ static void print_time(const char *label, int64_t etl) {
etl -= mins * 60;
secs = etl;
- fprintf(stderr, "[%3s %2d:%02d:%02d] ",
+ fprintf(stderr, "[%3s %2"PRId64":%02"PRId64": % 02"PRId64"] ",
label, hours, mins, secs);
} else {
fprintf(stderr, "[%3s unknown] ", label);
@@ -1688,7 +1691,7 @@ int main(int argc, const char **argv_) {
int64_t rate;
if (global.limit) {
- int frame_in_lagged = (seen_frames - lagged_count) * 1000;
+ off_t frame_in_lagged = (seen_frames - lagged_count) * 1000;
rate = cx_time ? frame_in_lagged * (int64_t)1000000 / cx_time : 0;
remaining = 1000 * (global.limit - global.skip_frames
diff --git a/warnings.c b/warnings.c
index 6defde9ac..7ac678ab4 100644
--- a/warnings.c
+++ b/warnings.c
@@ -54,11 +54,10 @@ static void add_warning(const char *warning_string,
}
static void free_warning_list(struct WarningList *warning_list) {
- struct WarningListNode *node = warning_list->warning_node;
while (warning_list->warning_node != NULL) {
- node = warning_list->warning_node->next_warning;
- free(warning_list->warning_node);
- warning_list->warning_node = node;
+ struct WarningListNode *const node = warning_list->warning_node;
+ warning_list->warning_node = node->next_warning;
+ free(node);
}
}