OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <stdint.h> | |
6 #include <string.h> | |
7 | |
8 #include <memory> | |
9 #include <queue> | |
10 #include <string> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/command_line.h" | |
14 #include "base/files/file_util.h" | |
15 #include "base/logging.h" | |
16 #include "media/base/test_data_util.h" | |
17 #include "media/gpu/h264_decoder.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 | |
20 namespace media { | |
21 namespace { | |
22 | |
23 const char* kBaselineFrame0 = "bear-320x192-baseline-frame-0.h264"; | |
kcwu
2017/03/17 06:47:44
Forgot to git add?
Owen Lin
2017/03/20 08:00:05
It was in another CL, but I have merge the two CL
| |
24 const char* kBaselineFrame1 = "bear-320x192-baseline-frame-1.h264"; | |
25 const char* kBaselineFrame2 = "bear-320x192-baseline-frame-2.h264"; | |
26 const char* kBaselineFrame3 = "bear-320x192-baseline-frame-3.h264"; | |
27 const char* kHighFrame0 = "bear-320x192-high-frame-0.h264"; | |
28 const char* kHighFrame1 = "bear-320x192-high-frame-1.h264"; | |
29 const char* kHighFrame2 = "bear-320x192-high-frame-2.h264"; | |
30 const char* kHighFrame3 = "bear-320x192-high-frame-3.h264"; | |
31 | |
32 // Forward declaration | |
33 class FakeH264Accelerator; | |
34 | |
35 class H264DecoderTest : public ::testing::Test { | |
36 public: | |
37 // The events we used to verify the correctness. Will check if these | |
38 // events are triggers in order. | |
39 struct Event { | |
40 enum Type { | |
41 CREATE_H264_PICTURE, | |
42 SUBMIT_DECODE, | |
43 OUTPUT_PICTURE, | |
44 RAN_OUT_OF_SURFACES, | |
45 NEED_CONTEXT_UPDATE, | |
46 ALLOCATE_NEW_SURFACES, | |
47 DECODE_ERROR, | |
48 }; | |
49 | |
50 Type type; | |
51 | |
52 Event(Type type) : type(type) {} | |
53 }; | |
54 | |
55 // The specialize Event for OutputPicture as we will also check the POC. | |
56 struct OutputPictureEvent : public Event { | |
57 int pic_order_cnt; | |
58 | |
59 OutputPictureEvent(int pic_order_cnt) | |
60 : Event(OUTPUT_PICTURE), pic_order_cnt(pic_order_cnt) {} | |
61 }; | |
62 | |
63 // Function called when an event dispatch to the test. | |
64 typedef std::function<void(const Event& event)> EventHandler; | |
kcwu
2017/03/17 06:47:43
Suggest to use c++11's "using" syntax.
Owen Lin
2017/03/20 08:00:05
Done.
| |
65 | |
66 H264DecoderTest() {} | |
67 | |
68 void SetUp() override; | |
69 | |
70 // Helper function to feed bitstreams. | |
71 void FeedData(std::vector<const char*> frames); | |
72 | |
73 // Called when an event happens. | |
74 void OnEvent(const Event& event); | |
75 | |
76 // Expects the specified event will be dispatched to the test. When it | |
77 // happens, handler will be called. The expected events will be queued. | |
78 // This function could be called multiple times and we expect those | |
79 // events will happen in order. | |
80 void ExpectEvent(Event::Type type, EventHandler handler = {}); | |
81 | |
82 // Expects the decoder output a picture with the specified POC.. | |
83 void ExpectOutputPictureWithPoc(int expected_poc); | |
84 | |
85 // Verifies there is no more expected events in the queue. | |
86 void VerifyNoMoreExpectedEvents(); | |
87 | |
88 protected: | |
89 std::unique_ptr<H264Decoder> decoder_; | |
90 std::unique_ptr<FakeH264Accelerator> accelerator_; | |
91 | |
92 private: | |
93 struct ExpectedEvent { | |
94 Event::Type type; | |
95 EventHandler handler; | |
96 | |
97 ExpectedEvent(Event::Type type, EventHandler handler) | |
98 : type(type), handler(handler) {} | |
99 }; | |
100 | |
101 std::queue<ExpectedEvent> expected_events_; | |
102 }; | |
103 | |
104 class FakeH264Accelerator : public H264Decoder::H264Accelerator { | |
kcwu
2017/03/17 06:47:43
Have you considered using gmock?
Owen Lin
2017/03/20 08:00:04
I don't think using mock will simplify the code or
| |
105 public: | |
106 FakeH264Accelerator(H264DecoderTest* test) : test_(test) {} | |
107 | |
108 scoped_refptr<H264Picture> CreateH264Picture() override { | |
109 if (new_picture_quota_ > 0) { | |
110 --new_picture_quota_; | |
111 return new H264Picture(); | |
112 } | |
113 return nullptr; | |
114 } | |
115 | |
116 // Implementations of H264Decoder::H264Accelerator interface. | |
117 | |
118 bool SubmitFrameMetadata(const H264SPS* sps, | |
119 const H264PPS* pps, | |
120 const H264DPB& dpb, | |
121 const H264Picture::Vector& ref_pic_listp0, | |
122 const H264Picture::Vector& ref_pic_listb0, | |
123 const H264Picture::Vector& ref_pic_listb1, | |
124 const scoped_refptr<H264Picture>& pic) override { | |
125 return true; | |
126 } | |
127 | |
128 bool SubmitSlice(const H264PPS* pps, | |
129 const H264SliceHeader* slice_hdr, | |
130 const H264Picture::Vector& ref_pic_list0, | |
131 const H264Picture::Vector& ref_pic_list1, | |
132 const scoped_refptr<H264Picture>& pic, | |
133 const uint8_t* data, | |
134 size_t size) override { | |
135 return true; | |
136 } | |
137 | |
138 bool SubmitDecode(const scoped_refptr<H264Picture>& pic) override { | |
139 test_->OnEvent(H264DecoderTest::Event::SUBMIT_DECODE); | |
140 return true; | |
141 } | |
142 | |
143 bool OutputPicture(const scoped_refptr<H264Picture>& pic) override { | |
144 test_->OnEvent(H264DecoderTest::OutputPictureEvent(pic->pic_order_cnt)); | |
145 return true; | |
146 } | |
147 | |
148 void Reset() override {} | |
149 | |
150 // How many times CreateH264Picture() will returns valid H264Picture. | |
151 void SetNewPictureQuota(size_t quota) { new_picture_quota_ = quota; } | |
152 | |
153 size_t GetNewPictureQuota() const { return new_picture_quota_; } | |
154 | |
155 private: | |
156 H264DecoderTest* test_; | |
157 size_t new_picture_quota_ = 0; | |
158 }; | |
159 | |
160 std::ostream& operator<<(std::ostream& os, | |
161 const H264DecoderTest::Event::Type type) { | |
162 switch (type) { | |
163 case H264DecoderTest::Event::CREATE_H264_PICTURE: | |
164 return os << "CreateH264Picture"; | |
165 case H264DecoderTest::Event::SUBMIT_DECODE: | |
166 return os << "SubmitDecode"; | |
167 case H264DecoderTest::Event::OUTPUT_PICTURE: | |
168 return os << "OutputPicture"; | |
169 case H264DecoderTest::Event::RAN_OUT_OF_SURFACES: | |
170 return os << "RanOutOfSurfaces"; | |
171 case H264DecoderTest::Event::NEED_CONTEXT_UPDATE: | |
172 return os << "NeedContextUpdate"; | |
173 case H264DecoderTest::Event::ALLOCATE_NEW_SURFACES: | |
174 return os << "AllocateNewSurfaces"; | |
175 case H264DecoderTest::Event::DECODE_ERROR: | |
176 return os << "DecodeError"; | |
177 } | |
178 return os; | |
179 } | |
180 | |
181 std::ostream& operator<<(std::ostream& os, const H264DecoderTest::Event& e) { | |
182 switch (e.type) { | |
183 case H264DecoderTest::Event::OUTPUT_PICTURE: { | |
184 const H264DecoderTest::OutputPictureEvent& event = | |
185 static_cast<const H264DecoderTest::OutputPictureEvent&>(e); | |
186 return os << e.type << "(poc=" << event.pic_order_cnt << ")"; | |
187 } | |
188 default: | |
189 return os << e.type; | |
190 } | |
191 } | |
192 | |
193 void H264DecoderTest::SetUp() { | |
194 accelerator_.reset(new FakeH264Accelerator(this)); | |
195 decoder_.reset(new H264Decoder(accelerator_.get())); | |
196 } | |
197 | |
198 void H264DecoderTest::FeedData(std::vector<const char*> frames) { | |
199 std::string bitstream; | |
200 auto frame_iter = frames.begin(); | |
201 while (true) { | |
202 switch (decoder_->Decode()) { | |
203 case AcceleratedVideoDecoder::kAllocateNewSurfaces: | |
204 ASSERT_NO_FATAL_FAILURE(OnEvent(Event::ALLOCATE_NEW_SURFACES)); | |
205 break; | |
206 case AcceleratedVideoDecoder::kRanOutOfStreamData: { | |
207 if (frame_iter == frames.end()) | |
208 return; | |
209 base::FilePath input_file = GetTestDataFilePath(*frame_iter++); | |
210 ASSERT_TRUE(base::ReadFileToString(input_file, &bitstream)) | |
211 << "failed to read input data from " << input_file.value(); | |
212 decoder_->SetStream(reinterpret_cast<const uint8_t*>(bitstream.data()), | |
213 bitstream.size()); | |
214 break; | |
215 } | |
216 case AcceleratedVideoDecoder::kRanOutOfSurfaces: | |
217 ASSERT_NO_FATAL_FAILURE(OnEvent(Event::RAN_OUT_OF_SURFACES)); | |
218 break; | |
219 case AcceleratedVideoDecoder::kNeedContextUpdate: | |
220 ASSERT_NO_FATAL_FAILURE(OnEvent(Event::NEED_CONTEXT_UPDATE)); | |
221 break; | |
222 case AcceleratedVideoDecoder::kDecodeError: | |
223 ASSERT_NO_FATAL_FAILURE(OnEvent(Event::DECODE_ERROR)); | |
224 break; | |
225 } | |
226 } | |
227 } | |
228 | |
229 void H264DecoderTest::OnEvent(const Event& event) { | |
230 VLOG(2) << "OnEvent(" << event << ")"; | |
231 ASSERT_FALSE(expected_events_.empty()) << "Unexpected event"; | |
232 ExpectedEvent ee = expected_events_.front(); | |
233 expected_events_.pop(); | |
234 ASSERT_EQ(ee.type, event.type); | |
235 if (ee.handler) | |
236 ASSERT_NO_FATAL_FAILURE(ee.handler(event)); | |
237 } | |
238 | |
239 void H264DecoderTest::ExpectEvent(Event::Type type, EventHandler handler) { | |
240 expected_events_.push({type, handler}); | |
241 } | |
242 | |
243 void H264DecoderTest::ExpectOutputPictureWithPoc(int expected_poc) { | |
244 ExpectEvent(Event::OUTPUT_PICTURE, [expected_poc](const Event& e) { | |
245 auto event = static_cast<const OutputPictureEvent&>(e); | |
246 EXPECT_EQ(expected_poc, event.pic_order_cnt); | |
247 }); | |
248 } | |
249 | |
250 void H264DecoderTest::VerifyNoMoreExpectedEvents() { | |
251 ASSERT_EQ(0u, expected_events_.size()); | |
kcwu
2017/03/17 06:47:43
1. IIRC, we prefer inline this kind of assertions
Owen Lin
2017/03/20 08:00:04
I agree.
kcwu
2017/03/20 08:28:09
You forgot to change code?
Owen Lin
2017/03/20 09:29:27
Done.
| |
252 } | |
253 | |
254 // Test Cases | |
255 | |
256 TEST_F(H264DecoderTest, DecodeSingleFrame) { | |
257 ExpectEvent(Event::ALLOCATE_NEW_SURFACES, [&](const Event&) { | |
258 EXPECT_EQ(decoder_->GetPicSize(), gfx::Size(320, 192)); | |
259 }); | |
260 | |
261 ExpectEvent(Event::RAN_OUT_OF_SURFACES, | |
262 [&](const Event&) { accelerator_->SetNewPictureQuota(1); }); | |
263 | |
264 ExpectEvent(Event::SUBMIT_DECODE); | |
265 ExpectEvent(Event::OUTPUT_PICTURE); | |
266 | |
267 ASSERT_NO_FATAL_FAILURE(FeedData({kBaselineFrame0})); | |
268 ASSERT_TRUE(decoder_->Flush()); | |
269 | |
270 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
271 VerifyNoMoreExpectedEvents(); | |
272 } | |
273 | |
274 TEST_F(H264DecoderTest, SkipNoneIDRFrames) { | |
275 ExpectEvent(Event::ALLOCATE_NEW_SURFACES, [&](const Event&) { | |
276 EXPECT_EQ(decoder_->GetPicSize(), gfx::Size(320, 192)); | |
277 }); | |
278 | |
279 ExpectEvent(Event::SUBMIT_DECODE); | |
280 ExpectOutputPictureWithPoc(0); | |
281 | |
282 accelerator_->SetNewPictureQuota(1); | |
283 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
284 kBaselineFrame1, kBaselineFrame2, kBaselineFrame0, | |
285 })); | |
286 ASSERT_TRUE(decoder_->Flush()); | |
287 | |
288 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
289 VerifyNoMoreExpectedEvents(); | |
290 } | |
291 | |
292 TEST_F(H264DecoderTest, DecodeProfileBaseline) { | |
293 accelerator_->SetNewPictureQuota(4); | |
294 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
295 ExpectEvent(Event::SUBMIT_DECODE); | |
296 ExpectOutputPictureWithPoc(0); | |
297 ExpectEvent(Event::SUBMIT_DECODE); | |
298 ExpectOutputPictureWithPoc(2); | |
299 ExpectEvent(Event::SUBMIT_DECODE); | |
300 ExpectOutputPictureWithPoc(4); | |
301 ExpectEvent(Event::SUBMIT_DECODE); | |
302 ExpectOutputPictureWithPoc(6); | |
303 | |
304 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
305 kBaselineFrame0, kBaselineFrame1, kBaselineFrame2, kBaselineFrame3, | |
306 })); | |
307 ASSERT_TRUE(decoder_->Flush()); | |
308 | |
309 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
310 VerifyNoMoreExpectedEvents(); | |
311 } | |
312 | |
313 TEST_F(H264DecoderTest, DecodeProfileHigh) { | |
314 accelerator_->SetNewPictureQuota(4); | |
315 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
316 | |
317 // Two pictures will be kept in DPB for reordering. The first picture should | |
318 // be outputted after feeding the third frame. | |
319 ExpectEvent(Event::SUBMIT_DECODE); | |
320 ExpectEvent(Event::SUBMIT_DECODE); | |
321 ExpectEvent(Event::SUBMIT_DECODE); | |
322 ExpectOutputPictureWithPoc(0); | |
323 ExpectEvent(Event::SUBMIT_DECODE); | |
324 ExpectOutputPictureWithPoc(2); | |
325 ExpectOutputPictureWithPoc(4); | |
326 ExpectOutputPictureWithPoc(6); | |
327 | |
328 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
329 kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3, | |
330 })); | |
331 ASSERT_TRUE(decoder_->Flush()); | |
332 | |
333 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
334 VerifyNoMoreExpectedEvents(); | |
335 } | |
336 | |
337 TEST_F(H264DecoderTest, SwitchBaselineToHigh) { | |
338 accelerator_->SetNewPictureQuota(5); | |
339 | |
340 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
341 ExpectEvent(Event::SUBMIT_DECODE); | |
342 ExpectOutputPictureWithPoc(0); | |
343 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
344 ExpectEvent(Event::SUBMIT_DECODE); | |
345 ExpectEvent(Event::SUBMIT_DECODE); | |
346 ExpectEvent(Event::SUBMIT_DECODE); | |
347 ExpectOutputPictureWithPoc(0); | |
348 ExpectEvent(Event::SUBMIT_DECODE); | |
349 ExpectOutputPictureWithPoc(2); | |
350 ExpectOutputPictureWithPoc(4); | |
351 ExpectOutputPictureWithPoc(6); | |
352 | |
353 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
354 kBaselineFrame0, kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3, | |
355 })); | |
356 ASSERT_TRUE(decoder_->Flush()); | |
357 | |
358 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
359 VerifyNoMoreExpectedEvents(); | |
360 } | |
361 | |
362 TEST_F(H264DecoderTest, SwitchHighToBaseline) { | |
363 accelerator_->SetNewPictureQuota(5); | |
364 | |
365 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
366 ExpectEvent(Event::SUBMIT_DECODE); | |
367 ExpectOutputPictureWithPoc(0); | |
368 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
369 ExpectEvent(Event::SUBMIT_DECODE); | |
370 ExpectOutputPictureWithPoc(0); | |
371 ExpectEvent(Event::SUBMIT_DECODE); | |
372 ExpectOutputPictureWithPoc(2); | |
373 ExpectEvent(Event::SUBMIT_DECODE); | |
374 ExpectOutputPictureWithPoc(4); | |
375 ExpectEvent(Event::SUBMIT_DECODE); | |
376 ExpectOutputPictureWithPoc(6); | |
377 | |
378 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
379 kHighFrame0, kBaselineFrame0, kBaselineFrame1, kBaselineFrame2, | |
380 kBaselineFrame3, | |
381 })); | |
382 ASSERT_TRUE(decoder_->Flush()); | |
383 | |
384 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
385 VerifyNoMoreExpectedEvents(); | |
386 } | |
387 | |
388 } // namespace | |
389 } // namespace media | |
390 | |
391 int main(int argc, char** argv) { | |
392 testing::InitGoogleTest(&argc, argv); | |
393 base::CommandLine::Init(argc, argv); | |
394 | |
395 // Needed to enable DVLOG through --vmodule. | |
396 logging::LoggingSettings settings; | |
397 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; | |
398 LOG_ASSERT(logging::InitLogging(settings)); | |
399 | |
400 return RUN_ALL_TESTS(); | |
401 } | |
OLD | NEW |