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), media_log_(media_log) {}
29 std::string DecryptingVideoDecoder::GetDisplayName() const {
33 void DecryptingVideoDecoder::Initialize(const VideoDecoderConfig& config,
35 CdmContext* cdm_context,
37 const OutputCB& output_cb,
38 const WaitingCB& waiting_cb) {
39 DVLOG(2) << __func__ << ": " << config.AsHumanReadableString();
41 DCHECK(task_runner_->BelongsToCurrentThread());
42 DCHECK(state_ == kUninitialized || state_ == kIdle ||
43 state_ == kDecodeFinished)
47 DCHECK(config.IsValidConfig());
49 init_cb_ = BindToCurrentLoop(std::move(init_cb));
51 // Once we have a CDM context, one should always be present.
52 DCHECK(!support_clear_content_);
53 std::move(init_cb_).Run(StatusCode::kDecoderMissingCdmForEncryptedContent);
57 if (!config.is_encrypted() && !support_clear_content_) {
58 std::move(init_cb_).Run(StatusCode::kClearContentUnsupported);
62 // Once initialized with encryption support, the value is sticky, so we'll use
63 // the decryptor for clear content as well.
64 support_clear_content_ = true;
66 output_cb_ = BindToCurrentLoop(output_cb);
67 weak_this_ = weak_factory_.GetWeakPtr();
71 waiting_cb_ = waiting_cb;
73 if (state_ == kUninitialized) {
74 if (!cdm_context->GetDecryptor()) {
75 DVLOG(1) << __func__ << ": no decryptor";
76 std::move(init_cb_).Run(StatusCode::kDecoderFailedInitialization);
80 decryptor_ = cdm_context->GetDecryptor();
82 // Reinitialization (i.e. upon a config change). The new config can be
83 // encrypted or clear.
84 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
87 state_ = kPendingDecoderInit;
88 decryptor_->InitializeVideoDecoder(
89 config_, BindToCurrentLoop(base::BindOnce(
90 &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
93 void DecryptingVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
95 DVLOG(3) << "Decode()";
96 DCHECK(task_runner_->BelongsToCurrentThread());
97 DCHECK(state_ == kIdle || state_ == kDecodeFinished || state_ == kError)
100 CHECK(!decode_cb_) << "Overlapping decodes are not supported.";
102 decode_cb_ = BindToCurrentLoop(std::move(decode_cb));
104 if (state_ == kError) {
105 std::move(decode_cb_).Run(DecodeStatus::DECODE_ERROR);
109 // Return empty frames if decoding has finished.
110 if (state_ == kDecodeFinished) {
111 std::move(decode_cb_).Run(DecodeStatus::OK);
115 pending_buffer_to_decode_ = std::move(buffer);
116 state_ = kPendingDecode;
117 DecodePendingBuffer();
120 void DecryptingVideoDecoder::Reset(base::OnceClosure closure) {
121 DVLOG(2) << "Reset() - state: " << state_;
122 DCHECK(task_runner_->BelongsToCurrentThread());
123 DCHECK(state_ == kIdle || state_ == kPendingDecode ||
124 state_ == kWaitingForKey || state_ == kDecodeFinished ||
127 DCHECK(!init_cb_); // No Reset() during pending initialization.
130 reset_cb_ = BindToCurrentLoop(std::move(closure));
132 decryptor_->ResetDecoder(Decryptor::kVideo);
134 // Reset() cannot complete if the decode callback is still pending.
135 // Defer the resetting process in this case. The |reset_cb_| will be fired
136 // after the decode callback is fired - see DecryptAndDecodeBuffer() and
138 if (state_ == kPendingDecode) {
143 if (state_ == kWaitingForKey) {
144 CompleteWaitingForDecryptionKey();
146 pending_buffer_to_decode_.reset();
147 std::move(decode_cb_).Run(DecodeStatus::ABORTED);
154 DecryptingVideoDecoder::~DecryptingVideoDecoder() {
155 DCHECK(task_runner_->BelongsToCurrentThread());
157 if (state_ == kUninitialized)
160 if (state_ == kWaitingForKey)
161 CompleteWaitingForDecryptionKey();
162 if (state_ == kPendingDecode)
163 CompletePendingDecode(Decryptor::kError);
166 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
167 decryptor_ = nullptr;
169 pending_buffer_to_decode_.reset();
171 std::move(init_cb_).Run(StatusCode::kDecoderInitializeNeverCompleted);
173 std::move(decode_cb_).Run(DecodeStatus::ABORTED);
175 std::move(reset_cb_).Run();
178 void DecryptingVideoDecoder::FinishInitialization(bool success) {
179 DVLOG(2) << "FinishInitialization()";
180 DCHECK(task_runner_->BelongsToCurrentThread());
181 DCHECK_EQ(state_, kPendingDecoderInit) << state_;
183 DCHECK(!reset_cb_); // No Reset() before initialization finished.
184 DCHECK(!decode_cb_); // No Decode() before initialization finished.
187 DVLOG(1) << __func__ << ": failed to init video decoder on decryptor";
188 std::move(init_cb_).Run(StatusCode::kDecoderInitializeNeverCompleted);
189 decryptor_ = nullptr;
194 decryptor_->RegisterNewKeyCB(
195 Decryptor::kVideo, BindToCurrentLoop(base::BindRepeating(
196 &DecryptingVideoDecoder::OnKeyAdded, weak_this_)));
200 std::move(init_cb_).Run(OkStatus());
203 void DecryptingVideoDecoder::DecodePendingBuffer() {
204 DCHECK(task_runner_->BelongsToCurrentThread());
205 DCHECK_EQ(state_, kPendingDecode) << state_;
207 // Note: Traces require a unique ID per decode, if we ever support multiple
208 // in flight decodes, the trace begin+end macros need the same unique id.
209 DCHECK_EQ(GetMaxDecodeRequests(), 1);
210 TRACE_EVENT_ASYNC_BEGIN1(
211 "media", "DecryptingVideoDecoder::DecodePendingBuffer", this,
213 pending_buffer_to_decode_->end_of_stream()
215 : pending_buffer_to_decode_->timestamp().InMicroseconds());
217 decryptor_->DecryptAndDecodeVideo(
218 pending_buffer_to_decode_,
219 BindToCurrentLoop(base::BindRepeating(
220 &DecryptingVideoDecoder::DeliverFrame, weak_this_)));
223 void DecryptingVideoDecoder::DeliverFrame(Decryptor::Status status,
224 scoped_refptr<VideoFrame> frame) {
225 DVLOG(3) << "DeliverFrame() - status: " << status;
226 DCHECK(task_runner_->BelongsToCurrentThread());
227 DCHECK_EQ(state_, kPendingDecode) << state_;
229 DCHECK(pending_buffer_to_decode_.get());
230 CompletePendingDecode(status);
232 bool need_to_try_again_if_nokey_is_returned = key_added_while_decode_pending_;
233 key_added_while_decode_pending_ = false;
235 scoped_refptr<DecoderBuffer> scoped_pending_buffer_to_decode =
236 std::move(pending_buffer_to_decode_);
239 std::move(decode_cb_).Run(DecodeStatus::ABORTED);
244 DCHECK_EQ(status == Decryptor::kSuccess, frame.get() != nullptr);
246 if (status == Decryptor::kError) {
247 DVLOG(2) << "DeliverFrame() - kError";
248 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": decode error";
250 std::move(decode_cb_).Run(DecodeStatus::DECODE_ERROR);
254 if (status == Decryptor::kNoKey) {
256 scoped_pending_buffer_to_decode->decrypt_config()->key_id();
257 std::string log_message =
258 "no key for key ID " + base::HexEncode(key_id.data(), key_id.size()) +
259 "; will resume decoding after new usable key is available";
260 DVLOG(1) << __func__ << ": " << log_message;
261 MEDIA_LOG(INFO, media_log_) << GetDisplayName() << ": " << log_message;
263 // Set |pending_buffer_to_decode_| back as we need to try decoding the
264 // pending buffer again when new key is added to the decryptor.
265 pending_buffer_to_decode_ = std::move(scoped_pending_buffer_to_decode);
267 if (need_to_try_again_if_nokey_is_returned) {
268 // The |state_| is still kPendingDecode.
269 MEDIA_LOG(INFO, media_log_)
270 << GetDisplayName() << ": key was added, resuming decode";
271 DecodePendingBuffer();
275 TRACE_EVENT_ASYNC_BEGIN0(
276 "media", "DecryptingVideoDecoder::WaitingForDecryptionKey", this);
277 state_ = kWaitingForKey;
278 waiting_cb_.Run(WaitingReason::kNoDecryptionKey);
282 if (status == Decryptor::kNeedMoreData) {
283 DVLOG(2) << "DeliverFrame() - kNeedMoreData";
284 state_ = scoped_pending_buffer_to_decode->end_of_stream() ? kDecodeFinished
286 std::move(decode_cb_).Run(DecodeStatus::OK);
290 DCHECK_EQ(status, Decryptor::kSuccess);
293 // Frame returned with kSuccess should not be an end-of-stream frame.
294 DCHECK(!frame->metadata()->end_of_stream);
296 // If color space is not set, use the color space in the |config_|.
297 if (!frame->ColorSpace().IsValid()) {
298 DVLOG(3) << "Setting color space using information in the config.";
299 if (config_.color_space_info().IsSpecified())
300 frame->set_color_space(config_.color_space_info().ToGfxColorSpace());
303 output_cb_.Run(std::move(frame));
305 if (scoped_pending_buffer_to_decode->end_of_stream()) {
306 // Set |pending_buffer_to_decode_| back as we need to keep flushing the
308 pending_buffer_to_decode_ = std::move(scoped_pending_buffer_to_decode);
309 DecodePendingBuffer();
314 std::move(decode_cb_).Run(DecodeStatus::OK);
317 void DecryptingVideoDecoder::OnKeyAdded() {
318 DVLOG(2) << "OnKeyAdded()";
319 DCHECK(task_runner_->BelongsToCurrentThread());
321 if (state_ == kPendingDecode) {
322 key_added_while_decode_pending_ = true;
326 if (state_ == kWaitingForKey) {
327 CompleteWaitingForDecryptionKey();
328 MEDIA_LOG(INFO, media_log_)
329 << GetDisplayName() << ": key added, resuming decode";
330 state_ = kPendingDecode;
331 DecodePendingBuffer();
335 void DecryptingVideoDecoder::DoReset() {
339 std::move(reset_cb_).Run();
342 void DecryptingVideoDecoder::CompletePendingDecode(Decryptor::Status status) {
343 DCHECK_EQ(state_, kPendingDecode);
344 TRACE_EVENT_ASYNC_END1("media", "DecryptingVideoDecoder::DecodePendingBuffer",
345 this, "status", Decryptor::GetStatusName(status));
348 void DecryptingVideoDecoder::CompleteWaitingForDecryptionKey() {
349 DCHECK_EQ(state_, kWaitingForKey);
350 TRACE_EVENT_ASYNC_END0(
351 "media", "DecryptingVideoDecoder::WaitingForDecryptionKey", this);