summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/video/buffered_frame_decryptor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/video/buffered_frame_decryptor.cc')
-rw-r--r--third_party/libwebrtc/video/buffered_frame_decryptor.cc123
1 files changed, 123 insertions, 0 deletions
diff --git a/third_party/libwebrtc/video/buffered_frame_decryptor.cc b/third_party/libwebrtc/video/buffered_frame_decryptor.cc
new file mode 100644
index 0000000000..24cbaf8265
--- /dev/null
+++ b/third_party/libwebrtc/video/buffered_frame_decryptor.cc
@@ -0,0 +1,123 @@
+/*
+ * 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 <utility>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtp_descriptor_authentication.h"
+#include "modules/video_coding/frame_object.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+
+BufferedFrameDecryptor::BufferedFrameDecryptor(
+ OnDecryptedFrameCallback* decrypted_frame_callback,
+ OnDecryptionStatusChangeCallback* decryption_status_change_callback,
+ const FieldTrialsView& field_trials)
+ : generic_descriptor_auth_experiment_(
+ !field_trials.IsDisabled("WebRTC-GenericDescriptorAuth")),
+ decrypted_frame_callback_(decrypted_frame_callback),
+ decryption_status_change_callback_(decryption_status_change_callback) {}
+
+BufferedFrameDecryptor::~BufferedFrameDecryptor() {}
+
+void BufferedFrameDecryptor::SetFrameDecryptor(
+ rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor) {
+ frame_decryptor_ = std::move(frame_decryptor);
+}
+
+void BufferedFrameDecryptor::ManageEncryptedFrame(
+ std::unique_ptr<RtpFrameObject> encrypted_frame) {
+ switch (DecryptFrame(encrypted_frame.get())) {
+ case FrameDecision::kStash:
+ if (stashed_frames_.size() >= kMaxStashedFrames) {
+ RTC_LOG(LS_WARNING) << "Encrypted frame stash full poping oldest item.";
+ stashed_frames_.pop_front();
+ }
+ stashed_frames_.push_back(std::move(encrypted_frame));
+ break;
+ case FrameDecision::kDecrypted:
+ RetryStashedFrames();
+ decrypted_frame_callback_->OnDecryptedFrame(std::move(encrypted_frame));
+ break;
+ case FrameDecision::kDrop:
+ break;
+ }
+}
+
+BufferedFrameDecryptor::FrameDecision BufferedFrameDecryptor::DecryptFrame(
+ RtpFrameObject* frame) {
+ // Optionally attempt to decrypt the raw video frame if it was provided.
+ if (frame_decryptor_ == nullptr) {
+ RTC_LOG(LS_INFO) << "Frame decryption required but not attached to this "
+ "stream. Stashing frame.";
+ return FrameDecision::kStash;
+ }
+ // Retrieve the maximum possible size of the decrypted payload.
+ const size_t max_plaintext_byte_size =
+ frame_decryptor_->GetMaxPlaintextByteSize(cricket::MEDIA_TYPE_VIDEO,
+ frame->size());
+ RTC_CHECK_LE(max_plaintext_byte_size, frame->size());
+ // Place the decrypted frame inline into the existing frame.
+ rtc::ArrayView<uint8_t> inline_decrypted_bitstream(frame->mutable_data(),
+ max_plaintext_byte_size);
+
+ // Enable authenticating the header if the field trial isn't disabled.
+ std::vector<uint8_t> additional_data;
+ if (generic_descriptor_auth_experiment_) {
+ additional_data = RtpDescriptorAuthentication(frame->GetRtpVideoHeader());
+ }
+
+ // Attempt to decrypt the video frame.
+ const FrameDecryptorInterface::Result decrypt_result =
+ frame_decryptor_->Decrypt(cricket::MEDIA_TYPE_VIDEO, /*csrcs=*/{},
+ additional_data, *frame,
+ inline_decrypted_bitstream);
+ // Optionally call the callback if there was a change in status
+ if (decrypt_result.status != last_status_) {
+ last_status_ = decrypt_result.status;
+ decryption_status_change_callback_->OnDecryptionStatusChange(
+ decrypt_result.status);
+ }
+
+ if (!decrypt_result.IsOk()) {
+ // Only stash frames if we have never decrypted a frame before.
+ return first_frame_decrypted_ ? FrameDecision::kDrop
+ : FrameDecision::kStash;
+ }
+ RTC_CHECK_LE(decrypt_result.bytes_written, max_plaintext_byte_size);
+ // Update the frame to contain just the written bytes.
+ frame->set_size(decrypt_result.bytes_written);
+
+ // Indicate that all future fail to decrypt frames should be dropped.
+ if (!first_frame_decrypted_) {
+ first_frame_decrypted_ = true;
+ }
+
+ return FrameDecision::kDecrypted;
+}
+
+void BufferedFrameDecryptor::RetryStashedFrames() {
+ if (!stashed_frames_.empty()) {
+ RTC_LOG(LS_INFO) << "Retrying stashed encrypted frames. Count: "
+ << stashed_frames_.size();
+ }
+ for (auto& frame : stashed_frames_) {
+ if (DecryptFrame(frame.get()) == FrameDecision::kDecrypted) {
+ decrypted_frame_callback_->OnDecryptedFrame(std::move(frame));
+ }
+ }
+ stashed_frames_.clear();
+}
+
+} // namespace webrtc