1 /* 2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <string> 12 13 #include "third_party/googletest/src/include/gtest/gtest.h" 14 #include "test/codec_factory.h" 15 #include "test/decode_test_driver.h" 16 #include "test/md5_helper.h" 17 #include "test/webm_video_source.h" 18 #include "vp9/decoder/vp9_thread.h" 19 20 namespace { 21 22 using std::string; 23 24 class VP9WorkerThreadTest : public ::testing::TestWithParam<bool> { 25 protected: 26 virtual ~VP9WorkerThreadTest() {} 27 virtual void SetUp() { 28 vp9_worker_init(&worker_); 29 } 30 31 virtual void TearDown() { 32 vp9_worker_end(&worker_); 33 } 34 35 VP9Worker worker_; 36 }; 37 38 int ThreadHook(void* data, void* return_value) { 39 int* const hook_data = reinterpret_cast<int*>(data); 40 *hook_data = 5; 41 return *reinterpret_cast<int*>(return_value); 42 } 43 44 TEST_P(VP9WorkerThreadTest, HookSuccess) { 45 EXPECT_NE(vp9_worker_sync(&worker_), 0); // should be a no-op. 46 47 for (int i = 0; i < 2; ++i) { 48 EXPECT_NE(vp9_worker_reset(&worker_), 0); 49 50 int hook_data = 0; 51 int return_value = 1; // return successfully from the hook 52 worker_.hook = ThreadHook; 53 worker_.data1 = &hook_data; 54 worker_.data2 = &return_value; 55 56 const bool synchronous = GetParam(); 57 if (synchronous) { 58 vp9_worker_execute(&worker_); 59 } else { 60 vp9_worker_launch(&worker_); 61 } 62 EXPECT_NE(vp9_worker_sync(&worker_), 0); 63 EXPECT_FALSE(worker_.had_error); 64 EXPECT_EQ(5, hook_data); 65 66 EXPECT_NE(vp9_worker_sync(&worker_), 0); // should be a no-op. 67 } 68 } 69 70 TEST_P(VP9WorkerThreadTest, HookFailure) { 71 EXPECT_NE(vp9_worker_reset(&worker_), 0); 72 73 int hook_data = 0; 74 int return_value = 0; // return failure from the hook 75 worker_.hook = ThreadHook; 76 worker_.data1 = &hook_data; 77 worker_.data2 = &return_value; 78 79 const bool synchronous = GetParam(); 80 if (synchronous) { 81 vp9_worker_execute(&worker_); 82 } else { 83 vp9_worker_launch(&worker_); 84 } 85 EXPECT_FALSE(vp9_worker_sync(&worker_)); 86 EXPECT_EQ(1, worker_.had_error); 87 88 // Ensure _reset() clears the error and _launch() can be called again. 89 return_value = 1; 90 EXPECT_NE(vp9_worker_reset(&worker_), 0); 91 EXPECT_FALSE(worker_.had_error); 92 vp9_worker_launch(&worker_); 93 EXPECT_NE(vp9_worker_sync(&worker_), 0); 94 EXPECT_FALSE(worker_.had_error); 95 } 96 97 // ----------------------------------------------------------------------------- 98 // Multi-threaded decode tests 99 100 // Decodes |filename| with |num_threads|. Returns the md5 of the decoded frames. 101 string DecodeFile(const string& filename, int num_threads) { 102 libvpx_test::WebMVideoSource video(filename); 103 video.Init(); 104 105 vpx_codec_dec_cfg_t cfg = {0}; 106 cfg.threads = num_threads; 107 libvpx_test::VP9Decoder decoder(cfg, 0); 108 109 libvpx_test::MD5 md5; 110 for (video.Begin(); video.cxdata(); video.Next()) { 111 const vpx_codec_err_t res = 112 decoder.DecodeFrame(video.cxdata(), video.frame_size()); 113 if (res != VPX_CODEC_OK) { 114 EXPECT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError(); 115 break; 116 } 117 118 libvpx_test::DxDataIterator dec_iter = decoder.GetDxData(); 119 const vpx_image_t *img = NULL; 120 121 // Get decompressed data 122 while ((img = dec_iter.Next())) { 123 md5.Add(img); 124 } 125 } 126 return string(md5.Get()); 127 } 128 129 TEST(VP9DecodeMTTest, MTDecode) { 130 // no tiles or frame parallel; this exercises loop filter threading. 131 EXPECT_STREQ("b35a1b707b28e82be025d960aba039bc", 132 DecodeFile("vp90-2-03-size-226x226.webm", 2).c_str()); 133 } 134 135 TEST(VP9DecodeMTTest, MTDecode2) { 136 static const struct { 137 const char *name; 138 const char *expected_md5; 139 } files[] = { 140 { "vp90-2-08-tile_1x2_frame_parallel.webm", 141 "68ede6abd66bae0a2edf2eb9232241b6" }, 142 { "vp90-2-08-tile_1x4_frame_parallel.webm", 143 "368ebc6ebf3a5e478d85b2c3149b2848" }, 144 }; 145 146 for (int i = 0; i < static_cast<int>(sizeof(files) / sizeof(files[0])); ++i) { 147 for (int t = 2; t <= 4; ++t) { 148 EXPECT_STREQ(files[i].expected_md5, DecodeFile(files[i].name, t).c_str()) 149 << "threads = " << t; 150 } 151 } 152 } 153 154 INSTANTIATE_TEST_CASE_P(Synchronous, VP9WorkerThreadTest, ::testing::Bool()); 155 156 } // namespace 157