OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chromecast/media/cma/pipeline/av_pipeline_impl.h" | 5 #include "chromecast/media/cma/pipeline/av_pipeline_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "base/message_loop/message_loop_proxy.h" | 9 #include "base/message_loop/message_loop_proxy.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 media_component_device_(media_component_device), | 38 media_component_device_(media_component_device), |
39 state_(kUninitialized), | 39 state_(kUninitialized), |
40 buffered_time_(::media::kNoTimestamp()), | 40 buffered_time_(::media::kNoTimestamp()), |
41 playable_buffered_time_(::media::kNoTimestamp()), | 41 playable_buffered_time_(::media::kNoTimestamp()), |
42 enable_feeding_(false), | 42 enable_feeding_(false), |
43 pending_read_(false), | 43 pending_read_(false), |
44 pending_push_(false), | 44 pending_push_(false), |
45 enable_time_update_(false), | 45 enable_time_update_(false), |
46 pending_time_update_task_(false), | 46 pending_time_update_task_(false), |
47 media_keys_(NULL), | 47 media_keys_(NULL), |
48 media_keys_callback_id_(kNoCallbackId), | 48 media_keys_callback_id_(kNoCallbackId) { |
49 weak_factory_(this) { | |
50 DCHECK(media_component_device); | 49 DCHECK(media_component_device); |
51 weak_this_ = weak_factory_.GetWeakPtr(); | |
52 thread_checker_.DetachFromThread(); | 50 thread_checker_.DetachFromThread(); |
53 } | 51 } |
54 | 52 |
55 AvPipelineImpl::~AvPipelineImpl() { | 53 AvPipelineImpl::~AvPipelineImpl() { |
56 // If there are weak pointers in the wild, they must be invalidated | 54 // If there are weak pointers in the wild, they must be invalidated |
57 // on the right thread. | 55 // on the right thread. |
58 DCHECK(thread_checker_.CalledOnValidThread()); | 56 DCHECK(thread_checker_.CalledOnValidThread()); |
59 media_component_device_->SetClient(MediaComponentDevice::Client()); | 57 media_component_device_->SetClient(MediaComponentDevice::Client()); |
60 | 58 |
61 if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) | 59 { |
62 media_keys_->UnregisterPlayer(media_keys_callback_id_); | 60 base::AutoLock lock(media_keys_lock_); |
| 61 if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) |
| 62 media_keys_->UnregisterPlayer(media_keys_callback_id_); |
| 63 } |
63 } | 64 } |
64 | 65 |
65 void AvPipelineImpl::TransitionToState(State state) { | 66 void AvPipelineImpl::TransitionToState(State state) { |
66 DCHECK(thread_checker_.CalledOnValidThread()); | 67 DCHECK(thread_checker_.CalledOnValidThread()); |
67 state_ = state; | 68 state_ = state; |
68 } | 69 } |
69 | 70 |
70 void AvPipelineImpl::SetCodedFrameProvider( | 71 void AvPipelineImpl::SetCodedFrameProvider( |
71 scoped_ptr<CodedFrameProvider> frame_provider, | 72 scoped_ptr<CodedFrameProvider> frame_provider, |
72 size_t max_buffer_size, | 73 size_t max_buffer_size, |
73 size_t max_frame_size) { | 74 size_t max_frame_size) { |
74 DCHECK_EQ(state_, kUninitialized); | 75 DCHECK_EQ(state_, kUninitialized); |
75 DCHECK(frame_provider); | 76 DCHECK(frame_provider); |
76 | 77 |
77 // Wrap the incoming frame provider to add some buffering capabilities. | 78 // Wrap the incoming frame provider to add some buffering capabilities. |
78 frame_provider_.reset( | 79 frame_provider_.reset( |
79 new BufferingFrameProvider( | 80 new BufferingFrameProvider( |
80 frame_provider.Pass(), | 81 frame_provider.Pass(), |
81 max_buffer_size, | 82 max_buffer_size, |
82 max_frame_size, | 83 max_frame_size, |
83 base::Bind(&AvPipelineImpl::OnFrameBuffered, weak_this_))); | 84 base::Bind(&AvPipelineImpl::OnFrameBuffered, this))); |
84 } | 85 } |
85 | 86 |
86 void AvPipelineImpl::SetClient(const AvPipelineClient& client) { | 87 void AvPipelineImpl::SetClient(const AvPipelineClient& client) { |
87 DCHECK(thread_checker_.CalledOnValidThread()); | 88 DCHECK(thread_checker_.CalledOnValidThread()); |
88 DCHECK_EQ(state_, kUninitialized); | 89 DCHECK_EQ(state_, kUninitialized); |
89 client_ = client; | 90 client_ = client; |
90 } | 91 } |
91 | 92 |
92 bool AvPipelineImpl::Initialize() { | 93 bool AvPipelineImpl::Initialize() { |
93 DCHECK(thread_checker_.CalledOnValidThread()); | 94 DCHECK(thread_checker_.CalledOnValidThread()); |
94 DCHECK_EQ(state_, kUninitialized); | 95 DCHECK_EQ(state_, kUninitialized); |
95 | 96 |
96 MediaComponentDevice::Client client; | 97 MediaComponentDevice::Client client; |
97 client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, weak_this_); | 98 client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, this); |
98 media_component_device_->SetClient(client); | 99 media_component_device_->SetClient(client); |
99 if (!media_component_device_->SetState(MediaComponentDevice::kStateIdle)) | 100 if (!media_component_device_->SetState(MediaComponentDevice::kStateIdle)) |
100 return false; | 101 return false; |
101 | 102 |
102 return true; | 103 return true; |
103 } | 104 } |
104 | 105 |
105 bool AvPipelineImpl::StartPlayingFrom( | 106 bool AvPipelineImpl::StartPlayingFrom( |
106 base::TimeDelta time, | 107 base::TimeDelta time, |
107 const scoped_refptr<BufferingState>& buffering_state) { | 108 const scoped_refptr<BufferingState>& buffering_state) { |
(...skipping 13 matching lines...) Expand all Loading... |
121 if (buffering_state_.get()) | 122 if (buffering_state_.get()) |
122 buffering_state_->SetMediaTime(time); | 123 buffering_state_->SetMediaTime(time); |
123 | 124 |
124 if (!media_component_device_->SetState(MediaComponentDevice::kStateRunning)) | 125 if (!media_component_device_->SetState(MediaComponentDevice::kStateRunning)) |
125 return false; | 126 return false; |
126 | 127 |
127 // Start feeding the pipeline. | 128 // Start feeding the pipeline. |
128 enable_feeding_ = true; | 129 enable_feeding_ = true; |
129 base::MessageLoopProxy::current()->PostTask( | 130 base::MessageLoopProxy::current()->PostTask( |
130 FROM_HERE, | 131 FROM_HERE, |
131 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); | 132 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); |
132 | 133 |
133 return true; | 134 return true; |
134 } | 135 } |
135 | 136 |
136 void AvPipelineImpl::Flush(const base::Closure& done_cb) { | 137 void AvPipelineImpl::Flush(const base::Closure& done_cb) { |
137 DCHECK(thread_checker_.CalledOnValidThread()); | 138 DCHECK(thread_checker_.CalledOnValidThread()); |
138 DCHECK_EQ(state_, kFlushing); | 139 DCHECK_EQ(state_, kFlushing); |
139 DCHECK_EQ( | 140 DCHECK_EQ( |
140 media_component_device_->GetState(), MediaComponentDevice::kStateRunning); | 141 media_component_device_->GetState(), MediaComponentDevice::kStateRunning); |
141 // Note: returning to idle state aborts any pending frame push. | 142 // Note: returning to idle state aborts any pending frame push. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 if (media_component_device_->GetState() == MediaComponentDevice::kStateIdle) { | 177 if (media_component_device_->GetState() == MediaComponentDevice::kStateIdle) { |
177 media_component_device_->SetState( | 178 media_component_device_->SetState( |
178 MediaComponentDevice::kStateUninitialized); | 179 MediaComponentDevice::kStateUninitialized); |
179 } | 180 } |
180 } | 181 } |
181 | 182 |
182 void AvPipelineImpl::SetCdm(BrowserCdmCast* media_keys) { | 183 void AvPipelineImpl::SetCdm(BrowserCdmCast* media_keys) { |
183 DCHECK(thread_checker_.CalledOnValidThread()); | 184 DCHECK(thread_checker_.CalledOnValidThread()); |
184 DCHECK(media_keys); | 185 DCHECK(media_keys); |
185 | 186 |
186 if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) | 187 { |
187 media_keys_->UnregisterPlayer(media_keys_callback_id_); | 188 base::AutoLock lock(media_keys_lock_); |
| 189 if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) |
| 190 media_keys_->UnregisterPlayer(media_keys_callback_id_); |
188 | 191 |
189 media_keys_ = media_keys; | 192 media_keys_ = media_keys; |
190 media_keys_callback_id_ = media_keys_->RegisterPlayer( | 193 media_keys_callback_id_ = media_keys_->RegisterPlayer( |
191 ::media::BindToCurrentLoop( | 194 ::media::BindToCurrentLoop( |
192 base::Bind(&AvPipelineImpl::OnCdmStateChanged, weak_this_)), | 195 base::Bind(&AvPipelineImpl::OnCdmStateChanged, this)), |
193 ::media::BindToCurrentLoop( | 196 // Note: this callback gets invoked in ~BrowserCdmCast. Posting |
194 base::Bind(&AvPipelineImpl::OnCdmDestroyed, weak_this_))); | 197 // OnCdmDestroyed to the media thread results in a race condition |
| 198 // with media_keys_ accesses. This callback must run synchronously, |
| 199 // otherwise media_keys_ access might occur after it is deleted. |
| 200 base::Bind(&AvPipelineImpl::OnCdmDestroyed, this)); |
| 201 } |
195 } | 202 } |
196 | 203 |
197 void AvPipelineImpl::OnEos() { | 204 void AvPipelineImpl::OnEos() { |
198 DCHECK(thread_checker_.CalledOnValidThread()); | 205 DCHECK(thread_checker_.CalledOnValidThread()); |
199 CMALOG(kLogControl) << __FUNCTION__; | 206 CMALOG(kLogControl) << __FUNCTION__; |
200 if (state_ != kPlaying) | 207 if (state_ != kPlaying) |
201 return; | 208 return; |
202 | 209 |
203 if (!client_.eos_cb.is_null()) | 210 if (!client_.eos_cb.is_null()) |
204 client_.eos_cb.Run(); | 211 client_.eos_cb.Run(); |
205 } | 212 } |
206 | 213 |
207 void AvPipelineImpl::FetchBufferIfNeeded() { | 214 void AvPipelineImpl::FetchBufferIfNeeded() { |
208 DCHECK(thread_checker_.CalledOnValidThread()); | 215 DCHECK(thread_checker_.CalledOnValidThread()); |
209 if (!enable_feeding_) | 216 if (!enable_feeding_) |
210 return; | 217 return; |
211 | 218 |
212 if (pending_read_ || pending_buffer_.get()) | 219 if (pending_read_ || pending_buffer_.get()) |
213 return; | 220 return; |
214 | 221 |
215 pending_read_ = true; | 222 pending_read_ = true; |
216 frame_provider_->Read( | 223 frame_provider_->Read( |
217 base::Bind(&AvPipelineImpl::OnNewFrame, weak_this_)); | 224 base::Bind(&AvPipelineImpl::OnNewFrame, this)); |
218 } | 225 } |
219 | 226 |
220 void AvPipelineImpl::OnNewFrame( | 227 void AvPipelineImpl::OnNewFrame( |
221 const scoped_refptr<DecoderBufferBase>& buffer, | 228 const scoped_refptr<DecoderBufferBase>& buffer, |
222 const ::media::AudioDecoderConfig& audio_config, | 229 const ::media::AudioDecoderConfig& audio_config, |
223 const ::media::VideoDecoderConfig& video_config) { | 230 const ::media::VideoDecoderConfig& video_config) { |
224 DCHECK(thread_checker_.CalledOnValidThread()); | 231 DCHECK(thread_checker_.CalledOnValidThread()); |
225 pending_read_ = false; | 232 pending_read_ = false; |
226 | 233 |
227 if (audio_config.IsValidConfig() || video_config.IsValidConfig()) | 234 if (audio_config.IsValidConfig() || video_config.IsValidConfig()) |
228 update_config_cb_.Run(audio_config, video_config); | 235 update_config_cb_.Run(audio_config, video_config); |
229 | 236 |
230 pending_buffer_ = buffer; | 237 pending_buffer_ = buffer; |
231 ProcessPendingBuffer(); | 238 ProcessPendingBuffer(); |
232 | 239 |
233 base::MessageLoopProxy::current()->PostTask( | 240 base::MessageLoopProxy::current()->PostTask( |
234 FROM_HERE, | 241 FROM_HERE, |
235 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); | 242 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); |
236 } | 243 } |
237 | 244 |
238 void AvPipelineImpl::ProcessPendingBuffer() { | 245 void AvPipelineImpl::ProcessPendingBuffer() { |
239 if (!enable_feeding_) | 246 if (!enable_feeding_) |
240 return; | 247 return; |
241 | 248 |
242 // Initiate a read if there isn't already one. | 249 // Initiate a read if there isn't already one. |
243 if (!pending_buffer_.get() && !pending_read_) { | 250 if (!pending_buffer_.get() && !pending_read_) { |
244 base::MessageLoopProxy::current()->PostTask( | 251 base::MessageLoopProxy::current()->PostTask( |
245 FROM_HERE, | 252 FROM_HERE, |
246 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); | 253 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); |
247 return; | 254 return; |
248 } | 255 } |
249 | 256 |
250 if (!pending_buffer_.get() || pending_push_) | 257 if (!pending_buffer_.get() || pending_push_) |
251 return; | 258 return; |
252 | 259 |
253 // Break the feeding loop when the end of stream is reached. | 260 // Break the feeding loop when the end of stream is reached. |
254 if (pending_buffer_->end_of_stream()) { | 261 if (pending_buffer_->end_of_stream()) { |
255 CMALOG(kLogControl) << __FUNCTION__ << ": EOS reached, stopped feeding"; | 262 CMALOG(kLogControl) << __FUNCTION__ << ": EOS reached, stopped feeding"; |
256 enable_feeding_ = false; | 263 enable_feeding_ = false; |
257 } | 264 } |
258 | 265 |
259 scoped_refptr<DecryptContext> decrypt_context; | 266 scoped_refptr<DecryptContext> decrypt_context; |
260 if (!pending_buffer_->end_of_stream() && | 267 if (!pending_buffer_->end_of_stream() && |
261 pending_buffer_->decrypt_config()) { | 268 pending_buffer_->decrypt_config()) { |
262 // Verify that CDM has the key ID. | 269 // Verify that CDM has the key ID. |
263 // Should not send the frame if the key ID is not available yet. | 270 // Should not send the frame if the key ID is not available yet. |
264 std::string key_id(pending_buffer_->decrypt_config()->key_id()); | 271 std::string key_id(pending_buffer_->decrypt_config()->key_id()); |
265 if (!media_keys_) { | 272 { |
266 CMALOG(kLogControl) << "No CDM for frame: pts=" | 273 base::AutoLock lock(media_keys_lock_); |
267 << pending_buffer_->timestamp().InMilliseconds(); | 274 if (!media_keys_) { |
268 return; | 275 CMALOG(kLogControl) << "No CDM for frame: pts=" |
| 276 << pending_buffer_->timestamp().InMilliseconds(); |
| 277 return; |
| 278 } |
| 279 decrypt_context = media_keys_->GetDecryptContext(key_id); |
269 } | 280 } |
270 decrypt_context = media_keys_->GetDecryptContext(key_id); | |
271 if (!decrypt_context.get()) { | 281 if (!decrypt_context.get()) { |
272 CMALOG(kLogControl) << "frame(pts=" | 282 CMALOG(kLogControl) << "frame(pts=" |
273 << pending_buffer_->timestamp().InMilliseconds() | 283 << pending_buffer_->timestamp().InMilliseconds() |
274 << "): waiting for key id " | 284 << "): waiting for key id " |
275 << base::HexEncode(&key_id[0], key_id.size()); | 285 << base::HexEncode(&key_id[0], key_id.size()); |
276 return; | 286 return; |
277 } | 287 } |
278 | 288 |
279 // If we do have the clear key, decrypt the pending buffer | 289 // If we do have the clear key, decrypt the pending buffer |
280 // and reset the decryption context (not needed anymore). | 290 // and reset the decryption context (not needed anymore). |
281 crypto::SymmetricKey* key = decrypt_context->GetKey(); | 291 crypto::SymmetricKey* key = decrypt_context->GetKey(); |
282 if (key != NULL) { | 292 if (key != NULL) { |
283 pending_buffer_ = DecryptDecoderBuffer(pending_buffer_, key); | 293 pending_buffer_ = DecryptDecoderBuffer(pending_buffer_, key); |
284 decrypt_context = scoped_refptr<DecryptContext>(); | 294 decrypt_context = scoped_refptr<DecryptContext>(); |
285 } | 295 } |
286 } | 296 } |
287 | 297 |
288 if (!pending_buffer_->end_of_stream() && buffering_state_.get()) { | 298 if (!pending_buffer_->end_of_stream() && buffering_state_.get()) { |
289 base::TimeDelta timestamp = pending_buffer_->timestamp(); | 299 base::TimeDelta timestamp = pending_buffer_->timestamp(); |
290 if (timestamp != ::media::kNoTimestamp()) | 300 if (timestamp != ::media::kNoTimestamp()) |
291 buffering_state_->SetMaxRenderingTime(timestamp); | 301 buffering_state_->SetMaxRenderingTime(timestamp); |
292 } | 302 } |
293 | 303 |
294 MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame( | 304 MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame( |
295 decrypt_context, | 305 decrypt_context, |
296 pending_buffer_, | 306 pending_buffer_, |
297 base::Bind(&AvPipelineImpl::OnFramePushed, weak_this_)); | 307 base::Bind(&AvPipelineImpl::OnFramePushed, this)); |
298 pending_buffer_ = scoped_refptr<DecoderBufferBase>(); | 308 pending_buffer_ = scoped_refptr<DecoderBufferBase>(); |
299 | 309 |
300 pending_push_ = (status == MediaComponentDevice::kFramePending); | 310 pending_push_ = (status == MediaComponentDevice::kFramePending); |
301 if (!pending_push_) | 311 if (!pending_push_) |
302 OnFramePushed(status); | 312 OnFramePushed(status); |
303 } | 313 } |
304 | 314 |
305 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status) { | 315 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status) { |
306 DCHECK(thread_checker_.CalledOnValidThread()); | 316 DCHECK(thread_checker_.CalledOnValidThread()); |
307 pending_push_ = false; | 317 pending_push_ = false; |
308 if (status == MediaComponentDevice::kFrameFailed) { | 318 if (status == MediaComponentDevice::kFrameFailed) { |
309 LOG(WARNING) << "AvPipelineImpl: PushFrame failed"; | 319 LOG(WARNING) << "AvPipelineImpl: PushFrame failed"; |
310 enable_feeding_ = false; | 320 enable_feeding_ = false; |
311 state_ = kError; | 321 state_ = kError; |
312 return; | 322 return; |
313 } | 323 } |
314 base::MessageLoopProxy::current()->PostTask( | 324 base::MessageLoopProxy::current()->PostTask( |
315 FROM_HERE, | 325 FROM_HERE, |
316 base::Bind(&AvPipelineImpl::ProcessPendingBuffer, weak_this_)); | 326 base::Bind(&AvPipelineImpl::ProcessPendingBuffer, this)); |
317 } | 327 } |
318 | 328 |
319 void AvPipelineImpl::OnCdmStateChanged() { | 329 void AvPipelineImpl::OnCdmStateChanged() { |
320 DCHECK(thread_checker_.CalledOnValidThread()); | 330 DCHECK(thread_checker_.CalledOnValidThread()); |
321 | 331 |
322 // Update the buffering state if needed. | 332 // Update the buffering state if needed. |
323 if (buffering_state_.get()) | 333 if (buffering_state_.get()) |
324 UpdatePlayableFrames(); | 334 UpdatePlayableFrames(); |
325 | 335 |
326 // Process the pending buffer in case the CDM now has the frame key id. | 336 // Process the pending buffer in case the CDM now has the frame key id. |
327 ProcessPendingBuffer(); | 337 ProcessPendingBuffer(); |
328 } | 338 } |
329 | 339 |
330 void AvPipelineImpl::OnCdmDestroyed() { | 340 void AvPipelineImpl::OnCdmDestroyed() { |
331 DCHECK(thread_checker_.CalledOnValidThread()); | 341 base::AutoLock lock(media_keys_lock_); |
332 media_keys_ = NULL; | 342 media_keys_ = NULL; |
333 } | 343 } |
334 | 344 |
335 void AvPipelineImpl::OnFrameBuffered( | 345 void AvPipelineImpl::OnFrameBuffered( |
336 const scoped_refptr<DecoderBufferBase>& buffer, | 346 const scoped_refptr<DecoderBufferBase>& buffer, |
337 bool is_at_max_capacity) { | 347 bool is_at_max_capacity) { |
338 DCHECK(thread_checker_.CalledOnValidThread()); | 348 DCHECK(thread_checker_.CalledOnValidThread()); |
339 | 349 |
340 if (!buffering_state_.get()) | 350 if (!buffering_state_.get()) |
341 return; | 351 return; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 } | 392 } |
383 } | 393 } |
384 | 394 |
385 // The frame is playable: remove it from the list of non playable frames. | 395 // The frame is playable: remove it from the list of non playable frames. |
386 non_playable_frames_.pop_front(); | 396 non_playable_frames_.pop_front(); |
387 } | 397 } |
388 } | 398 } |
389 | 399 |
390 } // namespace media | 400 } // namespace media |
391 } // namespace chromecast | 401 } // namespace chromecast |
OLD | NEW |