Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: media/gpu/h264_decoder_unittest.cc

Issue 2760513002: h264_decoder_unittests: Initial Change. (Closed)
Patch Set: Address kcwu's comments. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/gpu/BUILD.gn ('k') | media/gpu/h264_dpb.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « media/gpu/BUILD.gn ('k') | media/gpu/h264_dpb.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698