Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / filters / decrypting_demuxer_stream.cc
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.
4
5 #include "media/filters/decrypting_demuxer_stream.h"
6
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"
19
20 namespace media {
21
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()));
29 }
30
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) {}
41
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_;
47
48   DCHECK(!demuxer_stream_);
49   weak_this_ = weak_factory_.GetWeakPtr();
50   demuxer_stream_ = stream;
51   init_cb_ = BindToCurrentLoop(status_cb);
52
53   InitializeDecoderConfig();
54
55   state_ = kDecryptorRequested;
56   set_decryptor_ready_cb_.Run(BindToCurrentLoop(
57       base::Bind(&DecryptingDemuxerStream::SetDecryptor, weak_this_)));
58 }
59
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.";
66
67   read_cb_ = BindToCurrentLoop(read_cb);
68   state_ = kPendingDemuxerRead;
69   demuxer_stream_->Read(
70       base::Bind(&DecryptingDemuxerStream::DecryptBuffer, weak_this_));
71 }
72
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(reset_cb_.is_null());
78
79   reset_cb_ = BindToCurrentLoop(closure);
80
81   // TODO(xhwang): This should not happen. Remove it, DCHECK against the
82   // condition and clean up related tests.
83   if (state_ == kDecryptorRequested) {
84     DCHECK(!init_cb_.is_null());
85     set_decryptor_ready_cb_.Run(DecryptorReadyCB());
86     base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
87     DoReset();
88     return;
89   }
90
91   decryptor_->CancelDecrypt(GetDecryptorStreamType());
92
93   // Reset() cannot complete if the read callback is still pending.
94   // Defer the resetting process in this case. The |reset_cb_| will be fired
95   // after the read callback is fired - see DoDecryptBuffer() and
96   // DoDeliverBuffer().
97   if (state_ == kPendingDemuxerRead || state_ == kPendingDecrypt) {
98     DCHECK(!read_cb_.is_null());
99     return;
100   }
101
102   if (state_ == kWaitingForKey) {
103     DCHECK(!read_cb_.is_null());
104     pending_buffer_to_decrypt_ = NULL;
105     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
106   }
107
108   DCHECK(read_cb_.is_null());
109   DoReset();
110 }
111
112 AudioDecoderConfig DecryptingDemuxerStream::audio_decoder_config() {
113   DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_;
114   CHECK_EQ(demuxer_stream_->type(), AUDIO);
115   return audio_config_;
116 }
117
118 VideoDecoderConfig DecryptingDemuxerStream::video_decoder_config() {
119   DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_;
120   CHECK_EQ(demuxer_stream_->type(), VIDEO);
121   return video_config_;
122 }
123
124 DemuxerStream::Type DecryptingDemuxerStream::type() {
125   DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_;
126   return demuxer_stream_->type();
127 }
128
129 void DecryptingDemuxerStream::EnableBitstreamConverter() {
130   demuxer_stream_->EnableBitstreamConverter();
131 }
132
133 bool DecryptingDemuxerStream::SupportsConfigChanges() {
134   return demuxer_stream_->SupportsConfigChanges();
135 }
136
137 VideoRotation DecryptingDemuxerStream::video_rotation() {
138   return VIDEO_ROTATION_0;
139 }
140
141 DecryptingDemuxerStream::~DecryptingDemuxerStream() {
142   DVLOG(2) << __FUNCTION__ << " : state_ = " << state_;
143   DCHECK(task_runner_->BelongsToCurrentThread());
144
145   if (state_ == kUninitialized)
146     return;
147
148   if (decryptor_) {
149     decryptor_->CancelDecrypt(GetDecryptorStreamType());
150     decryptor_ = NULL;
151   }
152   if (!set_decryptor_ready_cb_.is_null())
153     base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
154   if (!init_cb_.is_null())
155     base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
156   if (!read_cb_.is_null())
157     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
158   if (!reset_cb_.is_null())
159     base::ResetAndReturn(&reset_cb_).Run();
160   pending_buffer_to_decrypt_ = NULL;
161 }
162
163 void DecryptingDemuxerStream::SetDecryptor(
164     Decryptor* decryptor,
165     const DecryptorAttachedCB& decryptor_attached_cb) {
166   DVLOG(2) << __FUNCTION__;
167   DCHECK(task_runner_->BelongsToCurrentThread());
168   DCHECK_EQ(state_, kDecryptorRequested) << state_;
169   DCHECK(!init_cb_.is_null());
170   DCHECK(!set_decryptor_ready_cb_.is_null());
171
172   set_decryptor_ready_cb_.Reset();
173
174   if (!decryptor) {
175     state_ = kUninitialized;
176     base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
177     decryptor_attached_cb.Run(false);
178     return;
179   }
180
181   decryptor_ = decryptor;
182
183   decryptor_->RegisterNewKeyCB(
184       GetDecryptorStreamType(),
185       BindToCurrentLoop(
186           base::Bind(&DecryptingDemuxerStream::OnKeyAdded, weak_this_)));
187
188   state_ = kIdle;
189   base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
190   decryptor_attached_cb.Run(true);
191 }
192
193 void DecryptingDemuxerStream::DecryptBuffer(
194     DemuxerStream::Status status,
195     const scoped_refptr<DecoderBuffer>& buffer) {
196   DVLOG(3) << __FUNCTION__;
197   DCHECK(task_runner_->BelongsToCurrentThread());
198   DCHECK_EQ(state_, kPendingDemuxerRead) << state_;
199   DCHECK(!read_cb_.is_null());
200   DCHECK_EQ(buffer.get() != NULL, status == kOk) << status;
201
202   // Even when |!reset_cb_.is_null()|, we need to pass |kConfigChanged| back to
203   // the caller so that the downstream decoder can be properly reinitialized.
204   if (status == kConfigChanged) {
205     DVLOG(2) << "DoDecryptBuffer() - kConfigChanged.";
206     DCHECK_EQ(demuxer_stream_->type() == AUDIO, audio_config_.IsValidConfig());
207     DCHECK_EQ(demuxer_stream_->type() == VIDEO, video_config_.IsValidConfig());
208
209     // Update the decoder config, which the decoder will use when it is notified
210     // of kConfigChanged.
211     InitializeDecoderConfig();
212     state_ = kIdle;
213     base::ResetAndReturn(&read_cb_).Run(kConfigChanged, NULL);
214     if (!reset_cb_.is_null())
215       DoReset();
216     return;
217   }
218
219   if (!reset_cb_.is_null()) {
220     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
221     DoReset();
222     return;
223   }
224
225   if (status == kAborted) {
226     DVLOG(2) << "DoDecryptBuffer() - kAborted.";
227     state_ = kIdle;
228     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
229     return;
230   }
231
232   if (buffer->end_of_stream()) {
233     DVLOG(2) << "DoDecryptBuffer() - EOS buffer.";
234     state_ = kIdle;
235     base::ResetAndReturn(&read_cb_).Run(status, buffer);
236     return;
237   }
238
239   DCHECK(buffer->decrypt_config());
240   // An empty iv string signals that the frame is unencrypted.
241   if (buffer->decrypt_config()->iv().empty()) {
242     DVLOG(2) << "DoDecryptBuffer() - clear buffer.";
243     scoped_refptr<DecoderBuffer> decrypted = DecoderBuffer::CopyFrom(
244         buffer->data(), buffer->data_size());
245     decrypted->set_timestamp(buffer->timestamp());
246     decrypted->set_duration(buffer->duration());
247     state_ = kIdle;
248     base::ResetAndReturn(&read_cb_).Run(kOk, decrypted);
249     return;
250   }
251
252   pending_buffer_to_decrypt_ = buffer;
253   state_ = kPendingDecrypt;
254   DecryptPendingBuffer();
255 }
256
257 void DecryptingDemuxerStream::DecryptPendingBuffer() {
258   DCHECK(task_runner_->BelongsToCurrentThread());
259   DCHECK_EQ(state_, kPendingDecrypt) << state_;
260   decryptor_->Decrypt(
261       GetDecryptorStreamType(),
262       pending_buffer_to_decrypt_,
263       BindToCurrentLoop(
264           base::Bind(&DecryptingDemuxerStream::DeliverBuffer, weak_this_)));
265 }
266
267 void DecryptingDemuxerStream::DeliverBuffer(
268     Decryptor::Status status,
269     const scoped_refptr<DecoderBuffer>& decrypted_buffer) {
270   DVLOG(3) << __FUNCTION__ << " - status: " << status;
271   DCHECK(task_runner_->BelongsToCurrentThread());
272   DCHECK_EQ(state_, kPendingDecrypt) << state_;
273   DCHECK_NE(status, Decryptor::kNeedMoreData);
274   DCHECK(!read_cb_.is_null());
275   DCHECK(pending_buffer_to_decrypt_.get());
276
277   bool need_to_try_again_if_nokey = key_added_while_decrypt_pending_;
278   key_added_while_decrypt_pending_ = false;
279
280   if (!reset_cb_.is_null()) {
281     pending_buffer_to_decrypt_ = NULL;
282     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
283     DoReset();
284     return;
285   }
286
287   DCHECK_EQ(status == Decryptor::kSuccess, decrypted_buffer.get() != NULL);
288
289   if (status == Decryptor::kError) {
290     DVLOG(2) << "DoDeliverBuffer() - kError";
291     pending_buffer_to_decrypt_ = NULL;
292     state_ = kIdle;
293     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
294     return;
295   }
296
297   if (status == Decryptor::kNoKey) {
298     DVLOG(2) << "DoDeliverBuffer() - kNoKey";
299     if (need_to_try_again_if_nokey) {
300       // The |state_| is still kPendingDecrypt.
301       DecryptPendingBuffer();
302       return;
303     }
304
305     state_ = kWaitingForKey;
306     return;
307   }
308
309   DCHECK_EQ(status, Decryptor::kSuccess);
310   pending_buffer_to_decrypt_ = NULL;
311   state_ = kIdle;
312   base::ResetAndReturn(&read_cb_).Run(kOk, decrypted_buffer);
313 }
314
315 void DecryptingDemuxerStream::OnKeyAdded() {
316   DCHECK(task_runner_->BelongsToCurrentThread());
317
318   if (state_ == kPendingDecrypt) {
319     key_added_while_decrypt_pending_ = true;
320     return;
321   }
322
323   if (state_ == kWaitingForKey) {
324     state_ = kPendingDecrypt;
325     DecryptPendingBuffer();
326   }
327 }
328
329 void DecryptingDemuxerStream::DoReset() {
330   DCHECK(state_ != kUninitialized);
331   DCHECK(init_cb_.is_null());
332   DCHECK(read_cb_.is_null());
333
334   if (state_ == kDecryptorRequested)
335     state_ = kUninitialized;
336   else
337     state_ = kIdle;
338
339   base::ResetAndReturn(&reset_cb_).Run();
340 }
341
342 Decryptor::StreamType DecryptingDemuxerStream::GetDecryptorStreamType() const {
343   if (demuxer_stream_->type() == AUDIO)
344     return Decryptor::kAudio;
345
346   DCHECK_EQ(demuxer_stream_->type(), VIDEO);
347   return Decryptor::kVideo;
348 }
349
350 void DecryptingDemuxerStream::InitializeDecoderConfig() {
351   // The decoder selector or upstream demuxer make sure the stream is valid and
352   // potentially encrypted.
353   DCHECK(IsStreamValidAndEncrypted(demuxer_stream_));
354
355   switch (demuxer_stream_->type()) {
356     case AUDIO: {
357       AudioDecoderConfig input_audio_config =
358           demuxer_stream_->audio_decoder_config();
359       audio_config_.Initialize(input_audio_config.codec(),
360                                input_audio_config.sample_format(),
361                                input_audio_config.channel_layout(),
362                                input_audio_config.samples_per_second(),
363                                input_audio_config.extra_data(),
364                                input_audio_config.extra_data_size(),
365                                false,  // Output audio is not encrypted.
366                                false,
367                                input_audio_config.seek_preroll(),
368                                input_audio_config.codec_delay());
369       break;
370     }
371
372     case VIDEO: {
373       VideoDecoderConfig input_video_config =
374           demuxer_stream_->video_decoder_config();
375       video_config_.Initialize(input_video_config.codec(),
376                                input_video_config.profile(),
377                                input_video_config.format(),
378                                input_video_config.coded_size(),
379                                input_video_config.visible_rect(),
380                                input_video_config.natural_size(),
381                                input_video_config.extra_data(),
382                                input_video_config.extra_data_size(),
383                                false,  // Output video is not encrypted.
384                                false);
385       break;
386     }
387
388     default:
389       NOTREACHED();
390       return;
391   }
392 }
393
394 }  // namespace media