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 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 29 matching lines...) Expand all Loading... |
40 running_(false), | 40 running_(false), |
41 did_loading_progress_(false), | 41 did_loading_progress_(false), |
42 volume_(1.0f), | 42 volume_(1.0f), |
43 playback_rate_(0.0), | 43 playback_rate_(0.0), |
44 status_(PIPELINE_OK), | 44 status_(PIPELINE_OK), |
45 state_(kCreated), | 45 state_(kCreated), |
46 suspend_timestamp_(kNoTimestamp()), | 46 suspend_timestamp_(kNoTimestamp()), |
47 renderer_ended_(false), | 47 renderer_ended_(false), |
48 text_renderer_ended_(false), | 48 text_renderer_ended_(false), |
49 demuxer_(NULL), | 49 demuxer_(NULL), |
| 50 client_(nullptr), |
50 cdm_context_(nullptr), | 51 cdm_context_(nullptr), |
51 weak_factory_(this) { | 52 weak_factory_(this) { |
52 weak_this_ = weak_factory_.GetWeakPtr(); | 53 weak_this_ = weak_factory_.GetWeakPtr(); |
53 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 54 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
54 } | 55 } |
55 | 56 |
56 PipelineImpl::~PipelineImpl() { | 57 PipelineImpl::~PipelineImpl() { |
57 DCHECK(thread_checker_.CalledOnValidThread()) | 58 DCHECK(thread_checker_.CalledOnValidThread()) |
58 << "Pipeline must be destroyed on same thread that created it"; | 59 << "Pipeline must be destroyed on same thread that created it"; |
59 DCHECK(!running_) << "Stop() must complete before destroying object"; | 60 DCHECK(!running_) << "Stop() must complete before destroying object"; |
60 DCHECK(stop_cb_.is_null()); | 61 DCHECK(stop_cb_.is_null()); |
61 DCHECK(seek_cb_.is_null()); | 62 DCHECK(seek_cb_.is_null()); |
62 } | 63 } |
63 | 64 |
64 void PipelineImpl::Start(Demuxer* demuxer, | 65 void PipelineImpl::Start(Demuxer* demuxer, |
65 scoped_ptr<Renderer> renderer, | 66 scoped_ptr<Renderer> renderer, |
66 const base::Closure& ended_cb, | 67 Client* client, |
67 const PipelineStatusCB& error_cb, | 68 const PipelineStatusCB& seek_cb) { |
68 const PipelineStatusCB& seek_cb, | 69 DCHECK(client); |
69 const PipelineMetadataCB& metadata_cb, | |
70 const BufferingStateCB& buffering_state_cb, | |
71 const base::Closure& duration_change_cb, | |
72 const AddTextTrackCB& add_text_track_cb, | |
73 const base::Closure& waiting_for_decryption_key_cb) { | |
74 DCHECK(!ended_cb.is_null()); | |
75 DCHECK(!error_cb.is_null()); | |
76 DCHECK(!seek_cb.is_null()); | 70 DCHECK(!seek_cb.is_null()); |
77 DCHECK(!metadata_cb.is_null()); | |
78 DCHECK(!buffering_state_cb.is_null()); | |
79 | 71 |
80 base::AutoLock auto_lock(lock_); | 72 base::AutoLock auto_lock(lock_); |
81 CHECK(!running_) << "Media pipeline is already running"; | 73 CHECK(!running_) << "Media pipeline is already running"; |
82 running_ = true; | 74 running_ = true; |
83 | 75 |
84 demuxer_ = demuxer; | 76 demuxer_ = demuxer; |
85 renderer_ = std::move(renderer); | 77 renderer_ = std::move(renderer); |
86 ended_cb_ = ended_cb; | 78 client_ = client; |
87 error_cb_ = error_cb; | |
88 seek_cb_ = seek_cb; | 79 seek_cb_ = seek_cb; |
89 metadata_cb_ = metadata_cb; | |
90 buffering_state_cb_ = buffering_state_cb; | |
91 duration_change_cb_ = duration_change_cb; | |
92 add_text_track_cb_ = add_text_track_cb; | |
93 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; | |
94 | |
95 task_runner_->PostTask(FROM_HERE, | 80 task_runner_->PostTask(FROM_HERE, |
96 base::Bind(&PipelineImpl::StartTask, weak_this_)); | 81 base::Bind(&PipelineImpl::StartTask, weak_this_)); |
97 } | 82 } |
98 | 83 |
99 void PipelineImpl::Stop(const base::Closure& stop_cb) { | 84 void PipelineImpl::Stop(const base::Closure& stop_cb) { |
100 DVLOG(2) << __FUNCTION__; | 85 DVLOG(2) << __FUNCTION__; |
101 task_runner_->PostTask( | 86 task_runner_->PostTask( |
102 FROM_HERE, base::Bind(&PipelineImpl::StopTask, weak_this_, stop_cb)); | 87 FROM_HERE, base::Bind(&PipelineImpl::StopTask, weak_this_, stop_cb)); |
103 } | 88 } |
104 | 89 |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 } | 292 } |
308 | 293 |
309 void PipelineImpl::SetDuration(TimeDelta duration) { | 294 void PipelineImpl::SetDuration(TimeDelta duration) { |
310 DCHECK(IsRunning()); | 295 DCHECK(IsRunning()); |
311 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, | 296 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, |
312 "duration", duration)); | 297 "duration", duration)); |
313 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 298 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
314 | 299 |
315 base::AutoLock auto_lock(lock_); | 300 base::AutoLock auto_lock(lock_); |
316 duration_ = duration; | 301 duration_ = duration; |
317 if (!duration_change_cb_.is_null()) | 302 client_->OnDurationChange(); |
318 duration_change_cb_.Run(); | |
319 } | 303 } |
320 | 304 |
321 void PipelineImpl::StateTransitionTask(PipelineStatus status) { | 305 void PipelineImpl::StateTransitionTask(PipelineStatus status) { |
322 DCHECK(task_runner_->BelongsToCurrentThread()); | 306 DCHECK(task_runner_->BelongsToCurrentThread()); |
323 | 307 |
324 // No-op any state transitions if we're stopping. | 308 // No-op any state transitions if we're stopping. |
325 if (state_ == kStopping || state_ == kStopped) | 309 if (state_ == kStopping || state_ == kStopped) |
326 return; | 310 return; |
327 | 311 |
328 // Preserve existing abnormal status, otherwise update based on the result of | 312 // Preserve existing abnormal status, otherwise update based on the result of |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
464 { | 448 { |
465 base::AutoLock auto_lock(lock_); | 449 base::AutoLock auto_lock(lock_); |
466 running_ = false; | 450 running_ = false; |
467 } | 451 } |
468 | 452 |
469 SetState(kStopped); | 453 SetState(kStopped); |
470 demuxer_ = NULL; | 454 demuxer_ = NULL; |
471 | 455 |
472 // If we stop during initialization/seeking/suspending we don't want to leave | 456 // If we stop during initialization/seeking/suspending we don't want to leave |
473 // outstanding callbacks around. | 457 // outstanding callbacks around. |
| 458 bool status_reported = false; |
474 if (!seek_cb_.is_null()) { | 459 if (!seek_cb_.is_null()) { |
475 base::ResetAndReturn(&seek_cb_).Run(status_); | 460 base::ResetAndReturn(&seek_cb_).Run(status_); |
476 error_cb_.Reset(); | 461 status_reported = true; |
477 } | 462 } |
478 if (!suspend_cb_.is_null()) { | 463 if (!suspend_cb_.is_null()) { |
479 base::ResetAndReturn(&suspend_cb_).Run(status_); | 464 base::ResetAndReturn(&suspend_cb_).Run(status_); |
480 error_cb_.Reset(); | 465 status_reported = true; |
481 } | 466 } |
482 if (!stop_cb_.is_null()) { | 467 if (!stop_cb_.is_null()) { |
483 error_cb_.Reset(); | |
484 | |
485 // Invalid all weak pointers so it's safe to destroy |this| on the render | 468 // Invalid all weak pointers so it's safe to destroy |this| on the render |
486 // main thread. | 469 // main thread. |
487 weak_factory_.InvalidateWeakPtrs(); | 470 weak_factory_.InvalidateWeakPtrs(); |
488 | 471 |
489 base::ResetAndReturn(&stop_cb_).Run(); | 472 base::ResetAndReturn(&stop_cb_).Run(); |
490 | 473 |
491 // NOTE: pipeline may be deleted at this point in time as a result of | 474 // NOTE: pipeline may be deleted at this point in time as a result of |
492 // executing |stop_cb_|. | 475 // executing |stop_cb_|. |
493 return; | 476 return; |
494 } | 477 } |
495 if (!error_cb_.is_null()) { | 478 if (!status_reported) { |
496 DCHECK_NE(status_, PIPELINE_OK); | 479 DCHECK_NE(status_, PIPELINE_OK); |
497 base::ResetAndReturn(&error_cb_).Run(status_); | 480 client_->OnError(status_); |
498 } | 481 } |
499 } | 482 } |
500 | 483 |
501 void PipelineImpl::OnBufferedTimeRangesChanged( | 484 void PipelineImpl::OnBufferedTimeRangesChanged( |
502 const Ranges<base::TimeDelta>& ranges) { | 485 const Ranges<base::TimeDelta>& ranges) { |
503 base::AutoLock auto_lock(lock_); | 486 base::AutoLock auto_lock(lock_); |
504 buffered_time_ranges_ = ranges; | 487 buffered_time_ranges_ = ranges; |
505 did_loading_progress_ = true; | 488 did_loading_progress_ = true; |
506 } | 489 } |
507 | 490 |
508 // Called from any thread. | 491 // Called from any thread. |
509 void PipelineImpl::OnUpdateStatistics(const PipelineStatistics& stats_delta) { | 492 void PipelineImpl::OnUpdateStatistics(const PipelineStatistics& stats_delta) { |
510 base::AutoLock auto_lock(lock_); | 493 base::AutoLock auto_lock(lock_); |
511 statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded; | 494 statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded; |
512 statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded; | 495 statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded; |
513 statistics_.video_frames_decoded += stats_delta.video_frames_decoded; | 496 statistics_.video_frames_decoded += stats_delta.video_frames_decoded; |
514 statistics_.video_frames_dropped += stats_delta.video_frames_dropped; | 497 statistics_.video_frames_dropped += stats_delta.video_frames_dropped; |
515 statistics_.audio_memory_usage += stats_delta.audio_memory_usage; | 498 statistics_.audio_memory_usage += stats_delta.audio_memory_usage; |
516 statistics_.video_memory_usage += stats_delta.video_memory_usage; | 499 statistics_.video_memory_usage += stats_delta.video_memory_usage; |
517 } | 500 } |
518 | 501 |
| 502 void PipelineImpl::OnWaitingForDecryptionKey() { |
| 503 client_->OnWaitingForDecryptionKey(); |
| 504 } |
| 505 |
519 void PipelineImpl::StartTask() { | 506 void PipelineImpl::StartTask() { |
520 DCHECK(task_runner_->BelongsToCurrentThread()); | 507 DCHECK(task_runner_->BelongsToCurrentThread()); |
521 | 508 |
522 CHECK_EQ(kCreated, state_) | 509 CHECK_EQ(kCreated, state_) |
523 << "Media pipeline cannot be started more than once"; | 510 << "Media pipeline cannot be started more than once"; |
524 | 511 |
525 text_renderer_ = CreateTextRenderer(); | 512 text_renderer_ = CreateTextRenderer(); |
526 if (text_renderer_) { | 513 if (text_renderer_) { |
527 text_renderer_->Initialize( | 514 text_renderer_->Initialize( |
528 base::Bind(&PipelineImpl::OnTextRendererEnded, weak_this_)); | 515 base::Bind(&PipelineImpl::OnTextRendererEnded, weak_this_)); |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
775 void PipelineImpl::RunEndedCallbackIfNeeded() { | 762 void PipelineImpl::RunEndedCallbackIfNeeded() { |
776 DCHECK(task_runner_->BelongsToCurrentThread()); | 763 DCHECK(task_runner_->BelongsToCurrentThread()); |
777 | 764 |
778 if (renderer_ && !renderer_ended_) | 765 if (renderer_ && !renderer_ended_) |
779 return; | 766 return; |
780 | 767 |
781 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) | 768 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) |
782 return; | 769 return; |
783 | 770 |
784 DCHECK_EQ(status_, PIPELINE_OK); | 771 DCHECK_EQ(status_, PIPELINE_OK); |
785 ended_cb_.Run(); | 772 client_->OnEnded(); |
786 } | 773 } |
787 | 774 |
788 scoped_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { | 775 scoped_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { |
789 DCHECK(task_runner_->BelongsToCurrentThread()); | 776 DCHECK(task_runner_->BelongsToCurrentThread()); |
790 | 777 |
791 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 778 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
792 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) | 779 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) |
793 return scoped_ptr<media::TextRenderer>(); | 780 return scoped_ptr<media::TextRenderer>(); |
794 | 781 |
795 return scoped_ptr<media::TextRenderer>(new media::TextRenderer( | 782 return scoped_ptr<media::TextRenderer>(new media::TextRenderer( |
(...skipping 11 matching lines...) Expand all Loading... |
807 | 794 |
808 void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) { | 795 void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) { |
809 DCHECK(task_runner_->BelongsToCurrentThread()); | 796 DCHECK(task_runner_->BelongsToCurrentThread()); |
810 if (text_renderer_) | 797 if (text_renderer_) |
811 text_renderer_->RemoveTextStream(text_stream); | 798 text_renderer_->RemoveTextStream(text_stream); |
812 } | 799 } |
813 | 800 |
814 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, | 801 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, |
815 const AddTextTrackDoneCB& done_cb) { | 802 const AddTextTrackDoneCB& done_cb) { |
816 DCHECK(task_runner_->BelongsToCurrentThread()); | 803 DCHECK(task_runner_->BelongsToCurrentThread()); |
817 add_text_track_cb_.Run(config, done_cb); | 804 client_->OnAddTextTrack(config, done_cb); |
818 } | 805 } |
819 | 806 |
820 void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) { | 807 void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) { |
821 DCHECK(task_runner_->BelongsToCurrentThread()); | 808 DCHECK(task_runner_->BelongsToCurrentThread()); |
822 demuxer_->Initialize(this, done_cb, !!text_renderer_); | 809 demuxer_->Initialize(this, done_cb, !!text_renderer_); |
823 } | 810 } |
824 | 811 |
825 void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) { | 812 void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) { |
826 DCHECK(task_runner_->BelongsToCurrentThread()); | 813 DCHECK(task_runner_->BelongsToCurrentThread()); |
827 | 814 |
828 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && | 815 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && |
829 !demuxer_->GetStream(DemuxerStream::VIDEO)) { | 816 !demuxer_->GetStream(DemuxerStream::VIDEO)) { |
830 { | 817 { |
831 base::AutoLock auto_lock(lock_); | 818 base::AutoLock auto_lock(lock_); |
832 renderer_.reset(); | 819 renderer_.reset(); |
833 } | 820 } |
834 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); | 821 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); |
835 return; | 822 return; |
836 } | 823 } |
837 | 824 |
838 if (cdm_context_) | 825 if (cdm_context_) |
839 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); | 826 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); |
840 | 827 |
841 renderer_->Initialize( | 828 renderer_->Initialize( |
842 demuxer_, done_cb, | 829 demuxer_, done_cb, |
843 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this_), | 830 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this_), |
844 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this_), | 831 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this_), |
845 base::Bind(&PipelineImpl::OnRendererEnded, weak_this_), | 832 base::Bind(&PipelineImpl::OnRendererEnded, weak_this_), |
846 base::Bind(&PipelineImpl::OnError, weak_this_), | 833 base::Bind(&PipelineImpl::OnError, weak_this_), |
847 waiting_for_decryption_key_cb_); | 834 base::Bind(&PipelineImpl::OnWaitingForDecryptionKey, weak_this_)); |
848 } | 835 } |
849 | 836 |
850 void PipelineImpl::ReportMetadata() { | 837 void PipelineImpl::ReportMetadata() { |
851 DCHECK(task_runner_->BelongsToCurrentThread()); | 838 DCHECK(task_runner_->BelongsToCurrentThread()); |
852 PipelineMetadata metadata; | 839 PipelineMetadata metadata; |
853 metadata.timeline_offset = demuxer_->GetTimelineOffset(); | 840 metadata.timeline_offset = demuxer_->GetTimelineOffset(); |
854 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); | 841 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
855 if (stream) { | 842 if (stream) { |
856 metadata.has_video = true; | 843 metadata.has_video = true; |
857 metadata.natural_size = stream->video_decoder_config().natural_size(); | 844 metadata.natural_size = stream->video_decoder_config().natural_size(); |
858 metadata.video_rotation = stream->video_rotation(); | 845 metadata.video_rotation = stream->video_rotation(); |
859 } | 846 } |
860 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { | 847 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { |
861 metadata.has_audio = true; | 848 metadata.has_audio = true; |
862 } | 849 } |
863 metadata_cb_.Run(metadata); | 850 client_->OnMetadata(metadata); |
864 } | 851 } |
865 | 852 |
866 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) { | 853 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) { |
867 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; | 854 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; |
868 DCHECK(task_runner_->BelongsToCurrentThread()); | 855 DCHECK(task_runner_->BelongsToCurrentThread()); |
869 buffering_state_cb_.Run(new_buffering_state); | 856 client_->OnBufferingStateChange(new_buffering_state); |
870 } | 857 } |
871 | 858 |
872 } // namespace media | 859 } // namespace media |
OLD | NEW |