Reland r246152 cros: Change how multi-profile is enabled.
[chromium-blink-merge.git] / media / filters / decrypting_video_decoder.cc
blobbae5ab13dfb3fceae1d518ea6272a16d2e2d7fe0
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/debug/trace_event.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.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 DecryptingVideoDecoder::DecryptingVideoDecoder(
23 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
24 const SetDecryptorReadyCB& set_decryptor_ready_cb)
25 : task_runner_(task_runner),
26 weak_factory_(this),
27 state_(kUninitialized),
28 set_decryptor_ready_cb_(set_decryptor_ready_cb),
29 decryptor_(NULL),
30 key_added_while_decode_pending_(false),
31 trace_id_(0) {
34 void DecryptingVideoDecoder::Initialize(const VideoDecoderConfig& config,
35 const PipelineStatusCB& status_cb) {
36 DVLOG(2) << "Initialize()";
37 DCHECK(task_runner_->BelongsToCurrentThread());
38 DCHECK(state_ == kUninitialized ||
39 state_ == kIdle ||
40 state_ == kDecodeFinished) << state_;
41 DCHECK(decode_cb_.is_null());
42 DCHECK(reset_cb_.is_null());
43 DCHECK(config.IsValidConfig());
44 DCHECK(config.is_encrypted());
46 init_cb_ = BindToCurrentLoop(status_cb);
47 weak_this_ = weak_factory_.GetWeakPtr();
48 config_ = config;
50 if (state_ == kUninitialized) {
51 state_ = kDecryptorRequested;
52 set_decryptor_ready_cb_.Run(BindToCurrentLoop(base::Bind(
53 &DecryptingVideoDecoder::SetDecryptor, weak_this_)));
54 return;
57 // Reinitialization.
58 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
59 state_ = kPendingDecoderInit;
60 decryptor_->InitializeVideoDecoder(config, BindToCurrentLoop(base::Bind(
61 &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
64 void DecryptingVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
65 const DecodeCB& decode_cb) {
66 DVLOG(3) << "Decode()";
67 DCHECK(task_runner_->BelongsToCurrentThread());
68 DCHECK(state_ == kIdle ||
69 state_ == kDecodeFinished ||
70 state_ == kError) << state_;
71 DCHECK(!decode_cb.is_null());
72 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported.";
74 decode_cb_ = BindToCurrentLoop(decode_cb);
76 if (state_ == kError) {
77 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL);
78 return;
81 // Return empty frames if decoding has finished.
82 if (state_ == kDecodeFinished) {
83 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEOSFrame());
84 return;
87 pending_buffer_to_decode_ = buffer;
88 state_ = kPendingDecode;
89 DecodePendingBuffer();
92 void DecryptingVideoDecoder::Reset(const base::Closure& closure) {
93 DVLOG(2) << "Reset() - state: " << state_;
94 DCHECK(task_runner_->BelongsToCurrentThread());
95 DCHECK(state_ == kIdle ||
96 state_ == kPendingDecode ||
97 state_ == kWaitingForKey ||
98 state_ == kDecodeFinished ||
99 state_ == kError) << state_;
100 DCHECK(init_cb_.is_null()); // No Reset() during pending initialization.
101 DCHECK(reset_cb_.is_null());
103 reset_cb_ = BindToCurrentLoop(closure);
105 decryptor_->ResetDecoder(Decryptor::kVideo);
107 // Reset() cannot complete if the decode callback is still pending.
108 // Defer the resetting process in this case. The |reset_cb_| will be fired
109 // after the decode callback is fired - see DecryptAndDecodeBuffer() and
110 // DeliverFrame().
111 if (state_ == kPendingDecode) {
112 DCHECK(!decode_cb_.is_null());
113 return;
116 if (state_ == kWaitingForKey) {
117 DCHECK(!decode_cb_.is_null());
118 pending_buffer_to_decode_ = NULL;
119 base::ResetAndReturn(&decode_cb_).Run(kAborted, NULL);
122 DCHECK(decode_cb_.is_null());
123 DoReset();
126 void DecryptingVideoDecoder::Stop(const base::Closure& closure) {
127 DCHECK(task_runner_->BelongsToCurrentThread());
128 DVLOG(2) << "Stop() - state: " << state_;
130 // At this point the render thread is likely paused (in WebMediaPlayerImpl's
131 // Destroy()), so running |closure| can't wait for anything that requires the
132 // render thread to be processing messages to complete (such as PPAPI
133 // callbacks).
134 if (decryptor_) {
135 decryptor_->RegisterNewKeyCB(Decryptor::kVideo, Decryptor::NewKeyCB());
136 decryptor_->DeinitializeDecoder(Decryptor::kVideo);
137 decryptor_ = NULL;
139 if (!set_decryptor_ready_cb_.is_null())
140 base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
141 pending_buffer_to_decode_ = NULL;
142 if (!init_cb_.is_null())
143 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
144 if (!decode_cb_.is_null())
145 base::ResetAndReturn(&decode_cb_).Run(kAborted, NULL);
146 if (!reset_cb_.is_null())
147 base::ResetAndReturn(&reset_cb_).Run();
148 state_ = kStopped;
149 BindToCurrentLoop(closure).Run();
152 DecryptingVideoDecoder::~DecryptingVideoDecoder() {
153 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
156 void DecryptingVideoDecoder::SetDecryptor(Decryptor* decryptor) {
157 DVLOG(2) << "SetDecryptor()";
158 DCHECK(task_runner_->BelongsToCurrentThread());
160 if (state_ == kStopped)
161 return;
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_ = kStopped;
171 return;
174 decryptor_ = decryptor;
176 state_ = kPendingDecoderInit;
177 decryptor_->InitializeVideoDecoder(
178 config_,
179 BindToCurrentLoop(base::Bind(
180 &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
183 void DecryptingVideoDecoder::FinishInitialization(bool success) {
184 DVLOG(2) << "FinishInitialization()";
185 DCHECK(task_runner_->BelongsToCurrentThread());
187 if (state_ == kStopped)
188 return;
190 DCHECK_EQ(state_, kPendingDecoderInit) << state_;
191 DCHECK(!init_cb_.is_null());
192 DCHECK(reset_cb_.is_null()); // No Reset() before initialization finished.
193 DCHECK(decode_cb_.is_null()); // No Decode() before initialization finished.
195 if (!success) {
196 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
197 state_ = kStopped;
198 return;
201 decryptor_->RegisterNewKeyCB(Decryptor::kVideo, BindToCurrentLoop(
202 base::Bind(&DecryptingVideoDecoder::OnKeyAdded, weak_this_)));
204 // Success!
205 state_ = kIdle;
206 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
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_);
216 int buffer_size = 0;
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(
227 int buffer_size,
228 Decryptor::Status status,
229 const scoped_refptr<VideoFrame>& frame) {
230 DVLOG(3) << "DeliverFrame() - status: " << status;
231 DCHECK(task_runner_->BelongsToCurrentThread());
232 TRACE_EVENT_ASYNC_END0(
233 "media", "DecryptingVideoDecoder::DecodePendingBuffer", trace_id_);
235 if (state_ == kStopped)
236 return;
238 DCHECK_EQ(state_, kPendingDecode) << state_;
239 DCHECK(!decode_cb_.is_null());
240 DCHECK(pending_buffer_to_decode_.get());
242 bool need_to_try_again_if_nokey_is_returned = key_added_while_decode_pending_;
243 key_added_while_decode_pending_ = false;
245 scoped_refptr<DecoderBuffer> scoped_pending_buffer_to_decode =
246 pending_buffer_to_decode_;
247 pending_buffer_to_decode_ = NULL;
249 if (!reset_cb_.is_null()) {
250 base::ResetAndReturn(&decode_cb_).Run(kAborted, NULL);
251 DoReset();
252 return;
255 DCHECK_EQ(status == Decryptor::kSuccess, frame.get() != NULL);
257 if (status == Decryptor::kError) {
258 DVLOG(2) << "DeliverFrame() - kError";
259 state_ = kError;
260 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL);
261 return;
264 if (status == Decryptor::kNoKey) {
265 DVLOG(2) << "DeliverFrame() - kNoKey";
266 // Set |pending_buffer_to_decode_| back as we need to try decoding the
267 // pending buffer again when new key is added to the decryptor.
268 pending_buffer_to_decode_ = scoped_pending_buffer_to_decode;
270 if (need_to_try_again_if_nokey_is_returned) {
271 // The |state_| is still kPendingDecode.
272 DecodePendingBuffer();
273 return;
276 state_ = kWaitingForKey;
277 return;
280 if (status == Decryptor::kNeedMoreData) {
281 DVLOG(2) << "DeliverFrame() - kNeedMoreData";
282 if (scoped_pending_buffer_to_decode->end_of_stream()) {
283 state_ = kDecodeFinished;
284 base::ResetAndReturn(&decode_cb_).Run(
285 kOk, media::VideoFrame::CreateEOSFrame());
286 return;
289 state_ = kIdle;
290 base::ResetAndReturn(&decode_cb_).Run(kNotEnoughData, NULL);
291 return;
294 DCHECK_EQ(status, Decryptor::kSuccess);
295 // No frame returned with kSuccess should be end-of-stream frame.
296 DCHECK(!frame->end_of_stream());
297 state_ = kIdle;
298 base::ResetAndReturn(&decode_cb_).Run(kOk, frame);
301 void DecryptingVideoDecoder::OnKeyAdded() {
302 DVLOG(2) << "OnKeyAdded()";
303 DCHECK(task_runner_->BelongsToCurrentThread());
305 if (state_ == kPendingDecode) {
306 key_added_while_decode_pending_ = true;
307 return;
310 if (state_ == kWaitingForKey) {
311 state_ = kPendingDecode;
312 DecodePendingBuffer();
316 void DecryptingVideoDecoder::DoReset() {
317 DCHECK(init_cb_.is_null());
318 DCHECK(decode_cb_.is_null());
319 state_ = kIdle;
320 base::ResetAndReturn(&reset_cb_).Run();
323 } // namespace media