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/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"
22 DecryptingVideoDecoder::DecryptingVideoDecoder(
23 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
24 const SetDecryptorReadyCB
& set_decryptor_ready_cb
)
25 : task_runner_(task_runner
),
27 state_(kUninitialized
),
28 set_decryptor_ready_cb_(set_decryptor_ready_cb
),
30 key_added_while_decode_pending_(false),
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
||
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();
50 if (state_
== kUninitialized
) {
51 state_
= kDecryptorRequested
;
52 set_decryptor_ready_cb_
.Run(BindToCurrentLoop(base::Bind(
53 &DecryptingVideoDecoder::SetDecryptor
, weak_this_
)));
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
);
81 // Return empty frames if decoding has finished.
82 if (state_
== kDecodeFinished
) {
83 base::ResetAndReturn(&decode_cb_
).Run(kOk
, VideoFrame::CreateEOSFrame());
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
111 if (state_
== kPendingDecode
) {
112 DCHECK(!decode_cb_
.is_null());
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());
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
135 decryptor_
->RegisterNewKeyCB(Decryptor::kVideo
, Decryptor::NewKeyCB());
136 decryptor_
->DeinitializeDecoder(Decryptor::kVideo
);
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();
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
)
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();
169 base::ResetAndReturn(&init_cb_
).Run(DECODER_ERROR_NOT_SUPPORTED
);
174 decryptor_
= decryptor
;
176 state_
= kPendingDecoderInit
;
177 decryptor_
->InitializeVideoDecoder(
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
)
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.
196 base::ResetAndReturn(&init_cb_
).Run(DECODER_ERROR_NOT_SUPPORTED
);
201 decryptor_
->RegisterNewKeyCB(Decryptor::kVideo
, BindToCurrentLoop(
202 base::Bind(&DecryptingVideoDecoder::OnKeyAdded
, weak_this_
)));
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_
);
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 TRACE_EVENT_ASYNC_END0(
233 "media", "DecryptingVideoDecoder::DecodePendingBuffer", trace_id_
);
235 if (state_
== kStopped
)
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
);
255 DCHECK_EQ(status
== Decryptor::kSuccess
, frame
.get() != NULL
);
257 if (status
== Decryptor::kError
) {
258 DVLOG(2) << "DeliverFrame() - kError";
260 base::ResetAndReturn(&decode_cb_
).Run(kDecodeError
, NULL
);
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();
276 state_
= kWaitingForKey
;
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());
290 base::ResetAndReturn(&decode_cb_
).Run(kNotEnoughData
, NULL
);
294 DCHECK_EQ(status
, Decryptor::kSuccess
);
295 // No frame returned with kSuccess should be end-of-stream frame.
296 DCHECK(!frame
->end_of_stream());
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;
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());
320 base::ResetAndReturn(&reset_cb_
).Run();