blob: 5aab1328248e57d019a3e9709ed3ea8013427fc7 [file] [log] [blame]
Benjamin Wright00765292018-12-01 00:18:261/*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "video/buffered_frame_decryptor.h"
12
13#include <utility>
14
15#include "rtc_base/logging.h"
16#include "rtc_base/system/fallthrough.h"
17
18namespace webrtc {
19
20BufferedFrameDecryptor::BufferedFrameDecryptor(
21 OnDecryptedFrameCallback* decrypted_frame_callback,
22 rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor)
23 : frame_decryptor_(std::move(frame_decryptor)),
24 decrypted_frame_callback_(decrypted_frame_callback) {}
25
26BufferedFrameDecryptor::~BufferedFrameDecryptor() {}
27
28void BufferedFrameDecryptor::ManageEncryptedFrame(
29 std::unique_ptr<video_coding::RtpFrameObject> encrypted_frame) {
30 switch (DecryptFrame(encrypted_frame.get())) {
31 case FrameDecision::kStash:
32 if (stashed_frames_.size() >= kMaxStashedFrames) {
33 stashed_frames_.pop_front();
34 }
35 stashed_frames_.push_back(std::move(encrypted_frame));
36 break;
37 case FrameDecision::kDecrypted:
38 RetryStashedFrames();
39 decrypted_frame_callback_->OnDecryptedFrame(std::move(encrypted_frame));
40 break;
41 case FrameDecision::kDrop:
42 break;
43 }
44}
45
46BufferedFrameDecryptor::FrameDecision BufferedFrameDecryptor::DecryptFrame(
47 video_coding::RtpFrameObject* frame) {
48 // Optionally attempt to decrypt the raw video frame if it was provided.
49 if (frame_decryptor_ == nullptr) {
50 RTC_LOG(LS_WARNING) << "Frame decryption required but not attached to this "
51 "stream. Dropping frame.";
52 return FrameDecision::kDrop;
53 }
54 // When using encryption we expect the frame to have the generic descriptor.
55 absl::optional<RtpGenericFrameDescriptor> descriptor =
56 frame->GetGenericFrameDescriptor();
57 if (!descriptor) {
58 RTC_LOG(LS_ERROR) << "No generic frame descriptor found dropping frame.";
59 return FrameDecision::kDrop;
60 }
61 // Retrieve the bitstream of the encrypted video frame.
62 rtc::ArrayView<const uint8_t> encrypted_frame_bitstream(frame->Buffer(),
63 frame->size());
64 // Retrieve the maximum possible size of the decrypted payload.
65 const size_t max_plaintext_byte_size =
66 frame_decryptor_->GetMaxPlaintextByteSize(cricket::MEDIA_TYPE_VIDEO,
67 frame->size());
68 RTC_CHECK_LE(max_plaintext_byte_size, frame->size());
69 // Place the decrypted frame inline into the existing frame.
70 rtc::ArrayView<uint8_t> inline_decrypted_bitstream(frame->MutableBuffer(),
71 max_plaintext_byte_size);
72 // Attempt to decrypt the video frame.
73 size_t bytes_written = 0;
74 if (frame_decryptor_->Decrypt(
75 cricket::MEDIA_TYPE_VIDEO, /*csrcs=*/{},
76 /*additional_data=*/nullptr, encrypted_frame_bitstream,
77 inline_decrypted_bitstream, &bytes_written) != 0) {
78 // Only stash frames if we have never decrypted a frame before.
79 return first_frame_decrypted_ ? FrameDecision::kDrop
80 : FrameDecision::kStash;
81 }
82 RTC_CHECK_LE(bytes_written, max_plaintext_byte_size);
83 // Update the frame to contain just the written bytes.
84 frame->SetSize(bytes_written);
85
86 // Indicate that all future fail to decrypt frames should be dropped.
87 if (!first_frame_decrypted_) {
88 first_frame_decrypted_ = true;
89 }
90
91 return FrameDecision::kDecrypted;
92}
93
94void BufferedFrameDecryptor::RetryStashedFrames() {
95 for (auto& frame : stashed_frames_) {
96 if (DecryptFrame(frame.get()) == FrameDecision::kDecrypted) {
97 decrypted_frame_callback_->OnDecryptedFrame(std::move(frame));
98 }
99 }
100 stashed_frames_.clear();
101}
102
103} // namespace webrtc