/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "video/video_stream_decoder_impl.h" #include #include "api/video/i420_buffer.h" #include "api/video_codecs/video_decoder.h" #include "test/fake_encoded_frame.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/scoped_key_value_config.h" #include "test/time_controller/simulated_time_controller.h" namespace webrtc { namespace { using ::testing::_; using ::testing::NiceMock; using ::testing::Return; class MockVideoStreamDecoderCallbacks : public VideoStreamDecoderInterface::Callbacks { public: MOCK_METHOD(void, OnNonDecodableState, (), (override)); MOCK_METHOD(void, OnContinuousUntil, (int64_t frame_id), (override)); MOCK_METHOD( void, OnDecodedFrame, (VideoFrame frame, const VideoStreamDecoderInterface::Callbacks::FrameInfo& frame_info), (override)); }; class StubVideoDecoder : public VideoDecoder { public: StubVideoDecoder() { ON_CALL(*this, Configure).WillByDefault(Return(true)); } MOCK_METHOD(bool, Configure, (const Settings&), (override)); int32_t Decode(const EncodedImage& input_image, bool missing_frames, int64_t render_time_ms) override { int32_t ret_code = DecodeCall(input_image, missing_frames, render_time_ms); if (ret_code == WEBRTC_VIDEO_CODEC_OK || ret_code == WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME) { VideoFrame frame = VideoFrame::Builder() .set_video_frame_buffer(I420Buffer::Create(1, 1)) .build(); callback_->Decoded(frame); } return ret_code; } MOCK_METHOD(int32_t, DecodeCall, (const EncodedImage& input_image, bool missing_frames, int64_t render_time_ms), ()); int32_t Release() override { return 0; } int32_t RegisterDecodeCompleteCallback( DecodedImageCallback* callback) override { callback_ = callback; return 0; } private: DecodedImageCallback* callback_; }; class WrappedVideoDecoder : public VideoDecoder { public: explicit WrappedVideoDecoder(StubVideoDecoder* decoder) : decoder_(decoder) {} bool Configure(const Settings& settings) override { return decoder_->Configure(settings); } int32_t Decode(const EncodedImage& input_image, bool missing_frames, int64_t render_time_ms) override { return decoder_->Decode(input_image, missing_frames, render_time_ms); } int32_t Release() override { return decoder_->Release(); } int32_t RegisterDecodeCompleteCallback( DecodedImageCallback* callback) override { return decoder_->RegisterDecodeCompleteCallback(callback); } private: StubVideoDecoder* decoder_; }; class FakeVideoDecoderFactory : public VideoDecoderFactory { public: std::vector GetSupportedFormats() const override { return {}; } std::unique_ptr CreateVideoDecoder( const SdpVideoFormat& format) override { if (format.name == "VP8") { return std::make_unique(&vp8_decoder_); } if (format.name == "AV1") { return std::make_unique(&av1_decoder_); } return {}; } StubVideoDecoder& Vp8Decoder() { return vp8_decoder_; } StubVideoDecoder& Av1Decoder() { return av1_decoder_; } private: NiceMock vp8_decoder_; NiceMock av1_decoder_; }; class VideoStreamDecoderImplTest : public ::testing::Test { public: VideoStreamDecoderImplTest() : time_controller_(Timestamp::Seconds(0)), video_stream_decoder_(&callbacks_, &decoder_factory_, time_controller_.GetTaskQueueFactory(), {{1, std::make_pair(SdpVideoFormat("VP8"), 1)}, {2, std::make_pair(SdpVideoFormat("AV1"), 1)}}, &field_trials_) { // Set the min playout delay to a value greater than zero to not activate // the low-latency renderer. video_stream_decoder_.SetMinPlayoutDelay(TimeDelta::Millis(10)); } test::ScopedKeyValueConfig field_trials_; NiceMock callbacks_; FakeVideoDecoderFactory decoder_factory_; GlobalSimulatedTimeController time_controller_; VideoStreamDecoderImpl video_stream_decoder_; }; TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrame) { video_stream_decoder_.OnFrame( test::FakeFrameBuilder().PayloadType(1).AsLast().Build()); EXPECT_CALL(callbacks_, OnDecodedFrame); time_controller_.AdvanceTime(TimeDelta::Millis(1)); } TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForKeyframe) { EXPECT_CALL(callbacks_, OnNonDecodableState); time_controller_.AdvanceTime(TimeDelta::Millis(200)); } TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForDeltaFrame) { video_stream_decoder_.OnFrame( test::FakeFrameBuilder().PayloadType(1).AsLast().Build()); EXPECT_CALL(callbacks_, OnDecodedFrame); time_controller_.AdvanceTime(TimeDelta::Millis(1)); EXPECT_CALL(callbacks_, OnNonDecodableState); time_controller_.AdvanceTime(TimeDelta::Millis(3000)); } TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrameWithKeyframeRequest) { video_stream_decoder_.OnFrame( test::FakeFrameBuilder().PayloadType(1).AsLast().Build()); EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall) .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME)); EXPECT_CALL(callbacks_, OnDecodedFrame); EXPECT_CALL(callbacks_, OnNonDecodableState); time_controller_.AdvanceTime(TimeDelta::Millis(1)); } TEST_F(VideoStreamDecoderImplTest, FailToInitDecoder) { video_stream_decoder_.OnFrame( test::FakeFrameBuilder() .ReceivedTime(time_controller_.GetClock()->CurrentTime()) .PayloadType(1) .AsLast() .Build()); ON_CALL(decoder_factory_.Vp8Decoder(), Configure) .WillByDefault(Return(false)); EXPECT_CALL(callbacks_, OnNonDecodableState); time_controller_.AdvanceTime(TimeDelta::Millis(1)); } TEST_F(VideoStreamDecoderImplTest, FailToDecodeFrame) { video_stream_decoder_.OnFrame( test::FakeFrameBuilder().PayloadType(1).AsLast().Build()); ON_CALL(decoder_factory_.Vp8Decoder(), DecodeCall) .WillByDefault(Return(WEBRTC_VIDEO_CODEC_ERROR)); EXPECT_CALL(callbacks_, OnNonDecodableState); time_controller_.AdvanceTime(TimeDelta::Millis(1)); } TEST_F(VideoStreamDecoderImplTest, ChangeFramePayloadType) { constexpr TimeDelta kFrameInterval = TimeDelta::Millis(1000 / 60); video_stream_decoder_.OnFrame( test::FakeFrameBuilder().PayloadType(1).Id(0).AsLast().Build()); EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall); EXPECT_CALL(callbacks_, OnDecodedFrame); time_controller_.AdvanceTime(kFrameInterval); video_stream_decoder_.OnFrame( test::FakeFrameBuilder().PayloadType(2).Id(1).AsLast().Build()); EXPECT_CALL(decoder_factory_.Av1Decoder(), DecodeCall); EXPECT_CALL(callbacks_, OnDecodedFrame); time_controller_.AdvanceTime(kFrameInterval); } } // namespace } // namespace webrtc