summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/video/buffered_frame_decryptor_unittest.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/video/buffered_frame_decryptor_unittest.cc
parentInitial commit. (diff)
downloadfirefox-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.cc230
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