123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <stdint.h>
- #include <string>
- #include "base/command_line.h"
- #include "base/files/file_util.h"
- #include "base/memory/raw_ptr.h"
- #include "media/base/test_data_util.h"
- #include "media/gpu/vp8_decoder.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using ::testing::_;
- using ::testing::InSequence;
- using ::testing::Invoke;
- using ::testing::Mock;
- using ::testing::Return;
- namespace media {
- namespace {
- const std::string kNullFrame = "";
- const std::string kIFrame = "vp8-I-frame-320x240";
- const std::string kPFrame = "vp8-P-frame-320x240";
- const std::string kCorruptFrame = "vp8-corrupt-I-frame";
- constexpr gfx::Size kVideoSize(320, 240);
- constexpr size_t kRequiredNumOfPictures = 8u;
- class MockVP8Accelerator : public VP8Decoder::VP8Accelerator {
- public:
- MockVP8Accelerator() = default;
- MOCK_METHOD0(CreateVP8Picture, scoped_refptr<VP8Picture>());
- MOCK_METHOD2(SubmitDecode,
- bool(scoped_refptr<VP8Picture> pic,
- const Vp8ReferenceFrameVector& reference_frames));
- MOCK_METHOD1(OutputPicture, bool(scoped_refptr<VP8Picture> pic));
- };
- // Test VP8Decoder by feeding different VP8 frame sequences and making sure it
- // behaves as expected.
- class VP8DecoderTest : public ::testing::Test {
- public:
- VP8DecoderTest() = default;
- void SetUp() override;
- AcceleratedVideoDecoder::DecodeResult Decode(std::string input_frame_file);
- protected:
- void SkipFrame() { bitstream_id_++; }
- void CompleteToDecodeFirstIFrame();
- std::unique_ptr<VP8Decoder> decoder_;
- raw_ptr<MockVP8Accelerator> accelerator_ = nullptr;
- private:
- void DecodeFirstIFrame();
- int32_t bitstream_id_ = 0;
- };
- void VP8DecoderTest::SetUp() {
- auto mock_accelerator = std::make_unique<MockVP8Accelerator>();
- accelerator_ = mock_accelerator.get();
- decoder_.reset(new VP8Decoder(std::move(mock_accelerator)));
- // Sets default behaviors for mock methods for convenience.
- ON_CALL(*accelerator_, CreateVP8Picture())
- .WillByDefault(Return(new VP8Picture()));
- ON_CALL(*accelerator_, SubmitDecode(_, _)).WillByDefault(Return(true));
- ON_CALL(*accelerator_, OutputPicture(_)).WillByDefault(Return(true));
- DecodeFirstIFrame();
- }
- void VP8DecoderTest::DecodeFirstIFrame() {
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kNullFrame));
- ASSERT_EQ(AcceleratedVideoDecoder::kConfigChange, Decode(kIFrame));
- EXPECT_EQ(8u, decoder_->GetBitDepth());
- EXPECT_EQ(kVideoSize, decoder_->GetPicSize());
- EXPECT_LE(kRequiredNumOfPictures, decoder_->GetRequiredNumOfPictures());
- }
- // DecodeFirstIFrame() allocates new surfaces so VP8Decoder::Decode() must be
- // called again to complete to decode the first frame.
- void VP8DecoderTest::CompleteToDecodeFirstIFrame() {
- {
- InSequence sequence;
- EXPECT_CALL(*accelerator_, CreateVP8Picture());
- EXPECT_CALL(*accelerator_, SubmitDecode(_, _));
- EXPECT_CALL(*accelerator_, OutputPicture(_));
- }
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kNullFrame));
- }
- AcceleratedVideoDecoder::DecodeResult VP8DecoderTest::Decode(
- std::string input_frame_file) {
- std::string bitstream;
- scoped_refptr<DecoderBuffer> buffer;
- if (!input_frame_file.empty()) {
- auto input_file = GetTestDataFilePath(input_frame_file);
- EXPECT_TRUE(base::ReadFileToString(input_file, &bitstream));
- buffer = DecoderBuffer::CopyFrom(
- reinterpret_cast<const uint8_t*>(bitstream.data()), bitstream.size());
- EXPECT_NE(buffer.get(), nullptr);
- decoder_->SetStream(bitstream_id_++, *buffer);
- }
- AcceleratedVideoDecoder::DecodeResult result = decoder_->Decode();
- if (input_frame_file.empty())
- return result;
- // Since |buffer| is destroyed in this function, Decode() must consume the
- // buffer by this Decode(). That happens if the return value is
- // kRanOutOfStreamData, kConfigChange , or kDecodeError (on failure).
- EXPECT_TRUE(result ==
- AcceleratedVideoDecoder::DecodeResult::kRanOutOfStreamData ||
- result == AcceleratedVideoDecoder::DecodeResult::kConfigChange ||
- result == AcceleratedVideoDecoder::DecodeResult::kDecodeError);
- if (result != AcceleratedVideoDecoder::DecodeResult::kDecodeError)
- EXPECT_EQ(8u, decoder_->GetBitDepth());
- return result;
- }
- // Test Cases
- TEST_F(VP8DecoderTest, DecodeSingleFrame) {
- CompleteToDecodeFirstIFrame();
- ASSERT_TRUE(Mock::VerifyAndClearExpectations(accelerator_));
- ASSERT_TRUE(decoder_->Flush());
- }
- TEST_F(VP8DecoderTest, FailCreatePicture) {
- EXPECT_CALL(*accelerator_, CreateVP8Picture()).WillOnce(Return(nullptr));
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfSurfaces, Decode(kNullFrame));
- ASSERT_TRUE(decoder_->Flush());
- }
- TEST_F(VP8DecoderTest, DecodeCorruptFrame) {
- CompleteToDecodeFirstIFrame();
- ASSERT_EQ(AcceleratedVideoDecoder::kDecodeError, Decode(kCorruptFrame));
- ASSERT_TRUE(Mock::VerifyAndClearExpectations(accelerator_));
- ASSERT_TRUE(decoder_->Flush());
- }
- TEST_F(VP8DecoderTest, DecodeIAndPFrames) {
- CompleteToDecodeFirstIFrame();
- {
- InSequence sequence;
- EXPECT_CALL(*accelerator_, CreateVP8Picture());
- EXPECT_CALL(*accelerator_, SubmitDecode(_, _));
- EXPECT_CALL(*accelerator_, OutputPicture(_));
- }
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kPFrame));
- ASSERT_TRUE(Mock::VerifyAndClearExpectations(accelerator_));
- ASSERT_TRUE(decoder_->Flush());
- }
- TEST_F(VP8DecoderTest, DecodeIandMultiplePFrames) {
- CompleteToDecodeFirstIFrame();
- for (size_t i = 0; i < 5; i++) {
- {
- InSequence sequence;
- EXPECT_CALL(*accelerator_, CreateVP8Picture());
- EXPECT_CALL(*accelerator_, SubmitDecode(_, _));
- EXPECT_CALL(*accelerator_, OutputPicture(_));
- }
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kPFrame));
- }
- ASSERT_TRUE(Mock::VerifyAndClearExpectations(accelerator_));
- ASSERT_TRUE(decoder_->Flush());
- }
- TEST_F(VP8DecoderTest, DecodeMultipleIAndPFrames) {
- CompleteToDecodeFirstIFrame();
- for (size_t i = 0; i < 10; i++) {
- {
- InSequence sequence;
- EXPECT_CALL(*accelerator_, CreateVP8Picture());
- EXPECT_CALL(*accelerator_, SubmitDecode(_, _));
- EXPECT_CALL(*accelerator_, OutputPicture(_));
- }
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData,
- Decode((i % 3) == 0 ? kIFrame : kPFrame));
- }
- ASSERT_TRUE(Mock::VerifyAndClearExpectations(accelerator_));
- ASSERT_TRUE(decoder_->Flush());
- }
- TEST_F(VP8DecoderTest, HaveSkippedFrames) {
- CompleteToDecodeFirstIFrame();
- SkipFrame();
- for (size_t i = 0; i < 5; i++) {
- // VP8Decoder::Decode() gives up decoding it and returns early.
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kPFrame));
- }
- ASSERT_TRUE(Mock::VerifyAndClearExpectations(accelerator_));
- ASSERT_TRUE(decoder_->Flush());
- }
- // Verify that |decoder_| returns kDecodeError if too many kPFrames are received
- // while expecting a kIFrame.
- TEST_F(VP8DecoderTest, HaveSkippedFramesAtMaxNumOfSizeChangeFailures) {
- CompleteToDecodeFirstIFrame();
- SkipFrame();
- for (size_t i = 0;
- i < AcceleratedVideoDecoder::kVPxMaxNumOfSizeChangeFailures; i++) {
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kPFrame));
- }
- ASSERT_EQ(AcceleratedVideoDecoder::kDecodeError, Decode(kPFrame));
- ASSERT_TRUE(Mock::VerifyAndClearExpectations(accelerator_));
- ASSERT_TRUE(decoder_->Flush());
- }
- // Verify that new kIFrame recovers |decoder_| to decode the frame when the
- // previous I frame is missing.
- TEST_F(VP8DecoderTest, RecoverFromSkippedFrames) {
- CompleteToDecodeFirstIFrame();
- SkipFrame();
- for (size_t i = 0; i < 5; i++)
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kPFrame));
- // The new I frame recovers to decode it correctly.
- {
- InSequence sequence;
- EXPECT_CALL(*accelerator_, CreateVP8Picture());
- EXPECT_CALL(*accelerator_, SubmitDecode(_, _));
- EXPECT_CALL(*accelerator_, OutputPicture(_));
- }
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kIFrame));
- for (size_t i = 0; i < 5; i++) {
- {
- InSequence sequence;
- EXPECT_CALL(*accelerator_, CreateVP8Picture());
- EXPECT_CALL(*accelerator_, SubmitDecode(_, _));
- EXPECT_CALL(*accelerator_, OutputPicture(_));
- }
- ASSERT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(kPFrame));
- }
- ASSERT_TRUE(Mock::VerifyAndClearExpectations(accelerator_));
- ASSERT_TRUE(decoder_->Flush());
- }
- } // namespace
- } // namespace media
|