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

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

Issue 2760513002: h264_decoder_unittests: Initial Change. (Closed)
Patch Set: Address review comments from posciak. Created 3 years, 6 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 "base/strings/stringprintf.h"
17 #include "media/base/test_data_util.h"
18 #include "media/gpu/h264_decoder.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace media {
22 namespace {
23
24 const std::string kBaselineFrame0 = "bear-320x192-baseline-frame-0.h264";
25 const std::string kBaselineFrame1 = "bear-320x192-baseline-frame-1.h264";
26 const std::string kBaselineFrame2 = "bear-320x192-baseline-frame-2.h264";
27 const std::string kBaselineFrame3 = "bear-320x192-baseline-frame-3.h264";
28 const std::string kHighFrame0 = "bear-320x192-high-frame-0.h264";
29 const std::string kHighFrame1 = "bear-320x192-high-frame-1.h264";
30 const std::string kHighFrame2 = "bear-320x192-high-frame-2.h264";
31 const std::string kHighFrame3 = "bear-320x192-high-frame-3.h264";
32
33 class FakeH264Accelerator;
34
35 // Test H264Decoder by feeding different of h264 frame sequences and make
36 // sure it behaves as expected.
37 class H264DecoderTest : public ::testing::Test {
38 public:
39 // The events we used to verify the correctness. Will check if these
40 // events are triggers in order.
Pawel Osciak 2017/06/23 02:07:34 s/triggers/triggered/ Also probably s/in order/at
Owen Lin 2017/06/26 09:09:00 The code is refactored out.
41 enum class EventType {
Pawel Osciak 2017/06/23 02:07:34 Could this be inside the Event class still?
Owen Lin 2017/06/26 09:09:00 Ditto.
42 CREATE_H264_PICTURE,
43 SUBMIT_DECODE,
44 OUTPUT_PICTURE,
45 RAN_OUT_OF_SURFACES,
46 NEED_CONTEXT_UPDATE,
47 ALLOCATE_NEW_SURFACES,
48 DECODE_ERROR,
49 };
50
51 struct Event {
52 EventType type;
53
54 explicit Event(EventType type) : type(type) {}
55 virtual std::string ToString() const;
56 };
57
58 // The specialize Event for OutputPicture as we will also check the POC.
59 struct OutputPictureEvent : public Event {
60 int pic_order_cnt;
61
62 OutputPictureEvent(int pic_order_cnt)
63 : Event(EventType::OUTPUT_PICTURE), pic_order_cnt(pic_order_cnt) {}
64
65 std::string ToString() const override;
66 };
67
68 // Function called when an event dispatch to the test.
69 using EventHandler = base::Callback<void(const Event& event)>;
Pawel Osciak 2017/06/23 02:07:34 Nit: OnceCallback?
Owen Lin 2017/06/26 09:09:00 Done.
70
71 H264DecoderTest() = default;
72
73 void SetUp() override;
74
75 // Helper function to feed bitstreams.
76 void FeedData(const std::vector<std::string>& frames);
77
78 // Called when an event happens.
79 void OnEvent(const Event& event);
80
81 // A candy function to call OnEvent(Event(type)).
82 void OnEvent(const EventType type);
83
84 // Expects the specified event will be dispatched to the test. When it
85 // happens, handler will be called. The expected events will be queued.
86 // This function could be called multiple times and we expect those
87 // events will happen in order.
88 void ExpectEvent(EventType type, const EventHandler& handler = {});
Pawel Osciak 2017/06/23 02:07:34 To be honest it took me a bit to understand the id
Owen Lin 2017/06/26 09:09:00 Same. Code has been removed.
89
90 void ExpectEvent(EventType type, const base::Closure& closure);
Pawel Osciak 2017/06/23 02:07:34 ... this ExpectEventAndRun() ? Do we also need to
Owen Lin 2017/06/26 09:09:00 Ditto.
91
92 // Expects the decoder output a picture with the specified POC..
93 void ExpectOutputPictureWithPoc(int expected_poc);
94
95 // Expects the decoder request for new surfaces of the expected size.
96 void ExpectAllocateNewSurfaces(const gfx::Size& size);
97
98 // Gets the number of remaining expected events.
99 size_t number_of_expected_events() const { return expected_events_.size(); }
100
101 protected:
102 std::unique_ptr<H264Decoder> decoder_;
103 std::unique_ptr<FakeH264Accelerator> accelerator_;
104
105 private:
106 struct ExpectedEvent {
107 EventType type;
108 EventHandler handler;
109
110 ExpectedEvent(EventType type, const EventHandler& handler)
111 : type(type), handler(handler) {}
112 };
113
114 std::queue<ExpectedEvent> expected_events_;
115
116 static void TestOutputPictureEvent(int expected_poc, const Event& e);
117 void TestAllocateNewSurfaceEvent(const gfx::Size& size);
118 };
119
120 class FakeH264Accelerator : public H264Decoder::H264Accelerator {
121 public:
122 FakeH264Accelerator(H264DecoderTest* test) : test_(test) {}
123
124 scoped_refptr<H264Picture> CreateH264Picture() override {
125 if (new_picture_quota_ > 0) {
126 --new_picture_quota_;
127 return new H264Picture();
128 }
129 return nullptr;
130 }
131
132 // Implementations of H264Decoder::H264Accelerator interface.
133
134 bool SubmitFrameMetadata(const H264SPS* sps,
135 const H264PPS* pps,
136 const H264DPB& dpb,
137 const H264Picture::Vector& ref_pic_listp0,
138 const H264Picture::Vector& ref_pic_listb0,
139 const H264Picture::Vector& ref_pic_listb1,
140 const scoped_refptr<H264Picture>& pic) override {
141 return true;
142 }
143
144 bool SubmitSlice(const H264PPS* pps,
145 const H264SliceHeader* slice_hdr,
146 const H264Picture::Vector& ref_pic_list0,
147 const H264Picture::Vector& ref_pic_list1,
148 const scoped_refptr<H264Picture>& pic,
149 const uint8_t* data,
150 size_t size) override {
151 return true;
152 }
153
154 bool SubmitDecode(const scoped_refptr<H264Picture>& pic) override {
155 test_->OnEvent(H264DecoderTest::EventType::SUBMIT_DECODE);
156 return true;
157 }
158
159 bool OutputPicture(const scoped_refptr<H264Picture>& pic) override {
160 test_->OnEvent(H264DecoderTest::OutputPictureEvent(pic->pic_order_cnt));
161 return true;
162 }
163
164 void Reset() override {}
165
166 // How many times CreateH264Picture() will returns valid H264Picture.
167 void SetNewPictureQuota(size_t quota) { new_picture_quota_ = quota; }
168
169 size_t GetNewPictureQuota() const { return new_picture_quota_; }
170
171 private:
172 H264DecoderTest* test_;
173 size_t new_picture_quota_ = 0;
174 };
175
176 std::string H264DecoderTest::Event::ToString() const {
177 switch (type) {
178 case EventType::CREATE_H264_PICTURE:
179 return "CreateH264Picture";
180 case EventType::SUBMIT_DECODE:
181 return "SubmitDecode";
182 case EventType::OUTPUT_PICTURE:
183 return "OutputPicture";
184 case EventType::RAN_OUT_OF_SURFACES:
185 return "RanOutOfSurfaces";
186 case EventType::NEED_CONTEXT_UPDATE:
187 return "NeedContextUpdate";
188 case EventType::ALLOCATE_NEW_SURFACES:
189 return "AllocateNewSurfaces";
190 case EventType::DECODE_ERROR:
191 return "DecodeError";
192 }
193 NOTREACHED();
194 }
195
196 std::string H264DecoderTest::OutputPictureEvent::ToString() const {
197 return base::StringPrintf("%s (poc=%d)", Event::ToString().c_str(),
198 pic_order_cnt);
199 }
200
201 void H264DecoderTest::SetUp() {
202 accelerator_.reset(new FakeH264Accelerator(this));
203 decoder_.reset(new H264Decoder(accelerator_.get()));
204 }
205
206 void H264DecoderTest::FeedData(const std::vector<std::string>& frames) {
207 std::string bitstream;
208 auto frame_iter = frames.begin();
209 while (true) {
210 switch (decoder_->Decode()) {
211 case AcceleratedVideoDecoder::kAllocateNewSurfaces:
212 ASSERT_NO_FATAL_FAILURE(
213 OnEvent(Event(EventType::ALLOCATE_NEW_SURFACES)));
214 break;
215 case AcceleratedVideoDecoder::kRanOutOfStreamData: {
216 if (frame_iter == frames.end())
217 return;
218 base::FilePath input_file = GetTestDataFilePath(*frame_iter++);
219 ASSERT_TRUE(base::ReadFileToString(input_file, &bitstream))
220 << "failed to read input data from " << input_file.value();
221 decoder_->SetStream(reinterpret_cast<const uint8_t*>(bitstream.data()),
222 bitstream.size());
223 break;
224 }
225 case AcceleratedVideoDecoder::kRanOutOfSurfaces:
226 ASSERT_NO_FATAL_FAILURE(OnEvent(EventType::RAN_OUT_OF_SURFACES));
227 break;
228 case AcceleratedVideoDecoder::kNeedContextUpdate:
229 ASSERT_NO_FATAL_FAILURE(OnEvent(EventType::NEED_CONTEXT_UPDATE));
230 break;
231 case AcceleratedVideoDecoder::kDecodeError:
232 ASSERT_NO_FATAL_FAILURE(OnEvent(EventType::DECODE_ERROR));
233 break;
234 }
235 }
236 }
237
238 void H264DecoderTest::OnEvent(const Event& event) {
239 VLOG(2) << "OnEvent(" << event.ToString() << ")";
240 ASSERT_FALSE(expected_events_.empty()) << "Unexpected event";
241 ExpectedEvent ee = expected_events_.front();
242 expected_events_.pop();
243 ASSERT_EQ(ee.type, event.type);
244 if (ee.handler)
245 ASSERT_NO_FATAL_FAILURE(ee.handler.Run(event));
246 }
247
248 void H264DecoderTest::OnEvent(EventType type) {
249 OnEvent(Event(type));
250 }
251
252 void H264DecoderTest::ExpectEvent(EventType type, const EventHandler& handler) {
253 expected_events_.push({type, handler});
254 }
255
256 static void RunClosureAndIgnoreEvent(const base::Closure& closure,
257 const H264DecoderTest::Event&) {
258 closure.Run();
259 }
260
261 void H264DecoderTest::ExpectEvent(EventType type,
262 const base::Closure& closure) {
263 ExpectEvent(type, base::Bind(RunClosureAndIgnoreEvent, closure));
Pawel Osciak 2017/06/23 02:07:34 Are we really ignoring the event here? I think we
Owen Lin 2017/06/26 09:09:00 Ditto.
264 }
265
266 void H264DecoderTest::TestOutputPictureEvent(int expected_poc, const Event& e) {
267 auto event = static_cast<const OutputPictureEvent&>(e);
Pawel Osciak 2017/06/23 02:07:34 Could we instead create a specialized event in Exp
Owen Lin 2017/06/26 09:09:00 Ditto.
268 EXPECT_EQ(expected_poc, event.pic_order_cnt);
269 }
270
271 void H264DecoderTest::ExpectOutputPictureWithPoc(int expected_poc) {
272 ExpectEvent(EventType::OUTPUT_PICTURE,
273 base::Bind(TestOutputPictureEvent, expected_poc));
274 }
275
276 void H264DecoderTest::TestAllocateNewSurfaceEvent(const gfx::Size& size) {
277 EXPECT_EQ(size, decoder_->GetPicSize());
278 }
279
280 void H264DecoderTest::ExpectAllocateNewSurfaces(const gfx::Size& size) {
281 ExpectEvent(EventType::ALLOCATE_NEW_SURFACES,
282 base::Bind(&H264DecoderTest::TestAllocateNewSurfaceEvent,
283 base::Unretained(this), size));
284 }
285
286 // Test Cases
287
288 TEST_F(H264DecoderTest, DecodeSingleFrame) {
289 ExpectAllocateNewSurfaces(gfx::Size(320, 192));
290
291 ExpectEvent(EventType::RAN_OUT_OF_SURFACES,
292 base::Bind(&FakeH264Accelerator::SetNewPictureQuota,
293 base::Unretained(accelerator_.get()), 1));
294
295 ExpectEvent(EventType::SUBMIT_DECODE);
296 ExpectEvent(EventType::OUTPUT_PICTURE);
297
298 ASSERT_NO_FATAL_FAILURE(FeedData({kBaselineFrame0}));
299 ASSERT_TRUE(decoder_->Flush());
300
301 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota());
302 EXPECT_EQ(0u, number_of_expected_events());
303 }
304
305 TEST_F(H264DecoderTest, SkipNoneIDRFrames) {
306 ExpectAllocateNewSurfaces(gfx::Size(320, 192));
307 ExpectEvent(EventType::SUBMIT_DECODE);
308 ExpectOutputPictureWithPoc(0);
309 accelerator_->SetNewPictureQuota(1);
310
311 ASSERT_NO_FATAL_FAILURE(FeedData({
312 kBaselineFrame1, kBaselineFrame2, kBaselineFrame0,
313 }));
314 ASSERT_TRUE(decoder_->Flush());
315
316 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota());
317 EXPECT_EQ(0u, number_of_expected_events());
318 }
319
320 TEST_F(H264DecoderTest, DecodeProfileBaseline) {
321 accelerator_->SetNewPictureQuota(4);
322 ExpectEvent(EventType::ALLOCATE_NEW_SURFACES);
323 ExpectEvent(EventType::SUBMIT_DECODE);
324 ExpectOutputPictureWithPoc(0);
325 ExpectEvent(EventType::SUBMIT_DECODE);
326 ExpectOutputPictureWithPoc(2);
327 ExpectEvent(EventType::SUBMIT_DECODE);
328 ExpectOutputPictureWithPoc(4);
329 ExpectEvent(EventType::SUBMIT_DECODE);
330 ExpectOutputPictureWithPoc(6);
331
332 ASSERT_NO_FATAL_FAILURE(FeedData({
333 kBaselineFrame0, kBaselineFrame1, kBaselineFrame2, kBaselineFrame3,
334 }));
335 ASSERT_TRUE(decoder_->Flush());
336
337 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota());
338 EXPECT_EQ(0u, number_of_expected_events());
339 }
340
341 TEST_F(H264DecoderTest, DecodeProfileHigh) {
342 accelerator_->SetNewPictureQuota(4);
343 ExpectEvent(EventType::ALLOCATE_NEW_SURFACES);
344
345 // Two pictures will be kept in DPB for reordering. The first picture should
346 // be outputted after feeding the third frame.
347 ExpectEvent(EventType::SUBMIT_DECODE);
348 ExpectEvent(EventType::SUBMIT_DECODE);
349 ExpectEvent(EventType::SUBMIT_DECODE);
350 ExpectOutputPictureWithPoc(0);
351 ExpectEvent(EventType::SUBMIT_DECODE);
352 ExpectOutputPictureWithPoc(2);
353 ExpectOutputPictureWithPoc(4);
354 ExpectOutputPictureWithPoc(6);
355
356 ASSERT_NO_FATAL_FAILURE(FeedData({
357 kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3,
358 }));
359 ASSERT_TRUE(decoder_->Flush());
360
361 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota());
362 EXPECT_EQ(0u, number_of_expected_events());
363 }
364
365 TEST_F(H264DecoderTest, SwitchBaselineToHigh) {
366 accelerator_->SetNewPictureQuota(5);
367
368 ExpectEvent(EventType::ALLOCATE_NEW_SURFACES);
369 ExpectEvent(EventType::SUBMIT_DECODE);
370 ExpectOutputPictureWithPoc(0);
371 ExpectEvent(EventType::ALLOCATE_NEW_SURFACES);
372 ExpectEvent(EventType::SUBMIT_DECODE);
373 ExpectEvent(EventType::SUBMIT_DECODE);
374 ExpectEvent(EventType::SUBMIT_DECODE);
375 ExpectOutputPictureWithPoc(0);
376 ExpectEvent(EventType::SUBMIT_DECODE);
377 ExpectOutputPictureWithPoc(2);
378 ExpectOutputPictureWithPoc(4);
379 ExpectOutputPictureWithPoc(6);
380
381 ASSERT_NO_FATAL_FAILURE(FeedData({
382 kBaselineFrame0, kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3,
383 }));
384 ASSERT_TRUE(decoder_->Flush());
385
386 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota());
387 EXPECT_EQ(0u, number_of_expected_events());
388 }
389
390 TEST_F(H264DecoderTest, SwitchHighToBaseline) {
391 accelerator_->SetNewPictureQuota(5);
392
393 ExpectEvent(EventType::ALLOCATE_NEW_SURFACES);
394 ExpectEvent(EventType::SUBMIT_DECODE);
395 ExpectOutputPictureWithPoc(0);
396 ExpectEvent(EventType::ALLOCATE_NEW_SURFACES);
397 ExpectEvent(EventType::SUBMIT_DECODE);
398 ExpectOutputPictureWithPoc(0);
399 ExpectEvent(EventType::SUBMIT_DECODE);
400 ExpectOutputPictureWithPoc(2);
401 ExpectEvent(EventType::SUBMIT_DECODE);
402 ExpectOutputPictureWithPoc(4);
403 ExpectEvent(EventType::SUBMIT_DECODE);
404 ExpectOutputPictureWithPoc(6);
405
406 ASSERT_NO_FATAL_FAILURE(FeedData({
407 kHighFrame0, kBaselineFrame0, kBaselineFrame1, kBaselineFrame2,
408 kBaselineFrame3,
409 }));
410 ASSERT_TRUE(decoder_->Flush());
411
412 EXPECT_EQ(0u, accelerator_->GetNewPictureQuota());
413 EXPECT_EQ(0u, number_of_expected_events());
414 }
415
416 } // namespace
417 } // 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