| 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/base/pipeline_impl.h" | 5 #include "media/base/pipeline_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/location.h" | 14 #include "base/location.h" |
| 15 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
| 16 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
| 17 #include "base/synchronization/lock.h" | 17 #include "base/synchronization/lock.h" |
| 18 #include "base/synchronization/waitable_event.h" | 18 #include "base/synchronization/waitable_event.h" |
| 19 #include "base/threading/thread_task_runner_handle.h" | 19 #include "base/threading/thread_task_runner_handle.h" |
| 20 #include "media/base/bind_to_current_loop.h" | 20 #include "media/base/bind_to_current_loop.h" |
| 21 #include "media/base/demuxer.h" | 21 #include "media/base/demuxer.h" |
| 22 #include "media/base/media_log.h" | 22 #include "media/base/media_log.h" |
| 23 #include "media/base/media_switches.h" | 23 #include "media/base/media_switches.h" |
| 24 #include "media/base/renderer.h" | 24 #include "media/base/renderer.h" |
| 25 #include "media/base/renderer_client.h" | 25 #include "media/base/renderer_client.h" |
| 26 #include "media/base/serial_runner.h" | 26 #include "media/base/serial_runner.h" |
| 27 #include "media/base/stream_position.h" |
| 27 #include "media/base/text_renderer.h" | 28 #include "media/base/text_renderer.h" |
| 28 #include "media/base/text_track_config.h" | 29 #include "media/base/text_track_config.h" |
| 29 #include "media/base/timestamp_constants.h" | 30 #include "media/base/timestamp_constants.h" |
| 30 #include "media/base/video_decoder_config.h" | 31 #include "media/base/video_decoder_config.h" |
| 31 | 32 |
| 32 static const double kDefaultPlaybackRate = 0.0; | 33 static const double kDefaultPlaybackRate = 0.0; |
| 33 static const float kDefaultVolume = 1.0f; | 34 static const float kDefaultVolume = 1.0f; |
| 34 | 35 |
| 35 namespace media { | 36 namespace media { |
| 36 | 37 |
| 37 class PipelineImpl::RendererWrapper : public DemuxerHost, | 38 class PipelineImpl::RendererWrapper : public DemuxerHost, |
| 38 public RendererClient { | 39 public RendererClient { |
| 39 public: | 40 public: |
| 40 RendererWrapper(scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, | 41 RendererWrapper(scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, |
| 41 scoped_refptr<MediaLog> media_log); | 42 scoped_refptr<MediaLog> media_log); |
| 42 ~RendererWrapper() final; | 43 ~RendererWrapper() final; |
| 43 | 44 |
| 44 void Start(Demuxer* demuxer, | 45 void Start(Demuxer* demuxer, |
| 45 std::unique_ptr<Renderer> renderer, | 46 std::unique_ptr<Renderer> renderer, |
| 46 std::unique_ptr<TextRenderer> text_renderer, | 47 std::unique_ptr<TextRenderer> text_renderer, |
| 47 base::WeakPtr<PipelineImpl> weak_pipeline); | 48 base::WeakPtr<PipelineImpl> weak_pipeline); |
| 48 void Stop(const base::Closure& stop_cb); | 49 void Stop(const base::Closure& stop_cb); |
| 49 void Seek(base::TimeDelta time); | 50 void Seek(StreamPosition position); |
| 50 void Suspend(); | 51 void Suspend(); |
| 51 void Resume(std::unique_ptr<Renderer> renderer, base::TimeDelta time); | 52 void Resume(std::unique_ptr<Renderer> renderer, base::TimeDelta time); |
| 52 void SetPlaybackRate(double playback_rate); | 53 void SetPlaybackRate(double playback_rate); |
| 53 void SetVolume(float volume); | 54 void SetVolume(float volume); |
| 54 base::TimeDelta GetMediaTime() const; | 55 base::TimeDelta GetMediaTime() const; |
| 55 Ranges<base::TimeDelta> GetBufferedTimeRanges() const; | 56 Ranges<base::TimeDelta> GetBufferedTimeRanges() const; |
| 56 bool DidLoadingProgress(); | 57 bool DidLoadingProgress(); |
| 57 PipelineStatistics GetStatistics() const; | 58 PipelineStatistics GetStatistics() const; |
| 58 void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); | 59 void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); |
| 59 | 60 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 void SetDuration(base::TimeDelta duration) final; | 103 void SetDuration(base::TimeDelta duration) final; |
| 103 void OnDemuxerError(PipelineStatus error) final; | 104 void OnDemuxerError(PipelineStatus error) final; |
| 104 void AddTextStream(DemuxerStream* text_stream, | 105 void AddTextStream(DemuxerStream* text_stream, |
| 105 const TextTrackConfig& config) final; | 106 const TextTrackConfig& config) final; |
| 106 void RemoveTextStream(DemuxerStream* text_stream) final; | 107 void RemoveTextStream(DemuxerStream* text_stream) final; |
| 107 | 108 |
| 108 // RendererClient implementation. | 109 // RendererClient implementation. |
| 109 void OnError(PipelineStatus error) final; | 110 void OnError(PipelineStatus error) final; |
| 110 void OnEnded() final; | 111 void OnEnded() final; |
| 111 void OnStatisticsUpdate(const PipelineStatistics& stats) final; | 112 void OnStatisticsUpdate(const PipelineStatistics& stats) final; |
| 113 void OnFirstVideoFrameTimestampKnown(base::TimeDelta timestamp) final; |
| 112 void OnBufferingStateChange(BufferingState state) final; | 114 void OnBufferingStateChange(BufferingState state) final; |
| 113 void OnWaitingForDecryptionKey() final; | 115 void OnWaitingForDecryptionKey() final; |
| 114 void OnVideoNaturalSizeChange(const gfx::Size& size) final; | 116 void OnVideoNaturalSizeChange(const gfx::Size& size) final; |
| 115 void OnVideoOpacityChange(bool opaque) final; | 117 void OnVideoOpacityChange(bool opaque) final; |
| 116 void OnDurationChange(base::TimeDelta duration) final; | 118 void OnDurationChange(base::TimeDelta duration) final; |
| 117 | 119 |
| 118 // TextRenderer tasks and notifications. | 120 // TextRenderer tasks and notifications. |
| 119 void OnTextRendererEnded(); | 121 void OnTextRendererEnded(); |
| 120 void AddTextStreamTask(DemuxerStream* text_stream, | 122 void AddTextStreamTask(DemuxerStream* text_stream, |
| 121 const TextTrackConfig& config); | 123 const TextTrackConfig& config); |
| 122 void RemoveTextStreamTask(DemuxerStream* text_stream); | 124 void RemoveTextStreamTask(DemuxerStream* text_stream); |
| 123 | 125 |
| 124 // Common handlers for notifications from renderers and demuxer. | 126 // Common handlers for notifications from renderers and demuxer. |
| 125 void OnPipelineError(PipelineStatus error); | 127 void OnPipelineError(PipelineStatus error); |
| 126 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, | 128 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, |
| 127 CdmContext* cdm_context, | 129 CdmContext* cdm_context, |
| 128 bool success); | 130 bool success); |
| 129 void CheckPlaybackEnded(); | 131 void CheckPlaybackEnded(); |
| 130 | 132 |
| 131 // State transition tasks. | 133 // State transition tasks. |
| 132 void SetState(State next_state); | 134 void SetState(State next_state); |
| 133 void CompleteSeek(base::TimeDelta seek_time, PipelineStatus status); | 135 void CompleteSeek(StreamPosition position, PipelineStatus status); |
| 134 void CompleteSuspend(PipelineStatus status); | 136 void CompleteSuspend(PipelineStatus status); |
| 135 void InitializeDemuxer(const PipelineStatusCB& done_cb); | 137 void InitializeDemuxer(const PipelineStatusCB& done_cb); |
| 136 void InitializeRenderer(const PipelineStatusCB& done_cb); | 138 void InitializeRenderer(const PipelineStatusCB& done_cb); |
| 137 void DestroyRenderer(); | 139 void DestroyRenderer(); |
| 138 void ReportMetadata(); | 140 void ReportMetadata(); |
| 139 | 141 |
| 140 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; | 142 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; |
| 141 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | 143 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
| 142 const scoped_refptr<MediaLog> media_log_; | 144 const scoped_refptr<MediaLog> media_log_; |
| 143 | 145 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 fns.Push(base::Bind(&RendererWrapper::InitializeDemuxer, weak_this_)); | 244 fns.Push(base::Bind(&RendererWrapper::InitializeDemuxer, weak_this_)); |
| 243 | 245 |
| 244 // Once the demuxer is initialized successfully, media metadata must be | 246 // Once the demuxer is initialized successfully, media metadata must be |
| 245 // available - report the metadata to client. | 247 // available - report the metadata to client. |
| 246 fns.Push(base::Bind(&RendererWrapper::ReportMetadata, weak_this_)); | 248 fns.Push(base::Bind(&RendererWrapper::ReportMetadata, weak_this_)); |
| 247 | 249 |
| 248 // Initialize renderer. | 250 // Initialize renderer. |
| 249 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); | 251 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); |
| 250 | 252 |
| 251 // Run tasks. | 253 // Run tasks. |
| 252 pending_callbacks_ = | 254 pending_callbacks_ = SerialRunner::Run( |
| 253 SerialRunner::Run(fns, base::Bind(&RendererWrapper::CompleteSeek, | 255 fns, base::Bind(&RendererWrapper::CompleteSeek, weak_this_, |
| 254 weak_this_, base::TimeDelta())); | 256 StreamPosition::Precise(base::TimeDelta()))); |
| 255 } | 257 } |
| 256 | 258 |
| 257 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) { | 259 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) { |
| 258 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 260 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 259 DCHECK(state_ != kStopping && state_ != kStopped); | 261 DCHECK(state_ != kStopping && state_ != kStopped); |
| 260 | 262 |
| 261 SetState(kStopping); | 263 SetState(kStopping); |
| 262 | 264 |
| 263 if (shared_state_.statistics.video_frames_decoded > 0) { | 265 if (shared_state_.statistics.video_frames_decoded > 0) { |
| 264 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", | 266 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", |
| (...skipping 18 matching lines...) Expand all Loading... |
| 283 | 285 |
| 284 // Post the stop callback to enqueue it after the tasks that may have been | 286 // Post the stop callback to enqueue it after the tasks that may have been |
| 285 // posted by Demuxer and Renderer during stopping. Note that in theory the | 287 // posted by Demuxer and Renderer during stopping. Note that in theory the |
| 286 // tasks posted by Demuxer/Renderer may post even more tasks that will get | 288 // tasks posted by Demuxer/Renderer may post even more tasks that will get |
| 287 // enqueued after |stop_cb|. This may be problematic because Demuxer may | 289 // enqueued after |stop_cb|. This may be problematic because Demuxer may |
| 288 // get destroyed as soon as |stop_cb| is run. In practice this is not a | 290 // get destroyed as soon as |stop_cb| is run. In practice this is not a |
| 289 // problem, but ideally Demuxer should be destroyed on the media thread. | 291 // problem, but ideally Demuxer should be destroyed on the media thread. |
| 290 media_task_runner_->PostTask(FROM_HERE, stop_cb); | 292 media_task_runner_->PostTask(FROM_HERE, stop_cb); |
| 291 } | 293 } |
| 292 | 294 |
| 293 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) { | 295 void PipelineImpl::RendererWrapper::Seek(StreamPosition position) { |
| 294 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 296 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 295 | 297 |
| 296 // Suppress seeking if we're not fully started. | 298 // Suppress seeking if we're not fully started. |
| 297 if (state_ != kPlaying) { | 299 if (state_ != kPlaying) { |
| 298 DCHECK(state_ == kStopping || state_ == kStopped) | 300 DCHECK(state_ == kStopping || state_ == kStopped) |
| 299 << "Receive seek in unexpected state: " << state_; | 301 << "Receive seek in unexpected state: " << state_; |
| 300 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); | 302 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); |
| 301 return; | 303 return; |
| 302 } | 304 } |
| 303 | 305 |
| 304 base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime()); | 306 position.time = std::max(position.time, demuxer_->GetStartTime()); |
| 305 | 307 |
| 306 SetState(kSeeking); | 308 SetState(kSeeking); |
| 307 renderer_ended_ = false; | 309 renderer_ended_ = false; |
| 308 text_renderer_ended_ = false; | 310 text_renderer_ended_ = false; |
| 309 | 311 |
| 310 // Queue asynchronous actions required to start. | 312 // Queue asynchronous actions required to start. |
| 311 DCHECK(!pending_callbacks_); | 313 DCHECK(!pending_callbacks_); |
| 312 SerialRunner::Queue bound_fns; | 314 SerialRunner::Queue bound_fns; |
| 313 | 315 |
| 314 // Abort any reads the renderer may be blocked on. | 316 // Abort any reads the renderer may be blocked on. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 325 bound_fns.Push(base::Bind(&Renderer::Flush, | 327 bound_fns.Push(base::Bind(&Renderer::Flush, |
| 326 base::Unretained(shared_state_.renderer.get()))); | 328 base::Unretained(shared_state_.renderer.get()))); |
| 327 | 329 |
| 328 if (text_renderer_) { | 330 if (text_renderer_) { |
| 329 bound_fns.Push(base::Bind(&TextRenderer::Flush, | 331 bound_fns.Push(base::Bind(&TextRenderer::Flush, |
| 330 base::Unretained(text_renderer_.get()))); | 332 base::Unretained(text_renderer_.get()))); |
| 331 } | 333 } |
| 332 | 334 |
| 333 // Seek demuxer. | 335 // Seek demuxer. |
| 334 bound_fns.Push( | 336 bound_fns.Push( |
| 335 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); | 337 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), position.time)); |
| 336 | 338 |
| 337 // Run tasks. | 339 // Run tasks. |
| 338 pending_callbacks_ = SerialRunner::Run( | 340 pending_callbacks_ = SerialRunner::Run( |
| 339 bound_fns, | 341 bound_fns, |
| 340 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, seek_timestamp)); | 342 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, position)); |
| 341 } | 343 } |
| 342 | 344 |
| 343 void PipelineImpl::RendererWrapper::Suspend() { | 345 void PipelineImpl::RendererWrapper::Suspend() { |
| 344 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 346 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 345 | 347 |
| 346 // Suppress suspending if we're not playing. | 348 // Suppress suspending if we're not playing. |
| 347 if (state_ != kPlaying) { | 349 if (state_ != kPlaying) { |
| 348 DCHECK(state_ == kStopping || state_ == kStopped) | 350 DCHECK(state_ == kStopping || state_ == kStopped) |
| 349 << "Receive suspend in unexpected state: " << state_; | 351 << "Receive suspend in unexpected state: " << state_; |
| 350 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); | 352 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 std::max(timestamp, demuxer_->GetStartTime()); | 405 std::max(timestamp, demuxer_->GetStartTime()); |
| 404 | 406 |
| 405 // Queue the asynchronous actions required to start playback. | 407 // Queue the asynchronous actions required to start playback. |
| 406 SerialRunner::Queue fns; | 408 SerialRunner::Queue fns; |
| 407 | 409 |
| 408 fns.Push( | 410 fns.Push( |
| 409 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp)); | 411 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp)); |
| 410 | 412 |
| 411 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); | 413 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); |
| 412 | 414 |
| 415 // XXX: Revisit. |
| 413 pending_callbacks_ = SerialRunner::Run( | 416 pending_callbacks_ = SerialRunner::Run( |
| 414 fns, | 417 fns, base::Bind(&RendererWrapper::CompleteSeek, weak_this_, |
| 415 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, start_timestamp)); | 418 StreamPosition::Precise(timestamp))); |
| 416 } | 419 } |
| 417 | 420 |
| 418 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) { | 421 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) { |
| 419 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 422 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 420 | 423 |
| 421 playback_rate_ = playback_rate; | 424 playback_rate_ = playback_rate; |
| 422 if (state_ == kPlaying) | 425 if (state_ == kPlaying) |
| 423 shared_state_.renderer->SetPlaybackRate(playback_rate_); | 426 shared_state_.renderer->SetPlaybackRate(playback_rate_); |
| 424 } | 427 } |
| 425 | 428 |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 DCHECK(shared_state_.renderer); | 603 DCHECK(shared_state_.renderer); |
| 601 | 604 |
| 602 base::TimeDelta currTime = (state_ == kPlaying) | 605 base::TimeDelta currTime = (state_ == kPlaying) |
| 603 ? shared_state_.renderer->GetMediaTime() | 606 ? shared_state_.renderer->GetMediaTime() |
| 604 : demuxer_->GetStartTime(); | 607 : demuxer_->GetStartTime(); |
| 605 demuxer_->OnSelectedVideoTrackChanged(selectedTrackId, currTime); | 608 demuxer_->OnSelectedVideoTrackChanged(selectedTrackId, currTime); |
| 606 } | 609 } |
| 607 | 610 |
| 608 void PipelineImpl::RendererWrapper::OnStatisticsUpdate( | 611 void PipelineImpl::RendererWrapper::OnStatisticsUpdate( |
| 609 const PipelineStatistics& stats) { | 612 const PipelineStatistics& stats) { |
| 610 DVLOG(3) << __func__; | |
| 611 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 613 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 612 | 614 |
| 613 base::AutoLock auto_lock(shared_state_lock_); | 615 base::AutoLock auto_lock(shared_state_lock_); |
| 614 shared_state_.statistics.audio_bytes_decoded += stats.audio_bytes_decoded; | 616 shared_state_.statistics.audio_bytes_decoded += stats.audio_bytes_decoded; |
| 615 shared_state_.statistics.video_bytes_decoded += stats.video_bytes_decoded; | 617 shared_state_.statistics.video_bytes_decoded += stats.video_bytes_decoded; |
| 616 shared_state_.statistics.video_frames_decoded += stats.video_frames_decoded; | 618 shared_state_.statistics.video_frames_decoded += stats.video_frames_decoded; |
| 617 shared_state_.statistics.video_frames_dropped += stats.video_frames_dropped; | 619 shared_state_.statistics.video_frames_dropped += stats.video_frames_dropped; |
| 618 shared_state_.statistics.audio_memory_usage += stats.audio_memory_usage; | 620 shared_state_.statistics.audio_memory_usage += stats.audio_memory_usage; |
| 619 shared_state_.statistics.video_memory_usage += stats.video_memory_usage; | 621 shared_state_.statistics.video_memory_usage += stats.video_memory_usage; |
| 620 } | 622 } |
| 621 | 623 |
| 624 void PipelineImpl::RendererWrapper::OnFirstVideoFrameTimestampKnown( |
| 625 base::TimeDelta timestamp) {} |
| 626 |
| 622 void PipelineImpl::RendererWrapper::OnBufferingStateChange( | 627 void PipelineImpl::RendererWrapper::OnBufferingStateChange( |
| 623 BufferingState state) { | 628 BufferingState state) { |
| 624 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 629 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 625 DVLOG(2) << __func__ << "(" << state << ") "; | 630 DVLOG(2) << __func__ << "(" << state << ") "; |
| 626 | 631 |
| 627 main_task_runner_->PostTask( | 632 main_task_runner_->PostTask( |
| 628 FROM_HERE, | 633 FROM_HERE, |
| 629 base::Bind(&PipelineImpl::OnBufferingStateChange, weak_pipeline_, state)); | 634 base::Bind(&PipelineImpl::OnBufferingStateChange, weak_pipeline_, state)); |
| 630 } | 635 } |
| 631 | 636 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 | 746 |
| 742 void PipelineImpl::RendererWrapper::SetState(State next_state) { | 747 void PipelineImpl::RendererWrapper::SetState(State next_state) { |
| 743 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 748 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 744 DVLOG(1) << PipelineImpl::GetStateString(state_) << " -> " | 749 DVLOG(1) << PipelineImpl::GetStateString(state_) << " -> " |
| 745 << PipelineImpl::GetStateString(next_state); | 750 << PipelineImpl::GetStateString(next_state); |
| 746 | 751 |
| 747 state_ = next_state; | 752 state_ = next_state; |
| 748 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); | 753 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); |
| 749 } | 754 } |
| 750 | 755 |
| 751 void PipelineImpl::RendererWrapper::CompleteSeek(base::TimeDelta seek_time, | 756 void PipelineImpl::RendererWrapper::CompleteSeek(StreamPosition position, |
| 752 PipelineStatus status) { | 757 PipelineStatus status) { |
| 753 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 758 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 754 DCHECK(state_ == kStarting || state_ == kSeeking || state_ == kResuming); | 759 DCHECK(state_ == kStarting || state_ == kSeeking || state_ == kResuming); |
| 755 | 760 |
| 756 DCHECK(pending_callbacks_); | 761 DCHECK(pending_callbacks_); |
| 757 pending_callbacks_.reset(); | 762 pending_callbacks_.reset(); |
| 758 | 763 |
| 759 if (status != PIPELINE_OK) { | 764 if (status != PIPELINE_OK) { |
| 760 OnPipelineError(status); | 765 OnPipelineError(status); |
| 761 return; | 766 return; |
| 762 } | 767 } |
| 763 | 768 |
| 764 shared_state_.renderer->StartPlayingFrom( | 769 position.time = std::max(position.time, demuxer_->GetStartTime()); |
| 765 std::max(seek_time, demuxer_->GetStartTime())); | 770 shared_state_.renderer->StartPlayingFrom(position); |
| 771 |
| 766 { | 772 { |
| 767 base::AutoLock auto_lock(shared_state_lock_); | 773 base::AutoLock auto_lock(shared_state_lock_); |
| 768 shared_state_.suspend_timestamp = kNoTimestamp; | 774 shared_state_.suspend_timestamp = kNoTimestamp; |
| 769 } | 775 } |
| 770 | 776 |
| 771 if (text_renderer_) | 777 if (text_renderer_) |
| 772 text_renderer_->StartPlaying(); | 778 text_renderer_->StartPlaying(); |
| 773 | 779 |
| 774 shared_state_.renderer->SetPlaybackRate(playback_rate_); | 780 shared_state_.renderer->SetPlaybackRate(playback_rate_); |
| 775 shared_state_.renderer->SetVolume(volume_); | 781 shared_state_.renderer->SetVolume(volume_); |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 965 // Reset all callbacks and client handle. | 971 // Reset all callbacks and client handle. |
| 966 seek_cb_.Reset(); | 972 seek_cb_.Reset(); |
| 967 suspend_cb_.Reset(); | 973 suspend_cb_.Reset(); |
| 968 client_ = nullptr; | 974 client_ = nullptr; |
| 969 | 975 |
| 970 // Invalidate self weak pointers effectively canceling all pending | 976 // Invalidate self weak pointers effectively canceling all pending |
| 971 // notifications in the message queue. | 977 // notifications in the message queue. |
| 972 weak_factory_.InvalidateWeakPtrs(); | 978 weak_factory_.InvalidateWeakPtrs(); |
| 973 } | 979 } |
| 974 | 980 |
| 975 void PipelineImpl::Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) { | 981 void PipelineImpl::Seek(StreamPosition position, |
| 976 DVLOG(2) << __func__ << " to " << time.InMicroseconds(); | 982 const PipelineStatusCB& seek_cb) { |
| 983 DVLOG(2) << __func__ << "(" << ToString(position) << ")"; |
| 977 DCHECK(thread_checker_.CalledOnValidThread()); | 984 DCHECK(thread_checker_.CalledOnValidThread()); |
| 978 DCHECK(!seek_cb.is_null()); | 985 DCHECK(!seek_cb.is_null()); |
| 979 | 986 |
| 980 if (!IsRunning()) { | 987 if (!IsRunning()) { |
| 981 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; | 988 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; |
| 982 return; | 989 return; |
| 983 } | 990 } |
| 984 | 991 |
| 985 DCHECK(seek_cb_.is_null()); | 992 DCHECK(seek_cb_.is_null()); |
| 986 seek_cb_ = seek_cb; | 993 seek_cb_ = seek_cb; |
| 987 last_media_time_ = base::TimeDelta(); | 994 last_media_time_ = base::TimeDelta(); |
| 988 media_task_runner_->PostTask( | 995 media_task_runner_->PostTask( |
| 989 FROM_HERE, base::Bind(&RendererWrapper::Seek, | 996 FROM_HERE, |
| 990 base::Unretained(renderer_wrapper_.get()), time)); | 997 base::Bind(&RendererWrapper::Seek, |
| 998 base::Unretained(renderer_wrapper_.get()), position)); |
| 991 } | 999 } |
| 992 | 1000 |
| 993 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { | 1001 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { |
| 994 DVLOG(2) << __func__; | 1002 DVLOG(2) << __func__; |
| 995 DCHECK(!suspend_cb.is_null()); | 1003 DCHECK(!suspend_cb.is_null()); |
| 996 | 1004 |
| 997 DCHECK(IsRunning()); | 1005 DCHECK(IsRunning()); |
| 998 DCHECK(suspend_cb_.is_null()); | 1006 DCHECK(suspend_cb_.is_null()); |
| 999 suspend_cb_ = suspend_cb; | 1007 suspend_cb_ = suspend_cb; |
| 1000 | 1008 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1069 DCHECK(thread_checker_.CalledOnValidThread()); | 1077 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1070 | 1078 |
| 1071 base::TimeDelta media_time = renderer_wrapper_->GetMediaTime(); | 1079 base::TimeDelta media_time = renderer_wrapper_->GetMediaTime(); |
| 1072 | 1080 |
| 1073 // Clamp current media time to the last reported value, this prevents higher | 1081 // Clamp current media time to the last reported value, this prevents higher |
| 1074 // level clients from seeing time go backwards based on inaccurate or spurious | 1082 // level clients from seeing time go backwards based on inaccurate or spurious |
| 1075 // delay values reported to the AudioClock. | 1083 // delay values reported to the AudioClock. |
| 1076 // | 1084 // |
| 1077 // It is expected that such events are transient and will be recovered as | 1085 // It is expected that such events are transient and will be recovered as |
| 1078 // rendering continues over time. | 1086 // rendering continues over time. |
| 1087 |
| 1088 // XXX: Revisit. Do we even need this logic? |
| 1089 /* |
| 1079 if (media_time < last_media_time_) { | 1090 if (media_time < last_media_time_) { |
| 1080 DVLOG(2) << __func__ << ": actual=" << media_time | 1091 DVLOG(2) << __func__ << ": actual=" << media_time |
| 1081 << " clamped=" << last_media_time_; | 1092 << " clamped=" << last_media_time_; |
| 1082 return last_media_time_; | 1093 return last_media_time_; |
| 1083 } | 1094 } |
| 1095 */ |
| 1084 | 1096 |
| 1085 DVLOG(3) << __FUNCTION__ << ": " << media_time.InMilliseconds() << " ms"; | 1097 DVLOG(3) << __FUNCTION__ << ": " << media_time.InMilliseconds() << " ms"; |
| 1086 last_media_time_ = media_time; | 1098 last_media_time_ = media_time; |
| 1087 return last_media_time_; | 1099 return last_media_time_; |
| 1088 } | 1100 } |
| 1089 | 1101 |
| 1090 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { | 1102 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { |
| 1091 DCHECK(thread_checker_.CalledOnValidThread()); | 1103 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1092 return renderer_wrapper_->GetBufferedTimeRanges(); | 1104 return renderer_wrapper_->GetBufferedTimeRanges(); |
| 1093 } | 1105 } |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1253 void PipelineImpl::OnSuspendDone() { | 1265 void PipelineImpl::OnSuspendDone() { |
| 1254 DVLOG(3) << __func__; | 1266 DVLOG(3) << __func__; |
| 1255 DCHECK(thread_checker_.CalledOnValidThread()); | 1267 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1256 DCHECK(IsRunning()); | 1268 DCHECK(IsRunning()); |
| 1257 | 1269 |
| 1258 DCHECK(!suspend_cb_.is_null()); | 1270 DCHECK(!suspend_cb_.is_null()); |
| 1259 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK); | 1271 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK); |
| 1260 } | 1272 } |
| 1261 | 1273 |
| 1262 } // namespace media | 1274 } // namespace media |
| OLD | NEW |