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

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

Issue 2760513002: h264_decoder_unittests: Initial Change. (Closed)
Patch Set: 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
« media/gpu/BUILD.gn ('K') | « media/gpu/BUILD.gn ('k') | no next file » | 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";
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 }
OLDNEW
« media/gpu/BUILD.gn ('K') | « media/gpu/BUILD.gn ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698