OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/filters/decrypting_demuxer_stream.h" | 5 #include "media/filters/decrypting_demuxer_stream.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/message_loop_proxy.h" | 11 #include "base/message_loop_proxy.h" |
12 #include "media/base/audio_decoder_config.h" | 12 #include "media/base/audio_decoder_config.h" |
13 #include "media/base/video_decoder_config.h" | 13 #include "media/base/video_decoder_config.h" |
14 #include "media/base/bind_to_loop.h" | 14 #include "media/base/bind_to_loop.h" |
15 #include "media/base/decoder_buffer.h" | 15 #include "media/base/decoder_buffer.h" |
16 #include "media/base/decryptor.h" | 16 #include "media/base/decryptor.h" |
17 #include "media/base/demuxer_stream.h" | 17 #include "media/base/demuxer_stream.h" |
18 #include "media/base/pipeline.h" | 18 #include "media/base/pipeline.h" |
19 | 19 |
20 namespace media { | 20 namespace media { |
21 | 21 |
22 #define BIND_TO_LOOP(function) \ | 22 #define BIND_TO_LOOP(function) \ |
23 media::BindToLoop(message_loop_, base::Bind(function, this)) | 23 media::BindToLoop(message_loop_, base::Bind(function, weak_this_)) |
24 | 24 |
25 static bool IsStreamValidAndEncrypted( | 25 static bool IsStreamValidAndEncrypted(DemuxerStream* stream) { |
26 const scoped_refptr<DemuxerStream>& stream) { | |
27 return ((stream->type() == DemuxerStream::AUDIO && | 26 return ((stream->type() == DemuxerStream::AUDIO && |
28 stream->audio_decoder_config().IsValidConfig() && | 27 stream->audio_decoder_config().IsValidConfig() && |
29 stream->audio_decoder_config().is_encrypted()) || | 28 stream->audio_decoder_config().is_encrypted()) || |
30 (stream->type() == DemuxerStream::VIDEO && | 29 (stream->type() == DemuxerStream::VIDEO && |
31 stream->video_decoder_config().IsValidConfig() && | 30 stream->video_decoder_config().IsValidConfig() && |
32 stream->video_decoder_config().is_encrypted())); | 31 stream->video_decoder_config().is_encrypted())); |
33 } | 32 } |
34 | 33 |
35 DecryptingDemuxerStream::DecryptingDemuxerStream( | 34 DecryptingDemuxerStream::DecryptingDemuxerStream( |
36 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 35 const scoped_refptr<base::MessageLoopProxy>& message_loop, |
37 const SetDecryptorReadyCB& set_decryptor_ready_cb) | 36 const SetDecryptorReadyCB& set_decryptor_ready_cb) |
38 : message_loop_(message_loop), | 37 : message_loop_(message_loop), |
38 weak_factory_(this), | |
39 state_(kUninitialized), | 39 state_(kUninitialized), |
40 demuxer_stream_(NULL), | |
40 stream_type_(UNKNOWN), | 41 stream_type_(UNKNOWN), |
41 set_decryptor_ready_cb_(set_decryptor_ready_cb), | 42 set_decryptor_ready_cb_(set_decryptor_ready_cb), |
42 decryptor_(NULL), | 43 decryptor_(NULL), |
43 key_added_while_decrypt_pending_(false) { | 44 key_added_while_decrypt_pending_(false) { |
44 } | 45 } |
45 | 46 |
46 void DecryptingDemuxerStream::Initialize( | 47 void DecryptingDemuxerStream::Initialize( |
47 const scoped_refptr<DemuxerStream>& stream, | 48 DemuxerStream* stream, |
48 const PipelineStatusCB& status_cb) { | 49 const PipelineStatusCB& status_cb) { |
49 if (!message_loop_->BelongsToCurrentThread()) { | 50 DVLOG(2) << "Initialize()"; |
acolwell GONE FROM CHROMIUM
2013/04/17 20:24:53
Would you mind moving these transformations to a s
scherkus (not reviewing)
2013/04/19 01:07:22
Done and landed http://crrev.com/194721
| |
50 message_loop_->PostTask(FROM_HERE, base::Bind( | 51 DCHECK(message_loop_->BelongsToCurrentThread()); |
51 &DecryptingDemuxerStream::DoInitialize, this, stream, status_cb)); | 52 DCHECK_EQ(state_, kUninitialized) << state_; |
52 return; | 53 |
53 } | 54 DCHECK(!demuxer_stream_); |
54 DoInitialize(stream, status_cb); | 55 weak_this_ = weak_factory_.GetWeakPtr(); |
56 demuxer_stream_ = stream; | |
57 stream_type_ = stream->type(); | |
58 init_cb_ = status_cb; | |
59 | |
60 SetDecoderConfig(stream); | |
61 | |
62 state_ = kDecryptorRequested; | |
63 set_decryptor_ready_cb_.Run( | |
64 BIND_TO_LOOP(&DecryptingDemuxerStream::SetDecryptor)); | |
55 } | 65 } |
56 | 66 |
57 void DecryptingDemuxerStream::Read(const ReadCB& read_cb) { | 67 void DecryptingDemuxerStream::Read(const ReadCB& read_cb) { |
58 DVLOG(3) << "Read()"; | 68 DVLOG(3) << "Read()"; |
59 DCHECK(message_loop_->BelongsToCurrentThread()); | 69 DCHECK(message_loop_->BelongsToCurrentThread()); |
60 DCHECK_EQ(state_, kIdle) << state_; | 70 DCHECK_EQ(state_, kIdle) << state_; |
61 DCHECK(!read_cb.is_null()); | 71 DCHECK(!read_cb.is_null()); |
62 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported."; | 72 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported."; |
63 | 73 |
64 read_cb_ = read_cb; | 74 read_cb_ = read_cb; |
65 state_ = kPendingDemuxerRead; | 75 state_ = kPendingDemuxerRead; |
66 demuxer_stream_->Read( | 76 demuxer_stream_->Read( |
67 base::Bind(&DecryptingDemuxerStream::DecryptBuffer, this)); | 77 base::Bind(&DecryptingDemuxerStream::DecryptBuffer, weak_this_)); |
68 } | 78 } |
69 | 79 |
70 void DecryptingDemuxerStream::Reset(const base::Closure& closure) { | 80 void DecryptingDemuxerStream::Reset(const base::Closure& closure) { |
71 if (!message_loop_->BelongsToCurrentThread()) { | |
72 message_loop_->PostTask(FROM_HERE, base::Bind( | |
73 &DecryptingDemuxerStream::Reset, this, closure)); | |
74 return; | |
75 } | |
76 | |
77 DVLOG(2) << "Reset() - state: " << state_; | 81 DVLOG(2) << "Reset() - state: " << state_; |
82 DCHECK(message_loop_->BelongsToCurrentThread()); | |
78 DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_; | 83 DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_; |
79 DCHECK(init_cb_.is_null()); // No Reset() during pending initialization. | 84 DCHECK(init_cb_.is_null()); // No Reset() during pending initialization. |
80 DCHECK(reset_cb_.is_null()); | 85 DCHECK(reset_cb_.is_null()); |
81 | 86 |
82 reset_cb_ = BindToCurrentLoop(closure); | 87 reset_cb_ = BindToCurrentLoop(closure); |
83 | 88 |
84 decryptor_->CancelDecrypt(GetDecryptorStreamType()); | 89 decryptor_->CancelDecrypt(GetDecryptorStreamType()); |
85 | 90 |
86 // Reset() cannot complete if the read callback is still pending. | 91 // Reset() cannot complete if the read callback is still pending. |
87 // Defer the resetting process in this case. The |reset_cb_| will be fired | 92 // Defer the resetting process in this case. The |reset_cb_| will be fired |
(...skipping 30 matching lines...) Expand all Loading... | |
118 DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_; | 123 DCHECK(state_ != kUninitialized && state_ != kDecryptorRequested) << state_; |
119 return stream_type_; | 124 return stream_type_; |
120 } | 125 } |
121 | 126 |
122 void DecryptingDemuxerStream::EnableBitstreamConverter() { | 127 void DecryptingDemuxerStream::EnableBitstreamConverter() { |
123 demuxer_stream_->EnableBitstreamConverter(); | 128 demuxer_stream_->EnableBitstreamConverter(); |
124 } | 129 } |
125 | 130 |
126 DecryptingDemuxerStream::~DecryptingDemuxerStream() {} | 131 DecryptingDemuxerStream::~DecryptingDemuxerStream() {} |
127 | 132 |
128 void DecryptingDemuxerStream::DoInitialize( | |
129 const scoped_refptr<DemuxerStream>& stream, | |
130 const PipelineStatusCB& status_cb) { | |
131 DVLOG(2) << "DoInitialize()"; | |
132 DCHECK(message_loop_->BelongsToCurrentThread()); | |
133 DCHECK_EQ(state_, kUninitialized) << state_; | |
134 | |
135 DCHECK(!demuxer_stream_); | |
136 demuxer_stream_ = stream; | |
137 stream_type_ = stream->type(); | |
138 init_cb_ = status_cb; | |
139 | |
140 SetDecoderConfig(stream); | |
141 | |
142 state_ = kDecryptorRequested; | |
143 set_decryptor_ready_cb_.Run( | |
144 BIND_TO_LOOP(&DecryptingDemuxerStream::SetDecryptor)); | |
145 } | |
146 | |
147 void DecryptingDemuxerStream::SetDecryptor(Decryptor* decryptor) { | 133 void DecryptingDemuxerStream::SetDecryptor(Decryptor* decryptor) { |
148 DVLOG(2) << "SetDecryptor()"; | 134 DVLOG(2) << "SetDecryptor()"; |
149 DCHECK(message_loop_->BelongsToCurrentThread()); | 135 DCHECK(message_loop_->BelongsToCurrentThread()); |
150 DCHECK_EQ(state_, kDecryptorRequested) << state_; | 136 DCHECK_EQ(state_, kDecryptorRequested) << state_; |
151 DCHECK(!init_cb_.is_null()); | 137 DCHECK(!init_cb_.is_null()); |
152 DCHECK(!set_decryptor_ready_cb_.is_null()); | 138 DCHECK(!set_decryptor_ready_cb_.is_null()); |
153 | 139 |
154 set_decryptor_ready_cb_.Reset(); | 140 set_decryptor_ready_cb_.Reset(); |
155 decryptor_ = decryptor; | 141 decryptor_ = decryptor; |
156 | 142 |
157 decryptor_->RegisterNewKeyCB( | 143 decryptor_->RegisterNewKeyCB( |
158 GetDecryptorStreamType(), | 144 GetDecryptorStreamType(), |
159 BIND_TO_LOOP(&DecryptingDemuxerStream::OnKeyAdded)); | 145 BIND_TO_LOOP(&DecryptingDemuxerStream::OnKeyAdded)); |
160 | 146 |
161 state_ = kIdle; | 147 state_ = kIdle; |
162 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 148 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
163 } | 149 } |
164 | 150 |
165 void DecryptingDemuxerStream::DecryptBuffer( | 151 void DecryptingDemuxerStream::DecryptBuffer( |
166 DemuxerStream::Status status, | 152 DemuxerStream::Status status, |
167 const scoped_refptr<DecoderBuffer>& buffer) { | 153 const scoped_refptr<DecoderBuffer>& buffer) { |
168 // In theory, we don't need to force post the task here, because we do a | 154 DVLOG(3) << "DecryptBuffer()"; |
169 // force task post in DeliverBuffer(). Therefore, even if | |
170 // demuxer_stream_->Read() execute the read callback on the same execution | |
171 // stack we are still fine. But it looks like a force post task makes the | |
172 // logic more understandable and manageable, so why not? | |
173 message_loop_->PostTask(FROM_HERE, base::Bind( | |
174 &DecryptingDemuxerStream::DoDecryptBuffer, this, status, buffer)); | |
175 } | |
176 | |
177 void DecryptingDemuxerStream::DoDecryptBuffer( | |
178 DemuxerStream::Status status, | |
179 const scoped_refptr<DecoderBuffer>& buffer) { | |
180 DVLOG(3) << "DoDecryptBuffer()"; | |
181 DCHECK(message_loop_->BelongsToCurrentThread()); | 155 DCHECK(message_loop_->BelongsToCurrentThread()); |
182 DCHECK_EQ(state_, kPendingDemuxerRead) << state_; | 156 DCHECK_EQ(state_, kPendingDemuxerRead) << state_; |
183 DCHECK(!read_cb_.is_null()); | 157 DCHECK(!read_cb_.is_null()); |
184 DCHECK_EQ(buffer != NULL, status == kOk) << status; | 158 DCHECK_EQ(buffer != NULL, status == kOk) << status; |
185 | 159 |
186 if (!reset_cb_.is_null()) { | 160 if (!reset_cb_.is_null()) { |
187 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); | 161 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); |
188 DoReset(); | 162 DoReset(); |
189 return; | 163 return; |
190 } | 164 } |
(...skipping 28 matching lines...) Expand all Loading... | |
219 state_ = kPendingDecrypt; | 193 state_ = kPendingDecrypt; |
220 DecryptPendingBuffer(); | 194 DecryptPendingBuffer(); |
221 } | 195 } |
222 | 196 |
223 void DecryptingDemuxerStream::DecryptPendingBuffer() { | 197 void DecryptingDemuxerStream::DecryptPendingBuffer() { |
224 DCHECK(message_loop_->BelongsToCurrentThread()); | 198 DCHECK(message_loop_->BelongsToCurrentThread()); |
225 DCHECK_EQ(state_, kPendingDecrypt) << state_; | 199 DCHECK_EQ(state_, kPendingDecrypt) << state_; |
226 decryptor_->Decrypt( | 200 decryptor_->Decrypt( |
227 GetDecryptorStreamType(), | 201 GetDecryptorStreamType(), |
228 pending_buffer_to_decrypt_, | 202 pending_buffer_to_decrypt_, |
229 base::Bind(&DecryptingDemuxerStream::DeliverBuffer, this)); | 203 BIND_TO_LOOP(&DecryptingDemuxerStream::DeliverBuffer)); |
230 } | 204 } |
231 | 205 |
232 void DecryptingDemuxerStream::DeliverBuffer( | 206 void DecryptingDemuxerStream::DeliverBuffer( |
233 Decryptor::Status status, | 207 Decryptor::Status status, |
234 const scoped_refptr<DecoderBuffer>& decrypted_buffer) { | 208 const scoped_refptr<DecoderBuffer>& decrypted_buffer) { |
235 // We need to force task post here because the DecryptCB can be executed | 209 DVLOG(3) << "DeliverBuffer() - status: " << status; |
236 // synchronously in Reset(). Instead of using more complicated logic in | |
237 // those function to fix it, why not force task post here to make everything | |
238 // simple and clear? | |
239 message_loop_->PostTask(FROM_HERE, base::Bind( | |
240 &DecryptingDemuxerStream::DoDeliverBuffer, this, | |
241 status, decrypted_buffer)); | |
242 } | |
243 | |
244 void DecryptingDemuxerStream::DoDeliverBuffer( | |
245 Decryptor::Status status, | |
246 const scoped_refptr<DecoderBuffer>& decrypted_buffer) { | |
247 DVLOG(3) << "DoDeliverBuffer() - status: " << status; | |
248 DCHECK(message_loop_->BelongsToCurrentThread()); | 210 DCHECK(message_loop_->BelongsToCurrentThread()); |
249 DCHECK_EQ(state_, kPendingDecrypt) << state_; | 211 DCHECK_EQ(state_, kPendingDecrypt) << state_; |
250 DCHECK_NE(status, Decryptor::kNeedMoreData); | 212 DCHECK_NE(status, Decryptor::kNeedMoreData); |
251 DCHECK(!read_cb_.is_null()); | 213 DCHECK(!read_cb_.is_null()); |
252 DCHECK(pending_buffer_to_decrypt_); | 214 DCHECK(pending_buffer_to_decrypt_); |
253 | 215 |
254 bool need_to_try_again_if_nokey = key_added_while_decrypt_pending_; | 216 bool need_to_try_again_if_nokey = key_added_while_decrypt_pending_; |
255 key_added_while_decrypt_pending_ = false; | 217 key_added_while_decrypt_pending_ = false; |
256 | 218 |
257 if (!reset_cb_.is_null()) { | 219 if (!reset_cb_.is_null()) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
308 DCHECK(read_cb_.is_null()); | 270 DCHECK(read_cb_.is_null()); |
309 state_ = kIdle; | 271 state_ = kIdle; |
310 base::ResetAndReturn(&reset_cb_).Run(); | 272 base::ResetAndReturn(&reset_cb_).Run(); |
311 } | 273 } |
312 | 274 |
313 Decryptor::StreamType DecryptingDemuxerStream::GetDecryptorStreamType() const { | 275 Decryptor::StreamType DecryptingDemuxerStream::GetDecryptorStreamType() const { |
314 DCHECK(stream_type_ == AUDIO || stream_type_ == VIDEO); | 276 DCHECK(stream_type_ == AUDIO || stream_type_ == VIDEO); |
315 return stream_type_ == AUDIO ? Decryptor::kAudio : Decryptor::kVideo; | 277 return stream_type_ == AUDIO ? Decryptor::kAudio : Decryptor::kVideo; |
316 } | 278 } |
317 | 279 |
318 void DecryptingDemuxerStream::SetDecoderConfig( | 280 void DecryptingDemuxerStream::SetDecoderConfig(DemuxerStream* stream) { |
acolwell GONE FROM CHROMIUM
2013/04/17 20:24:53
nit: All callers essentially pass demuxer_stream_
| |
319 const scoped_refptr<DemuxerStream>& stream) { | |
320 // The decoder selector or upstream demuxer make sure the stream is valid and | 281 // The decoder selector or upstream demuxer make sure the stream is valid and |
321 // potentially encrypted. | 282 // potentially encrypted. |
322 DCHECK(IsStreamValidAndEncrypted(stream)); | 283 DCHECK(IsStreamValidAndEncrypted(stream)); |
323 | 284 |
324 switch (stream_type_) { | 285 switch (stream_type_) { |
325 case AUDIO: { | 286 case AUDIO: { |
326 const AudioDecoderConfig& input_audio_config = | 287 const AudioDecoderConfig& input_audio_config = |
327 stream->audio_decoder_config(); | 288 stream->audio_decoder_config(); |
328 audio_config_.reset(new AudioDecoderConfig()); | 289 audio_config_.reset(new AudioDecoderConfig()); |
329 audio_config_->Initialize(input_audio_config.codec(), | 290 audio_config_->Initialize(input_audio_config.codec(), |
(...skipping 24 matching lines...) Expand all Loading... | |
354 break; | 315 break; |
355 } | 316 } |
356 | 317 |
357 default: | 318 default: |
358 NOTREACHED(); | 319 NOTREACHED(); |
359 return; | 320 return; |
360 } | 321 } |
361 } | 322 } |
362 | 323 |
363 } // namespace media | 324 } // namespace media |
OLD | NEW |