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