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/command_line.h" | |
13 #include "base/files/file_util.h" | |
14 #include "base/logging.h" | |
15 #include "media/base/test_data_util.h" | |
16 #include "media/gpu/h264_decoder.h" | |
17 #include "testing/gmock/include/gmock/gmock.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 | |
20 using ::testing::_; | |
21 using ::testing::InSequence; | |
22 using ::testing::Invoke; | |
23 using ::testing::MakeMatcher; | |
24 using ::testing::Matcher; | |
25 using ::testing::MatcherInterface; | |
26 using ::testing::MatchResultListener; | |
27 using ::testing::Mock; | |
28 using ::testing::Return; | |
29 | |
30 namespace media { | |
31 namespace { | |
32 | |
33 const std::string kBaselineFrame0 = "bear-320x192-baseline-frame-0.h264"; | |
34 const std::string kBaselineFrame1 = "bear-320x192-baseline-frame-1.h264"; | |
35 const std::string kBaselineFrame2 = "bear-320x192-baseline-frame-2.h264"; | |
36 const std::string kBaselineFrame3 = "bear-320x192-baseline-frame-3.h264"; | |
37 const std::string kHighFrame0 = "bear-320x192-high-frame-0.h264"; | |
38 const std::string kHighFrame1 = "bear-320x192-high-frame-1.h264"; | |
39 const std::string kHighFrame2 = "bear-320x192-high-frame-2.h264"; | |
40 const std::string kHighFrame3 = "bear-320x192-high-frame-3.h264"; | |
41 | |
42 class MockH264Accelerator : public H264Decoder::H264Accelerator { | |
43 public: | |
44 MockH264Accelerator() {} | |
45 | |
46 MOCK_METHOD0(CreateH264Picture, scoped_refptr<H264Picture>()); | |
47 MOCK_METHOD1(SubmitDecode, bool(const scoped_refptr<H264Picture>& pic)); | |
48 MOCK_METHOD1(OutputPicture, bool(const scoped_refptr<H264Picture>& pic)); | |
49 | |
50 bool SubmitFrameMetadata(const H264SPS* sps, | |
51 const H264PPS* pps, | |
52 const H264DPB& dpb, | |
53 const H264Picture::Vector& ref_pic_listp0, | |
54 const H264Picture::Vector& ref_pic_listb0, | |
55 const H264Picture::Vector& ref_pic_listb1, | |
56 const scoped_refptr<H264Picture>& pic) override { | |
57 return true; | |
58 } | |
59 | |
60 bool SubmitSlice(const H264PPS* pps, | |
61 const H264SliceHeader* slice_hdr, | |
62 const H264Picture::Vector& ref_pic_list0, | |
63 const H264Picture::Vector& ref_pic_list1, | |
64 const scoped_refptr<H264Picture>& pic, | |
65 const uint8_t* data, | |
66 size_t size) override { | |
67 return true; | |
68 } | |
69 | |
70 void Reset() override {} | |
71 }; | |
72 | |
73 // Test H264Decoder by feeding different of h264 frame sequences and make | |
74 // sure it behaves as expected. | |
75 class H264DecoderTest : public ::testing::Test { | |
76 public: | |
77 H264DecoderTest() = default; | |
78 | |
79 void SetUp() override; | |
80 | |
81 // Sets the bitstreams to be decoded, frame by frame. The content of each | |
82 // file is the encoded bitstream of a single video frame. | |
83 void SetInputFrameFiles(const std::vector<std::string>& frame_files); | |
84 | |
85 // Keeps decoding the input bitstream set at |SetInputFrameFiles| until the | |
86 // decoder has consumed all bitstreams or returned from | |
87 // |H264Decoder::Decode|. Returns the same result as |H264Decoder::Decode|. | |
88 AcceleratedVideoDecoder::DecodeResult Decode(); | |
89 | |
90 protected: | |
91 std::unique_ptr<H264Decoder> decoder_; | |
92 MockH264Accelerator accelerator_; | |
93 | |
94 private: | |
95 std::queue<std::string> input_frame_files_; | |
96 std::string bitstream_; | |
97 }; | |
98 | |
99 void H264DecoderTest::SetUp() { | |
100 decoder_.reset(new H264Decoder(&accelerator_)); | |
101 | |
102 // Sets default behaviors for mock methods for convenience. | |
103 ON_CALL(accelerator_, CreateH264Picture()).WillByDefault(Invoke([]() { | |
104 return new H264Picture(); | |
105 })); | |
106 ON_CALL(accelerator_, SubmitDecode(_)).WillByDefault(Return(true)); | |
107 ON_CALL(accelerator_, OutputPicture(_)).WillByDefault(Return(true)); | |
108 } | |
109 | |
110 void H264DecoderTest::SetInputFrameFiles( | |
111 const std::vector<std::string>& input_frame_files) { | |
112 for (auto f : input_frame_files) | |
113 input_frame_files_.push(f); | |
114 } | |
115 | |
116 AcceleratedVideoDecoder::DecodeResult H264DecoderTest::Decode() { | |
117 while (true) { | |
118 auto result = decoder_->Decode(); | |
119 if (result != AcceleratedVideoDecoder::kRanOutOfStreamData || | |
120 input_frame_files_.empty()) | |
121 return result; | |
122 auto input_file = GetTestDataFilePath(input_frame_files_.front()); | |
123 input_frame_files_.pop(); | |
124 CHECK(base::ReadFileToString(input_file, &bitstream_)); | |
125 decoder_->SetStream(reinterpret_cast<const uint8_t*>(bitstream_.data()), | |
126 bitstream_.size()); | |
127 } | |
128 } | |
129 | |
130 // To have better description on mismatch. | |
131 class WithPocMatcher | |
132 : public MatcherInterface<const scoped_refptr<H264Picture>&> { | |
133 public: | |
134 explicit WithPocMatcher(int expected_poc) : expected_poc_(expected_poc) {} | |
135 | |
136 bool MatchAndExplain(const scoped_refptr<H264Picture>& p, | |
137 MatchResultListener* listener) const override { | |
138 if (p->pic_order_cnt == expected_poc_) | |
139 return true; | |
140 *listener << "with poc: " << p->pic_order_cnt; | |
141 return false; | |
142 } | |
143 | |
144 void DescribeTo(std::ostream* os) const override { | |
145 *os << "with poc " << expected_poc_; | |
146 } | |
147 | |
148 private: | |
149 int expected_poc_; | |
150 }; | |
151 | |
152 inline Matcher<const scoped_refptr<H264Picture>&> WithPoc(int expected_poc) { | |
153 return MakeMatcher(new WithPocMatcher(expected_poc)); | |
154 } | |
155 | |
156 // Test Cases | |
157 | |
158 TEST_F(H264DecoderTest, DecodeSingleFrame) { | |
159 SetInputFrameFiles({kBaselineFrame0}); | |
160 ASSERT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, Decode()); | |
161 EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize()); | |
162 | |
163 EXPECT_CALL(accelerator_, CreateH264Picture()).WillOnce(Return(nullptr)); | |
164 ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfSurfaces, Decode()); | |
165 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&accelerator_)); | |
166 | |
167 { | |
168 InSequence sequence; | |
169 EXPECT_CALL(accelerator_, CreateH264Picture()); | |
170 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
171 EXPECT_CALL(accelerator_, OutputPicture(_)); | |
172 } | |
173 ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode()); | |
174 ASSERT_TRUE(decoder_->Flush()); | |
175 } | |
176 | |
177 TEST_F(H264DecoderTest, SkipNoneIDRFrames) { | |
Pawel Osciak
2017/06/28 07:59:25
s/None/Non/
Owen Lin
2017/06/28 09:03:38
Done.
| |
178 SetInputFrameFiles({kBaselineFrame1, kBaselineFrame2, kBaselineFrame0}); | |
179 ASSERT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, Decode()); | |
180 EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize()); | |
181 { | |
182 InSequence sequence; | |
183 EXPECT_CALL(accelerator_, CreateH264Picture()); | |
184 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
185 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(0))); | |
186 } | |
187 ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode()); | |
188 ASSERT_TRUE(decoder_->Flush()); | |
189 } | |
190 | |
191 TEST_F(H264DecoderTest, DecodeProfileBaseline) { | |
192 SetInputFrameFiles({ | |
193 kBaselineFrame0, kBaselineFrame1, kBaselineFrame2, kBaselineFrame3, | |
194 }); | |
195 ASSERT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, Decode()); | |
196 EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize()); | |
197 | |
198 EXPECT_CALL(accelerator_, CreateH264Picture()).Times(4); | |
199 { | |
200 InSequence sequence; | |
201 EXPECT_CALL(accelerator_, SubmitDecode(WithPoc(0))); | |
Pawel Osciak
2017/06/28 07:59:25
If I understand the stream correctly, would this b
Owen Lin
2017/06/28 09:03:38
Done.
| |
202 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(0))); | |
203 EXPECT_CALL(accelerator_, SubmitDecode(WithPoc(2))); | |
204 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(2))); | |
205 EXPECT_CALL(accelerator_, SubmitDecode(WithPoc(4))); | |
206 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(4))); | |
207 EXPECT_CALL(accelerator_, SubmitDecode(WithPoc(6))); | |
208 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(6))); | |
209 } | |
210 ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode()); | |
211 ASSERT_TRUE(decoder_->Flush()); | |
212 } | |
213 | |
214 TEST_F(H264DecoderTest, DecodeProfileHigh) { | |
215 SetInputFrameFiles({kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3}); | |
216 ASSERT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, Decode()); | |
217 EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize()); | |
218 | |
219 // Two pictures will be kept in DPB for reordering. The first picture should | |
220 // be outputted after feeding the third frame. | |
221 EXPECT_CALL(accelerator_, CreateH264Picture()).Times(4); | |
222 { | |
223 InSequence sequence; | |
224 EXPECT_CALL(accelerator_, SubmitDecode(WithPoc(0))); | |
225 EXPECT_CALL(accelerator_, SubmitDecode(WithPoc(4))); | |
226 EXPECT_CALL(accelerator_, SubmitDecode(WithPoc(2))); | |
227 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(0))); | |
228 EXPECT_CALL(accelerator_, SubmitDecode(WithPoc(6))); | |
229 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(2))); | |
230 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(4))); | |
231 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(6))); | |
232 } | |
233 ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode()); | |
234 ASSERT_TRUE(decoder_->Flush()); | |
235 } | |
236 | |
237 TEST_F(H264DecoderTest, SwitchBaselineToHigh) { | |
238 SetInputFrameFiles({ | |
239 kBaselineFrame0, kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3, | |
240 }); | |
241 ASSERT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, Decode()); | |
242 EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize()); | |
243 | |
244 EXPECT_CALL(accelerator_, CreateH264Picture()); | |
245 { | |
246 InSequence sequence; | |
247 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
248 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(0))); | |
249 } | |
250 ASSERT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, Decode()); | |
251 EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize()); | |
Pawel Osciak
2017/06/28 07:59:25
Should we also EXPECT for decoder_->GetRequiredNum
Owen Lin
2017/06/28 09:03:38
Done.
| |
252 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&accelerator_)); | |
253 | |
254 EXPECT_CALL(accelerator_, CreateH264Picture()).Times(4); | |
255 { | |
256 InSequence sequence; | |
257 EXPECT_CALL(accelerator_, SubmitDecode(_)).Times(3); | |
258 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(0))); | |
259 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
260 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(2))); | |
261 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(4))); | |
262 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(6))); | |
263 } | |
264 ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode()); | |
265 ASSERT_TRUE(decoder_->Flush()); | |
266 } | |
267 | |
268 TEST_F(H264DecoderTest, SwitchHighToBaseline) { | |
269 SetInputFrameFiles({ | |
270 kHighFrame0, kBaselineFrame0, kBaselineFrame1, kBaselineFrame2, | |
271 kBaselineFrame3, | |
272 }); | |
273 ASSERT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, Decode()); | |
274 EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize()); | |
275 | |
276 EXPECT_CALL(accelerator_, CreateH264Picture()); | |
277 { | |
278 InSequence sequence; | |
279 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
280 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(0))); | |
281 } | |
282 ASSERT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, Decode()); | |
283 EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize()); | |
284 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&accelerator_)); | |
285 | |
286 EXPECT_CALL(accelerator_, CreateH264Picture()).Times(4); | |
287 { | |
288 InSequence sequence; | |
289 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
290 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(0))); | |
291 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
292 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(2))); | |
293 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
294 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(4))); | |
295 EXPECT_CALL(accelerator_, SubmitDecode(_)); | |
296 EXPECT_CALL(accelerator_, OutputPicture(WithPoc(6))); | |
297 } | |
298 ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode()); | |
299 ASSERT_TRUE(decoder_->Flush()); | |
300 } | |
301 | |
302 } // namespace | |
303 } // namespace media | |
OLD | NEW |