| 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) { |
| 49 DCHECK(media_component_device); | 50 DCHECK(media_component_device); |
| 51 weak_this_ = weak_factory_.GetWeakPtr(); |
| 50 thread_checker_.DetachFromThread(); | 52 thread_checker_.DetachFromThread(); |
| 51 } | 53 } |
| 52 | 54 |
| 53 AvPipelineImpl::~AvPipelineImpl() { | 55 AvPipelineImpl::~AvPipelineImpl() { |
| 54 } | 56 } |
| 55 | 57 |
| 56 void AvPipelineImpl::TransitionToState(State state) { | 58 void AvPipelineImpl::TransitionToState(State state) { |
| 57 DCHECK(thread_checker_.CalledOnValidThread()); | 59 DCHECK(thread_checker_.CalledOnValidThread()); |
| 58 state_ = state; | 60 state_ = state; |
| 59 } | 61 } |
| 60 | 62 |
| 61 void AvPipelineImpl::SetCodedFrameProvider( | 63 void AvPipelineImpl::SetCodedFrameProvider( |
| 62 scoped_ptr<CodedFrameProvider> frame_provider, | 64 scoped_ptr<CodedFrameProvider> frame_provider, |
| 63 size_t max_buffer_size, | 65 size_t max_buffer_size, |
| 64 size_t max_frame_size) { | 66 size_t max_frame_size) { |
| 65 DCHECK_EQ(state_, kUninitialized); | 67 DCHECK_EQ(state_, kUninitialized); |
| 66 DCHECK(frame_provider); | 68 DCHECK(frame_provider); |
| 67 | 69 |
| 68 // Wrap the incoming frame provider to add some buffering capabilities. | 70 // Wrap the incoming frame provider to add some buffering capabilities. |
| 69 frame_provider_.reset( | 71 frame_provider_.reset( |
| 70 new BufferingFrameProvider( | 72 new BufferingFrameProvider( |
| 71 frame_provider.Pass(), | 73 frame_provider.Pass(), |
| 72 max_buffer_size, | 74 max_buffer_size, |
| 73 max_frame_size, | 75 max_frame_size, |
| 74 base::Bind(&AvPipelineImpl::OnFrameBuffered, this))); | 76 base::Bind(&AvPipelineImpl::OnFrameBuffered, weak_this_))); |
| 75 } | 77 } |
| 76 | 78 |
| 77 void AvPipelineImpl::SetClient(const AvPipelineClient& client) { | 79 void AvPipelineImpl::SetClient(const AvPipelineClient& client) { |
| 78 DCHECK(thread_checker_.CalledOnValidThread()); | 80 DCHECK(thread_checker_.CalledOnValidThread()); |
| 79 DCHECK_EQ(state_, kUninitialized); | 81 DCHECK_EQ(state_, kUninitialized); |
| 80 client_ = client; | 82 client_ = client; |
| 81 } | 83 } |
| 82 | 84 |
| 83 bool AvPipelineImpl::Initialize() { | 85 bool AvPipelineImpl::Initialize() { |
| 84 DCHECK(thread_checker_.CalledOnValidThread()); | 86 DCHECK(thread_checker_.CalledOnValidThread()); |
| 85 DCHECK_EQ(state_, kUninitialized); | 87 DCHECK_EQ(state_, kUninitialized); |
| 86 | 88 |
| 87 MediaComponentDevice::Client client; | 89 MediaComponentDevice::Client client; |
| 88 client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, this); | 90 client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, weak_this_); |
| 89 media_component_device_->SetClient(client); | 91 media_component_device_->SetClient(client); |
| 90 if (!media_component_device_->SetState(MediaComponentDevice::kStateIdle)) | 92 if (!media_component_device_->SetState(MediaComponentDevice::kStateIdle)) |
| 91 return false; | 93 return false; |
| 92 | 94 |
| 93 return true; | 95 return true; |
| 94 } | 96 } |
| 95 | 97 |
| 96 void AvPipelineImpl::Finalize() { | 98 void AvPipelineImpl::Finalize() { |
| 97 DCHECK(thread_checker_.CalledOnValidThread()); | 99 DCHECK(thread_checker_.CalledOnValidThread()); |
| 98 media_component_device_->SetClient(MediaComponentDevice::Client()); | 100 media_component_device_->SetClient(MediaComponentDevice::Client()); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 126 if (buffering_state_.get()) | 128 if (buffering_state_.get()) |
| 127 buffering_state_->SetMediaTime(time); | 129 buffering_state_->SetMediaTime(time); |
| 128 | 130 |
| 129 if (!media_component_device_->SetState(MediaComponentDevice::kStateRunning)) | 131 if (!media_component_device_->SetState(MediaComponentDevice::kStateRunning)) |
| 130 return false; | 132 return false; |
| 131 | 133 |
| 132 // Start feeding the pipeline. | 134 // Start feeding the pipeline. |
| 133 enable_feeding_ = true; | 135 enable_feeding_ = true; |
| 134 base::MessageLoopProxy::current()->PostTask( | 136 base::MessageLoopProxy::current()->PostTask( |
| 135 FROM_HERE, | 137 FROM_HERE, |
| 136 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); | 138 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); |
| 137 | 139 |
| 138 return true; | 140 return true; |
| 139 } | 141 } |
| 140 | 142 |
| 141 void AvPipelineImpl::Flush(const base::Closure& done_cb) { | 143 void AvPipelineImpl::Flush(const base::Closure& done_cb) { |
| 142 DCHECK(thread_checker_.CalledOnValidThread()); | 144 DCHECK(thread_checker_.CalledOnValidThread()); |
| 143 DCHECK_EQ(state_, kFlushing); | 145 DCHECK_EQ(state_, kFlushing); |
| 144 DCHECK_EQ( | 146 DCHECK_EQ( |
| 145 media_component_device_->GetState(), MediaComponentDevice::kStateRunning); | 147 media_component_device_->GetState(), MediaComponentDevice::kStateRunning); |
| 146 // Note: returning to idle state aborts any pending frame push. | 148 // Note: returning to idle state aborts any pending frame push. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 DCHECK(media_keys); | 191 DCHECK(media_keys); |
| 190 | 192 |
| 191 { | 193 { |
| 192 base::AutoLock lock(media_keys_lock_); | 194 base::AutoLock lock(media_keys_lock_); |
| 193 if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) | 195 if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) |
| 194 media_keys_->UnregisterPlayer(media_keys_callback_id_); | 196 media_keys_->UnregisterPlayer(media_keys_callback_id_); |
| 195 | 197 |
| 196 media_keys_ = media_keys; | 198 media_keys_ = media_keys; |
| 197 media_keys_callback_id_ = media_keys_->RegisterPlayer( | 199 media_keys_callback_id_ = media_keys_->RegisterPlayer( |
| 198 ::media::BindToCurrentLoop( | 200 ::media::BindToCurrentLoop( |
| 199 base::Bind(&AvPipelineImpl::OnCdmStateChanged, this)), | 201 base::Bind(&AvPipelineImpl::OnCdmStateChanged, weak_this_)), |
| 200 // Note: this callback gets invoked in ~BrowserCdmCast. Posting | 202 // Note: this callback gets invoked in ~BrowserCdmCast. Posting |
| 201 // OnCdmDestroyed to the media thread results in a race condition | 203 // OnCdmDestroyed to the media thread results in a race condition |
| 202 // with media_keys_ accesses. This callback must run synchronously, | 204 // with media_keys_ accesses. This callback must run synchronously, |
| 203 // otherwise media_keys_ access might occur after it is deleted. | 205 // otherwise media_keys_ access might occur after it is deleted. |
| 206 // It cannot use the weak-ptr reference, since it's invoked on the UI |
| 207 // thread. |
| 204 base::Bind(&AvPipelineImpl::OnCdmDestroyed, this)); | 208 base::Bind(&AvPipelineImpl::OnCdmDestroyed, this)); |
| 205 } | 209 } |
| 206 } | 210 } |
| 207 | 211 |
| 208 void AvPipelineImpl::OnEos() { | 212 void AvPipelineImpl::OnEos() { |
| 209 DCHECK(thread_checker_.CalledOnValidThread()); | 213 DCHECK(thread_checker_.CalledOnValidThread()); |
| 210 CMALOG(kLogControl) << __FUNCTION__; | 214 CMALOG(kLogControl) << __FUNCTION__; |
| 211 if (state_ != kPlaying) | 215 if (state_ != kPlaying) |
| 212 return; | 216 return; |
| 213 | 217 |
| 214 if (!client_.eos_cb.is_null()) | 218 if (!client_.eos_cb.is_null()) |
| 215 client_.eos_cb.Run(); | 219 client_.eos_cb.Run(); |
| 216 } | 220 } |
| 217 | 221 |
| 218 void AvPipelineImpl::FetchBufferIfNeeded() { | 222 void AvPipelineImpl::FetchBufferIfNeeded() { |
| 219 DCHECK(thread_checker_.CalledOnValidThread()); | 223 DCHECK(thread_checker_.CalledOnValidThread()); |
| 220 if (!enable_feeding_) | 224 if (!enable_feeding_) |
| 221 return; | 225 return; |
| 222 | 226 |
| 223 if (pending_read_ || pending_buffer_.get()) | 227 if (pending_read_ || pending_buffer_.get()) |
| 224 return; | 228 return; |
| 225 | 229 |
| 226 pending_read_ = true; | 230 pending_read_ = true; |
| 227 frame_provider_->Read( | 231 frame_provider_->Read( |
| 228 base::Bind(&AvPipelineImpl::OnNewFrame, this)); | 232 base::Bind(&AvPipelineImpl::OnNewFrame, weak_this_)); |
| 229 } | 233 } |
| 230 | 234 |
| 231 void AvPipelineImpl::OnNewFrame( | 235 void AvPipelineImpl::OnNewFrame( |
| 232 const scoped_refptr<DecoderBufferBase>& buffer, | 236 const scoped_refptr<DecoderBufferBase>& buffer, |
| 233 const ::media::AudioDecoderConfig& audio_config, | 237 const ::media::AudioDecoderConfig& audio_config, |
| 234 const ::media::VideoDecoderConfig& video_config) { | 238 const ::media::VideoDecoderConfig& video_config) { |
| 235 DCHECK(thread_checker_.CalledOnValidThread()); | 239 DCHECK(thread_checker_.CalledOnValidThread()); |
| 236 pending_read_ = false; | 240 pending_read_ = false; |
| 237 | 241 |
| 238 if (audio_config.IsValidConfig() || video_config.IsValidConfig()) | 242 if (audio_config.IsValidConfig() || video_config.IsValidConfig()) |
| 239 update_config_cb_.Run(audio_config, video_config); | 243 update_config_cb_.Run(audio_config, video_config); |
| 240 | 244 |
| 241 pending_buffer_ = buffer; | 245 pending_buffer_ = buffer; |
| 242 ProcessPendingBuffer(); | 246 ProcessPendingBuffer(); |
| 243 | 247 |
| 244 base::MessageLoopProxy::current()->PostTask( | 248 base::MessageLoopProxy::current()->PostTask( |
| 245 FROM_HERE, | 249 FROM_HERE, |
| 246 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); | 250 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); |
| 247 } | 251 } |
| 248 | 252 |
| 249 void AvPipelineImpl::ProcessPendingBuffer() { | 253 void AvPipelineImpl::ProcessPendingBuffer() { |
| 250 if (!enable_feeding_) | 254 if (!enable_feeding_) |
| 251 return; | 255 return; |
| 252 | 256 |
| 253 // Initiate a read if there isn't already one. | 257 // Initiate a read if there isn't already one. |
| 254 if (!pending_buffer_.get() && !pending_read_) { | 258 if (!pending_buffer_.get() && !pending_read_) { |
| 255 base::MessageLoopProxy::current()->PostTask( | 259 base::MessageLoopProxy::current()->PostTask( |
| 256 FROM_HERE, | 260 FROM_HERE, |
| 257 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); | 261 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); |
| 258 return; | 262 return; |
| 259 } | 263 } |
| 260 | 264 |
| 261 if (!pending_buffer_.get() || pending_push_) | 265 if (!pending_buffer_.get() || pending_push_) |
| 262 return; | 266 return; |
| 263 | 267 |
| 264 // Break the feeding loop when the end of stream is reached. | 268 // Break the feeding loop when the end of stream is reached. |
| 265 if (pending_buffer_->end_of_stream()) { | 269 if (pending_buffer_->end_of_stream()) { |
| 266 CMALOG(kLogControl) << __FUNCTION__ << ": EOS reached, stopped feeding"; | 270 CMALOG(kLogControl) << __FUNCTION__ << ": EOS reached, stopped feeding"; |
| 267 enable_feeding_ = false; | 271 enable_feeding_ = false; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 | 305 |
| 302 if (!pending_buffer_->end_of_stream() && buffering_state_.get()) { | 306 if (!pending_buffer_->end_of_stream() && buffering_state_.get()) { |
| 303 base::TimeDelta timestamp = pending_buffer_->timestamp(); | 307 base::TimeDelta timestamp = pending_buffer_->timestamp(); |
| 304 if (timestamp != ::media::kNoTimestamp()) | 308 if (timestamp != ::media::kNoTimestamp()) |
| 305 buffering_state_->SetMaxRenderingTime(timestamp); | 309 buffering_state_->SetMaxRenderingTime(timestamp); |
| 306 } | 310 } |
| 307 | 311 |
| 308 MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame( | 312 MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame( |
| 309 decrypt_context, | 313 decrypt_context, |
| 310 pending_buffer_, | 314 pending_buffer_, |
| 311 base::Bind(&AvPipelineImpl::OnFramePushed, this)); | 315 base::Bind(&AvPipelineImpl::OnFramePushed, weak_this_)); |
| 312 pending_buffer_ = scoped_refptr<DecoderBufferBase>(); | 316 pending_buffer_ = scoped_refptr<DecoderBufferBase>(); |
| 313 | 317 |
| 314 pending_push_ = (status == MediaComponentDevice::kFramePending); | 318 pending_push_ = (status == MediaComponentDevice::kFramePending); |
| 315 if (!pending_push_) | 319 if (!pending_push_) |
| 316 OnFramePushed(status); | 320 OnFramePushed(status); |
| 317 } | 321 } |
| 318 | 322 |
| 319 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status) { | 323 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status) { |
| 320 DCHECK(thread_checker_.CalledOnValidThread()); | 324 DCHECK(thread_checker_.CalledOnValidThread()); |
| 321 pending_push_ = false; | 325 pending_push_ = false; |
| 322 if (status == MediaComponentDevice::kFrameFailed) { | 326 if (status == MediaComponentDevice::kFrameFailed) { |
| 323 LOG(WARNING) << "AvPipelineImpl: PushFrame failed"; | 327 LOG(WARNING) << "AvPipelineImpl: PushFrame failed"; |
| 324 enable_feeding_ = false; | 328 enable_feeding_ = false; |
| 325 state_ = kError; | 329 state_ = kError; |
| 326 return; | 330 return; |
| 327 } | 331 } |
| 328 base::MessageLoopProxy::current()->PostTask( | 332 base::MessageLoopProxy::current()->PostTask( |
| 329 FROM_HERE, | 333 FROM_HERE, |
| 330 base::Bind(&AvPipelineImpl::ProcessPendingBuffer, this)); | 334 base::Bind(&AvPipelineImpl::ProcessPendingBuffer, weak_this_)); |
| 331 } | 335 } |
| 332 | 336 |
| 333 void AvPipelineImpl::OnCdmStateChanged() { | 337 void AvPipelineImpl::OnCdmStateChanged() { |
| 334 DCHECK(thread_checker_.CalledOnValidThread()); | 338 DCHECK(thread_checker_.CalledOnValidThread()); |
| 335 | 339 |
| 336 // Update the buffering state if needed. | 340 // Update the buffering state if needed. |
| 337 if (buffering_state_.get()) | 341 if (buffering_state_.get()) |
| 338 UpdatePlayableFrames(); | 342 UpdatePlayableFrames(); |
| 339 | 343 |
| 340 // Process the pending buffer in case the CDM now has the frame key id. | 344 // Process the pending buffer in case the CDM now has the frame key id. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 } | 400 } |
| 397 } | 401 } |
| 398 | 402 |
| 399 // The frame is playable: remove it from the list of non playable frames. | 403 // The frame is playable: remove it from the list of non playable frames. |
| 400 non_playable_frames_.pop_front(); | 404 non_playable_frames_.pop_front(); |
| 401 } | 405 } |
| 402 } | 406 } |
| 403 | 407 |
| 404 } // namespace media | 408 } // namespace media |
| 405 } // namespace chromecast | 409 } // namespace chromecast |
| OLD | NEW |