Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / media / filters / decrypting_video_decoder.cc
blobd9bba50331a1532129ce9d50c178980af3115a38
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"
7 #include "base/bind.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/trace_event/trace_event.h"
13 #include "media/base/bind_to_current_loop.h"
14 #include "media/base/decoder_buffer.h"
15 #include "media/base/decryptor.h"
16 #include "media/base/pipeline.h"
17 #include "media/base/video_decoder_config.h"
18 #include "media/base/video_frame.h"
20 namespace media {
22 const char DecryptingVideoDecoder::kDecoderName[] = "DecryptingVideoDecoder";
24 DecryptingVideoDecoder::DecryptingVideoDecoder(
25 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
26 const SetDecryptorReadyCB& set_decryptor_ready_cb,
27 const base::Closure& waiting_for_decryption_key_cb)
28 : task_runner_(task_runner),
29 state_(kUninitialized),
30 waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
31 set_decryptor_ready_cb_(set_decryptor_ready_cb),
32 decryptor_(NULL),
33 key_added_while_decode_pending_(false),
34 trace_id_(0),
35 weak_factory_(this) {
38 std::string DecryptingVideoDecoder::GetDisplayName() const {
39 return kDecoderName;
42 void DecryptingVideoDecoder::Initialize(const VideoDecoderConfig& config,
43 bool /* low_delay */,
44 const PipelineStatusCB& status_cb,
45 const OutputCB& output_cb) {
46 DVLOG(2) << "Initialize()";
47 DCHECK(task_runner_->BelongsToCurrentThread());
48 DCHECK(state_ == kUninitialized ||
49 state_ == kIdle ||
50 state_ == kDecodeFinished) << state_;
51 DCHECK(decode_cb_.is_null());
52 DCHECK(reset_cb_.is_null());
53 DCHECK(config.IsValidConfig());
54 DCHECK(config.is_encrypted());
56 init_cb_ = BindToCurrentLoop(status_cb);
57 output_cb_ = BindToCurrentLoop(output_cb);
58 weak_this_ = weak_factory_.GetWeakPtr();
59 config_ = config;
61 if (state_ == kUninitialized) {
62 state_ = kDecryptorRequested;
63 set_decryptor_ready_cb_.Run(BindToCurrentLoop(base::Bind(
64 &DecryptingVideoDecoder::SetDecryptor, weak_this_)));
65 return;
68 // Reinitialization.
69 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
70 state_ = kPendingDecoderInit;
71 decryptor_->InitializeVideoDecoder(config, BindToCurrentLoop(base::Bind(
72 &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
75 void DecryptingVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
76 const DecodeCB& decode_cb) {
77 DVLOG(3) << "Decode()";
78 DCHECK(task_runner_->BelongsToCurrentThread());
79 DCHECK(state_ == kIdle ||
80 state_ == kDecodeFinished ||
81 state_ == kError) << state_;
82 DCHECK(!decode_cb.is_null());
83 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported.";
85 decode_cb_ = BindToCurrentLoop(decode_cb);
87 if (state_ == kError) {
88 base::ResetAndReturn(&decode_cb_).Run(kDecodeError);
89 return;
92 // Return empty frames if decoding has finished.
93 if (state_ == kDecodeFinished) {
94 base::ResetAndReturn(&decode_cb_).Run(kOk);
95 return;
98 pending_buffer_to_decode_ = buffer;
99 state_ = kPendingDecode;
100 DecodePendingBuffer();
103 void DecryptingVideoDecoder::Reset(const base::Closure& closure) {
104 DVLOG(2) << "Reset() - state: " << state_;
105 DCHECK(task_runner_->BelongsToCurrentThread());
106 DCHECK(state_ == kIdle ||
107 state_ == kPendingDecode ||
108 state_ == kWaitingForKey ||
109 state_ == kDecodeFinished ||
110 state_ == kError) << state_;
111 DCHECK(init_cb_.is_null()); // No Reset() during pending initialization.
112 DCHECK(reset_cb_.is_null());
114 reset_cb_ = BindToCurrentLoop(closure);
116 decryptor_->ResetDecoder(Decryptor::kVideo);
118 // Reset() cannot complete if the decode callback is still pending.
119 // Defer the resetting process in this case. The |reset_cb_| will be fired
120 // after the decode callback is fired - see DecryptAndDecodeBuffer() and
121 // DeliverFrame().
122 if (state_ == kPendingDecode) {
123 DCHECK(!decode_cb_.is_null());
124 return;
127 if (state_ == kWaitingForKey) {
128 DCHECK(!decode_cb_.is_null());
129 pending_buffer_to_decode_ = NULL;
130 base::ResetAndReturn(&decode_cb_).Run(kAborted);
133 DCHECK(decode_cb_.is_null());
134 DoReset();
137 DecryptingVideoDecoder::~DecryptingVideoDecoder() {
138 DCHECK(task_runner_->BelongsToCurrentThread());
140 if (state_ == kUninitialized)
141 return;
143 if (decryptor_) {
144 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
145 decryptor_ = NULL;
147 if (!set_decryptor_ready_cb_.is_null())
148 base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
149 pending_buffer_to_decode_ = NULL;
150 if (!init_cb_.is_null())
151 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
152 if (!decode_cb_.is_null())
153 base::ResetAndReturn(&decode_cb_).Run(kAborted);
154 if (!reset_cb_.is_null())
155 base::ResetAndReturn(&reset_cb_).Run();
158 void DecryptingVideoDecoder::SetDecryptor(
159 Decryptor* decryptor,
160 const DecryptorAttachedCB& decryptor_attached_cb) {
161 DVLOG(2) << "SetDecryptor()";
162 DCHECK(task_runner_->BelongsToCurrentThread());
163 DCHECK_EQ(state_, kDecryptorRequested) << state_;
164 DCHECK(!init_cb_.is_null());
165 DCHECK(!set_decryptor_ready_cb_.is_null());
166 set_decryptor_ready_cb_.Reset();
168 if (!decryptor) {
169 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
170 state_ = kError;
171 decryptor_attached_cb.Run(false);
172 return;
175 decryptor_ = decryptor;
177 state_ = kPendingDecoderInit;
178 decryptor_->InitializeVideoDecoder(
179 config_,
180 BindToCurrentLoop(base::Bind(
181 &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
182 decryptor_attached_cb.Run(true);
185 void DecryptingVideoDecoder::FinishInitialization(bool success) {
186 DVLOG(2) << "FinishInitialization()";
187 DCHECK(task_runner_->BelongsToCurrentThread());
188 DCHECK_EQ(state_, kPendingDecoderInit) << state_;
189 DCHECK(!init_cb_.is_null());
190 DCHECK(reset_cb_.is_null()); // No Reset() before initialization finished.
191 DCHECK(decode_cb_.is_null()); // No Decode() before initialization finished.
193 if (!success) {
194 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
195 decryptor_ = NULL;
196 state_ = kError;
197 return;
200 decryptor_->RegisterNewKeyCB(
201 Decryptor::kVideo,
202 BindToCurrentLoop(
203 base::Bind(&DecryptingVideoDecoder::OnKeyAdded, weak_this_)));
205 // Success!
206 state_ = kIdle;
207 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
211 void DecryptingVideoDecoder::DecodePendingBuffer() {
212 DCHECK(task_runner_->BelongsToCurrentThread());
213 DCHECK_EQ(state_, kPendingDecode) << state_;
214 TRACE_EVENT_ASYNC_BEGIN0(
215 "media", "DecryptingVideoDecoder::DecodePendingBuffer", ++trace_id_);
217 int buffer_size = 0;
218 if (!pending_buffer_to_decode_->end_of_stream()) {
219 buffer_size = pending_buffer_to_decode_->data_size();
222 decryptor_->DecryptAndDecodeVideo(
223 pending_buffer_to_decode_, BindToCurrentLoop(base::Bind(
224 &DecryptingVideoDecoder::DeliverFrame, weak_this_, buffer_size)));
227 void DecryptingVideoDecoder::DeliverFrame(
228 int buffer_size,
229 Decryptor::Status status,
230 const scoped_refptr<VideoFrame>& frame) {
231 DVLOG(3) << "DeliverFrame() - status: " << status;
232 DCHECK(task_runner_->BelongsToCurrentThread());
233 DCHECK_EQ(state_, kPendingDecode) << state_;
234 DCHECK(!decode_cb_.is_null());
235 DCHECK(pending_buffer_to_decode_.get());
237 TRACE_EVENT_ASYNC_END2(
238 "media", "DecryptingVideoDecoder::DecodePendingBuffer", trace_id_,
239 "buffer_size", buffer_size, "status", status);
241 bool need_to_try_again_if_nokey_is_returned = key_added_while_decode_pending_;
242 key_added_while_decode_pending_ = false;
244 scoped_refptr<DecoderBuffer> scoped_pending_buffer_to_decode =
245 pending_buffer_to_decode_;
246 pending_buffer_to_decode_ = NULL;
248 if (!reset_cb_.is_null()) {
249 base::ResetAndReturn(&decode_cb_).Run(kAborted);
250 DoReset();
251 return;
254 DCHECK_EQ(status == Decryptor::kSuccess, frame.get() != NULL);
256 if (status == Decryptor::kError) {
257 DVLOG(2) << "DeliverFrame() - kError";
258 state_ = kError;
259 base::ResetAndReturn(&decode_cb_).Run(kDecodeError);
260 return;
263 if (status == Decryptor::kNoKey) {
264 DVLOG(2) << "DeliverFrame() - kNoKey";
265 // Set |pending_buffer_to_decode_| back as we need to try decoding the
266 // pending buffer again when new key is added to the decryptor.
267 pending_buffer_to_decode_ = scoped_pending_buffer_to_decode;
269 if (need_to_try_again_if_nokey_is_returned) {
270 // The |state_| is still kPendingDecode.
271 DecodePendingBuffer();
272 return;
275 state_ = kWaitingForKey;
276 waiting_for_decryption_key_cb_.Run();
277 return;
280 if (status == Decryptor::kNeedMoreData) {
281 DVLOG(2) << "DeliverFrame() - kNeedMoreData";
282 state_ = scoped_pending_buffer_to_decode->end_of_stream() ? kDecodeFinished
283 : kIdle;
284 base::ResetAndReturn(&decode_cb_).Run(kOk);
285 return;
288 DCHECK_EQ(status, Decryptor::kSuccess);
289 // No frame returned with kSuccess should be end-of-stream frame.
290 DCHECK(!frame->end_of_stream());
291 output_cb_.Run(frame);
293 if (scoped_pending_buffer_to_decode->end_of_stream()) {
294 // Set |pending_buffer_to_decode_| back as we need to keep flushing the
295 // decryptor.
296 pending_buffer_to_decode_ = scoped_pending_buffer_to_decode;
297 DecodePendingBuffer();
298 return;
301 state_ = kIdle;
302 base::ResetAndReturn(&decode_cb_).Run(kOk);
305 void DecryptingVideoDecoder::OnKeyAdded() {
306 DVLOG(2) << "OnKeyAdded()";
307 DCHECK(task_runner_->BelongsToCurrentThread());
309 if (state_ == kPendingDecode) {
310 key_added_while_decode_pending_ = true;
311 return;
314 if (state_ == kWaitingForKey) {
315 state_ = kPendingDecode;
316 DecodePendingBuffer();
320 void DecryptingVideoDecoder::DoReset() {
321 DCHECK(init_cb_.is_null());
322 DCHECK(decode_cb_.is_null());
323 state_ = kIdle;
324 base::ResetAndReturn(&reset_cb_).Run();
327 } // namespace media