diff options
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; +} @@ -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; -} @@ -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 @@ -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(§ionstats); - 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(§ionstats, &next_frame); } avg_stats(§ionstats); - 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 @@ -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) { @@ -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); } } |