For 1 layer CBR only. Support for temporal layers comes later. Rename the library to libvpxrc Bug: b/188853141
Unified · Split
| @@ -94,15 +94,28 @@ ifeq ($(CONFIG_VP9_ENCODER),yes) · 93 unmodified lines | |||
| 94 | INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/% | 94 | INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/% |
| 95 | CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h vpx/vpx_ext_ratectrl.h | 95 | CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h vpx/vpx_ext_ratectrl.h |
| 96 | CODEC_DOC_SECTIONS += vp9 vp9_encoder | 96 | CODEC_DOC_SECTIONS += vp9 vp9_encoder |
| 97 | endif | ||
| 97 | 98 | ||
| 98 | RC_RTC_SRCS := $(addprefix $(VP9_PREFIX),$(call enabled,VP9_CX_SRCS)) | 99 | RC_RTC_SRCS := vpx/vp8.h vpx/vp8cx.h |
| 99 | RC_RTC_SRCS += $(VP9_PREFIX)vp9cx.mk vpx/vp8.h vpx/vp8cx.h | 100 | RC_RTC_SRCS += vpx/vpx_ext_ratectrl.h |
| 100 | RC_RTC_SRCS += vpx/vpx_ext_ratectrl.h | 101 | RC_RTC_SRCS += vpx/internal/vpx_ratectrl_rtc.h |
| 102 | ifeq ($(CONFIG_VP9_ENCODER),yes) | ||
| 103 | VP9_PREFIX=vp9/ | ||
| 104 | RC_RTC_SRCS += $(addprefix $(VP9_PREFIX),$(call enabled,VP9_CX_SRCS)) | ||
| 105 | RC_RTC_SRCS += $(VP9_PREFIX)vp9cx.mk | ||
| 101 | RC_RTC_SRCS += $(VP9_PREFIX)ratectrl_rtc.cc | 106 | RC_RTC_SRCS += $(VP9_PREFIX)ratectrl_rtc.cc |
| 102 | RC_RTC_SRCS += $(VP9_PREFIX)ratectrl_rtc.h | 107 | RC_RTC_SRCS += $(VP9_PREFIX)ratectrl_rtc.h |
| 103 | INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)ratectrl_rtc.cc | 108 | INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)ratectrl_rtc.cc |
| 104 | INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)ratectrl_rtc.h | 109 | INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)ratectrl_rtc.h |
| 105 | endif | 110 | endif |
| 111 | ifeq ($(CONFIG_VP8_ENCODER),yes) | ||
| 112 | VP8_PREFIX=vp8/ | ||
| 113 | RC_RTC_SRCS += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_CX_SRCS)) | ||
| 114 | RC_RTC_SRCS += $(VP8_PREFIX)vp8_ratectrl_rtc.cc | ||
| 115 | RC_RTC_SRCS += $(VP8_PREFIX)vp8_ratectrl_rtc.h | ||
| 116 | INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP8_PREFIX)vp8_ratectrl_rtc.cc | ||
| 117 | INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP8_PREFIX)vp8_ratectrl_rtc.h | ||
| 118 | endif | ||
| 106 | 119 | ||
| 107 | ifeq ($(CONFIG_VP9_DECODER),yes) | 120 | ifeq ($(CONFIG_VP9_DECODER),yes) |
| 108 | VP9_PREFIX=vp9/ | 121 | VP9_PREFIX=vp9/ |
| @@ -126,7 +139,7 @@ endif · 17 unmodified lines | |||
| 126 | ifeq ($(CONFIG_MSVS),yes) | 139 | ifeq ($(CONFIG_MSVS),yes) |
| 127 | CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd) | 140 | CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd) |
| 128 | GTEST_LIB=$(if $(CONFIG_STATIC_MSVCRT),gtestmt,gtestmd) | 141 | GTEST_LIB=$(if $(CONFIG_STATIC_MSVCRT),gtestmt,gtestmd) |
| 129 | RC_RTC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vp9rcmt,vp9rcmd) | 142 | RC_RTC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxrcmt,vpxrcmd) |
| 130 | # This variable uses deferred expansion intentionally, since the results of | 143 | # This variable uses deferred expansion intentionally, since the results of |
| 131 | # $(wildcard) may change during the course of the Make. | 144 | # $(wildcard) may change during the course of the Make. |
| 132 | VS_PLATFORMS = $(foreach d,$(wildcard */Release/$(CODEC_LIB).lib),$(word 1,$(subst /, ,$(d)))) | 145 | VS_PLATFORMS = $(foreach d,$(wildcard */Release/$(CODEC_LIB).lib),$(word 1,$(subst /, ,$(d)))) |
| @@ -249,16 +262,16 @@ PROJECTS-yes += vpx.$(VCPROJ_SFX) · 116 unmodified lines | |||
| 249 | vpx.$(VCPROJ_SFX): vpx_config.asm | 262 | vpx.$(VCPROJ_SFX): vpx_config.asm |
| 250 | vpx.$(VCPROJ_SFX): $(RTCD) | 263 | vpx.$(VCPROJ_SFX): $(RTCD) |
| 251 | 264 | ||
| 252 | vp9rc.$(VCPROJ_SFX): \ | 265 | vpxrc.$(VCPROJ_SFX): \ |
| 253 | VCPROJ_SRCS=$(filter-out $(addprefix %, $(ASM_INCLUDES)), $^) | 266 | VCPROJ_SRCS=$(filter-out $(addprefix %, $(ASM_INCLUDES)), $^) |
| 254 | 267 | ||
| 255 | vp9rc.$(VCPROJ_SFX): $(RC_RTC_SRCS) | 268 | vpxrc.$(VCPROJ_SFX): $(RC_RTC_SRCS) |
| 256 | @echo " [CREATE] $@" | 269 | @echo " [CREATE] $@" |
| 257 | $(qexec)$(GEN_VCPROJ) \ | 270 | $(qexec)$(GEN_VCPROJ) \ |
| 258 | $(if $(CONFIG_SHARED),--dll,--lib) \ | 271 | $(if $(CONFIG_SHARED),--dll,--lib) \ |
| 259 | --target=$(TOOLCHAIN) \ | 272 | --target=$(TOOLCHAIN) \ |
| 260 | $(if $(CONFIG_STATIC_MSVCRT),--static-crt) \ | 273 | $(if $(CONFIG_STATIC_MSVCRT),--static-crt) \ |
| 261 | --name=vp9rc \ | 274 | --name=vpxrc \ |
| 262 | --proj-guid=C26FF952-9494-4838-9A3F-7F3D4F613385 \ | 275 | --proj-guid=C26FF952-9494-4838-9A3F-7F3D4F613385 \ |
| 263 | --ver=$(CONFIG_VS_VERSION) \ | 276 | --ver=$(CONFIG_VS_VERSION) \ |
| 264 | --src-path-bare="$(SRC_PATH_BARE)" \ | 277 | --src-path-bare="$(SRC_PATH_BARE)" \ |
| @@ -275,10 +288,10 @@ vp9rc.$(VCPROJ_SFX): $(RC_RTC_SRCS) · 10 unmodified lines | |||
| 275 | $(VCPROJ_SRCS)) \ | 288 | $(VCPROJ_SRCS)) \ |
| 276 | --src-path-bare="$(SRC_PATH_BARE)" \ | 289 | --src-path-bare="$(SRC_PATH_BARE)" \ |
| 277 | 290 | ||
| 278 | PROJECTS-yes += vp9rc.$(VCPROJ_SFX) | 291 | PROJECTS-yes += vpxrc.$(VCPROJ_SFX) |
| 279 | 292 | ||
| 280 | vp9rc.$(VCPROJ_SFX): vpx_config.asm | 293 | vpxrc.$(VCPROJ_SFX): vpx_config.asm |
| 281 | vp9rc.$(VCPROJ_SFX): $(RTCD) | 294 | vpxrc.$(VCPROJ_SFX): $(RTCD) |
| 282 | 295 | ||
| 283 | endif # ifeq ($(CONFIG_MSVS),yes) | 296 | endif # ifeq ($(CONFIG_MSVS),yes) |
| 284 | else # ifeq ($(CONFIG_EXTERNAL_BUILD),yes) | 297 | else # ifeq ($(CONFIG_EXTERNAL_BUILD),yes) |
| @@ -398,12 +411,11 @@ INSTALL-LIBS-yes += $(LIBSUBDIR)/pkgconfig/vpx.pc · 113 unmodified lines | |||
| 398 | INSTALL_MAPS += $(LIBSUBDIR)/pkgconfig/%.pc %.pc | 411 | INSTALL_MAPS += $(LIBSUBDIR)/pkgconfig/%.pc %.pc |
| 399 | CLEAN-OBJS += vpx.pc | 412 | CLEAN-OBJS += vpx.pc |
| 400 | 413 | ||
| 401 | ifeq ($(CONFIG_VP9_ENCODER),yes) | 414 | ifeq ($(CONFIG_ENCODERS),yes) |
| 402 | RC_RTC_OBJS=$(call objs,$(RC_RTC_SRCS)) | ||
| 403 | RC_RTC_OBJS=$(call objs,$(RC_RTC_SRCS)) | 415 | RC_RTC_OBJS=$(call objs,$(RC_RTC_SRCS)) |
| 404 | OBJS-yes += $(RC_RTC_OBJS) | 416 | OBJS-yes += $(RC_RTC_OBJS) |
| 405 | LIBS-yes += $(BUILD_PFX)libvp9rc.a $(BUILD_PFX)libvp9rc_g.a | 417 | LIBS-yes += $(BUILD_PFX)libvpxrc.a $(BUILD_PFX)libvpxrc_g.a |
| 406 | $(BUILD_PFX)libvp9rc_g.a: $(RC_RTC_OBJS) | 418 | $(BUILD_PFX)libvpxrc_g.a: $(RC_RTC_OBJS) |
| 407 | endif | 419 | endif |
| 408 | 420 | ||
| 409 | ifeq ($(CONFIG_VP9_ENCODER)$(CONFIG_RATE_CTRL),yesyes) | 421 | ifeq ($(CONFIG_VP9_ENCODER)$(CONFIG_RATE_CTRL),yesyes) |
| @@ -493,7 +505,7 @@ TEST_INTRA_PRED_SPEED_SRCS=$(call addprefix_clean,test/,\ · 83 unmodified lines | |||
| 493 | $(call enabled,TEST_INTRA_PRED_SPEED_SRCS)) | 505 | $(call enabled,TEST_INTRA_PRED_SPEED_SRCS)) |
| 494 | TEST_INTRA_PRED_SPEED_OBJS := $(sort $(call objs,$(TEST_INTRA_PRED_SPEED_SRCS))) | 506 | TEST_INTRA_PRED_SPEED_OBJS := $(sort $(call objs,$(TEST_INTRA_PRED_SPEED_SRCS))) |
| 495 | 507 | ||
| 496 | ifeq ($(CONFIG_VP9_ENCODER),yes) | 508 | ifeq ($(CONFIG_ENCODERS),yes) |
| 497 | RC_INTERFACE_TEST_BIN=./test_rc_interface$(EXE_SFX) | 509 | RC_INTERFACE_TEST_BIN=./test_rc_interface$(EXE_SFX) |
| 498 | RC_INTERFACE_TEST_SRCS=$(call addprefix_clean,test/,\ | 510 | RC_INTERFACE_TEST_SRCS=$(call addprefix_clean,test/,\ |
| 499 | $(call enabled,RC_INTERFACE_TEST_SRCS)) | 511 | $(call enabled,RC_INTERFACE_TEST_SRCS)) |
| @@ -599,11 +611,11 @@ test_intra_pred_speed.$(VCPROJ_SFX): $(TEST_INTRA_PRED_SPEED_SRCS) vpx.$(VCPROJ_ · 99 unmodified lines | |||
| 599 | -L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^ | 611 | -L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^ |
| 600 | endif # TEST_INTRA_PRED_SPEED | 612 | endif # TEST_INTRA_PRED_SPEED |
| 601 | 613 | ||
| 602 | ifeq ($(CONFIG_VP9_ENCODER),yes) | 614 | ifeq ($(CONFIG_ENCODERS),yes) |
| 603 | ifneq ($(strip $(RC_INTERFACE_TEST_OBJS)),) | 615 | ifneq ($(strip $(RC_INTERFACE_TEST_OBJS)),) |
| 604 | PROJECTS-$(CONFIG_MSVS) += test_rc_interface.$(VCPROJ_SFX) | 616 | PROJECTS-$(CONFIG_MSVS) += test_rc_interface.$(VCPROJ_SFX) |
| 605 | test_rc_interface.$(VCPROJ_SFX): $(RC_INTERFACE_TEST_SRCS) vpx.$(VCPROJ_SFX) \ | 617 | test_rc_interface.$(VCPROJ_SFX): $(RC_INTERFACE_TEST_SRCS) vpx.$(VCPROJ_SFX) \ |
| 606 | vp9rc.$(VCPROJ_SFX) gtest.$(VCPROJ_SFX) | 618 | vpxrc.$(VCPROJ_SFX) gtest.$(VCPROJ_SFX) |
| 607 | @echo " [CREATE] $@" | 619 | @echo " [CREATE] $@" |
| 608 | $(qexec)$(GEN_VCPROJ) \ | 620 | $(qexec)$(GEN_VCPROJ) \ |
| 609 | --exe \ | 621 | --exe \ |
| @@ -661,19 +673,19 @@ $(eval $(call linkerxx_template,$(TEST_INTRA_PRED_SPEED_BIN), \ · 51 unmodified lines | |||
| 661 | -L. -lvpx -lgtest $(extralibs) -lm)) | 673 | -L. -lvpx -lgtest $(extralibs) -lm)) |
| 662 | endif # TEST_INTRA_PRED_SPEED | 674 | endif # TEST_INTRA_PRED_SPEED |
| 663 | 675 | ||
| 664 | ifeq ($(CONFIG_VP9_ENCODER),yes) | 676 | ifeq ($(CONFIG_ENCODERS),yes) |
| 665 | ifneq ($(strip $(RC_INTERFACE_TEST_OBJS)),) | 677 | ifneq ($(strip $(RC_INTERFACE_TEST_OBJS)),) |
| 666 | $(RC_INTERFACE_TEST_OBJS) $(RC_INTERFACE_TEST_OBJS:.o=.d): \ | 678 | $(RC_INTERFACE_TEST_OBJS) $(RC_INTERFACE_TEST_OBJS:.o=.d): \ |
| 667 | CXXFLAGS += $(GTEST_INCLUDES) | 679 | CXXFLAGS += $(GTEST_INCLUDES) |
| 668 | OBJS-yes += $(RC_INTERFACE_TEST_OBJS) | 680 | OBJS-yes += $(RC_INTERFACE_TEST_OBJS) |
| 669 | BINS-yes += $(RC_INTERFACE_TEST_BIN) | 681 | BINS-yes += $(RC_INTERFACE_TEST_BIN) |
| 670 | 682 | ||
| 671 | $(RC_INTERFACE_TEST_BIN): $(TEST_LIBS) libvp9rc.a | 683 | $(RC_INTERFACE_TEST_BIN): $(TEST_LIBS) libvpxrc.a |
| 672 | $(eval $(call linkerxx_template,$(RC_INTERFACE_TEST_BIN), \ | 684 | $(eval $(call linkerxx_template,$(RC_INTERFACE_TEST_BIN), \ |
| 673 | $(RC_INTERFACE_TEST_OBJS) \ | 685 | $(RC_INTERFACE_TEST_OBJS) \ |
| 674 | -L. -lvpx -lgtest -lvp9rc $(extralibs) -lm)) | 686 | -L. -lvpx -lgtest -lvpxrc $(extralibs) -lm)) |
| 675 | endif # RC_INTERFACE_TEST | 687 | endif # RC_INTERFACE_TEST |
| 676 | endif # CONFIG_VP9_ENCODER | 688 | endif # CONFIG_ENCODERS |
| 677 | 689 | ||
| 678 | ifneq ($(strip $(SIMPLE_ENCODE_TEST_OBJS)),) | 690 | ifneq ($(strip $(SIMPLE_ENCODE_TEST_OBJS)),) |
| 679 | $(SIMPLE_ENCODE_TEST_OBJS) $(SIMPLE_ENCODE_TEST_OBJS:.o=.d): \ | 691 | $(SIMPLE_ENCODE_TEST_OBJS) $(SIMPLE_ENCODE_TEST_OBJS:.o=.d): \ |
| @@ -213,9 +213,11 @@ endif · 212 unmodified lines | |||
| 213 | TEST_INTRA_PRED_SPEED_SRCS-yes := test_intra_pred_speed.cc | 213 | TEST_INTRA_PRED_SPEED_SRCS-yes := test_intra_pred_speed.cc |
| 214 | TEST_INTRA_PRED_SPEED_SRCS-yes += ../md5_utils.h ../md5_utils.c | 214 | TEST_INTRA_PRED_SPEED_SRCS-yes += ../md5_utils.h ../md5_utils.c |
| 215 | 215 | ||
| 216 | RC_INTERFACE_TEST_SRCS-$(CONFIG_VP9_ENCODER) := ratectrl_rtc_test.cc | 216 | RC_INTERFACE_TEST_SRCS-yes := test_rc_interface.cc |
| 217 | RC_INTERFACE_TEST_SRCS-$(CONFIG_VP9_ENCODER) += encode_test_driver.cc | 217 | RC_INTERFACE_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_ratectrl_rtc_test.cc |
| 218 | RC_INTERFACE_TEST_SRCS-$(CONFIG_VP9_ENCODER) += encode_test_driver.h | 218 | RC_INTERFACE_TEST_SRCS-$(CONFIG_VP8_ENCODER) += vp8_ratectrl_rtc_test.cc |
| 219 | RC_INTERFACE_TEST_SRCS-$(CONFIG_ENCODERS) += encode_test_driver.cc | ||
| 220 | RC_INTERFACE_TEST_SRCS-$(CONFIG_ENCODERS) += encode_test_driver.h | ||
| 219 | RC_INTERFACE_TEST_SRCS-yes += decode_test_driver.cc | 221 | RC_INTERFACE_TEST_SRCS-yes += decode_test_driver.cc |
| 220 | RC_INTERFACE_TEST_SRCS-yes += decode_test_driver.h | 222 | RC_INTERFACE_TEST_SRCS-yes += decode_test_driver.h |
| 221 | RC_INTERFACE_TEST_SRCS-yes += codec_factory.h | 223 | RC_INTERFACE_TEST_SRCS-yes += codec_factory.h |
| @@ -0,0 +1,6 @@ | |||
| 1 | #include "third_party/googletest/src/include/gtest/gtest.h" | ||
| 2 | |||
| 3 | int main(int argc, char **argv) { | ||
| 4 | ::testing::InitGoogleTest(&argc, argv); | ||
| 5 | return RUN_ALL_TESTS(); | ||
| 6 | } | ||
| @@ -0,0 +1,180 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2021 The WebM project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license | ||
| 5 | * that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. An additional intellectual property rights grant can be found | ||
| 7 | * in the file PATENTS. All contributing project authors may | ||
| 8 | * be found in the AUTHORS file in the root of the source tree. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <fstream> // NOLINT | ||
| 12 | #include <string> | ||
| 13 | |||
| 14 | #include "./vpx_config.h" | ||
| 15 | #include "third_party/googletest/src/include/gtest/gtest.h" | ||
| 16 | #include "test/codec_factory.h" | ||
| 17 | #include "test/encode_test_driver.h" | ||
| 18 | #include "test/i420_video_source.h" | ||
| 19 | #include "test/util.h" | ||
| 20 | #include "test/video_source.h" | ||
| 21 | #include "vp8/vp8_ratectrl_rtc.h" | ||
| 22 | #include "vpx/vpx_codec.h" | ||
| 23 | #include "vpx_ports/bitops.h" | ||
| 24 | |||
| 25 | namespace { | ||
| 26 | |||
| 27 | struct Vp8RCTestVideo { | ||
| 28 | Vp8RCTestVideo() {} | ||
| 29 | Vp8RCTestVideo(const char *name_, int width_, int height_, | ||
| 30 | unsigned int frames_) | ||
| 31 | : name(name_), width(width_), height(height_), frames(frames_) {} | ||
| 32 | |||
| 33 | friend std::ostream &operator<<(std::ostream &os, | ||
| 34 | const Vp8RCTestVideo &video) { | ||
| 35 | os << video.name << " " << video.width << " " << video.height << " " | ||
| 36 | << video.frames; | ||
| 37 | return os; | ||
| 38 | } | ||
| 39 | const char *name; | ||
| 40 | int width; | ||
| 41 | int height; | ||
| 42 | unsigned int frames; | ||
| 43 | }; | ||
| 44 | |||
| 45 | const Vp8RCTestVideo kVp8RCTestVectors[] = { | ||
| 46 | Vp8RCTestVideo("niklas_640_480_30.yuv", 640, 480, 470), | ||
| 47 | Vp8RCTestVideo("desktop_office1.1280_720-020.yuv", 1280, 720, 300), | ||
| 48 | }; | ||
| 49 | |||
| 50 | class Vp8RcInterfaceTest | ||
| 51 | : public ::libvpx_test::EncoderTest, | ||
| 52 | public ::libvpx_test::CodecTestWith2Params<int, Vp8RCTestVideo> { | ||
| 53 | public: | ||
| 54 | Vp8RcInterfaceTest() | ||
| 55 | : EncoderTest(GET_PARAM(0)), key_interval_(3000), encoder_exit_(false) {} | ||
| 56 | virtual ~Vp8RcInterfaceTest() {} | ||
| 57 | |||
| 58 | protected: | ||
| 59 | virtual void SetUp() { | ||
| 60 | InitializeConfig(); | ||
| 61 | SetMode(::libvpx_test::kRealTime); | ||
| 62 | } | ||
| 63 | |||
| 64 | virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, | ||
| 65 | ::libvpx_test::Encoder *encoder) { | ||
| 66 | if (video->frame() == 0) { | ||
| 67 | encoder->Control(VP8E_SET_CPUUSED, -6); | ||
| 68 | encoder->Control(VP8E_SET_RTC_EXTERNAL_RATECTRL, 1); | ||
| 69 | encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 1000); | ||
| 70 | } | ||
| 71 | frame_params_.frame_type = | ||
| 72 | video->frame() % key_interval_ == 0 ? KEY_FRAME : INTER_FRAME; | ||
| 73 | if (frame_params_.frame_type == INTER_FRAME) { | ||
| 74 | // Disable golden frame update. | ||
| 75 | frame_flags_ |= VP8_EFLAG_NO_UPD_GF; | ||
| 76 | frame_flags_ |= VP8_EFLAG_NO_UPD_ARF; | ||
| 77 | } | ||
| 78 | encoder_exit_ = video->frame() == test_video_.frames; | ||
| 79 | } | ||
| 80 | |||
| 81 | virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) { | ||
| 82 | if (encoder_exit_) { | ||
| 83 | return; | ||
| 84 | } | ||
| 85 | int qp; | ||
| 86 | encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp); | ||
| 87 | rc_api_->ComputeQP(frame_params_); | ||
| 88 | ASSERT_EQ(rc_api_->GetQP(), qp); | ||
| 89 | } | ||
| 90 | |||
| 91 | virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { | ||
| 92 | rc_api_->PostEncodeUpdate(pkt->data.frame.sz); | ||
| 93 | } | ||
| 94 | |||
| 95 | void RunOneLayer() { | ||
| 96 | test_video_ = GET_PARAM(2); | ||
| 97 | target_bitrate_ = GET_PARAM(1); | ||
| 98 | if (test_video_.width == 1280 && target_bitrate_ == 200) return; | ||
| 99 | if (test_video_.width == 640 && target_bitrate_ == 1000) return; | ||
| 100 | SetConfig(); | ||
| 101 | rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_); | ||
| 102 | rc_api_->UpdateRateControl(rc_cfg_); | ||
| 103 | |||
| 104 | ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width, | ||
| 105 | test_video_.height, 30, 1, 0, | ||
| 106 | test_video_.frames); | ||
| 107 | |||
| 108 | ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); | ||
| 109 | } | ||
| 110 | |||
| 111 | void RunPeriodicKey() { | ||
| 112 | test_video_ = GET_PARAM(2); | ||
| 113 | target_bitrate_ = GET_PARAM(1); | ||
| 114 | if (test_video_.width == 1280 && target_bitrate_ == 200) return; | ||
| 115 | if (test_video_.width == 640 && target_bitrate_ == 1000) return; | ||
| 116 | key_interval_ = 100; | ||
| 117 | SetConfig(); | ||
| 118 | rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_); | ||
| 119 | rc_api_->UpdateRateControl(rc_cfg_); | ||
| 120 | |||
| 121 | ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width, | ||
| 122 | test_video_.height, 30, 1, 0, | ||
| 123 | test_video_.frames); | ||
| 124 | |||
| 125 | ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); | ||
| 126 | } | ||
| 127 | |||
| 128 | private: | ||
| 129 | void SetConfig() { | ||
| 130 | rc_cfg_.width = test_video_.width; | ||
| 131 | rc_cfg_.height = test_video_.height; | ||
| 132 | rc_cfg_.max_quantizer = 60; | ||
| 133 | rc_cfg_.min_quantizer = 2; | ||
| 134 | rc_cfg_.target_bandwidth = target_bitrate_; | ||
| 135 | rc_cfg_.buf_initial_sz = 600; | ||
| 136 | rc_cfg_.buf_optimal_sz = 600; | ||
| 137 | rc_cfg_.buf_sz = target_bitrate_; | ||
| 138 | rc_cfg_.undershoot_pct = 50; | ||
| 139 | rc_cfg_.overshoot_pct = 50; | ||
| 140 | rc_cfg_.max_intra_bitrate_pct = 1000; | ||
| 141 | rc_cfg_.framerate = 30.0; | ||
| 142 | rc_cfg_.layer_target_bitrate[0] = target_bitrate_; | ||
| 143 | |||
| 144 | // Encoder settings for ground truth. | ||
| 145 | cfg_.g_w = test_video_.width; | ||
| 146 | cfg_.g_h = test_video_.height; | ||
| 147 | cfg_.rc_undershoot_pct = 50; | ||
| 148 | cfg_.rc_overshoot_pct = 50; | ||
| 149 | cfg_.rc_buf_initial_sz = 600; | ||
| 150 | cfg_.rc_buf_optimal_sz = 600; | ||
| 151 | cfg_.rc_buf_sz = target_bitrate_; | ||
| 152 | cfg_.rc_dropframe_thresh = 0; | ||
| 153 | cfg_.rc_min_quantizer = 2; | ||
| 154 | cfg_.rc_max_quantizer = 60; | ||
| 155 | cfg_.rc_end_usage = VPX_CBR; | ||
| 156 | cfg_.g_lag_in_frames = 0; | ||
| 157 | cfg_.g_error_resilient = 1; | ||
| 158 | cfg_.rc_target_bitrate = target_bitrate_; | ||
| 159 | cfg_.kf_min_dist = key_interval_; | ||
| 160 | cfg_.kf_max_dist = key_interval_; | ||
| 161 | } | ||
| 162 | |||
| 163 | std::unique_ptr<libvpx::VP8RateControlRTC> rc_api_; | ||
| 164 | libvpx::VP8RateControlRtcConfig rc_cfg_; | ||
| 165 | int key_interval_; | ||
| 166 | int target_bitrate_; | ||
| 167 | Vp8RCTestVideo test_video_; | ||
| 168 | libvpx::VP8FrameParamsQpRTC frame_params_; | ||
| 169 | bool encoder_exit_; | ||
| 170 | }; | ||
| 171 | |||
| 172 | TEST_P(Vp8RcInterfaceTest, OneLayer) { RunOneLayer(); } | ||
| 173 | |||
| 174 | TEST_P(Vp8RcInterfaceTest, OneLayerPeriodicKey) { RunPeriodicKey(); } | ||
| 175 | |||
| 176 | VP8_INSTANTIATE_TEST_SUITE(Vp8RcInterfaceTest, | ||
| 177 | ::testing::Values(200, 400, 1000), | ||
| 178 | ::testing::ValuesIn(kVp8RCTestVectors)); | ||
| 179 | |||
| 180 | } // namespace | ||
| @@ -371,8 +371,3 @@ VP9_INSTANTIATE_TEST_SUITE(RcInterfaceTest, ::testing::Values(0, 3), · 370 unmodified lines | |||
| 371 | ::testing::Values(VPX_CBR, VPX_VBR)); | 371 | ::testing::Values(VPX_CBR, VPX_VBR)); |
| 372 | VP9_INSTANTIATE_TEST_SUITE(RcInterfaceSvcTest, ::testing::Values(0, 3)); | 372 | VP9_INSTANTIATE_TEST_SUITE(RcInterfaceSvcTest, ::testing::Values(0, 3)); |
| 373 | } // namespace | 373 | } // namespace |
| 374 | |||
| 375 | int main(int argc, char **argv) { | ||
| 376 | ::testing::InitGoogleTest(&argc, argv); | ||
| 377 | return RUN_ALL_TESTS(); | ||
| 378 | } | ||
| @@ -4017,7 +4017,8 @@ static void encode_frame_to_data_rate(VP8_COMP *cpi, size_t *size, · 4016 unmodified lines | |||
| 4017 | if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1; | 4017 | if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1; |
| 4018 | 4018 | ||
| 4019 | /* Are we are overshooting and up against the limit of active max Q. */ | 4019 | /* Are we are overshooting and up against the limit of active max Q. */ |
| 4020 | if (((cpi->pass != 2) || | 4020 | if (!cpi->rt_always_update_correction_factor && |
| 4021 | ((cpi->pass != 2) || | ||
| 4021 | (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) && | 4022 | (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) && |
| 4022 | (Q == cpi->active_worst_quality) && | 4023 | (Q == cpi->active_worst_quality) && |
| 4023 | (cpi->active_worst_quality < cpi->worst_quality) && | 4024 | (cpi->active_worst_quality < cpi->worst_quality) && |
| @@ -4446,8 +4447,7 @@ static void encode_frame_to_data_rate(VP8_COMP *cpi, size_t *size, · 422 unmodified lines | |||
| 4446 | } | 4447 | } |
| 4447 | } | 4448 | } |
| 4448 | 4449 | ||
| 4449 | if (cpi->rt_always_update_correction_factor || !active_worst_qchanged) | 4450 | if (!active_worst_qchanged) vp8_update_rate_correction_factors(cpi, 2); |
| 4450 | vp8_update_rate_correction_factors(cpi, 2); | ||
| 4451 | 4451 | ||
| 4452 | cpi->last_q[cm->frame_type] = cm->base_qindex; | 4452 | cpi->last_q[cm->frame_type] = cm->base_qindex; |
| 4453 | 4453 | ||
| @@ -327,7 +327,8 @@ static void calc_iframe_target_size(VP8_COMP *cpi) { · 326 unmodified lines | |||
| 327 | int initial_boost = 32; /* |3.0 * per_frame_bandwidth| */ | 327 | int initial_boost = 32; /* |3.0 * per_frame_bandwidth| */ |
| 328 | /* Boost depends somewhat on frame rate: only used for 1 layer case. */ | 328 | /* Boost depends somewhat on frame rate: only used for 1 layer case. */ |
| 329 | if (cpi->oxcf.number_of_layers == 1) { | 329 | if (cpi->oxcf.number_of_layers == 1) { |
| 330 | kf_boost = VPXMAX(initial_boost, (int)(2 * cpi->output_framerate - 16)); | 330 | kf_boost = |
| 331 | VPXMAX(initial_boost, (int)round(2 * cpi->output_framerate - 16)); | ||
| 331 | } else { | 332 | } else { |
| 332 | /* Initial factor: set target size to: |3.0 * per_frame_bandwidth|. */ | 333 | /* Initial factor: set target size to: |3.0 * per_frame_bandwidth|. */ |
| 333 | kf_boost = initial_boost; | 334 | kf_boost = initial_boost; |
| @@ -0,0 +1,288 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2021 The WebM project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license | ||
| 5 | * that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. An additional intellectual property rights grant can be found | ||
| 7 | * in the file PATENTS. All contributing project authors may | ||
| 8 | * be found in the AUTHORS file in the root of the source tree. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <new> | ||
| 12 | #include "vp8/vp8_ratectrl_rtc.h" | ||
| 13 | #include "vp8/encoder/ratectrl.h" | ||
| 14 | |||
| 15 | namespace libvpx { | ||
| 16 | /* Quant MOD */ | ||
| 17 | static const int kQTrans[] = { | ||
| 18 | 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, | ||
| 19 | 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 35, 37, 39, 41, | ||
| 20 | 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 64, 67, 70, 73, 76, 79, | ||
| 21 | 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, | ||
| 22 | }; | ||
| 23 | |||
| 24 | static const unsigned char kf_high_motion_minq[QINDEX_RANGE] = { | ||
| 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 26 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, | ||
| 27 | 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, | ||
| 28 | 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 10, 10, | ||
| 29 | 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, | ||
| 30 | 16, 16, 16, 17, 17, 18, 18, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, | ||
| 31 | 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30 | ||
| 32 | }; | ||
| 33 | |||
| 34 | static const unsigned char inter_minq[QINDEX_RANGE] = { | ||
| 35 | 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, | ||
| 36 | 11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 24, | ||
| 37 | 24, 25, 26, 27, 27, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, | ||
| 38 | 39, 39, 40, 41, 42, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 50, 51, 52, 53, | ||
| 39 | 54, 55, 55, 56, 57, 58, 59, 60, 60, 61, 62, 63, 64, 65, 66, 67, 67, 68, 69, | ||
| 40 | 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 86, | ||
| 41 | 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 | ||
| 42 | }; | ||
| 43 | |||
| 44 | static int rescale(int val, int num, int denom) { | ||
| 45 | int64_t llnum = num; | ||
| 46 | int64_t llden = denom; | ||
| 47 | int64_t llval = val; | ||
| 48 | |||
| 49 | return (int)(llval * llnum / llden); | ||
| 50 | } | ||
| 51 | |||
| 52 | std::unique_ptr<VP8RateControlRTC> VP8RateControlRTC::Create( | ||
| 53 | const VP8RateControlRtcConfig &cfg) { | ||
| 54 | std::unique_ptr<VP8RateControlRTC> rc_api(new (std::nothrow) | ||
| 55 | VP8RateControlRTC()); | ||
| 56 | if (!rc_api) return nullptr; | ||
| 57 | rc_api->cpi_ = static_cast<VP8_COMP *>(vpx_memalign(32, sizeof(*cpi_))); | ||
| 58 | if (!rc_api->cpi_) return nullptr; | ||
| 59 | vp8_zero(*rc_api->cpi_); | ||
| 60 | |||
| 61 | rc_api->InitRateControl(cfg); | ||
| 62 | |||
| 63 | return rc_api; | ||
| 64 | } | ||
| 65 | |||
| 66 | void VP8RateControlRTC::InitRateControl(const VP8RateControlRtcConfig &rc_cfg) { | ||
| 67 | VP8_COMMON *cm = &cpi_->common; | ||
| 68 | VP8_CONFIG *oxcf = &cpi_->oxcf; | ||
| 69 | oxcf->end_usage = USAGE_STREAM_FROM_SERVER; | ||
| 70 | cpi_->pass = 0; | ||
| 71 | cm->show_frame = 1; | ||
| 72 | oxcf->drop_frames_water_mark = 0; | ||
| 73 | cm->current_video_frame = 0; | ||
| 74 | cpi_->auto_gold = 1; | ||
| 75 | cpi_->key_frame_count = 1; | ||
| 76 | cpi_->rate_correction_factor = 1.0; | ||
| 77 | cpi_->key_frame_rate_correction_factor = 1.0; | ||
| 78 | cpi_->cyclic_refresh_mode_enabled = 0; | ||
| 79 | cpi_->auto_worst_q = 1; | ||
| 80 | cpi_->kf_overspend_bits = 0; | ||
| 81 | cpi_->kf_bitrate_adjustment = 0; | ||
| 82 | cpi_->gf_overspend_bits = 0; | ||
| 83 | cpi_->non_gf_bitrate_adjustment = 0; | ||
| 84 | UpdateRateControl(rc_cfg); | ||
| 85 | cpi_->buffer_level = oxcf->starting_buffer_level; | ||
| 86 | cpi_->bits_off_target = oxcf->starting_buffer_level; | ||
| 87 | } | ||
| 88 | |||
| 89 | void VP8RateControlRTC::UpdateRateControl( | ||
| 90 | const VP8RateControlRtcConfig &rc_cfg) { | ||
| 91 | VP8_COMMON *cm = &cpi_->common; | ||
| 92 | VP8_CONFIG *oxcf = &cpi_->oxcf; | ||
| 93 | |||
| 94 | cm->Width = rc_cfg.width; | ||
| 95 | cm->Height = rc_cfg.height; | ||
| 96 | oxcf->Width = rc_cfg.width; | ||
| 97 | oxcf->Height = rc_cfg.height; | ||
| 98 | oxcf->worst_allowed_q = kQTrans[rc_cfg.max_quantizer]; | ||
| 99 | oxcf->best_allowed_q = kQTrans[rc_cfg.min_quantizer]; | ||
| 100 | cpi_->worst_quality = oxcf->worst_allowed_q; | ||
| 101 | cpi_->best_quality = oxcf->best_allowed_q; | ||
| 102 | cpi_->output_framerate = rc_cfg.framerate; | ||
| 103 | oxcf->target_bandwidth = 1000 * rc_cfg.target_bandwidth; | ||
| 104 | oxcf->fixed_q = -1; | ||
| 105 | oxcf->error_resilient_mode = 1; | ||
| 106 | oxcf->starting_buffer_level_in_ms = rc_cfg.buf_initial_sz; | ||
| 107 | oxcf->optimal_buffer_level_in_ms = rc_cfg.buf_optimal_sz; | ||
| 108 | oxcf->maximum_buffer_size_in_ms = rc_cfg.buf_sz; | ||
| 109 | oxcf->starting_buffer_level = rc_cfg.buf_initial_sz; | ||
| 110 | oxcf->optimal_buffer_level = rc_cfg.buf_optimal_sz; | ||
| 111 | oxcf->maximum_buffer_size = rc_cfg.buf_sz; | ||
| 112 | oxcf->number_of_layers = 1; | ||
| 113 | cpi_->buffered_mode = oxcf->optimal_buffer_level > 0; | ||
| 114 | oxcf->under_shoot_pct = rc_cfg.undershoot_pct; | ||
| 115 | oxcf->over_shoot_pct = rc_cfg.overshoot_pct; | ||
| 116 | cpi_->oxcf.rc_max_intra_bitrate_pct = rc_cfg.max_intra_bitrate_pct; | ||
| 117 | cpi_->framerate = rc_cfg.framerate; | ||
| 118 | for (int i = 0; i < KEY_FRAME_CONTEXT; ++i) { | ||
| 119 | cpi_->prior_key_frame_distance[i] = | ||
| 120 | static_cast<int>(cpi_->output_framerate); | ||
| 121 | } | ||
| 122 | |||
| 123 | cpi_->total_actual_bits = 0; | ||
| 124 | cpi_->total_target_vs_actual = 0; | ||
| 125 | |||
| 126 | cm->mb_rows = cm->Height >> 4; | ||
| 127 | cm->mb_cols = cm->Width >> 4; | ||
| 128 | cm->MBs = cm->mb_rows * cm->mb_cols; | ||
| 129 | cm->mode_info_stride = cm->mb_cols + 1; | ||
| 130 | |||
| 131 | oxcf->starting_buffer_level = | ||
| 132 | rescale((int)oxcf->starting_buffer_level, oxcf->target_bandwidth, 1000); | ||
| 133 | /* Set or reset optimal and maximum buffer levels. */ | ||
| 134 | if (oxcf->optimal_buffer_level == 0) { | ||
| 135 | oxcf->optimal_buffer_level = oxcf->target_bandwidth / 8; | ||
| 136 | } else { | ||
| 137 | oxcf->optimal_buffer_level = | ||
| 138 | rescale((int)oxcf->optimal_buffer_level, oxcf->target_bandwidth, 1000); | ||
| 139 | } | ||
| 140 | if (oxcf->maximum_buffer_size == 0) { | ||
| 141 | oxcf->maximum_buffer_size = oxcf->target_bandwidth / 8; | ||
| 142 | } else { | ||
| 143 | oxcf->maximum_buffer_size = | ||
| 144 | rescale((int)oxcf->maximum_buffer_size, oxcf->target_bandwidth, 1000); | ||
| 145 | } | ||
| 146 | |||
| 147 | if (cpi_->bits_off_target > oxcf->maximum_buffer_size) { | ||
| 148 | cpi_->bits_off_target = oxcf->maximum_buffer_size; | ||
| 149 | cpi_->buffer_level = cpi_->bits_off_target; | ||
| 150 | } | ||
| 151 | |||
| 152 | vp8_new_framerate(cpi_, cpi_->framerate); | ||
| 153 | } | ||
| 154 | |||
| 155 | void VP8RateControlRTC::ComputeQP(const VP8FrameParamsQpRTC &frame_params) { | ||
| 156 | VP8_COMMON *const cm = &cpi_->common; | ||
| 157 | cm->frame_type = frame_params.frame_type; | ||
| 158 | cm->refresh_golden_frame = (cm->frame_type == KEY_FRAME) ? 1 : 0; | ||
| 159 | cm->refresh_alt_ref_frame = (cm->frame_type == KEY_FRAME) ? 1 : 0; | ||
| 160 | if (cm->frame_type == KEY_FRAME && cpi_->common.current_video_frame > 0) { | ||
| 161 | cpi_->common.frame_flags |= FRAMEFLAGS_KEY; | ||
| 162 | } | ||
| 163 | |||
| 164 | vp8_pick_frame_size(cpi_); | ||
| 165 | |||
| 166 | if (cpi_->buffer_level >= cpi_->oxcf.optimal_buffer_level && | ||
| 167 | cpi_->buffered_mode) { | ||
| 168 | /* Max adjustment is 1/4 */ | ||
| 169 | int Adjustment = cpi_->active_worst_quality / 4; | ||
| 170 | if (Adjustment) { | ||
| 171 | int buff_lvl_step; | ||
| 172 | if (cpi_->buffer_level < cpi_->oxcf.maximum_buffer_size) { | ||
| 173 | buff_lvl_step = (int)((cpi_->oxcf.maximum_buffer_size - | ||
| 174 | cpi_->oxcf.optimal_buffer_level) / | ||
| 175 | Adjustment); | ||
| 176 | if (buff_lvl_step) { | ||
| 177 | Adjustment = | ||
| 178 | (int)((cpi_->buffer_level - cpi_->oxcf.optimal_buffer_level) / | ||
| 179 | buff_lvl_step); | ||
| 180 | } else { | ||
| 181 | Adjustment = 0; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | cpi_->active_worst_quality -= Adjustment; | ||
| 185 | if (cpi_->active_worst_quality < cpi_->active_best_quality) { | ||
| 186 | cpi_->active_worst_quality = cpi_->active_best_quality; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | if (cpi_->ni_frames > 150) { | ||
| 192 | int q = cpi_->active_worst_quality; | ||
| 193 | if (cm->frame_type == KEY_FRAME) { | ||
| 194 | cpi_->active_best_quality = kf_high_motion_minq[q]; | ||
| 195 | } else { | ||
| 196 | cpi_->active_best_quality = inter_minq[q]; | ||
| 197 | } | ||
| 198 | |||
| 199 | if (cpi_->buffer_level >= cpi_->oxcf.maximum_buffer_size) { | ||
| 200 | cpi_->active_best_quality = cpi_->best_quality; | ||
| 201 | |||
| 202 | } else if (cpi_->buffer_level > cpi_->oxcf.optimal_buffer_level) { | ||
| 203 | int Fraction = | ||
| 204 | (int)(((cpi_->buffer_level - cpi_->oxcf.optimal_buffer_level) * 128) / | ||
| 205 | (cpi_->oxcf.maximum_buffer_size - | ||
| 206 | cpi_->oxcf.optimal_buffer_level)); | ||
| 207 | int min_qadjustment = | ||
| 208 | ((cpi_->active_best_quality - cpi_->best_quality) * Fraction) / 128; | ||
| 209 | |||
| 210 | cpi_->active_best_quality -= min_qadjustment; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | /* Clip the active best and worst quality values to limits */ | ||
| 215 | if (cpi_->active_worst_quality > cpi_->worst_quality) { | ||
| 216 | cpi_->active_worst_quality = cpi_->worst_quality; | ||
| 217 | } | ||
| 218 | if (cpi_->active_best_quality < cpi_->best_quality) { | ||
| 219 | cpi_->active_best_quality = cpi_->best_quality; | ||
| 220 | } | ||
| 221 | if (cpi_->active_worst_quality < cpi_->active_best_quality) { | ||
| 222 | cpi_->active_worst_quality = cpi_->active_best_quality; | ||
| 223 | } | ||
| 224 | |||
| 225 | q_ = vp8_regulate_q(cpi_, cpi_->this_frame_target); | ||
| 226 | vp8_set_quantizer(cpi_, q_); | ||
| 227 | } | ||
| 228 | |||
| 229 | int VP8RateControlRTC::GetQP() const { return q_; } | ||
| 230 | |||
| 231 | void VP8RateControlRTC::PostEncodeUpdate(uint64_t encoded_frame_size) { | ||
| 232 | VP8_COMMON *const cm = &cpi_->common; | ||
| 233 | |||
| 234 | cpi_->total_byte_count += encoded_frame_size; | ||
| 235 | cpi_->projected_frame_size = static_cast<int>(encoded_frame_size << 3); | ||
| 236 | |||
| 237 | vp8_update_rate_correction_factors(cpi_, 2); | ||
| 238 | |||
| 239 | cpi_->last_q[cm->frame_type] = cm->base_qindex; | ||
| 240 | |||
| 241 | if (cm->frame_type == KEY_FRAME) { | ||
| 242 | vp8_adjust_key_frame_context(cpi_); | ||
| 243 | } | ||
| 244 | |||
| 245 | /* Keep a record of ambient average Q. */ | ||
| 246 | if (cm->frame_type != KEY_FRAME) { | ||
| 247 | cpi_->avg_frame_qindex = | ||
| 248 | (2 + 3 * cpi_->avg_frame_qindex + cm->base_qindex) >> 2; | ||
| 249 | } | ||
| 250 | /* Keep a record from which we can calculate the average Q excluding | ||
| 251 | * key frames. | ||
| 252 | */ | ||
| 253 | if (cm->frame_type != KEY_FRAME) { | ||
| 254 | cpi_->ni_frames++; | ||
| 255 | /* Damp value for first few frames */ | ||
| 256 | if (cpi_->ni_frames > 150) { | ||
| 257 | cpi_->ni_tot_qi += q_; | ||
| 258 | cpi_->ni_av_qi = (cpi_->ni_tot_qi / cpi_->ni_frames); | ||
| 259 | } else { | ||
| 260 | cpi_->ni_tot_qi += q_; | ||
| 261 | cpi_->ni_av_qi = | ||
| 262 | ((cpi_->ni_tot_qi / cpi_->ni_frames) + cpi_->worst_quality + 1) / 2; | ||
| 263 | } | ||
| 264 | |||
| 265 | /* If the average Q is higher than what was used in the last | ||
| 266 | * frame (after going through the recode loop to keep the frame | ||
| 267 | * size within range) then use the last frame value - 1. The -1 | ||
| 268 | * is designed to stop Q and hence the data rate, from | ||
| 269 | * progressively falling away during difficult sections, but at | ||
| 270 | * the same time reduce the number of itterations around the | ||
| 271 | * recode loop. | ||
| 272 | */ | ||
| 273 | if (q_ > cpi_->ni_av_qi) cpi_->ni_av_qi = q_ - 1; | ||
| 274 | } | ||
| 275 | |||
| 276 | cpi_->bits_off_target += | ||
| 277 | cpi_->av_per_frame_bandwidth - cpi_->projected_frame_size; | ||
| 278 | if (cpi_->bits_off_target > cpi_->oxcf.maximum_buffer_size) { | ||
| 279 | cpi_->bits_off_target = cpi_->oxcf.maximum_buffer_size; | ||
| 280 | } | ||
| 281 | |||
| 282 | cpi_->total_actual_bits += cpi_->projected_frame_size; | ||
| 283 | cpi_->buffer_level = cpi_->bits_off_target; | ||
| 284 | |||
| 285 | cpi_->common.current_video_frame++; | ||
| 286 | cpi_->frames_since_key++; | ||
| 287 | } | ||
| 288 | } // namespace libvpx | ||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2021 The WebM project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license | ||
| 5 | * that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. An additional intellectual property rights grant can be found | ||
| 7 | * in the file PATENTS. All contributing project authors may | ||
| 8 | * be found in the AUTHORS file in the root of the source tree. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef VPX_VP8_RATECTRL_RTC_H_ | ||
| 12 | #define VPX_VP8_RATECTRL_RTC_H_ | ||
| 13 | |||
| 14 | #include <cstdint> | ||
| 15 | #include <memory> | ||
| 16 | |||
| 17 | #include "vp8/encoder/onyx_int.h" | ||
| 18 | #include "vp8/common/common.h" | ||
| 19 | #include "vpx/internal/vpx_ratectrl_rtc.h" | ||
| 20 | |||
| 21 | namespace libvpx { | ||
| 22 | struct VP8RateControlRtcConfig : public VpxRateControlRtcConfig { | ||
| 23 | public: | ||
| 24 | VP8RateControlRtcConfig() { | ||
| 25 | vp8_zero(layer_target_bitrate); | ||
| 26 | vp8_zero(ts_rate_decimator); | ||
| 27 | } | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct VP8FrameParamsQpRTC { | ||
| 31 | FRAME_TYPE frame_type; | ||
| 32 | }; | ||
| 33 | |||
| 34 | class VP8RateControlRTC { | ||
| 35 | public: | ||
| 36 | static std::unique_ptr<VP8RateControlRTC> Create( | ||
| 37 | const VP8RateControlRtcConfig &cfg); | ||
| 38 | ~VP8RateControlRTC() { | ||
| 39 | if (cpi_) { | ||
| 40 | vpx_free(cpi_->gf_active_flags); | ||
| 41 | vpx_free(cpi_); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | void UpdateRateControl(const VP8RateControlRtcConfig &rc_cfg); | ||
| 46 | // GetQP() needs to be called after ComputeQP() to get the latest QP | ||
| 47 | int GetQP() const; | ||
| 48 | // int GetLoopfilterLevel() const; | ||
| 49 | void ComputeQP(const VP8FrameParamsQpRTC &frame_params); | ||
| 50 | // Feedback to rate control with the size of current encoded frame | ||
| 51 | void PostEncodeUpdate(uint64_t encoded_frame_size); | ||
| 52 | |||
| 53 | private: | ||
| 54 | VP8RateControlRTC() {} | ||
| 55 | void InitRateControl(const VP8RateControlRtcConfig &cfg); | ||
| 56 | VP8_COMP *cpi_; | ||
| 57 | int q_; | ||
| 58 | }; | ||
| 59 | |||
| 60 | } // namespace libvpx | ||
| 61 | |||
| 62 | #endif // VPX_VP8_RATECTRL_RTC_H_ | ||
| @@ -22,28 +22,14 @@ · 21 unmodified lines | |||
| 22 | #include "vp9/encoder/vp9_encoder.h" | 22 | #include "vp9/encoder/vp9_encoder.h" |
| 23 | #include "vp9/encoder/vp9_firstpass.h" | 23 | #include "vp9/encoder/vp9_firstpass.h" |
| 24 | #include "vp9/vp9_cx_iface.h" | 24 | #include "vp9/vp9_cx_iface.h" |
| 25 | #include "vpx/internal/vpx_ratectrl_rtc.h" | ||
| 25 | #include "vpx_mem/vpx_mem.h" | 26 | #include "vpx_mem/vpx_mem.h" |
| 26 | 27 | ||
| 27 | namespace libvpx { | 28 | namespace libvpx { |
| 28 | 29 | ||
| 29 | struct VP9RateControlRtcConfig { | 30 | struct VP9RateControlRtcConfig : public VpxRateControlRtcConfig { |
| 30 | public: | 31 | public: |
| 31 | VP9RateControlRtcConfig() { | 32 | VP9RateControlRtcConfig() { |
| 32 | width = 1280; | ||
| 33 | height = 720; | ||
| 34 | max_quantizer = 63; | ||
| 35 | min_quantizer = 2; | ||
| 36 | target_bandwidth = 1000; | ||
| 37 | buf_initial_sz = 600; | ||
| 38 | buf_optimal_sz = 600; | ||
| 39 | buf_sz = 1000; | ||
| 40 | undershoot_pct = overshoot_pct = 50; | ||
| 41 | max_intra_bitrate_pct = 50; | ||
| 42 | max_inter_bitrate_pct = 0; | ||
| 43 | framerate = 30.0; | ||
| 44 | ss_number_layers = ts_number_layers = 1; | ||
| 45 | rc_mode = VPX_CBR; | ||
| 46 | aq_mode = 0; | ||
| 47 | vp9_zero(max_quantizers); | 33 | vp9_zero(max_quantizers); |
| 48 | vp9_zero(min_quantizers); | 34 | vp9_zero(min_quantizers); |
| 49 | vp9_zero(scaling_factor_den); | 35 | vp9_zero(scaling_factor_den); |
| @@ -52,26 +38,10 @@ struct VP9RateControlRtcConfig { · 2 unmodified lines | |||
| 52 | vp9_zero(ts_rate_decimator); | 38 | vp9_zero(ts_rate_decimator); |
| 53 | scaling_factor_num[0] = 1; | 39 | scaling_factor_num[0] = 1; |
| 54 | scaling_factor_den[0] = 1; | 40 | scaling_factor_den[0] = 1; |
| 55 | layer_target_bitrate[0] = static_cast<int>(target_bandwidth); | ||
| 56 | max_quantizers[0] = max_quantizer; | 41 | max_quantizers[0] = max_quantizer; |
| 57 | min_quantizers[0] = min_quantizer; | 42 | min_quantizers[0] = min_quantizer; |
| 58 | ts_rate_decimator[0] = 1; | ||
| 59 | } | 43 | } |
| 60 | 44 | ||
| 61 | int width; | ||
| 62 | int height; | ||
| 63 | // 0-63 | ||
| 64 | int max_quantizer; | ||
| 65 | int min_quantizer; | ||
| 66 | int64_t target_bandwidth; | ||
| 67 | int64_t buf_initial_sz; | ||
| 68 | int64_t buf_optimal_sz; | ||
| 69 | int64_t buf_sz; | ||
| 70 | int undershoot_pct; | ||
| 71 | int overshoot_pct; | ||
| 72 | int max_intra_bitrate_pct; | ||
| 73 | int max_inter_bitrate_pct; | ||
| 74 | double framerate; | ||
| 75 | // Number of spatial layers | 45 | // Number of spatial layers |
| 76 | int ss_number_layers; | 46 | int ss_number_layers; |
| 77 | // Number of temporal layers | 47 | // Number of temporal layers |
| @@ -80,11 +50,6 @@ struct VP9RateControlRtcConfig { · 2 unmodified lines | |||
| 80 | int min_quantizers[VPX_MAX_LAYERS]; | 50 | int min_quantizers[VPX_MAX_LAYERS]; |
| 81 | int scaling_factor_num[VPX_SS_MAX_LAYERS]; | 51 | int scaling_factor_num[VPX_SS_MAX_LAYERS]; |
| 82 | int scaling_factor_den[VPX_SS_MAX_LAYERS]; | 52 | int scaling_factor_den[VPX_SS_MAX_LAYERS]; |
| 83 | int layer_target_bitrate[VPX_MAX_LAYERS]; | ||
| 84 | int ts_rate_decimator[VPX_TS_MAX_LAYERS]; | ||
| 85 | // vbr, cbr | ||
| 86 | enum vpx_rc_mode rc_mode; | ||
| 87 | int aq_mode; | ||
| 88 | }; | 53 | }; |
| 89 | 54 | ||
| 90 | struct VP9FrameParamsQpRTC { | 55 | struct VP9FrameParamsQpRTC { |
| @@ -94,7 +59,7 @@ struct VP9FrameParamsQpRTC { · 3 unmodified lines | |||
| 94 | }; | 59 | }; |
| 95 | 60 | ||
| 96 | // This interface allows using VP9 real-time rate control without initializing | 61 | // This interface allows using VP9 real-time rate control without initializing |
| 97 | // the encoder. To use this interface, you need to link with libvp9rc.a. | 62 | // the encoder. To use this interface, you need to link with libvpxrc.a. |
| 98 | // | 63 | // |
| 99 | // #include "vp9/ratectrl_rtc.h" | 64 | // #include "vp9/ratectrl_rtc.h" |
| 100 | // VP9RateControlRTC rc_api; | 65 | // VP9RateControlRTC rc_api; |
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2021 The WebM project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license | ||
| 5 | * that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. An additional intellectual property rights grant can be found | ||
| 7 | * in the file PATENTS. All contributing project authors may | ||
| 8 | * be found in the AUTHORS file in the root of the source tree. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef VPX_VPX_RATECTRL_RTC_H_ | ||
| 12 | #define VPX_VPX_RATECTRL_RTC_H_ | ||
| 13 | |||
| 14 | #include "vpx/vpx_encoder.h" | ||
| 15 | |||
| 16 | namespace libvpx { | ||
| 17 | struct VpxRateControlRtcConfig { | ||
| 18 | public: | ||
| 19 | VpxRateControlRtcConfig() { | ||
| 20 | width = 1280; | ||
| 21 | height = 720; | ||
| 22 | max_quantizer = 63; | ||
| 23 | min_quantizer = 2; | ||
| 24 | target_bandwidth = 1000; | ||
| 25 | buf_initial_sz = 600; | ||
| 26 | buf_optimal_sz = 600; | ||
| 27 | buf_sz = 1000; | ||
| 28 | undershoot_pct = overshoot_pct = 50; | ||
| 29 | max_intra_bitrate_pct = 50; | ||
| 30 | max_inter_bitrate_pct = 0; | ||
| 31 | framerate = 30.0; | ||
| 32 | ts_number_layers = 1; | ||
| 33 | rc_mode = VPX_CBR; | ||
| 34 | aq_mode = 0; | ||
| 35 | layer_target_bitrate[0] = static_cast<int>(target_bandwidth); | ||
| 36 | ts_rate_decimator[0] = 1; | ||
| 37 | } | ||
| 38 | |||
| 39 | int width; | ||
| 40 | int height; | ||
| 41 | // 0-63 | ||
| 42 | int max_quantizer; | ||
| 43 | int min_quantizer; | ||
| 44 | int64_t target_bandwidth; | ||
| 45 | int64_t buf_initial_sz; | ||
| 46 | int64_t buf_optimal_sz; | ||
| 47 | int64_t buf_sz; | ||
| 48 | int undershoot_pct; | ||
| 49 | int overshoot_pct; | ||
| 50 | int max_intra_bitrate_pct; | ||
| 51 | int max_inter_bitrate_pct; | ||
| 52 | double framerate; | ||
| 53 | // Number of temporal layers | ||
| 54 | int ts_number_layers; | ||
| 55 | int layer_target_bitrate[VPX_MAX_LAYERS]; | ||
| 56 | int ts_rate_decimator[VPX_TS_MAX_LAYERS]; | ||
| 57 | // vbr, cbr | ||
| 58 | enum vpx_rc_mode rc_mode; | ||
| 59 | int aq_mode; | ||
| 60 | }; | ||
| 61 | } // namespace libvpx | ||
| 62 | #endif | ||
| @@ -747,7 +747,7 @@ enum vp8e_enc_control_id { · 746 unmodified lines | |||
| 747 | * | 747 | * |
| 748 | * This will turn off cyclic refresh for vp8. | 748 | * This will turn off cyclic refresh for vp8. |
| 749 | * | 749 | * |
| 750 | * With those, the rate control is expected to work exactly the same as the | 750 | * With this, the rate control is expected to work exactly the same as the |
| 751 | * interface provided in vp8_ratectrl_rtc.cc/h | 751 | * interface provided in vp8_ratectrl_rtc.cc/h |
| 752 | * | 752 | * |
| 753 | * Supported in codecs: VP8 | 753 | * Supported in codecs: VP8 |
| @@ -33,6 +33,7 @@ API_SRCS-yes += vpx_decoder.h · 32 unmodified lines | |||
| 33 | API_SRCS-yes += src/vpx_encoder.c | 33 | API_SRCS-yes += src/vpx_encoder.c |
| 34 | API_SRCS-yes += vpx_encoder.h | 34 | API_SRCS-yes += vpx_encoder.h |
| 35 | API_SRCS-yes += internal/vpx_codec_internal.h | 35 | API_SRCS-yes += internal/vpx_codec_internal.h |
| 36 | API_SRCS-yes += internal/vpx_ratectrl_rtc.h | ||
| 36 | API_SRCS-yes += src/vpx_codec.c | 37 | API_SRCS-yes += src/vpx_codec.c |
| 37 | API_SRCS-yes += src/vpx_image.c | 38 | API_SRCS-yes += src/vpx_image.c |
| 38 | API_SRCS-yes += vpx_codec.h | 39 | API_SRCS-yes += vpx_codec.h |