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"; | |
Pawel Osciak
2017/03/23 08:34:21
Perhaps const std::string, as GetTestDataFilePath(
Owen Lin
2017/06/21 07:37:29
Done.
| |
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 | |
Pawel Osciak
2017/03/23 08:34:20
Nit: comment perhaps not needed.
Owen Lin
2017/06/21 07:37:29
Done.
| |
33 class FakeH264Accelerator; | |
34 | |
35 class H264DecoderTest : public ::testing::Test { | |
Pawel Osciak
2017/03/23 08:34:21
Please add a comment what this test is for.
Owen Lin
2017/06/21 07:37:29
Done.
| |
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 { | |
Pawel Osciak
2017/03/23 08:34:20
enum class?
Owen Lin
2017/06/21 07:37:28
Done.
| |
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) {} | |
Pawel Osciak
2017/03/23 08:34:20
explicit?
Owen Lin
2017/06/21 07:37:29
You're right. Implicit conversion is not allowed.
| |
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 using EventHandler = std::function<void(const Event& event)>; | |
Pawel Osciak
2017/03/23 08:34:20
std::function is not allowed per Chromium coding s
Owen Lin
2017/06/21 07:37:29
Done.
| |
65 | |
66 H264DecoderTest() {} | |
Pawel Osciak
2017/03/23 08:34:20
= default; perhaps?
Owen Lin
2017/06/21 07:37:29
Done.
| |
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 // Gets the number of remaining expected events. | |
86 size_t GetNumberOfExpectedEvents() const { return expected_events_.size(); } | |
DaleCurtis
2017/03/21 18:07:18
Inline should be hacker_style().
Owen Lin
2017/06/21 07:37:29
Done.
| |
87 | |
88 protected: | |
Pawel Osciak
2017/03/23 08:34:20
Do we need protected instead of private?
Owen Lin
2017/06/21 07:37:29
Some tests can directly access these members.
| |
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 { | |
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(); | |
Pawel Osciak
2017/03/23 08:34:20
To mimic the actual behavior of the accelerator, w
Owen Lin
2017/06/21 07:37:29
It sounds like we should add some tests about free
Pawel Osciak
2017/06/23 02:07:34
Acknowledged.
| |
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); | |
Pawel Osciak
2017/03/23 08:34:20
Perhaps we could instead have a virtual AsString()
Owen Lin
2017/06/21 07:37:29
Done. But follow most namings in chromium as ToStr
| |
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) { | |
Pawel Osciak
2017/03/23 08:34:20
Perhaps const vector<std::string>&?
Owen Lin
2017/06/21 07:37:29
Done.
| |
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) { | |
Pawel Osciak
2017/03/23 08:34:20
Should this take ownership of handler here and whe
Owen Lin
2017/06/21 07:37:29
I did some code study I think
we should pass by r
| |
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 // Test Cases | |
251 | |
252 TEST_F(H264DecoderTest, DecodeSingleFrame) { | |
253 ExpectEvent(Event::ALLOCATE_NEW_SURFACES, [&](const Event&) { | |
254 EXPECT_EQ(decoder_->GetPicSize(), gfx::Size(320, 192)); | |
Pawel Osciak
2017/03/23 08:34:20
Perhaps have another specialization of Event for A
kcwu
2017/03/23 08:54:33
Please swap the arguments.
They are read as EXPECT
Owen Lin
2017/06/21 07:37:29
Done.
Owen Lin
2017/06/21 07:37:29
Done.
| |
255 }); | |
256 | |
257 ExpectEvent(Event::RAN_OUT_OF_SURFACES, | |
258 [&](const Event&) { accelerator_->SetNewPictureQuota(1); }); | |
259 | |
260 ExpectEvent(Event::SUBMIT_DECODE); | |
261 ExpectEvent(Event::OUTPUT_PICTURE); | |
262 | |
263 ASSERT_NO_FATAL_FAILURE(FeedData({kBaselineFrame0})); | |
264 ASSERT_TRUE(decoder_->Flush()); | |
265 | |
266 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
267 EXPECT_EQ(0u, GetNumberOfExpectedEvents()); | |
268 } | |
269 | |
270 TEST_F(H264DecoderTest, SkipNoneIDRFrames) { | |
271 ExpectEvent(Event::ALLOCATE_NEW_SURFACES, [&](const Event&) { | |
272 EXPECT_EQ(decoder_->GetPicSize(), gfx::Size(320, 192)); | |
kcwu
2017/03/23 08:54:33
Please swap the arguments.
They are read as EXPECT
Owen Lin
2017/06/21 07:37:29
Done.
| |
273 }); | |
274 | |
275 ExpectEvent(Event::SUBMIT_DECODE); | |
276 ExpectOutputPictureWithPoc(0); | |
277 | |
278 accelerator_->SetNewPictureQuota(1); | |
279 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
280 kBaselineFrame1, kBaselineFrame2, kBaselineFrame0, | |
281 })); | |
282 ASSERT_TRUE(decoder_->Flush()); | |
283 | |
284 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
285 EXPECT_EQ(0u, GetNumberOfExpectedEvents()); | |
286 } | |
287 | |
288 TEST_F(H264DecoderTest, DecodeProfileBaseline) { | |
289 accelerator_->SetNewPictureQuota(4); | |
Pawel Osciak
2017/03/23 08:34:21
Should we perhaps SetNewPictureQuota() in the ALLO
Owen Lin
2017/06/21 07:37:29
I would prefer we focus on one thing we are testin
Pawel Osciak
2017/06/23 02:07:34
Acknowledged.
| |
290 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
291 ExpectEvent(Event::SUBMIT_DECODE); | |
292 ExpectOutputPictureWithPoc(0); | |
293 ExpectEvent(Event::SUBMIT_DECODE); | |
294 ExpectOutputPictureWithPoc(2); | |
295 ExpectEvent(Event::SUBMIT_DECODE); | |
296 ExpectOutputPictureWithPoc(4); | |
297 ExpectEvent(Event::SUBMIT_DECODE); | |
298 ExpectOutputPictureWithPoc(6); | |
299 | |
300 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
301 kBaselineFrame0, kBaselineFrame1, kBaselineFrame2, kBaselineFrame3, | |
302 })); | |
303 ASSERT_TRUE(decoder_->Flush()); | |
304 | |
305 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
306 EXPECT_EQ(0u, GetNumberOfExpectedEvents()); | |
307 } | |
308 | |
309 TEST_F(H264DecoderTest, DecodeProfileHigh) { | |
310 accelerator_->SetNewPictureQuota(4); | |
311 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
312 | |
313 // Two pictures will be kept in DPB for reordering. The first picture should | |
314 // be outputted after feeding the third frame. | |
315 ExpectEvent(Event::SUBMIT_DECODE); | |
316 ExpectEvent(Event::SUBMIT_DECODE); | |
317 ExpectEvent(Event::SUBMIT_DECODE); | |
318 ExpectOutputPictureWithPoc(0); | |
319 ExpectEvent(Event::SUBMIT_DECODE); | |
320 ExpectOutputPictureWithPoc(2); | |
321 ExpectOutputPictureWithPoc(4); | |
322 ExpectOutputPictureWithPoc(6); | |
323 | |
324 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
325 kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3, | |
326 })); | |
327 ASSERT_TRUE(decoder_->Flush()); | |
328 | |
329 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
330 EXPECT_EQ(0u, GetNumberOfExpectedEvents()); | |
331 } | |
332 | |
333 TEST_F(H264DecoderTest, SwitchBaselineToHigh) { | |
334 accelerator_->SetNewPictureQuota(5); | |
335 | |
336 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
337 ExpectEvent(Event::SUBMIT_DECODE); | |
338 ExpectOutputPictureWithPoc(0); | |
339 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
340 ExpectEvent(Event::SUBMIT_DECODE); | |
341 ExpectEvent(Event::SUBMIT_DECODE); | |
342 ExpectEvent(Event::SUBMIT_DECODE); | |
343 ExpectOutputPictureWithPoc(0); | |
344 ExpectEvent(Event::SUBMIT_DECODE); | |
345 ExpectOutputPictureWithPoc(2); | |
346 ExpectOutputPictureWithPoc(4); | |
347 ExpectOutputPictureWithPoc(6); | |
348 | |
349 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
350 kBaselineFrame0, kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3, | |
351 })); | |
352 ASSERT_TRUE(decoder_->Flush()); | |
353 | |
354 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
355 EXPECT_EQ(0u, GetNumberOfExpectedEvents()); | |
356 } | |
357 | |
358 TEST_F(H264DecoderTest, SwitchHighToBaseline) { | |
359 accelerator_->SetNewPictureQuota(5); | |
360 | |
361 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
362 ExpectEvent(Event::SUBMIT_DECODE); | |
363 ExpectOutputPictureWithPoc(0); | |
364 ExpectEvent(Event::ALLOCATE_NEW_SURFACES); | |
365 ExpectEvent(Event::SUBMIT_DECODE); | |
366 ExpectOutputPictureWithPoc(0); | |
367 ExpectEvent(Event::SUBMIT_DECODE); | |
368 ExpectOutputPictureWithPoc(2); | |
369 ExpectEvent(Event::SUBMIT_DECODE); | |
370 ExpectOutputPictureWithPoc(4); | |
371 ExpectEvent(Event::SUBMIT_DECODE); | |
372 ExpectOutputPictureWithPoc(6); | |
373 | |
374 ASSERT_NO_FATAL_FAILURE(FeedData({ | |
375 kHighFrame0, kBaselineFrame0, kBaselineFrame1, kBaselineFrame2, | |
376 kBaselineFrame3, | |
377 })); | |
378 ASSERT_TRUE(decoder_->Flush()); | |
379 | |
380 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota()); | |
381 EXPECT_EQ(0u, GetNumberOfExpectedEvents()); | |
382 } | |
383 | |
384 } // namespace | |
385 } // namespace media | |
OLD | NEW |