1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/decrypting_video_decoder.h"
7 #include "base/functional/bind.h"
8 #include "base/functional/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/task/bind_post_task.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/trace_event/trace_event.h"
15 #include "media/base/cdm_context.h"
16 #include "media/base/decoder_buffer.h"
17 #include "media/base/media_log.h"
18 #include "media/base/video_frame.h"
22 const char DecryptingVideoDecoder::kDecoderName[] = "DecryptingVideoDecoder";
24 DecryptingVideoDecoder::DecryptingVideoDecoder(
25 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
27 : task_runner_(task_runner), media_log_(media_log) {
28 DETACH_FROM_SEQUENCE(sequence_checker_);
31 VideoDecoderType DecryptingVideoDecoder::GetDecoderType() const {
32 return VideoDecoderType::kDecrypting;
35 void DecryptingVideoDecoder::Initialize(const VideoDecoderConfig& config,
37 CdmContext* cdm_context,
39 const OutputCB& output_cb,
40 const WaitingCB& waiting_cb) {
41 DVLOG(2) << __func__ << ": " << config.AsHumanReadableString();
43 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
44 DCHECK(state_ == kUninitialized || state_ == kIdle ||
45 state_ == kDecodeFinished)
49 DCHECK(config.IsValidConfig());
51 init_cb_ = base::BindPostTaskToCurrentDefault(std::move(init_cb));
54 // Once we have a CDM context, one should always be present.
55 DCHECK(!support_clear_content_);
56 std::move(init_cb_).Run(DecoderStatus::Codes::kUnsupportedEncryptionMode);
60 if (!config.is_encrypted() && !support_clear_content_) {
61 std::move(init_cb_).Run(DecoderStatus::Codes::kUnsupportedEncryptionMode);
65 // Once initialized with encryption support, the value is sticky, so we'll use
66 // the decryptor for clear content as well.
67 support_clear_content_ = true;
69 output_cb_ = base::BindPostTaskToCurrentDefault(output_cb);
73 waiting_cb_ = waiting_cb;
75 if (state_ == kUninitialized) {
76 if (!cdm_context->GetDecryptor()) {
77 DVLOG(1) << __func__ << ": no decryptor";
78 std::move(init_cb_).Run(DecoderStatus::Codes::kUnsupportedEncryptionMode);
82 decryptor_ = cdm_context->GetDecryptor();
83 event_cb_registration_ = cdm_context->RegisterEventCB(
84 base::BindRepeating(&DecryptingVideoDecoder::OnCdmContextEvent,
85 weak_factory_.GetWeakPtr()));
87 // Reinitialization (i.e. upon a config change). The new config can be
88 // encrypted or clear.
89 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
92 state_ = kPendingDecoderInit;
93 decryptor_->InitializeVideoDecoder(
94 config_, base::BindPostTaskToCurrentDefault(
95 base::BindOnce(&DecryptingVideoDecoder::FinishInitialization,
96 weak_factory_.GetWeakPtr())));
99 bool DecryptingVideoDecoder::SupportsDecryption() const {
103 void DecryptingVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
104 DecodeCB decode_cb) {
105 DVLOG(3) << "Decode()";
106 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107 DCHECK(state_ == kIdle || state_ == kDecodeFinished || state_ == kError)
110 CHECK(!decode_cb_) << "Overlapping decodes are not supported.";
112 decode_cb_ = base::BindPostTaskToCurrentDefault(std::move(decode_cb));
114 if (state_ == kError) {
115 std::move(decode_cb_).Run(DecoderStatus::Codes::kPlatformDecodeFailure);
119 // Return empty frames if decoding has finished.
120 if (state_ == kDecodeFinished) {
121 std::move(decode_cb_).Run(DecoderStatus::Codes::kOk);
125 // One time set of `has_clear_lead_`.
126 if (!has_clear_lead_.has_value()) {
127 has_clear_lead_ = !buffer->end_of_stream() && !buffer->decrypt_config();
130 // Although the stream may switch from clear to encrypted to clear multiple
131 // times (e.g ad-insertions), we only log to the Media log the first switch
132 // from clear to encrypted.
133 if (HasClearLead() && !switched_clear_to_encrypted_ &&
134 !buffer->end_of_stream() && buffer->is_encrypted()) {
135 MEDIA_LOG(INFO, media_log_)
136 << "First switch from clear to encrypted buffers.";
137 switched_clear_to_encrypted_ = true;
140 pending_buffer_to_decode_ = std::move(buffer);
141 state_ = kPendingDecode;
142 DecodePendingBuffer();
145 void DecryptingVideoDecoder::Reset(base::OnceClosure closure) {
146 DVLOG(2) << "Reset() - state: " << state_;
147 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
148 DCHECK(state_ == kIdle || state_ == kPendingDecode ||
149 state_ == kWaitingForKey || state_ == kDecodeFinished ||
152 DCHECK(!init_cb_); // No Reset() during pending initialization.
155 reset_cb_ = base::BindPostTaskToCurrentDefault(std::move(closure));
157 decryptor_->ResetDecoder(Decryptor::kVideo);
159 // Reset() cannot complete if the decode callback is still pending.
160 // Defer the resetting process in this case. The |reset_cb_| will be fired
161 // after the decode callback is fired - see DecryptAndDecodeBuffer() and
163 if (state_ == kPendingDecode) {
168 if (state_ == kWaitingForKey) {
169 CompleteWaitingForDecryptionKey();
171 pending_buffer_to_decode_.reset();
172 std::move(decode_cb_).Run(DecoderStatus::Codes::kAborted);
179 DecryptingVideoDecoder::~DecryptingVideoDecoder() {
180 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
182 if (state_ == kUninitialized)
185 if (state_ == kWaitingForKey)
186 CompleteWaitingForDecryptionKey();
187 if (state_ == kPendingDecode)
188 CompletePendingDecode(Decryptor::kError);
191 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
192 decryptor_ = nullptr;
194 pending_buffer_to_decode_.reset();
196 std::move(init_cb_).Run(DecoderStatus::Codes::kInterrupted);
198 std::move(decode_cb_).Run(DecoderStatus::Codes::kAborted);
200 std::move(reset_cb_).Run();
203 void DecryptingVideoDecoder::FinishInitialization(bool success) {
204 DVLOG(2) << "FinishInitialization()";
205 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
206 DCHECK_EQ(state_, kPendingDecoderInit) << state_;
208 DCHECK(!reset_cb_); // No Reset() before initialization finished.
209 DCHECK(!decode_cb_); // No Decode() before initialization finished.
212 DVLOG(1) << __func__ << ": failed to init video decoder on decryptor";
213 // TODO(*) Is there a better reason? Should this method itself take a
215 std::move(init_cb_).Run(DecoderStatus::Codes::kFailed);
216 decryptor_ = nullptr;
217 event_cb_registration_.reset();
224 std::move(init_cb_).Run(DecoderStatus::Codes::kOk);
227 void DecryptingVideoDecoder::DecodePendingBuffer() {
228 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
229 DCHECK_EQ(state_, kPendingDecode) << state_;
231 auto& buffer = pending_buffer_to_decode_;
233 // Note: Traces require a unique ID per decode, if we ever support multiple
234 // in flight decodes, the trace begin+end macros need the same unique id.
235 DCHECK_EQ(GetMaxDecodeRequests(), 1);
236 const bool is_end_of_stream = buffer->end_of_stream();
237 const bool is_encrypted = !is_end_of_stream && buffer->decrypt_config();
238 const auto timestamp_us =
239 is_end_of_stream ? 0 : buffer->timestamp().InMicroseconds();
240 TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
241 "media", "DecryptingVideoDecoder::DecodePendingBuffer", this,
242 "is_encrypted", is_encrypted, "timestamp_us", timestamp_us);
244 if (!DecoderBuffer::DoSubsamplesMatch(*buffer)) {
245 MEDIA_LOG(ERROR, media_log_)
246 << "DecryptingVideoDecoder: Subsamples for Buffer do not match";
248 std::move(decode_cb_).Run(DecoderStatus::Codes::kPlatformDecodeFailure);
252 decryptor_->DecryptAndDecodeVideo(
254 base::BindPostTaskToCurrentDefault(base::BindRepeating(
255 &DecryptingVideoDecoder::DeliverFrame, weak_factory_.GetWeakPtr())));
258 void DecryptingVideoDecoder::DeliverFrame(Decryptor::Status status,
259 scoped_refptr<VideoFrame> frame) {
260 DVLOG(3) << "DeliverFrame() - status: " << status;
261 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
262 DCHECK_EQ(state_, kPendingDecode) << state_;
264 DCHECK(pending_buffer_to_decode_.get());
265 CompletePendingDecode(status);
267 bool need_to_try_again_if_nokey_is_returned = key_added_while_decode_pending_;
268 key_added_while_decode_pending_ = false;
270 scoped_refptr<DecoderBuffer> scoped_pending_buffer_to_decode =
271 std::move(pending_buffer_to_decode_);
274 std::move(decode_cb_).Run(DecoderStatus::Codes::kAborted);
279 DCHECK_EQ(status == Decryptor::kSuccess, frame.get() != nullptr);
281 if (status == Decryptor::kError) {
282 DVLOG(2) << "DeliverFrame() - kError";
283 MEDIA_LOG(ERROR, media_log_) << GetDecoderType() << ": decode error";
285 std::move(decode_cb_).Run(DecoderStatus::Codes::kPlatformDecodeFailure);
289 if (status == Decryptor::kNoKey) {
291 scoped_pending_buffer_to_decode->decrypt_config()->key_id();
292 std::string log_message =
293 "no key for key ID " + base::HexEncode(key_id.data(), key_id.size()) +
294 "; will resume decoding after new usable key is available";
295 DVLOG(1) << __func__ << ": " << log_message;
296 MEDIA_LOG(INFO, media_log_) << GetDecoderType() << ": " << log_message;
298 // Set |pending_buffer_to_decode_| back as we need to try decoding the
299 // pending buffer again when new key is added to the decryptor.
300 pending_buffer_to_decode_ = std::move(scoped_pending_buffer_to_decode);
302 if (need_to_try_again_if_nokey_is_returned) {
303 // The |state_| is still kPendingDecode.
304 MEDIA_LOG(INFO, media_log_)
305 << GetDecoderType() << ": key was added, resuming decode";
306 DecodePendingBuffer();
310 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
311 "media", "DecryptingVideoDecoder::WaitingForDecryptionKey", this);
312 state_ = kWaitingForKey;
313 waiting_cb_.Run(WaitingReason::kNoDecryptionKey);
317 if (status == Decryptor::kNeedMoreData) {
318 DVLOG(2) << "DeliverFrame() - kNeedMoreData";
319 state_ = scoped_pending_buffer_to_decode->end_of_stream() ? kDecodeFinished
321 std::move(decode_cb_).Run(DecoderStatus::Codes::kOk);
325 DCHECK_EQ(status, Decryptor::kSuccess);
328 // Frame returned with kSuccess should not be an end-of-stream frame.
329 DCHECK(!frame->metadata().end_of_stream);
331 // If color space is not set, use the color space in the |config_|.
332 if (!frame->ColorSpace().IsValid()) {
333 DVLOG(3) << "Setting color space using information in the config.";
334 if (config_.color_space_info().IsSpecified())
335 frame->set_color_space(config_.color_space_info().ToGfxColorSpace());
338 output_cb_.Run(std::move(frame));
340 if (scoped_pending_buffer_to_decode->end_of_stream()) {
341 // Set |pending_buffer_to_decode_| back as we need to keep flushing the
343 pending_buffer_to_decode_ = std::move(scoped_pending_buffer_to_decode);
344 DecodePendingBuffer();
349 std::move(decode_cb_).Run(DecoderStatus::Codes::kOk);
352 void DecryptingVideoDecoder::OnCdmContextEvent(CdmContext::Event event) {
353 DVLOG(2) << __func__;
354 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
356 if (event != CdmContext::Event::kHasAdditionalUsableKey)
359 if (state_ == kPendingDecode) {
360 key_added_while_decode_pending_ = true;
364 if (state_ == kWaitingForKey) {
365 CompleteWaitingForDecryptionKey();
366 MEDIA_LOG(INFO, media_log_)
367 << GetDecoderType() << ": key added, resuming decode";
368 state_ = kPendingDecode;
369 DecodePendingBuffer();
373 void DecryptingVideoDecoder::DoReset() {
377 std::move(reset_cb_).Run();
380 void DecryptingVideoDecoder::CompletePendingDecode(Decryptor::Status status) {
381 DCHECK_EQ(state_, kPendingDecode);
382 TRACE_EVENT_NESTABLE_ASYNC_END1(
383 "media", "DecryptingVideoDecoder::DecodePendingBuffer", this, "status",
384 Decryptor::GetStatusName(status));
387 void DecryptingVideoDecoder::CompleteWaitingForDecryptionKey() {
388 DCHECK_EQ(state_, kWaitingForKey);
389 TRACE_EVENT_NESTABLE_ASYNC_END0(
390 "media", "DecryptingVideoDecoder::WaitingForDecryptionKey", this);