ref: a3ef7d5a5086b2aa2832ff92b23fa6b6b0664c98
parent: 44395a21da75a8fa6ca71a39bee1c9fe55a1358e
author: hkuang <[email protected]>
date: Fri Aug 8 10:49:55 EDT 2014
Add VP9 frame-parallel unit test. Make sure VP9 frame-parallel decode passes all the standard test vectors. Only test running with 2,3,4 threads now. Also refactor the video decode test driver to support passing in decode flags which is used to enable frame-parallel decode. Change-Id: I6a712464232c2e13681634951c7e176312522e1e
--- a/test/codec_factory.h
+++ b/test/codec_factory.h
@@ -35,6 +35,10 @@
virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
unsigned long deadline) const = 0;
+ virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
+ const vpx_codec_flags_t flags,
+ unsigned long deadline) const = 0; // NOLINT
+
virtual Encoder* CreateEncoder(vpx_codec_enc_cfg_t cfg,
unsigned long deadline,
const unsigned long init_flags,
@@ -72,6 +76,10 @@
VP8Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
: Decoder(cfg, deadline) {}
+ VP8Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag,
+ unsigned long deadline) // NOLINT
+ : Decoder(cfg, flag, deadline) {}
+
protected:
virtual vpx_codec_iface_t* CodecInterface() const {
#if CONFIG_VP8_DECODER
@@ -104,8 +112,14 @@
virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
unsigned long deadline) const {
+ return CreateDecoder(cfg, 0, deadline);
+ }
+
+ virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
+ const vpx_codec_flags_t flags,
+ unsigned long deadline) const { // NOLINT
#if CONFIG_VP8_DECODER
- return new VP8Decoder(cfg, deadline);
+ return new VP8Decoder(cfg, flags, deadline);
#else
return NULL;
#endif
@@ -154,6 +168,10 @@
VP9Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
: Decoder(cfg, deadline) {}
+ VP9Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag,
+ unsigned long deadline) // NOLINT
+ : Decoder(cfg, flag, deadline) {}
+
protected:
virtual vpx_codec_iface_t* CodecInterface() const {
#if CONFIG_VP9_DECODER
@@ -186,8 +204,14 @@
virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
unsigned long deadline) const {
+ return CreateDecoder(cfg, 0, deadline);
+ }
+
+ virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
+ const vpx_codec_flags_t flags,
+ unsigned long deadline) const { // NOLINT
#if CONFIG_VP9_DECODER
- return new VP9Decoder(cfg, deadline);
+ return new VP9Decoder(cfg, flags, deadline);
#else
return NULL;
#endif
--- a/test/decode_test_driver.cc
+++ b/test/decode_test_driver.cc
@@ -40,8 +40,7 @@
}
void DecoderTest::RunLoop(CompressedVideoSource *video) {
- vpx_codec_dec_cfg_t dec_cfg = {0};
- Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0);
+ Decoder* const decoder = codec_->CreateDecoder(cfg_, flags_);
ASSERT_TRUE(decoder != NULL);
const char *codec_name = decoder->GetDecoderName();
const bool is_vp8 = strncmp(kVP8Name, codec_name, sizeof(kVP8Name) - 1) == 0;
@@ -84,5 +83,13 @@
}
delete decoder;
+}
+
+void DecoderTest::set_cfg(const vpx_codec_dec_cfg_t &dec_cfg) {
+ memcpy(&cfg_, &dec_cfg, sizeof(cfg_));
+}
+
+void DecoderTest::set_flags(const vpx_codec_flags_t flags) {
+ flags_ = flags;
}
} // namespace libvpx_test
--- a/test/decode_test_driver.h
+++ b/test/decode_test_driver.h
@@ -41,10 +41,16 @@
class Decoder {
public:
Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
- : cfg_(cfg), deadline_(deadline), init_done_(false) {
+ : cfg_(cfg), flags_(0), deadline_(deadline), init_done_(false) {
memset(&decoder_, 0, sizeof(decoder_));
}
+ Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag,
+ unsigned long deadline) // NOLINT
+ : cfg_(cfg), flags_(flag), deadline_(deadline), init_done_(false) {
+ memset(&decoder_, 0, sizeof(decoder_));
+ }
+
virtual ~Decoder() {
vpx_codec_destroy(&decoder_);
}
@@ -102,7 +108,7 @@
if (!init_done_) {
const vpx_codec_err_t res = vpx_codec_dec_init(&decoder_,
CodecInterface(),
- &cfg_, 0);
+ &cfg_, flags_);
ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError();
init_done_ = true;
}
@@ -110,6 +116,7 @@
vpx_codec_ctx_t decoder_;
vpx_codec_dec_cfg_t cfg_;
+ vpx_codec_flags_t flags_;
unsigned int deadline_;
bool init_done_;
};
@@ -120,6 +127,9 @@
// Main decoding loop
virtual void RunLoop(CompressedVideoSource *video);
+ virtual void set_cfg(const vpx_codec_dec_cfg_t &dec_cfg);
+ virtual void set_flags(const vpx_codec_flags_t flags);
+
// Hook to be called before decompressing every frame.
virtual void PreDecodeFrameHook(const CompressedVideoSource& video,
Decoder *decoder) {}
@@ -137,11 +147,15 @@
const unsigned int frame_number) {}
protected:
- explicit DecoderTest(const CodecFactory *codec) : codec_(codec) {}
+ explicit DecoderTest(const CodecFactory *codec) : codec_(codec), flags_(0) {
+ memset(&cfg_, 0, sizeof(cfg_));
+ }
virtual ~DecoderTest() {}
const CodecFactory *codec_;
+ vpx_codec_dec_cfg_t cfg_;
+ vpx_codec_flags_t flags_;
};
} // namespace libvpx_test
--- a/test/test_vector_test.cc
+++ b/test/test_vector_test.cc
@@ -12,6 +12,7 @@
#include <cstdlib>
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
+#include "../tools_common.h"
#include "./vpx_config.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
@@ -26,10 +27,24 @@
namespace {
+enum DecodeMode {
+ kSerialMode,
+ kFrameParallMode
+};
+
+const int kDecodeMode = 0;
+const int kThreads = 1;
+const int kFileName = 2;
+
+typedef std::tr1::tuple<int, int, const char *> DecodeParam;
+
class TestVectorTest : public ::libvpx_test::DecoderTest,
- public ::libvpx_test::CodecTestWithParam<const char*> {
+ public ::libvpx_test::CodecTestWithParam<DecodeParam> {
protected:
- TestVectorTest() : DecoderTest(GET_PARAM(0)), md5_file_(NULL) {}
+ TestVectorTest()
+ : DecoderTest(GET_PARAM(0)),
+ md5_file_(NULL) {
+ }
virtual ~TestVectorTest() {
if (md5_file_)
@@ -71,9 +86,26 @@
// checksums match the correct md5 data, then the test is passed. Otherwise,
// the test failed.
TEST_P(TestVectorTest, MD5Match) {
- const std::string filename = GET_PARAM(1);
+ const DecodeParam input = GET_PARAM(1);
+ const std::string filename = std::tr1::get<kFileName>(input);
+ const int threads = std::tr1::get<kThreads>(input);
+ const int mode = std::tr1::get<kDecodeMode>(input);
libvpx_test::CompressedVideoSource *video = NULL;
+ vpx_codec_flags_t flags = 0;
+ vpx_codec_dec_cfg_t cfg = {0};
+ char str[256];
+ if (mode == kFrameParallMode) {
+ flags |= VPX_CODEC_USE_FRAME_THREADING;
+ }
+
+ cfg.threads = threads;
+
+ snprintf(str, sizeof(str) / sizeof(str[0]) - 1,
+ "file: %s mode: %s threads: %d",
+ filename.c_str(), mode == 0 ? "Serial" : "Parallel", threads);
+ SCOPED_TRACE(str);
+
// Open compressed video file.
if (filename.substr(filename.length() - 3, 3) == "ivf") {
video = new libvpx_test::IVFVideoSource(filename);
@@ -92,18 +124,53 @@
const std::string md5_filename = filename + ".md5";
OpenMD5File(md5_filename);
+ // Set decode config and flags.
+ set_cfg(cfg);
+ set_flags(flags);
+
// Decode frame, and check the md5 matching.
ASSERT_NO_FATAL_FAILURE(RunLoop(video));
delete video;
}
-VP8_INSTANTIATE_TEST_CASE(TestVectorTest,
- ::testing::ValuesIn(libvpx_test::kVP8TestVectors,
- libvpx_test::kVP8TestVectors +
- libvpx_test::kNumVP8TestVectors));
-VP9_INSTANTIATE_TEST_CASE(TestVectorTest,
- ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
- libvpx_test::kVP9TestVectors +
- libvpx_test::kNumVP9TestVectors));
+// Test VP8 decode in serial mode with single thread.
+// NOTE: VP8 only support serial mode.
+INSTANTIATE_TEST_CASE_P(
+ VP8, TestVectorTest,
+ ::testing::Combine(
+ ::testing::Values(
+ static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP8)),
+ ::testing::Combine(
+ ::testing::Values(0), // Serial Mode.
+ ::testing::Values(1), // Single thread.
+ ::testing::ValuesIn(libvpx_test::kVP8TestVectors,
+ libvpx_test::kVP8TestVectors +
+ libvpx_test::kNumVP8TestVectors))));
+// Test VP9 decode in serial mode with single thread.
+INSTANTIATE_TEST_CASE_P(
+ VP9, TestVectorTest,
+ ::testing::Combine(
+ ::testing::Values(
+ static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)),
+ ::testing::Combine(
+ ::testing::Values(0), // Serial Mode.
+ ::testing::Values(1), // Single thread.
+ ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
+ libvpx_test::kVP9TestVectors +
+ libvpx_test::kNumVP9TestVectors))));
+
+
+// Test VP9 decode in frame parallel mode with different number of threads.
+INSTANTIATE_TEST_CASE_P(
+ VP9MultiThreadedFrameParallel, TestVectorTest,
+ ::testing::Combine(
+ ::testing::Values(
+ static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)),
+ ::testing::Combine(
+ ::testing::Values(1), // Frame Parallel mode.
+ ::testing::Values(2, 3, 4), // With 2, 3, 4 threads.
+ ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
+ libvpx_test::kVP9TestVectors +
+ libvpx_test::kNumVP9TestVectors))));
} // namespace