diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/video/buffered_frame_decryptor_unittest.cc | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/video/buffered_frame_decryptor_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/video/buffered_frame_decryptor_unittest.cc | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/third_party/libwebrtc/video/buffered_frame_decryptor_unittest.cc b/third_party/libwebrtc/video/buffered_frame_decryptor_unittest.cc new file mode 100644 index 0000000000..074777bf3a --- /dev/null +++ b/third_party/libwebrtc/video/buffered_frame_decryptor_unittest.cc @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2018 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/buffered_frame_decryptor.h" + +#include <map> +#include <memory> +#include <vector> + +#include "api/test/mock_frame_decryptor.h" +#include "modules/video_coding/packet_buffer.h" +#include "system_wrappers/include/clock.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/scoped_key_value_config.h" + +using ::testing::Return; + +namespace webrtc { +namespace { + +FrameDecryptorInterface::Result DecryptSuccess() { + return FrameDecryptorInterface::Result(FrameDecryptorInterface::Status::kOk, + 0); +} + +FrameDecryptorInterface::Result DecryptFail() { + return FrameDecryptorInterface::Result( + FrameDecryptorInterface::Status::kFailedToDecrypt, 0); +} + +} // namespace + +class BufferedFrameDecryptorTest : public ::testing::Test, + public OnDecryptedFrameCallback, + public OnDecryptionStatusChangeCallback { + public: + // Implements the OnDecryptedFrameCallbackInterface + void OnDecryptedFrame(std::unique_ptr<RtpFrameObject> frame) override { + decrypted_frame_call_count_++; + } + + void OnDecryptionStatusChange(FrameDecryptorInterface::Status status) { + ++decryption_status_change_count_; + } + + // Returns a new fake RtpFrameObject it abstracts the difficult construction + // of the RtpFrameObject to simplify testing. + std::unique_ptr<RtpFrameObject> CreateRtpFrameObject(bool key_frame) { + seq_num_++; + RTPVideoHeader rtp_video_header; + rtp_video_header.generic.emplace(); + + // clang-format off + return std::make_unique<RtpFrameObject>( + seq_num_, + seq_num_, + /*markerBit=*/true, + /*times_nacked=*/0, + /*first_packet_received_time=*/0, + /*last_packet_received_time=*/0, + /*rtp_timestamp=*/0, + /*ntp_time_ms=*/0, + VideoSendTiming(), + /*payload_type=*/0, + kVideoCodecGeneric, + kVideoRotation_0, + VideoContentType::UNSPECIFIED, + rtp_video_header, + /*color_space=*/absl::nullopt, + RtpPacketInfos(), + EncodedImageBuffer::Create(/*size=*/0)); + // clang-format on + } + + protected: + BufferedFrameDecryptorTest() { + fake_packet_data_ = std::vector<uint8_t>(100); + decrypted_frame_call_count_ = 0; + decryption_status_change_count_ = 0; + seq_num_ = 0; + mock_frame_decryptor_ = rtc::make_ref_counted<MockFrameDecryptor>(); + buffered_frame_decryptor_ = + std::make_unique<BufferedFrameDecryptor>(this, this, field_trials_); + buffered_frame_decryptor_->SetFrameDecryptor(mock_frame_decryptor_); + } + + static const size_t kMaxStashedFrames; + + test::ScopedKeyValueConfig field_trials_; + std::vector<uint8_t> fake_packet_data_; + rtc::scoped_refptr<MockFrameDecryptor> mock_frame_decryptor_; + std::unique_ptr<BufferedFrameDecryptor> buffered_frame_decryptor_; + size_t decrypted_frame_call_count_; + size_t decryption_status_change_count_ = 0; + uint16_t seq_num_; +}; + +const size_t BufferedFrameDecryptorTest::kMaxStashedFrames = 24; + +// Callback should always be triggered on a successful decryption. +TEST_F(BufferedFrameDecryptorTest, CallbackCalledOnSuccessfulDecryption) { + EXPECT_CALL(*mock_frame_decryptor_, Decrypt) + .Times(1) + .WillOnce(Return(DecryptSuccess())); + EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize) + .Times(1) + .WillOnce(Return(0)); + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(1)); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1)); +} + +// An initial fail to decrypt should not trigger the callback. +TEST_F(BufferedFrameDecryptorTest, CallbackNotCalledOnFailedDecryption) { + EXPECT_CALL(*mock_frame_decryptor_, Decrypt) + .Times(1) + .WillOnce(Return(DecryptFail())); + EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize) + .Times(1) + .WillOnce(Return(0)); + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(0)); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1)); +} + +// Initial failures should be stored and retried after the first successful +// decryption. +TEST_F(BufferedFrameDecryptorTest, DelayedCallbackOnBufferedFrames) { + EXPECT_CALL(*mock_frame_decryptor_, Decrypt) + .Times(3) + .WillOnce(Return(DecryptFail())) + .WillOnce(Return(DecryptSuccess())) + .WillOnce(Return(DecryptSuccess())); + EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize) + .Times(3) + .WillRepeatedly(Return(0)); + + // The first decrypt will fail stashing the first frame. + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(0)); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1)); + // The second call will succeed playing back both frames. + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(false)); + EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(2)); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(2)); +} + +// Subsequent failure to decrypts after the first successful decryption should +// fail to decryptk +TEST_F(BufferedFrameDecryptorTest, FTDDiscardedAfterFirstSuccess) { + EXPECT_CALL(*mock_frame_decryptor_, Decrypt) + .Times(4) + .WillOnce(Return(DecryptFail())) + .WillOnce(Return(DecryptSuccess())) + .WillOnce(Return(DecryptSuccess())) + .WillOnce(Return(DecryptFail())); + EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize) + .Times(4) + .WillRepeatedly(Return(0)); + + // The first decrypt will fail stashing the first frame. + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(0)); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1)); + // The second call will succeed playing back both frames. + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(false)); + EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(2)); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(2)); + // A new failure call will not result in an additional decrypted frame + // callback. + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(2)); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(3)); +} + +// Validate that the maximum number of stashed frames cannot be exceeded even if +// more than its maximum arrives before the first successful decryption. +TEST_F(BufferedFrameDecryptorTest, MaximumNumberOfFramesStored) { + const size_t failed_to_decrypt_count = kMaxStashedFrames * 2; + EXPECT_CALL(*mock_frame_decryptor_, Decrypt) + .Times(failed_to_decrypt_count) + .WillRepeatedly(Return(DecryptFail())); + EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize) + .WillRepeatedly(Return(0)); + + for (size_t i = 0; i < failed_to_decrypt_count; ++i) { + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + } + EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(0)); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1)); + + EXPECT_CALL(*mock_frame_decryptor_, Decrypt) + .Times(kMaxStashedFrames + 1) + .WillRepeatedly(Return(DecryptSuccess())); + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + EXPECT_EQ(decrypted_frame_call_count_, kMaxStashedFrames + 1); + EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(2)); +} + +// Verifies if a BufferedFrameDecryptor is attached but has no FrameDecryptor +// attached it will still store frames up to the frame max. +TEST_F(BufferedFrameDecryptorTest, FramesStoredIfDecryptorNull) { + buffered_frame_decryptor_->SetFrameDecryptor(nullptr); + for (size_t i = 0; i < (2 * kMaxStashedFrames); ++i) { + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + } + + EXPECT_CALL(*mock_frame_decryptor_, Decrypt) + .Times(kMaxStashedFrames + 1) + .WillRepeatedly(Return(DecryptSuccess())); + EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize) + .WillRepeatedly(Return(0)); + + // Attach the frame decryptor at a later point after frames have arrived. + buffered_frame_decryptor_->SetFrameDecryptor(mock_frame_decryptor_); + + // Next frame should trigger kMaxStashedFrame decryptions. + buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true)); + EXPECT_EQ(decrypted_frame_call_count_, kMaxStashedFrames + 1); +} + +} // namespace webrtc |