Add codec control to get GOP info Change-Id: I820c3cc05efcbb8ec235711eedb85b2163cd5dcd
diff --git a/aom/aomcx.h b/aom/aomcx.h index e7bfe96..4b39f34 100644 --- a/aom/aomcx.h +++ b/aom/aomcx.h
@@ -1624,6 +1624,12 @@ */ AV1E_SET_EXTERNAL_RATE_CONTROL = 173, + /*!\brief Codec control function to get GOP structure from the encoder. + * + * args: a pointer to aom_gop_info_t + */ + AV1E_GET_GOP_INFO, + // Any new encoder control IDs should be added above. // Maximum allowed encoder control ID is 229. // No encoder control ID should be added below. @@ -1860,6 +1866,20 @@ AOM_FULL_SUPERFRAME_DROP, /**< Only full superframe can drop. */ } AOM_SVC_FRAME_DROP_MODE; +/*!\brief The GOP structure information determined by the encoder. + * 250 is MAX_STATIC_GF_GROUP_LENGTH defined in av1/firstpass.h. + * This is a subset of GF_GROUP. More fields can be added if needed. + */ +typedef struct aom_gop_info { + int gop_size; /**< The number of frames of this GOP */ + /*! The coding index for each entry in the gop */ + int coding_index[250]; + /*! The display index for each entry in the gop */ + int display_index[250]; + /*! The layer depth for each entry in the gop */ + int layer_depth[250]; +} aom_gop_info_t; + /*!\cond */ /*!\brief Encoder control function parameter type * @@ -2370,6 +2390,9 @@ AOM_CTRL_USE_TYPE(AV1E_SET_EXTERNAL_RATE_CONTROL, aom_rc_funcs_t *) #define AOM_CTRL_AV1E_SET_EXTERNAL_RATE_CONTROL +AOM_CTRL_USE_TYPE(AV1E_GET_GOP_INFO, aom_gop_info_t *) +#define AOM_CTRL_AV1E_GET_GOP_INFO + /*!\endcond */ /*! @} - end defgroup aom_encoder */ #ifdef __cplusplus
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index fc4c431..a1ee702 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -1721,6 +1721,20 @@ return res; } +static aom_codec_err_t ctrl_get_gop_info(aom_codec_alg_priv_t *ctx, + va_list args) { + aom_gop_info_t *const gop_info = va_arg(args, aom_gop_info_t *); + if (gop_info == NULL) return AOM_CODEC_INVALID_PARAM; + const GF_GROUP *const gf_group = &ctx->ppi->gf_group; + gop_info->gop_size = gf_group->size; + for (int i = 0; i < gf_group->size; ++i) { + gop_info->coding_index[i] = i; + gop_info->display_index[i] = gf_group->display_idx[i]; + gop_info->layer_depth[i] = gf_group->layer_depth[i]; + } + return AOM_CODEC_OK; +} + static aom_codec_err_t ctrl_set_cpuused(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -4961,6 +4975,7 @@ { AV1E_GET_LUMA_CDEF_STRENGTH, ctrl_get_luma_cdef_strength }, { AV1E_GET_HIGH_MOTION_CONTENT_SCREEN_RTC, ctrl_get_high_motion_content_screen_rtc }, + { AV1E_GET_GOP_INFO, ctrl_get_gop_info }, CTRL_MAP_END, };
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc index 60a2575..71bb049 100644 --- a/test/encode_api_test.cc +++ b/test/encode_api_test.cc
@@ -24,6 +24,11 @@ #include "aom/aom_encoder.h" #include "aom/aom_image.h" +#include "test/codec_factory.h" +#include "test/encode_test_driver.h" +#include "test/util.h" +#include "test/video_source.h" + namespace { #if CONFIG_REALTIME_ONLY @@ -1729,4 +1734,49 @@ ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); } +class GetGopInfoTest : public ::libaom_test::EncoderTest, + public ::testing::Test { + protected: + GetGopInfoTest() : EncoderTest(&::libaom_test::kAV1) {} + ~GetGopInfoTest() override = default; + + void SetUp() override { + InitializeConfig(::libaom_test::kTwoPassGood); + cfg_.g_w = 176; + cfg_.g_h = 144; + cfg_.rc_target_bitrate = 200; + cfg_.g_lag_in_frames = 25; + cfg_.g_limit = kFrameLimit; + } + + void PreEncodeFrameHook(::libaom_test::VideoSource *video, + ::libaom_test::Encoder *encoder) override { + if (video->frame() == 0) { + encoder->Control(AOME_SET_CPUUSED, 3); + } + } + + void PostEncodeFrameHook(::libaom_test::Encoder *encoder) override { + if (cfg_.g_pass == AOM_RC_FIRST_PASS) return; + encoder->Control(AV1E_GET_GOP_INFO, &gop_info_); + } + + void FramePktHook(const aom_codec_cx_pkt_t * /*pkt*/) override { + // This is verified here (not in PostEncodeFrameHook) because + // PostEncodeFrameHook is also called when encoder is reading frames into + // lookahead buffer, when GOP structure hasn't been determined. + ASSERT_GT(gop_info_.gop_size, 0); + } + + aom_gop_info_t gop_info_; + static constexpr int kFrameLimit = 10; +}; + +TEST_F(GetGopInfoTest, GetGopInfo) { + ::libaom_test::RandomVideoSource video; + video.SetSize(cfg_.g_w, cfg_.g_h); + video.set_limit(kFrameLimit); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + } // namespace
diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h index 739e9a0..a05d645 100644 --- a/test/encode_test_driver.h +++ b/test/encode_test_driver.h
@@ -163,7 +163,12 @@ const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); } -#endif + + void Control(int ctrl_id, aom_gop_info_t *arg) { + const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); + ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); + } +#endif // CONFIG_AV1_ENCODER void SetOption(const char *name, const char *value) { const aom_codec_err_t res = aom_codec_set_option(&encoder_, name, value);