cleanup: pass string as const reference from c/b/extension
[chromium-blink-merge.git] / media / filters / decrypting_demuxer_stream.cc
blob6a1de5f38c41b48a16821be84cf3542a4028e0a9
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_demuxer_stream.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 "media/base/audio_decoder_config.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/demuxer_stream.h"
17 #include "media/base/pipeline.h"
18 #include "media/base/video_decoder_config.h"
20 namespace media {
22 static bool IsStreamValidAndEncrypted(DemuxerStream* stream) {
23 return ((stream->type() == DemuxerStream::AUDIO &&
24 stream->audio_decoder_config().IsValidConfig() &&
25 stream->audio_decoder_config().is_encrypted()) ||
26 (stream->type() == DemuxerStream::VIDEO &&
27 stream->video_decoder_config().IsValidConfig() &&
28 stream->video_decoder_config().is_encrypted()));
31 DecryptingDemuxerStream::DecryptingDemuxerStream(
32 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
33 const SetDecryptorReadyCB& set_decryptor_ready_cb)
34 : task_runner_(task_runner),
35 state_(kUninitialized),
36 demuxer_stream_(NULL),
37 set_decryptor_ready_cb_(set_decryptor_ready_cb),
38 decryptor_(NULL),
39 key_added_while_decrypt_pending_(false),
40 weak_factory_(this) {}
42 void DecryptingDemuxerStream::Initialize(DemuxerStream* stream,
43 const PipelineStatusCB& status_cb) {
44 DVLOG(2) << __FUNCTION__;
45 DCHECK(task_runner_->BelongsToCurrentThread());
46 DCHECK_EQ(state_, kUninitialized) << state_;
48 DCHECK(!demuxer_stream_);
49 weak_this_ = weak_factory_.GetWeakPtr();
50 demuxer_stream_ = stream;
51 init_cb_ = BindToCurrentLoop(status_cb);
53 InitializeDecoderConfig();
55 state_ = kDecryptorRequested;
56 set_decryptor_ready_cb_.Run(BindToCurrentLoop(
57 base::Bind(&DecryptingDemuxerStream::SetDecryptor, weak_this_)));
60 void DecryptingDemuxerStream::Read(const ReadCB& read_cb) {
61 DVLOG(3) << __FUNCTION__;
62 DCHECK(task_runner_->BelongsToCurrentThread());
63 DCHECK_EQ(state_, kIdle) << state_;
64 DCHECK(!read_cb.is_null());
65 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported.";
67 read_cb_ = BindToCurrentLoop(read_cb);
68 state_ = kPendingDemuxerRead;
69 demuxer_stream_->Read(
70 base::Bind(&DecryptingDemuxerStream::DecryptBuffer, weak_this_));
73 void DecryptingDemuxerStream::Reset(const base::Closure& closure) {
74 DVLOG(2) << __FUNCTION__ << " - state: " << state_;
75 DCHECK(task_runner_->BelongsToCurrentThread());
76 DCHECK(state_ != kUninitialized) << state_;
77 DCHECK(state_ != kStopped) << state_;
78 DCHECK(reset_cb_.is_null());
80 reset_cb_ = BindToCurrentLoop(closure);
82 // TODO(xhwang): This should not happen. Remove it, DCHECK against the
83 // condition and clean up related tests.
84 if (state_ == kDecryptorRequested) {
85 DCHECK(!init_cb_.is_null());
86 set_decryptor_ready_cb_.Run(DecryptorReadyCB());
87 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
88 DoReset();
89 return;
92 decryptor_->CancelDecrypt(GetDecryptorStreamType());
94 // Reset() cannot complete if the read callback is still pending.
95 // Defer the resetting process in this case. The |reset_cb_| will be fired
96 // after the read callback is fired - see DoDecryptBuffer() and
97 // DoDeliverBuffer().
98 if (state_ == kPendingDemuxerRead || state_ == kPendingDecrypt) {
99 DCHECK(!read_cb_.is_null());
100 return;
103 if (state_ == kWaitingForKey) {
104 DCHECK(!read_cb_.is_null());
105 pending_buffer_to_decrypt_ = NULL;
106 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
109 DCHECK(read_cb_.is_null());
110 DoReset();
113 void DecryptingDemuxerStream::Stop(const base::Closure& closure) {
114 DVLOG(2) << __FUNCTION__ << " - state: " << state_;
115 DCHECK(task_runner_->BelongsToCurrentThread());
116 DCHECK(state_ != kUninitialized) << state_;
118 // Invalidate all weak pointers so that pending callbacks won't be fired into
119 // this object.
120 weak_factory_.InvalidateWeakPtrs();
122 // At this point the render thread is likely paused (in WebMediaPlayerImpl's
123 // Destroy()), so running |closure| can't wait for anything that requires the
124 // render thread to process messages to complete (such as PPAPI methods).
125 if (decryptor_) {
126 decryptor_->CancelDecrypt(GetDecryptorStreamType());
127 decryptor_ = NULL;
129 if (!set_decryptor_ready_cb_.is_null())
130 base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
131 if (!init_cb_.is_null())
132 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
133 if (!read_cb_.is_null())
134 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
135 if (!reset_cb_.is_null())
136 base::ResetAndReturn(&reset_cb_).Run();
137 pending_buffer_to_decrypt_ = NULL;
139 state_ = kStopped;
140 BindToCurrentLoop(closure).Run();
143 AudioDecoderConfig DecryptingDemuxerStream::audio_decoder_config() {
144 DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_;
145 CHECK_EQ(demuxer_stream_->type(), AUDIO);
146 return audio_config_;
149 VideoDecoderConfig DecryptingDemuxerStream::video_decoder_config() {
150 DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_;
151 CHECK_EQ(demuxer_stream_->type(), VIDEO);
152 return video_config_;
155 DemuxerStream::Type DecryptingDemuxerStream::type() {
156 DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_;
157 return demuxer_stream_->type();
160 void DecryptingDemuxerStream::EnableBitstreamConverter() {
161 demuxer_stream_->EnableBitstreamConverter();
164 bool DecryptingDemuxerStream::SupportsConfigChanges() {
165 return demuxer_stream_->SupportsConfigChanges();
168 DecryptingDemuxerStream::~DecryptingDemuxerStream() {
169 DVLOG(2) << __FUNCTION__ << " : state_ = " << state_;
172 void DecryptingDemuxerStream::SetDecryptor(Decryptor* decryptor) {
173 DVLOG(2) << __FUNCTION__;
174 DCHECK(task_runner_->BelongsToCurrentThread());
175 DCHECK_EQ(state_, kDecryptorRequested) << state_;
176 DCHECK(!init_cb_.is_null());
177 DCHECK(!set_decryptor_ready_cb_.is_null());
179 set_decryptor_ready_cb_.Reset();
181 if (!decryptor) {
182 state_ = kUninitialized;
183 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
184 return;
187 decryptor_ = decryptor;
189 decryptor_->RegisterNewKeyCB(
190 GetDecryptorStreamType(),
191 BindToCurrentLoop(
192 base::Bind(&DecryptingDemuxerStream::OnKeyAdded, weak_this_)));
194 state_ = kIdle;
195 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
198 void DecryptingDemuxerStream::DecryptBuffer(
199 DemuxerStream::Status status,
200 const scoped_refptr<DecoderBuffer>& buffer) {
201 DVLOG(3) << __FUNCTION__;
202 DCHECK(task_runner_->BelongsToCurrentThread());
203 DCHECK_EQ(state_, kPendingDemuxerRead) << state_;
204 DCHECK(!read_cb_.is_null());
205 DCHECK_EQ(buffer.get() != NULL, status == kOk) << status;
207 // Even when |!reset_cb_.is_null()|, we need to pass |kConfigChanged| back to
208 // the caller so that the downstream decoder can be properly reinitialized.
209 if (status == kConfigChanged) {
210 DVLOG(2) << "DoDecryptBuffer() - kConfigChanged.";
211 DCHECK_EQ(demuxer_stream_->type() == AUDIO, audio_config_.IsValidConfig());
212 DCHECK_EQ(demuxer_stream_->type() == VIDEO, video_config_.IsValidConfig());
214 // Update the decoder config, which the decoder will use when it is notified
215 // of kConfigChanged.
216 InitializeDecoderConfig();
217 state_ = kIdle;
218 base::ResetAndReturn(&read_cb_).Run(kConfigChanged, NULL);
219 if (!reset_cb_.is_null())
220 DoReset();
221 return;
224 if (!reset_cb_.is_null()) {
225 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
226 DoReset();
227 return;
230 if (status == kAborted) {
231 DVLOG(2) << "DoDecryptBuffer() - kAborted.";
232 state_ = kIdle;
233 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
234 return;
237 if (buffer->end_of_stream()) {
238 DVLOG(2) << "DoDecryptBuffer() - EOS buffer.";
239 state_ = kIdle;
240 base::ResetAndReturn(&read_cb_).Run(status, buffer);
241 return;
244 DCHECK(buffer->decrypt_config());
245 // An empty iv string signals that the frame is unencrypted.
246 if (buffer->decrypt_config()->iv().empty()) {
247 DVLOG(2) << "DoDecryptBuffer() - clear buffer.";
248 scoped_refptr<DecoderBuffer> decrypted = DecoderBuffer::CopyFrom(
249 buffer->data(), buffer->data_size());
250 decrypted->set_timestamp(buffer->timestamp());
251 decrypted->set_duration(buffer->duration());
252 state_ = kIdle;
253 base::ResetAndReturn(&read_cb_).Run(kOk, decrypted);
254 return;
257 pending_buffer_to_decrypt_ = buffer;
258 state_ = kPendingDecrypt;
259 DecryptPendingBuffer();
262 void DecryptingDemuxerStream::DecryptPendingBuffer() {
263 DCHECK(task_runner_->BelongsToCurrentThread());
264 DCHECK_EQ(state_, kPendingDecrypt) << state_;
265 decryptor_->Decrypt(
266 GetDecryptorStreamType(),
267 pending_buffer_to_decrypt_,
268 BindToCurrentLoop(
269 base::Bind(&DecryptingDemuxerStream::DeliverBuffer, weak_this_)));
272 void DecryptingDemuxerStream::DeliverBuffer(
273 Decryptor::Status status,
274 const scoped_refptr<DecoderBuffer>& decrypted_buffer) {
275 DVLOG(3) << __FUNCTION__ << " - status: " << status;
276 DCHECK(task_runner_->BelongsToCurrentThread());
277 DCHECK_EQ(state_, kPendingDecrypt) << state_;
278 DCHECK_NE(status, Decryptor::kNeedMoreData);
279 DCHECK(!read_cb_.is_null());
280 DCHECK(pending_buffer_to_decrypt_.get());
282 bool need_to_try_again_if_nokey = key_added_while_decrypt_pending_;
283 key_added_while_decrypt_pending_ = false;
285 if (!reset_cb_.is_null()) {
286 pending_buffer_to_decrypt_ = NULL;
287 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
288 DoReset();
289 return;
292 DCHECK_EQ(status == Decryptor::kSuccess, decrypted_buffer.get() != NULL);
294 if (status == Decryptor::kError) {
295 DVLOG(2) << "DoDeliverBuffer() - kError";
296 pending_buffer_to_decrypt_ = NULL;
297 state_ = kIdle;
298 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
299 return;
302 if (status == Decryptor::kNoKey) {
303 DVLOG(2) << "DoDeliverBuffer() - kNoKey";
304 if (need_to_try_again_if_nokey) {
305 // The |state_| is still kPendingDecrypt.
306 DecryptPendingBuffer();
307 return;
310 state_ = kWaitingForKey;
311 return;
314 DCHECK_EQ(status, Decryptor::kSuccess);
315 pending_buffer_to_decrypt_ = NULL;
316 state_ = kIdle;
317 base::ResetAndReturn(&read_cb_).Run(kOk, decrypted_buffer);
320 void DecryptingDemuxerStream::OnKeyAdded() {
321 DCHECK(task_runner_->BelongsToCurrentThread());
323 if (state_ == kPendingDecrypt) {
324 key_added_while_decrypt_pending_ = true;
325 return;
328 if (state_ == kWaitingForKey) {
329 state_ = kPendingDecrypt;
330 DecryptPendingBuffer();
334 void DecryptingDemuxerStream::DoReset() {
335 DCHECK(state_ != kUninitialized);
336 DCHECK(init_cb_.is_null());
337 DCHECK(read_cb_.is_null());
339 if (state_ == kDecryptorRequested)
340 state_ = kUninitialized;
341 else
342 state_ = kIdle;
344 base::ResetAndReturn(&reset_cb_).Run();
347 Decryptor::StreamType DecryptingDemuxerStream::GetDecryptorStreamType() const {
348 if (demuxer_stream_->type() == AUDIO)
349 return Decryptor::kAudio;
351 DCHECK_EQ(demuxer_stream_->type(), VIDEO);
352 return Decryptor::kVideo;
355 void DecryptingDemuxerStream::InitializeDecoderConfig() {
356 // The decoder selector or upstream demuxer make sure the stream is valid and
357 // potentially encrypted.
358 DCHECK(IsStreamValidAndEncrypted(demuxer_stream_));
360 switch (demuxer_stream_->type()) {
361 case AUDIO: {
362 AudioDecoderConfig input_audio_config =
363 demuxer_stream_->audio_decoder_config();
364 audio_config_.Initialize(input_audio_config.codec(),
365 input_audio_config.sample_format(),
366 input_audio_config.channel_layout(),
367 input_audio_config.samples_per_second(),
368 input_audio_config.extra_data(),
369 input_audio_config.extra_data_size(),
370 false, // Output audio is not encrypted.
371 false,
372 base::TimeDelta(),
374 break;
377 case VIDEO: {
378 VideoDecoderConfig input_video_config =
379 demuxer_stream_->video_decoder_config();
380 video_config_.Initialize(input_video_config.codec(),
381 input_video_config.profile(),
382 input_video_config.format(),
383 input_video_config.coded_size(),
384 input_video_config.visible_rect(),
385 input_video_config.natural_size(),
386 input_video_config.extra_data(),
387 input_video_config.extra_data_size(),
388 false, // Output video is not encrypted.
389 false);
390 break;
393 default:
394 NOTREACHED();
395 return;
399 } // namespace media