av1_encode_strategy: inter frame needs ref frames
av1_encode_strategy() should fail if we are encoding an inter frame
(INTER_FRAME or S_FRAME) but no reference frames are available.
Replace the ref_frames[] array with a single ref_frame variable in
av1_encode_strategy().
Acknowledgment: This bug was reported by afosscontact@gmail.com.
Bug: aomedia:3218
Change-Id: I54d9e0452f892ff5fc6005a9ebf50466222ada51
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index b1fff37..e95f2e3 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -1475,7 +1475,6 @@
gf_group->refbuf_state[cpi->gf_frame_index], force_refresh_all);
if (!is_stat_generation_stage(cpi)) {
- const RefCntBuffer *ref_frames[INTER_REFS_PER_FRAME];
const YV12_BUFFER_CONFIG *ref_frame_buf[INTER_REFS_PER_FRAME];
RefFrameMapPair ref_frame_map_pairs[REF_FRAMES];
@@ -1501,9 +1500,16 @@
}
// Get the reference frames
+ bool has_ref_frames = false;
for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
- ref_frames[i] = get_ref_frame_buf(cm, ref_frame_priority_order[i]);
- ref_frame_buf[i] = ref_frames[i] != NULL ? &ref_frames[i]->buf : NULL;
+ const RefCntBuffer *ref_frame =
+ get_ref_frame_buf(cm, ref_frame_priority_order[i]);
+ ref_frame_buf[i] = ref_frame != NULL ? &ref_frame->buf : NULL;
+ if (ref_frame != NULL) has_ref_frames = true;
+ }
+ if (!has_ref_frames && (frame_params.frame_type == INTER_FRAME ||
+ frame_params.frame_type == S_FRAME)) {
+ return AOM_CODEC_ERROR;
}
// Work out which reference frame slots may be used.
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index 2566abe..c37ea1a 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -17,6 +17,7 @@
#include "aom/aomcx.h"
#include "aom/aom_encoder.h"
+#include "aom/aom_image.h"
namespace {
@@ -81,6 +82,30 @@
EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
}
+TEST(EncodeAPI, SetSFrameOnFirstFrame) {
+ constexpr int kWidth = 2;
+ constexpr int kHeight = 128;
+ unsigned char kBuffer[kWidth * kHeight * 3] = { 0 };
+ aom_image_t img;
+ ASSERT_EQ(aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1, kBuffer),
+ &img);
+
+ aom_codec_iface_t *iface = aom_codec_av1_cx();
+ aom_codec_enc_cfg_t cfg;
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, 0), AOM_CODEC_OK);
+ cfg.g_w = kWidth;
+ cfg.g_h = kHeight;
+
+ aom_codec_ctx_t enc;
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+ // One of these aom_codec_encode() calls should fail.
+ if (aom_codec_encode(&enc, &img, 0, 1, AOM_EFLAG_SET_S_FRAME) ==
+ AOM_CODEC_OK) {
+ EXPECT_NE(aom_codec_encode(&enc, NULL, 0, 0, 0), AOM_CODEC_OK);
+ }
+ EXPECT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
+}
+
#if !CONFIG_REALTIME_ONLY
TEST(EncodeAPI, AllIntraMode) {
aom_codec_iface_t *iface = aom_codec_av1_cx();