1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/trace_event/trace_event.h"
14 #include "media/base/bind_to_current_loop.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::SingleThreadTaskRunner>& task_runner,
27 : task_runner_(task_runner),
28 media_log_(media_log),
29 state_(kUninitialized),
31 key_added_while_decode_pending_(false),
33 support_clear_content_(false),
34 weak_factory_(this) {}
36 std::string DecryptingVideoDecoder::GetDisplayName() const {
40 void DecryptingVideoDecoder::Initialize(
41 const VideoDecoderConfig& config,
43 CdmContext* cdm_context,
44 const InitCB& init_cb,
45 const OutputCB& output_cb,
46 const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb) {
47 DVLOG(2) << __func__ << ": " << config.AsHumanReadableString();
49 DCHECK(task_runner_->BelongsToCurrentThread());
50 DCHECK(state_ == kUninitialized ||
52 state_ == kDecodeFinished) << state_;
53 DCHECK(decode_cb_.is_null());
54 DCHECK(reset_cb_.is_null());
55 DCHECK(config.IsValidConfig());
57 init_cb_ = BindToCurrentLoop(init_cb);
59 // Once we have a CDM context, one should always be present.
60 DCHECK(!support_clear_content_);
61 base::ResetAndReturn(&init_cb_).Run(false);
65 if (!config.is_encrypted() && !support_clear_content_) {
66 base::ResetAndReturn(&init_cb_).Run(false);
70 // Once initialized with encryption support, the value is sticky, so we'll use
71 // the decryptor for clear content as well.
72 support_clear_content_ = true;
74 output_cb_ = BindToCurrentLoop(output_cb);
75 weak_this_ = weak_factory_.GetWeakPtr();
78 DCHECK(!waiting_for_decryption_key_cb.is_null());
79 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
81 if (state_ == kUninitialized) {
82 if (!cdm_context->GetDecryptor()) {
83 MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": no decryptor";
84 base::ResetAndReturn(&init_cb_).Run(false);
88 decryptor_ = cdm_context->GetDecryptor();
90 // Reinitialization (i.e. upon a config change). The new config can be
91 // encrypted or clear.
92 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
95 state_ = kPendingDecoderInit;
96 decryptor_->InitializeVideoDecoder(
97 config_, BindToCurrentLoop(base::Bind(
98 &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
101 void DecryptingVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
102 const DecodeCB& decode_cb) {
103 DVLOG(3) << "Decode()";
104 DCHECK(task_runner_->BelongsToCurrentThread());
105 DCHECK(state_ == kIdle ||
106 state_ == kDecodeFinished ||
107 state_ == kError) << state_;
108 DCHECK(!decode_cb.is_null());
109 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported.";
111 decode_cb_ = BindToCurrentLoop(decode_cb);
113 if (state_ == kError) {
114 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::DECODE_ERROR);
118 // Return empty frames if decoding has finished.
119 if (state_ == kDecodeFinished) {
120 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::OK);
124 pending_buffer_to_decode_ = std::move(buffer);
125 state_ = kPendingDecode;
126 DecodePendingBuffer();
129 void DecryptingVideoDecoder::Reset(const base::Closure& closure) {
130 DVLOG(2) << "Reset() - state: " << state_;
131 DCHECK(task_runner_->BelongsToCurrentThread());
132 DCHECK(state_ == kIdle ||
133 state_ == kPendingDecode ||
134 state_ == kWaitingForKey ||
135 state_ == kDecodeFinished ||
136 state_ == kError) << state_;
137 DCHECK(init_cb_.is_null()); // No Reset() during pending initialization.
138 DCHECK(reset_cb_.is_null());
140 reset_cb_ = BindToCurrentLoop(closure);
142 decryptor_->ResetDecoder(Decryptor::kVideo);
144 // Reset() cannot complete if the decode callback is still pending.
145 // Defer the resetting process in this case. The |reset_cb_| will be fired
146 // after the decode callback is fired - see DecryptAndDecodeBuffer() and
148 if (state_ == kPendingDecode) {
149 DCHECK(!decode_cb_.is_null());
153 if (state_ == kWaitingForKey) {
154 DCHECK(!decode_cb_.is_null());
155 pending_buffer_to_decode_ = NULL;
156 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::ABORTED);
159 DCHECK(decode_cb_.is_null());
163 DecryptingVideoDecoder::~DecryptingVideoDecoder() {
164 DCHECK(task_runner_->BelongsToCurrentThread());
166 if (state_ == kUninitialized)
170 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
173 pending_buffer_to_decode_ = NULL;
174 if (!init_cb_.is_null())
175 base::ResetAndReturn(&init_cb_).Run(false);
176 if (!decode_cb_.is_null())
177 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::ABORTED);
178 if (!reset_cb_.is_null())
179 base::ResetAndReturn(&reset_cb_).Run();
182 void DecryptingVideoDecoder::FinishInitialization(bool success) {
183 DVLOG(2) << "FinishInitialization()";
184 DCHECK(task_runner_->BelongsToCurrentThread());
185 DCHECK_EQ(state_, kPendingDecoderInit) << state_;
186 DCHECK(!init_cb_.is_null());
187 DCHECK(reset_cb_.is_null()); // No Reset() before initialization finished.
188 DCHECK(decode_cb_.is_null()); // No Decode() before initialization finished.
191 MEDIA_LOG(DEBUG, media_log_) << GetDisplayName()
192 << ": failed to init decoder on decryptor";
193 base::ResetAndReturn(&init_cb_).Run(false);
199 decryptor_->RegisterNewKeyCB(
202 base::Bind(&DecryptingVideoDecoder::OnKeyAdded, weak_this_)));
206 base::ResetAndReturn(&init_cb_).Run(true);
210 void DecryptingVideoDecoder::DecodePendingBuffer() {
211 DCHECK(task_runner_->BelongsToCurrentThread());
212 DCHECK_EQ(state_, kPendingDecode) << state_;
213 TRACE_EVENT_ASYNC_BEGIN0(
214 "media", "DecryptingVideoDecoder::DecodePendingBuffer", ++trace_id_);
217 if (!pending_buffer_to_decode_->end_of_stream()) {
218 buffer_size = pending_buffer_to_decode_->data_size();
221 decryptor_->DecryptAndDecodeVideo(
222 pending_buffer_to_decode_, BindToCurrentLoop(base::Bind(
223 &DecryptingVideoDecoder::DeliverFrame, weak_this_, buffer_size)));
226 void DecryptingVideoDecoder::DeliverFrame(
228 Decryptor::Status status,
229 const scoped_refptr<VideoFrame>& frame) {
230 DVLOG(3) << "DeliverFrame() - status: " << status;
231 DCHECK(task_runner_->BelongsToCurrentThread());
232 DCHECK_EQ(state_, kPendingDecode) << state_;
233 DCHECK(!decode_cb_.is_null());
234 DCHECK(pending_buffer_to_decode_.get());
236 TRACE_EVENT_ASYNC_END2(
237 "media", "DecryptingVideoDecoder::DecodePendingBuffer", trace_id_,
238 "buffer_size", buffer_size, "status", status);
240 bool need_to_try_again_if_nokey_is_returned = key_added_while_decode_pending_;
241 key_added_while_decode_pending_ = false;
243 scoped_refptr<DecoderBuffer> scoped_pending_buffer_to_decode =
244 std::move(pending_buffer_to_decode_);
246 if (!reset_cb_.is_null()) {
247 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::ABORTED);
252 DCHECK_EQ(status == Decryptor::kSuccess, frame.get() != NULL);
254 if (status == Decryptor::kError) {
255 DVLOG(2) << "DeliverFrame() - kError";
256 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": decode error";
258 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::DECODE_ERROR);
262 if (status == Decryptor::kNoKey) {
264 scoped_pending_buffer_to_decode->decrypt_config()->key_id();
265 std::string missing_key_id = base::HexEncode(key_id.data(), key_id.size());
266 DVLOG(1) << "DeliverFrame() - no key for key ID " << missing_key_id;
267 MEDIA_LOG(INFO, media_log_) << GetDisplayName() << ": no key for key ID "
270 // Set |pending_buffer_to_decode_| back as we need to try decoding the
271 // pending buffer again when new key is added to the decryptor.
272 pending_buffer_to_decode_ = std::move(scoped_pending_buffer_to_decode);
274 if (need_to_try_again_if_nokey_is_returned) {
275 // The |state_| is still kPendingDecode.
276 MEDIA_LOG(INFO, media_log_) << GetDisplayName()
277 << ": key was added, resuming decode";
278 DecodePendingBuffer();
282 state_ = kWaitingForKey;
283 waiting_for_decryption_key_cb_.Run();
287 if (status == Decryptor::kNeedMoreData) {
288 DVLOG(2) << "DeliverFrame() - kNeedMoreData";
289 state_ = scoped_pending_buffer_to_decode->end_of_stream() ? kDecodeFinished
291 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::OK);
295 DCHECK_EQ(status, Decryptor::kSuccess);
298 // Frame returned with kSuccess should not be an end-of-stream frame.
299 DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
301 // If color space is not set, use the color space in the |config_|.
302 if (!frame->ColorSpace().IsValid()) {
303 DVLOG(3) << "Setting color space using information in the config.";
304 frame->metadata()->SetInteger(VideoFrameMetadata::COLOR_SPACE,
305 config_.color_space());
306 if (config_.color_space_info() != VideoColorSpace())
307 frame->set_color_space(config_.color_space_info().ToGfxColorSpace());
310 output_cb_.Run(frame);
312 if (scoped_pending_buffer_to_decode->end_of_stream()) {
313 // Set |pending_buffer_to_decode_| back as we need to keep flushing the
315 pending_buffer_to_decode_ = std::move(scoped_pending_buffer_to_decode);
316 DecodePendingBuffer();
321 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::OK);
324 void DecryptingVideoDecoder::OnKeyAdded() {
325 DVLOG(2) << "OnKeyAdded()";
326 DCHECK(task_runner_->BelongsToCurrentThread());
328 if (state_ == kPendingDecode) {
329 key_added_while_decode_pending_ = true;
333 if (state_ == kWaitingForKey) {
334 MEDIA_LOG(INFO, media_log_) << GetDisplayName()
335 << ": key added, resuming decode";
336 state_ = kPendingDecode;
337 DecodePendingBuffer();
341 void DecryptingVideoDecoder::DoReset() {
342 DCHECK(init_cb_.is_null());
343 DCHECK(decode_cb_.is_null());
345 base::ResetAndReturn(&reset_cb_).Run();