Chromium Code Reviews| 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 |