Add unit test for decoder row based multi-threading
Added row-mt/row_mt as a command-line/init-time API parameter
in the decoder. Currently, decoding with row-mt=1 has only tile
level multi-threading. Support for row level multi-threading of
the decoding stage will be added eventually.
Change-Id: I429540c3d9fe882a3666d84fb24c85921a0d0ecf
diff --git a/aom/aomdx.h b/aom/aomdx.h
index 7ff21a5..5a6da21 100644
--- a/aom/aomdx.h
+++ b/aom/aomdx.h
@@ -187,6 +187,12 @@
*/
AV1D_EXT_TILE_DEBUG,
+ /** control function to enable the row based multi-threading of decoding. A
+ * value that is equal to 1 indicates that row based multi-threading is
+ * enabled.
+ */
+ AV1D_SET_ROW_MT,
+
/** control function to indicate whether bitstream is in Annex-B format. */
AV1D_SET_IS_ANNEXB,
@@ -258,6 +264,8 @@
#define AOM_CTRL_AV1D_SET_EXT_REF_PTR
AOM_CTRL_USE_TYPE(AV1D_EXT_TILE_DEBUG, unsigned int)
#define AOM_CTRL_AV1D_EXT_TILE_DEBUG
+AOM_CTRL_USE_TYPE(AV1D_SET_ROW_MT, unsigned int)
+#define AOM_CTRL_AV1D_SET_ROW_MT
AOM_CTRL_USE_TYPE(AV1D_SET_IS_ANNEXB, unsigned int)
#define AOM_CTRL_AV1D_SET_IS_ANNEXB
AOM_CTRL_USE_TYPE(AV1D_SET_OPERATING_POINT, int)
diff --git a/apps/aomdec.c b/apps/aomdec.c
index 6c4d724..834f161 100644
--- a/apps/aomdec.c
+++ b/apps/aomdec.c
@@ -83,6 +83,8 @@
ARG_DEF("o", "output", 1, "Output file name pattern (see below)");
static const arg_def_t threadsarg =
ARG_DEF("t", "threads", 1, "Max threads to use");
+static const arg_def_t rowmtarg =
+ ARG_DEF(NULL, "row-mt", 1, "Enable row based multi-threading");
static const arg_def_t verbosearg =
ARG_DEF("v", "verbose", 0, "Show version string");
static const arg_def_t scalearg =
@@ -114,12 +116,12 @@
NULL, "all-layers", 0, "Output all decoded frames of a scalable bitstream");
static const arg_def_t *all_args[] = {
- &help, &codecarg, &use_yv12, &use_i420, &flipuvarg,
- &rawvideo, &noblitarg, &progressarg, &limitarg, &skiparg,
- &postprocarg, &summaryarg, &outputfile, &threadsarg, &verbosearg,
- &scalearg, &fb_arg, &md5arg, &framestatsarg, &continuearg,
- &outbitdeptharg, &tilem, &tiler, &tilec, &isannexb,
- &oppointarg, &outallarg, NULL
+ &help, &codecarg, &use_yv12, &use_i420, &flipuvarg,
+ &rawvideo, &noblitarg, &progressarg, &limitarg, &skiparg,
+ &postprocarg, &summaryarg, &outputfile, &threadsarg, &rowmtarg,
+ &verbosearg, &scalearg, &fb_arg, &md5arg, &framestatsarg,
+ &continuearg, &outbitdeptharg, &tilem, &tiler, &tilec,
+ &isannexb, &oppointarg, &outallarg, NULL
};
#if CONFIG_LIBYUV
@@ -512,6 +514,7 @@
int do_scale = 0;
int operating_point = 0;
int output_all_layers = 0;
+ unsigned int row_mt = 0;
aom_image_t *scaled_img = NULL;
aom_image_t *img_shifted = NULL;
int frame_avail, got_data, flush_decoder = 0;
@@ -601,6 +604,8 @@
summary = 1;
} else if (arg_match(&arg, &threadsarg, argi)) {
cfg.threads = arg_parse_uint(&arg);
+ } else if (arg_match(&arg, &rowmtarg, argi)) {
+ row_mt = arg_parse_uint(&arg);
} else if (arg_match(&arg, &verbosearg, argi)) {
quiet = 0;
} else if (arg_match(&arg, &scalearg, argi)) {
@@ -763,6 +768,11 @@
aom_codec_error(&decoder));
goto fail;
}
+
+ if (aom_codec_control(&decoder, AV1D_SET_ROW_MT, row_mt)) {
+ fprintf(stderr, "Failed to set row_mt: %s\n", aom_codec_error(&decoder));
+ goto fail;
+ }
#endif
if (arg_skip) fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index db338f7..f0862da 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -50,6 +50,7 @@
int decode_tile_col;
unsigned int tile_mode;
unsigned int ext_tile_debug;
+ unsigned int row_mt;
EXTERNAL_REFERENCES ext_refs;
unsigned int is_annexb;
int operating_point;
@@ -429,6 +430,7 @@
frame_worker_data->pbi->operating_point = ctx->operating_point;
frame_worker_data->pbi->output_all_layers = ctx->output_all_layers;
frame_worker_data->pbi->ext_tile_debug = ctx->ext_tile_debug;
+ frame_worker_data->pbi->row_mt = ctx->row_mt;
worker->hook = (AVxWorkerHook)frame_worker_hook;
if (!winterface->reset(worker)) {
@@ -489,6 +491,7 @@
frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row;
frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col;
frame_worker_data->pbi->ext_tile_debug = ctx->ext_tile_debug;
+ frame_worker_data->pbi->row_mt = ctx->row_mt;
frame_worker_data->pbi->ext_refs = ctx->ext_refs;
frame_worker_data->pbi->common.is_annexb = ctx->is_annexb;
@@ -1124,6 +1127,12 @@
return AOM_CODEC_OK;
}
+static aom_codec_err_t ctrl_set_row_mt(aom_codec_alg_priv_t *ctx,
+ va_list args) {
+ ctx->row_mt = va_arg(args, unsigned int);
+ return AOM_CODEC_OK;
+}
+
static aom_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
{ AV1_COPY_REFERENCE, ctrl_copy_reference },
@@ -1145,6 +1154,7 @@
{ AV1D_SET_OUTPUT_ALL_LAYERS, ctrl_set_output_all_layers },
{ AV1_SET_INSPECTION_CALLBACK, ctrl_set_inspection_callback },
{ AV1D_EXT_TILE_DEBUG, ctrl_ext_tile_debug },
+ { AV1D_SET_ROW_MT, ctrl_set_row_mt },
{ AV1D_SET_EXT_REF_PTR, ctrl_set_ext_ref_ptr },
// Getters
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 8de2b47..3ae2743 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -4386,8 +4386,11 @@
if (initialize_flag) setup_frame_info(pbi);
- if (pbi->max_threads > 1 && tile_count_tg > 1 &&
- !(cm->large_scale_tile && !pbi->ext_tile_debug))
+ if (pbi->max_threads > 1 && !(cm->large_scale_tile && !pbi->ext_tile_debug) &&
+ pbi->row_mt)
+ *p_data_end = decode_tiles_mt(pbi, data, data_end, start_tile, end_tile);
+ else if (pbi->max_threads > 1 && tile_count_tg > 1 &&
+ !(cm->large_scale_tile && !pbi->ext_tile_debug))
*p_data_end = decode_tiles_mt(pbi, data, data_end, start_tile, end_tile);
else
*p_data_end = decode_tiles(pbi, data, data_end, start_tile, end_tile);
diff --git a/av1/decoder/decoder.h b/av1/decoder/decoder.h
index 42fcc12..3056cda 100644
--- a/av1/decoder/decoder.h
+++ b/av1/decoder/decoder.h
@@ -162,6 +162,7 @@
int tile_count_minus_1;
uint32_t coded_tile_data_size;
unsigned int ext_tile_debug; // for ext-tile software debug & testing
+ unsigned int row_mt;
EXTERNAL_REFERENCES ext_refs;
size_t tile_list_size;
uint8_t *tile_list_output;
diff --git a/test/codec_factory.h b/test/codec_factory.h
index 65b7609..e6ae7f8 100644
--- a/test/codec_factory.h
+++ b/test/codec_factory.h
@@ -71,6 +71,11 @@
: public ::testing::TestWithParam< ::testing::tuple<
const libaom_test::CodecFactory *, T1, T2, T3, T4> > {};
+template <class T1, class T2, class T3, class T4, class T5>
+class CodecTestWith5Params
+ : public ::testing::TestWithParam< ::testing::tuple<
+ const libaom_test::CodecFactory *, T1, T2, T3, T4, T5> > {};
+
/*
* AV1 Codec Definitions
*/
diff --git a/test/decode_multithreaded_test.cc b/test/decode_multithreaded_test.cc
index cde612d..cea1d14 100644
--- a/test/decode_multithreaded_test.cc
+++ b/test/decode_multithreaded_test.cc
@@ -26,13 +26,14 @@
static const int kNumMultiThreadDecoders = 3;
class AV1DecodeMultiThreadedTest
- : public ::libaom_test::CodecTestWith4Params<int, int, int, int>,
+ : public ::libaom_test::CodecTestWith5Params<int, int, int, int, int>,
public ::libaom_test::EncoderTest {
protected:
AV1DecodeMultiThreadedTest()
: EncoderTest(GET_PARAM(0)), md5_single_thread_(), md5_multi_thread_(),
n_tile_cols_(GET_PARAM(1)), n_tile_rows_(GET_PARAM(2)),
- n_tile_groups_(GET_PARAM(3)), set_cpu_used_(GET_PARAM(4)) {
+ n_tile_groups_(GET_PARAM(3)), set_cpu_used_(GET_PARAM(4)),
+ row_mt_(GET_PARAM(5)) {
init_flags_ = AOM_CODEC_USE_PSNR;
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
cfg.w = 704;
@@ -45,6 +46,7 @@
for (int i = 0; i < kNumMultiThreadDecoders; ++i) {
cfg.threads <<= 1;
multi_thread_dec_[i] = codec_->CreateDecoder(cfg, 0);
+ multi_thread_dec_[i]->Control(AV1D_SET_ROW_MT, row_mt_);
}
if (single_thread_dec_->IsAV1()) {
@@ -130,6 +132,7 @@
int n_tile_rows_;
int n_tile_groups_;
int set_cpu_used_;
+ int row_mt_;
};
// run an encode and do the decode both in single thread
@@ -156,11 +159,12 @@
// TODO(ranjit): More tests have to be added using pre-generated MD5.
AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedTest, ::testing::Values(1, 2),
::testing::Values(1, 2), ::testing::Values(1),
- ::testing::Values(3));
+ ::testing::Values(3), ::testing::Values(0, 1));
AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedTestLarge,
::testing::Values(0, 1, 2, 6),
::testing::Values(0, 1, 2, 6),
- ::testing::Values(1, 4), ::testing::Values(0));
+ ::testing::Values(1, 4), ::testing::Values(0),
+ ::testing::Values(0, 1));
class AV1DecodeMultiThreadedLSTestLarge
: public AV1DecodeMultiThreadedTestLarge {};
@@ -175,6 +179,7 @@
AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedLSTestLarge,
::testing::Values(6), ::testing::Values(6),
- ::testing::Values(1), ::testing::Values(0, 3));
+ ::testing::Values(1), ::testing::Values(0, 3),
+ ::testing::Values(0, 1));
} // namespace
diff --git a/test/test_vector_test.cc b/test/test_vector_test.cc
index 2997e8f..733b925 100644
--- a/test/test_vector_test.cc
+++ b/test/test_vector_test.cc
@@ -30,8 +30,9 @@
const int kThreads = 0;
const int kFileName = 1;
+const int kRowMT = 2;
-typedef ::testing::tuple<int, const char *> DecodeParam;
+typedef ::testing::tuple<int, const char *, int> DecodeParam;
class TestVectorTest : public ::libaom_test::DecoderTest,
public ::libaom_test::CodecTestWithParam<DecodeParam> {
@@ -48,6 +49,12 @@
<< "Md5 file open failed. Filename: " << md5_file_name_;
}
+ virtual void PreDecodeFrameHook(
+ const libaom_test::CompressedVideoSource &video,
+ libaom_test::Decoder *decoder) {
+ if (video.frame_number() == 0) decoder->Control(AV1D_SET_ROW_MT, row_mt_);
+ }
+
virtual void DecompressedFrameHook(const aom_image_t &img,
const unsigned int frame_number) {
ASSERT_TRUE(md5_file_ != NULL);
@@ -84,6 +91,8 @@
<< "Md5 checksums don't match: frame number = " << frame_number;
}
+ unsigned int row_mt_;
+
private:
FILE *md5_file_;
};
@@ -100,6 +109,7 @@
char str[256];
cfg.threads = ::testing::get<kThreads>(input);
+ row_mt_ = ::testing::get<kRowMT>(input);
snprintf(str, sizeof(str) / sizeof(str[0]) - 1, "file: %s threads: %d",
filename.c_str(), cfg.threads);
@@ -140,11 +150,11 @@
#if CONFIG_AV1_DECODER
AV1_INSTANTIATE_TEST_CASE(
TestVectorTest,
- ::testing::Combine(
- ::testing::Values(1), // Single thread.
- ::testing::ValuesIn(libaom_test::kAV1TestVectors,
- libaom_test::kAV1TestVectors +
- libaom_test::kNumAV1TestVectors)));
+ ::testing::Combine(::testing::Values(1), // Single thread.
+ ::testing::ValuesIn(libaom_test::kAV1TestVectors,
+ libaom_test::kAV1TestVectors +
+ libaom_test::kNumAV1TestVectors),
+ ::testing::Values(0)));
// Test AV1 decode in with different numbers of threads.
INSTANTIATE_TEST_CASE_P(
@@ -156,7 +166,8 @@
::testing::Range(2, 9), // With 2 ~ 8 threads.
::testing::ValuesIn(libaom_test::kAV1TestVectors,
libaom_test::kAV1TestVectors +
- libaom_test::kNumAV1TestVectors))));
+ libaom_test::kNumAV1TestVectors),
+ ::testing::Range(0, 2))));
#endif // CONFIG_AV1_DECODER