From ac4c37c6841d4229586b8ca4dda19c9b7f2cdcfe Mon Sep 17 00:00:00 2001 From: James Zern Date: Fri, 19 Feb 2016 11:05:33 -0800 Subject: [PATCH] vp9/10: fix forced keyframes w/alt-refs enabled in 1-pass encodes. issues with 2-pass as well as other forced flags persist. Change-Id: Ic7ceb906fccea6456d5df96483c10cacd46e01c7 --- test/altref_test.cc | 101 ++++++++++++++++++++++++++++++++++++++ test/test.mk | 2 +- vp10/encoder/encoder.c | 14 ++++++ vp9/encoder/vp9_encoder.c | 14 ++++++ 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/test/altref_test.cc b/test/altref_test.cc index af25b7285..8b706eab5 100644 --- a/test/altref_test.cc +++ b/test/altref_test.cc @@ -14,6 +14,8 @@ #include "test/util.h" namespace { +#if CONFIG_VP8_ENCODER + // lookahead range: [kLookAheadMin, kLookAheadMax). const int kLookAheadMin = 5; const int kLookAheadMax = 26; @@ -63,7 +65,106 @@ TEST_P(AltRefTest, MonotonicTimestamps) { EXPECT_GE(altref_count(), 1); } +#endif // CONFIG_VP8_ENCODER + +class AltRefForcedKeyTest + : public ::libvpx_test::EncoderTest, + public ::libvpx_test::CodecTestWith2Params { + protected: + AltRefForcedKeyTest() + : EncoderTest(GET_PARAM(0)), + encoding_mode_(GET_PARAM(1)), + cpu_used_(GET_PARAM(2)), + forced_kf_frame_num_(1), + frame_num_(0) {} + virtual ~AltRefForcedKeyTest() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(encoding_mode_); + cfg_.rc_end_usage = VPX_VBR; + cfg_.g_threads = 0; + } + + virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, + ::libvpx_test::Encoder *encoder) { + if (video->frame() == 0) { + encoder->Control(VP8E_SET_CPUUSED, cpu_used_); + encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1); + // override test default for tile columns if necessary. +#if CONFIG_VP9_ENCODER + if (GET_PARAM(0) == &libvpx_test::kVP9) { + encoder->Control(VP9E_SET_TILE_COLUMNS, 6); + } +#endif +#if CONFIG_VP10_ENCODER + if (GET_PARAM(0) == &libvpx_test::kVP10) { + encoder->Control(VP9E_SET_TILE_COLUMNS, 6); + } +#endif + } + frame_flags_ = + (video->frame() == forced_kf_frame_num_) ? VPX_EFLAG_FORCE_KF : 0; + } + + virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { + if (frame_num_ == forced_kf_frame_num_) { + ASSERT_TRUE(!!(pkt->data.frame.flags & VPX_FRAME_IS_KEY)) + << "Frame #" << frame_num_ << " isn't a keyframe!"; + } + ++frame_num_; + } + + ::libvpx_test::TestMode encoding_mode_; + int cpu_used_; + unsigned int forced_kf_frame_num_; + unsigned int frame_num_; +}; + +TEST_P(AltRefForcedKeyTest, Frame1IsKey) { + const vpx_rational timebase = { 1, 30 }; + const int lag_values[] = { 3, 15, 25, -1 }; + + forced_kf_frame_num_ = 1; + for (int i = 0; lag_values[i] != -1; ++i) { + frame_num_ = 0; + cfg_.g_lag_in_frames = lag_values[i]; + libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + timebase.den, timebase.num, 0, 30); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + } +} + +TEST_P(AltRefForcedKeyTest, ForcedFrameIsKey) { + const vpx_rational timebase = { 1, 30 }; + const int lag_values[] = { 3, 15, 25, -1 }; + + for (int i = 0; lag_values[i] != -1; ++i) { + frame_num_ = 0; + forced_kf_frame_num_ = lag_values[i] - 1; + cfg_.g_lag_in_frames = lag_values[i]; + libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + timebase.den, timebase.num, 0, 30); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + } +} VP8_INSTANTIATE_TEST_CASE(AltRefTest, ::testing::Range(kLookAheadMin, kLookAheadMax)); + +VP8_INSTANTIATE_TEST_CASE( + AltRefForcedKeyTest, + ::testing::Values(::libvpx_test::kOnePassGood), + ::testing::Range(0, 9)); + +VP9_INSTANTIATE_TEST_CASE( + AltRefForcedKeyTest, + ::testing::Values(::libvpx_test::kOnePassGood), + ::testing::Range(0, 9)); + +VP10_INSTANTIATE_TEST_CASE( + AltRefForcedKeyTest, + ::testing::Values(::libvpx_test::kOnePassGood), + ::testing::Range(0, 9)); + } // namespace diff --git a/test/test.mk b/test/test.mk index e8e830489..0a4b69ce0 100644 --- a/test/test.mk +++ b/test/test.mk @@ -18,6 +18,7 @@ LIBVPX_TEST_SRCS-yes += video_source.h LIBVPX_TEST_SRCS-yes += ../md5_utils.h ../md5_utils.c LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ivf_video_source.h LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += ../y4minput.h ../y4minput.c +LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += altref_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += aq_segment_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += datarate_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += encode_api_test.cc @@ -27,7 +28,6 @@ LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += resize_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += y4m_video_source.h LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += yuv_video_source.h -LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += altref_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += config_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += cq_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += keyframe_test.cc diff --git a/vp10/encoder/encoder.c b/vp10/encoder/encoder.c index 775fd22a5..31a93906b 100644 --- a/vp10/encoder/encoder.c +++ b/vp10/encoder/encoder.c @@ -4007,6 +4007,20 @@ int vp10_get_compressed_data(VP10_COMP *cpi, unsigned int *frame_flags, // Should we encode an arf frame. arf_src_index = get_arf_src_index(cpi); + if (arf_src_index) { + for (i = 0; i <= arf_src_index; ++i) { + struct lookahead_entry *e = vp10_lookahead_peek(cpi->lookahead, i); + // Avoid creating an alt-ref if there's a forced keyframe pending. + if (e == NULL) { + break; + } else if (e->flags == VPX_EFLAG_FORCE_KF) { + arf_src_index = 0; + flush = 1; + break; + } + } + } + if (arf_src_index) { assert(arf_src_index <= rc->frames_to_key); diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 84989083d..06d245ef3 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -4373,6 +4373,20 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, if (is_two_pass_svc(cpi) && source != NULL) arf_src_index = 0; + if (arf_src_index) { + for (i = 0; i <= arf_src_index; ++i) { + struct lookahead_entry *e = vp9_lookahead_peek(cpi->lookahead, i); + // Avoid creating an alt-ref if there's a forced keyframe pending. + if (e == NULL) { + break; + } else if (e->flags == VPX_EFLAG_FORCE_KF) { + arf_src_index = 0; + flush = 1; + break; + } + } + } + if (arf_src_index) { assert(arf_src_index <= rc->frames_to_key);