diff options
author | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-03 05:23:19 +0000 |
---|---|---|
committer | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-03 05:23:19 +0000 |
commit | c5d8cb643fe8186dc3e34c799fd455d180545d17 (patch) | |
tree | bc4dceaf3e56d0e44c01a8788730b6af8a72313b | |
parent | 50f5c864605b67c717e66c1580da5e9eb79f2764 (diff) | |
download | chromium_src-c5d8cb643fe8186dc3e34c799fd455d180545d17.zip chromium_src-c5d8cb643fe8186dc3e34c799fd455d180545d17.tar.gz chromium_src-c5d8cb643fe8186dc3e34c799fd455d180545d17.tar.bz2 |
Merge 219225 "Run |demuxer_| related tasks in the media thread i..."
> Run |demuxer_| related tasks in the media thread in GTV.
>
> - We found that the reading from |demuxer_| and its read-callback loops run very slowly, in the heavy load situation in the render thread.
> to improve the response time of the readings, we run tasks related to |demuxer_| in the media thread.
>
> BUG=268208
>
> Review URL: https://chromiumcodereview.appspot.com/22875030
TBR=ycheo@chromium.org
Review URL: https://codereview.chromium.org/23757015
git-svn-id: svn://svn.chromium.org/chrome/branches/1599/src@220900 0039d316-1c4b-4281-b951-d872f2087c98
5 files changed, 276 insertions, 91 deletions
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc index 1193766..c13a498 100644 --- a/content/renderer/media/android/media_source_delegate.cc +++ b/content/renderer/media/android/media_source_delegate.cc @@ -37,35 +37,44 @@ const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff }; namespace content { -// TODO(xhwang): BIND_TO_RENDER_LOOP* force posts callback! Since everything -// works on the same thread in this class, not all force posts are necessary. - #define BIND_TO_RENDER_LOOP(function) \ - media::BindToLoop(base::MessageLoopProxy::current(), \ - base::Bind(function, weak_this_.GetWeakPtr())) + media::BindToLoop(main_loop_, \ + base::Bind(function, main_weak_this_.GetWeakPtr())) #define BIND_TO_RENDER_LOOP_1(function, arg1) \ - media::BindToLoop(base::MessageLoopProxy::current(), \ - base::Bind(function, weak_this_.GetWeakPtr(), arg1)) - -#define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \ - media::BindToLoop(base::MessageLoopProxy::current(), \ - base::Bind(function, weak_this_.GetWeakPtr(), arg1, arg2)) + media::BindToLoop(main_loop_, \ + base::Bind(function, main_weak_this_.GetWeakPtr(), arg1)) -#define BIND_TO_RENDER_LOOP_3(function, arg1, arg2, arg3) \ - media::BindToLoop(base::MessageLoopProxy::current(), \ - base::Bind(function, \ - weak_this_.GetWeakPtr(), arg1, arg2, arg3)) +#if defined(GOOGLE_TV) +#define DCHECK_BELONG_TO_MEDIA_LOOP() \ + DCHECK(media_loop_->BelongsToCurrentThread()) +#else +#define DCHECK_BELONG_TO_MEDIA_LOOP() \ + DCHECK(main_loop_->BelongsToCurrentThread()) +#endif static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log, const std::string& error) { media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); } -MediaSourceDelegate::MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy, - int player_id, - media::MediaLog* media_log) - : weak_this_(this), +MediaSourceDelegate::MediaSourceDelegate( + WebMediaPlayerProxyAndroid* proxy, + int player_id, + const scoped_refptr<base::MessageLoopProxy>& media_loop, + media::MediaLog* media_log) + : main_weak_this_(this), + media_weak_this_(this), + main_loop_(base::MessageLoopProxy::current()), +#if defined(GOOGLE_TV) + media_loop_(media_loop), + send_read_from_demuxer_ack_cb_( + BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendReadFromDemuxerAck)), + send_seek_request_ack_cb_( + BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendSeekRequestAck)), + send_demuxer_ready_cb_( + BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendDemuxerReady)), +#endif proxy_(proxy), player_id_(player_id), media_log_(media_log), @@ -80,6 +89,7 @@ MediaSourceDelegate::MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy, } MediaSourceDelegate::~MediaSourceDelegate() { + DCHECK(main_loop_->BelongsToCurrentThread()); DVLOG(1) << "~MediaSourceDelegate() : " << player_id_; DCHECK(!chunk_demuxer_); DCHECK(!demuxer_); @@ -90,6 +100,7 @@ MediaSourceDelegate::~MediaSourceDelegate() { } void MediaSourceDelegate::Destroy() { + DCHECK(main_loop_->BelongsToCurrentThread()); DVLOG(1) << "Destroy() : " << player_id_; if (!demuxer_) { delete this; @@ -101,7 +112,27 @@ void MediaSourceDelegate::Destroy() { media_source_.reset(); proxy_ = NULL; - demuxer_ = NULL; + main_weak_this_.InvalidateWeakPtrs(); + DCHECK(!main_weak_this_.HasWeakPtrs()); + + if (chunk_demuxer_) + chunk_demuxer_->Shutdown(); +#if defined(GOOGLE_TV) + // |this| will be transfered to the callback StopDemuxer() and + // OnDemuxerStopDone(). they own |this| and OnDemuxerStopDone() will delete + // it when called. Hence using base::Unretained(this) is safe here. + media_loop_->PostTask(FROM_HERE, + base::Bind(&MediaSourceDelegate::StopDemuxer, + base::Unretained(this))); +#else + StopDemuxer(); +#endif +} + +void MediaSourceDelegate::StopDemuxer() { + DCHECK_BELONG_TO_MEDIA_LOOP(); + DCHECK(demuxer_); + audio_stream_ = NULL; video_stream_ = NULL; // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or @@ -109,15 +140,14 @@ void MediaSourceDelegate::Destroy() { audio_decrypting_demuxer_stream_.reset(); video_decrypting_demuxer_stream_.reset(); - weak_this_.InvalidateWeakPtrs(); - DCHECK(!weak_this_.HasWeakPtrs()); + media_weak_this_.InvalidateWeakPtrs(); + DCHECK(!media_weak_this_.HasWeakPtrs()); - if (chunk_demuxer_) { - // The callback OnDemuxerStopDone() owns |this| and will delete it when - // called. Hence using base::Unretained(this) is safe here. - chunk_demuxer_->Stop(base::Bind(&MediaSourceDelegate::OnDemuxerStopDone, - base::Unretained(this))); - } + // The callback OnDemuxerStopDone() owns |this| and will delete it when + // called. Hence using base::Unretained(this) is safe here. + demuxer_->Stop(media::BindToLoop(main_loop_, + base::Bind(&MediaSourceDelegate::OnDemuxerStopDone, + base::Unretained(this)))); } void MediaSourceDelegate::InitializeMediaSource( @@ -126,12 +156,13 @@ void MediaSourceDelegate::InitializeMediaSource( const media::SetDecryptorReadyCB& set_decryptor_ready_cb, const UpdateNetworkStateCB& update_network_state_cb, const DurationChangeCB& duration_change_cb) { + DCHECK(main_loop_->BelongsToCurrentThread()); DCHECK(media_source); media_source_.reset(media_source); need_key_cb_ = need_key_cb; set_decryptor_ready_cb_ = set_decryptor_ready_cb; - update_network_state_cb_ = update_network_state_cb; - duration_change_cb_ = duration_change_cb; + update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); + duration_change_cb_ = media::BindToCurrentLoop(duration_change_cb); access_unit_size_ = kAccessUnitSizeForMediaSource; chunk_demuxer_.reset(new media::ChunkDemuxer( @@ -142,23 +173,40 @@ void MediaSourceDelegate::InitializeMediaSource( base::Bind(&LogMediaSourceError, media_log_))); demuxer_ = chunk_demuxer_.get(); - chunk_demuxer_->Initialize(this, - BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone)); +#if defined(GOOGLE_TV) + // |this| will be retained until StopDemuxer() is posted, so Unretained() is + // safe here. + media_loop_->PostTask(FROM_HERE, + base::Bind(&MediaSourceDelegate::InitializeDemuxer, + base::Unretained(this))); +#else + InitializeDemuxer(); +#endif +} + +void MediaSourceDelegate::InitializeDemuxer() { + DCHECK_BELONG_TO_MEDIA_LOOP(); + demuxer_->Initialize(this, base::Bind(&MediaSourceDelegate::OnDemuxerInitDone, + media_weak_this_.GetWeakPtr())); } #if defined(GOOGLE_TV) void MediaSourceDelegate::InitializeMediaStream( media::Demuxer* demuxer, const UpdateNetworkStateCB& update_network_state_cb) { + DCHECK(main_loop_->BelongsToCurrentThread()); DCHECK(demuxer); demuxer_ = demuxer; - update_network_state_cb_ = update_network_state_cb; + update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); // When playing Media Stream, don't wait to accumulate multiple packets per // IPC communication. access_unit_size_ = 1; - demuxer_->Initialize(this, - BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone)); + // |this| will be retained until StopDemuxer() is posted, so Unretained() is + // safe here. + media_loop_->PostTask(FROM_HERE, + base::Bind(&MediaSourceDelegate::InitializeDemuxer, + base::Unretained(this))); } #endif @@ -185,13 +233,14 @@ size_t MediaSourceDelegate::VideoDecodedByteCount() const { } void MediaSourceDelegate::Seek(base::TimeDelta time, unsigned seek_request_id) { + DCHECK(main_loop_->BelongsToCurrentThread()); DVLOG(1) << "Seek(" << time.InSecondsF() << ") : " << player_id_; last_seek_time_ = time; last_seek_request_id_ = seek_request_id; if (chunk_demuxer_) { - if (seeking_) { + if (IsSeeking()) { chunk_demuxer_->CancelPendingSeek(time); return; } @@ -199,10 +248,22 @@ void MediaSourceDelegate::Seek(base::TimeDelta time, unsigned seek_request_id) { chunk_demuxer_->StartWaitingForSeek(time); } - seeking_ = true; - demuxer_->Seek(time, - BIND_TO_RENDER_LOOP_1(&MediaSourceDelegate::OnDemuxerSeekDone, - seek_request_id)); + SetSeeking(true); +#if defined(GOOGLE_TV) + media_loop_->PostTask(FROM_HERE, + base::Bind(&MediaSourceDelegate::SeekInternal, + base::Unretained(this), + time, seek_request_id)); +#else + SeekInternal(time, seek_request_id); +#endif +} + +void MediaSourceDelegate::SeekInternal(base::TimeDelta time, + unsigned request_id) { + DCHECK_BELONG_TO_MEDIA_LOOP(); + demuxer_->Seek(time, base::Bind(&MediaSourceDelegate::OnDemuxerSeekDone, + media_weak_this_.GetWeakPtr(), request_id)); } void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) { @@ -220,45 +281,61 @@ void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start, void MediaSourceDelegate::SetDuration(base::TimeDelta duration) { DVLOG(1) << "SetDuration(" << duration.InSecondsF() << ") : " << player_id_; - // Notify our owner (e.g. WebMediaPlayerAndroid) that - // duration has changed. + // Notify our owner (e.g. WebMediaPlayerAndroid) that duration has changed. + // |duration_change_cb_| is bound to the main thread. if (!duration_change_cb_.is_null()) duration_change_cb_.Run(duration); } void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) { + DCHECK(main_loop_->BelongsToCurrentThread()); +#if defined(GOOGLE_TV) + media_loop_->PostTask( + FROM_HERE, + base::Bind(&MediaSourceDelegate::OnReadFromDemuxerInternal, + base::Unretained(this), type)); +#else + OnReadFromDemuxerInternal(type); +#endif +} + +void MediaSourceDelegate::OnReadFromDemuxerInternal( + media::DemuxerStream::Type type) { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "OnReadFromDemuxer(" << type << ") : " << player_id_; - if (seeking_) + if (IsSeeking()) return; // Drop the request during seeking. DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); // The access unit size should have been initialized properly at this stage. DCHECK_GT(access_unit_size_, 0u); - MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params = - type == DemuxerStream::AUDIO ? &audio_params_ : &video_params_; + scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params( + new MediaPlayerHostMsg_ReadFromDemuxerAck_Params()); params->type = type; params->access_units.resize(access_unit_size_); - ReadFromDemuxerStream(type, params, 0); + ReadFromDemuxerStream(type, params.Pass(), 0); } void MediaSourceDelegate::ReadFromDemuxerStream( media::DemuxerStream::Type type, - MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params, + scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params, size_t index) { - DCHECK(!seeking_); + DCHECK_BELONG_TO_MEDIA_LOOP(); // DemuxerStream::Read() always returns the read callback asynchronously. DemuxerStream* stream = (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_; - stream->Read(base::Bind(&MediaSourceDelegate::OnBufferReady, - weak_this_.GetWeakPtr(), type, params, index)); + stream->Read(base::Bind( + &MediaSourceDelegate::OnBufferReady, + media_weak_this_.GetWeakPtr(), type, base::Passed(¶ms), index)); } void MediaSourceDelegate::OnBufferReady( media::DemuxerStream::Type type, - MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params, + scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params, size_t index, DemuxerStream::Status status, const scoped_refptr<media::DecoderBuffer>& buffer) { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "OnBufferReady(" << index << ", " << status << ", " << ((!buffer || buffer->end_of_stream()) ? -1 : buffer->timestamp().InMilliseconds()) @@ -267,9 +344,8 @@ void MediaSourceDelegate::OnBufferReady( // No new OnReadFromDemuxer() will be called during seeking. So this callback // must be from previous OnReadFromDemuxer() call and should be ignored. - if (seeking_) { + if (IsSeeking()) { DVLOG(1) << "OnBufferReady(): Ignore previous read during seeking."; - params->access_units.clear(); return; } @@ -288,7 +364,6 @@ void MediaSourceDelegate::OnBufferReady( case DemuxerStream::kAborted: // Because the abort was caused by the seek, don't respond ack. DVLOG(1) << "OnBufferReady() : Aborted"; - params->access_units.clear(); return; case DemuxerStream::kConfigChanged: @@ -348,7 +423,7 @@ void MediaSourceDelegate::OnBufferReady( buffer->decrypt_config()->subsamples(); } if (++index < params->access_units.size()) { - ReadFromDemuxerStream(type, params, index); + ReadFromDemuxerStream(type, params.Pass(), index); return; } break; @@ -357,19 +432,29 @@ void MediaSourceDelegate::OnBufferReady( NOTREACHED(); } - if (proxy_) - proxy_->ReadFromDemuxerAck(player_id_, *params); +#if defined(GOOGLE_TV) + send_read_from_demuxer_ack_cb_.Run(params.Pass()); +#else + SendReadFromDemuxerAck(params.Pass()); +#endif +} - params->access_units.clear(); +void MediaSourceDelegate::SendReadFromDemuxerAck( + scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params) { + DCHECK(main_loop_->BelongsToCurrentThread()); + if (!IsSeeking() && proxy_) + proxy_->ReadFromDemuxerAck(player_id_, *params); } void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) { DVLOG(1) << "OnDemuxerError(" << status << ") : " << player_id_; + // |update_network_state_cb_| is bound to the main thread. if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); } void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "OnDemuxerInitDone(" << status << ") : " << player_id_; DCHECK(demuxer_); @@ -402,6 +487,7 @@ void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) { } void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "InitAudioDecryptingDemuxerStream() : " << player_id_; DCHECK(!set_decryptor_ready_cb_.is_null()); @@ -409,11 +495,12 @@ void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() { base::MessageLoopProxy::current(), set_decryptor_ready_cb_)); audio_decrypting_demuxer_stream_->Initialize( audio_stream_, - BIND_TO_RENDER_LOOP( - &MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone)); + base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone, + media_weak_this_.GetWeakPtr())); } void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "InitVideoDecryptingDemuxerStream() : " << player_id_; DCHECK(!set_decryptor_ready_cb_.is_null()); @@ -421,12 +508,13 @@ void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() { base::MessageLoopProxy::current(), set_decryptor_ready_cb_)); video_decrypting_demuxer_stream_->Initialize( video_stream_, - BIND_TO_RENDER_LOOP( - &MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone)); + base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone, + media_weak_this_.GetWeakPtr())); } void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone( media::PipelineStatus status) { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "OnAudioDecryptingDemuxerStreamInitDone(" << status << ") : " << player_id_; DCHECK(demuxer_); @@ -450,6 +538,7 @@ void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone( void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone( media::PipelineStatus status) { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "OnVideoDecryptingDemuxerStreamInitDone(" << status << ") : " << player_id_; DCHECK(demuxer_); @@ -467,8 +556,9 @@ void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone( void MediaSourceDelegate::OnDemuxerSeekDone(unsigned seek_request_id, media::PipelineStatus status) { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "OnDemuxerSeekDone(" << status << ") : " << player_id_; - DCHECK(seeking_); + DCHECK(IsSeeking()); if (status != media::PIPELINE_OK) { OnDemuxerError(status); @@ -479,10 +569,7 @@ void MediaSourceDelegate::OnDemuxerSeekDone(unsigned seek_request_id, if (seek_request_id != last_seek_request_id_) { if (chunk_demuxer_) chunk_demuxer_->StartWaitingForSeek(last_seek_time_); - demuxer_->Seek( - last_seek_time_, - BIND_TO_RENDER_LOOP_1(&MediaSourceDelegate::OnDemuxerSeekDone, - last_seek_request_id_)); + SeekInternal(last_seek_time_, last_seek_request_id_); return; } @@ -490,46 +577,73 @@ void MediaSourceDelegate::OnDemuxerSeekDone(unsigned seek_request_id, } void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "ResetAudioDecryptingDemuxerStream() : " << player_id_; if (audio_decrypting_demuxer_stream_) { audio_decrypting_demuxer_stream_->Reset( base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream, - weak_this_.GetWeakPtr())); + media_weak_this_.GetWeakPtr())); } else { ResetVideoDecryptingDemuxerStream(); } } void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "ResetVideoDecryptingDemuxerStream()"; +#if defined(GOOGLE_TV) + if (video_decrypting_demuxer_stream_) + video_decrypting_demuxer_stream_->Reset(send_seek_request_ack_cb_); + else + send_seek_request_ack_cb_.Run(); +#else if (video_decrypting_demuxer_stream_) { video_decrypting_demuxer_stream_->Reset( base::Bind(&MediaSourceDelegate::SendSeekRequestAck, - weak_this_.GetWeakPtr())); + main_weak_this_.GetWeakPtr())); } else { SendSeekRequestAck(); } +#endif } void MediaSourceDelegate::SendSeekRequestAck() { DVLOG(1) << "SendSeekRequestAck() : " << player_id_; - seeking_ = false; + SetSeeking(false); proxy_->SeekRequestAck(player_id_, last_seek_request_id_); last_seek_request_id_ = 0; } void MediaSourceDelegate::OnDemuxerStopDone() { + DCHECK(main_loop_->BelongsToCurrentThread()); DVLOG(1) << "OnDemuxerStopDone() : " << player_id_; chunk_demuxer_.reset(); + demuxer_ = NULL; delete this; } void MediaSourceDelegate::OnMediaConfigRequest() { +#if defined(GOOGLE_TV) + if (!media_loop_->BelongsToCurrentThread()) { + media_loop_->PostTask(FROM_HERE, + base::Bind(&MediaSourceDelegate::OnMediaConfigRequest, + base::Unretained(this))); + return; + } +#endif if (CanNotifyDemuxerReady()) NotifyDemuxerReady(); } void MediaSourceDelegate::NotifyKeyAdded(const std::string& key_system) { +#if defined(GOOGLE_TV) + if (!media_loop_->BelongsToCurrentThread()) { + media_loop_->PostTask(FROM_HERE, + base::Bind(&MediaSourceDelegate::NotifyKeyAdded, + base::Unretained(this), key_system)); + return; + } +#endif DVLOG(1) << "NotifyKeyAdded() : " << player_id_; // TODO(kjyoun): Enhance logic to detect when to call NotifyDemuxerReady() // For now, we calls it when the first key is added. See @@ -545,6 +659,7 @@ void MediaSourceDelegate::NotifyKeyAdded(const std::string& key_system) { } bool MediaSourceDelegate::CanNotifyDemuxerReady() { + DCHECK_BELONG_TO_MEDIA_LOOP(); // This can happen when a key is added before the demuxer is initialized. // See NotifyKeyAdded(). // TODO(kjyoun): Remove NotifyDemxuerReady() call from NotifyKeyAdded() so @@ -558,36 +673,49 @@ bool MediaSourceDelegate::CanNotifyDemuxerReady() { } void MediaSourceDelegate::NotifyDemuxerReady() { + DCHECK_BELONG_TO_MEDIA_LOOP(); DVLOG(1) << "NotifyDemuxerReady() : " << player_id_; DCHECK(CanNotifyDemuxerReady()); - MediaPlayerHostMsg_DemuxerReady_Params params; + scoped_ptr<MediaPlayerHostMsg_DemuxerReady_Params> params( + new MediaPlayerHostMsg_DemuxerReady_Params()); if (audio_stream_) { media::AudioDecoderConfig config = audio_stream_->audio_decoder_config(); - params.audio_codec = config.codec(); - params.audio_channels = + params->audio_codec = config.codec(); + params->audio_channels = media::ChannelLayoutToChannelCount(config.channel_layout()); - params.audio_sampling_rate = config.samples_per_second(); - params.is_audio_encrypted = config.is_encrypted(); - params.audio_extra_data = std::vector<uint8>( + params->audio_sampling_rate = config.samples_per_second(); + params->is_audio_encrypted = config.is_encrypted(); + params->audio_extra_data = std::vector<uint8>( config.extra_data(), config.extra_data() + config.extra_data_size()); } if (video_stream_) { media::VideoDecoderConfig config = video_stream_->video_decoder_config(); - params.video_codec = config.codec(); - params.video_size = config.natural_size(); - params.is_video_encrypted = config.is_encrypted(); - params.video_extra_data = std::vector<uint8>( + params->video_codec = config.codec(); + params->video_size = config.natural_size(); + params->is_video_encrypted = config.is_encrypted(); + params->video_extra_data = std::vector<uint8>( config.extra_data(), config.extra_data() + config.extra_data_size()); } - params.duration_ms = GetDurationMs(); - params.key_system = HasEncryptedStream() ? key_system_ : ""; + params->duration_ms = GetDurationMs(); + params->key_system = HasEncryptedStream() ? key_system_ : ""; +#if defined(GOOGLE_TV) + send_demuxer_ready_cb_.Run(params.Pass()); +#else + SendDemuxerReady(params.Pass()); +#endif +} + +void MediaSourceDelegate::SendDemuxerReady( + scoped_ptr<MediaPlayerHostMsg_DemuxerReady_Params> params) { + DCHECK(main_loop_->BelongsToCurrentThread()); if (proxy_) - proxy_->DemuxerReady(player_id_, params); + proxy_->DemuxerReady(player_id_, *params); } int MediaSourceDelegate::GetDurationMs() { + DCHECK_BELONG_TO_MEDIA_LOOP(); if (!chunk_demuxer_) return -1; @@ -601,6 +729,7 @@ int MediaSourceDelegate::GetDurationMs() { } void MediaSourceDelegate::OnDemuxerOpened() { + DCHECK(main_loop_->BelongsToCurrentThread()); if (!media_source_) return; @@ -612,6 +741,7 @@ void MediaSourceDelegate::OnNeedKey(const std::string& session_id, const std::string& type, scoped_ptr<uint8[]> init_data, int init_data_size) { + DCHECK(main_loop_->BelongsToCurrentThread()); if (need_key_cb_.is_null()) return; @@ -626,10 +756,21 @@ scoped_ptr<media::TextTrack> MediaSourceDelegate::OnAddTextTrack( } bool MediaSourceDelegate::HasEncryptedStream() { + DCHECK_BELONG_TO_MEDIA_LOOP(); return (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted()) || (video_stream_ && video_stream_->video_decoder_config().is_encrypted()); } +void MediaSourceDelegate::SetSeeking(bool seeking) { + base::AutoLock auto_lock(seeking_lock_); + seeking_ = seeking; +} + +bool MediaSourceDelegate::IsSeeking() const { + base::AutoLock auto_lock(seeking_lock_); + return seeking_; +} + } // namespace content diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h index 88b9b2d..1c358d5 100644 --- a/content/renderer/media/android/media_source_delegate.h +++ b/content/renderer/media/android/media_source_delegate.h @@ -9,8 +9,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" #include "base/time/time.h" -#include "media/base/android/demuxer_stream_player_params.h" #include "media/base/decryptor.h" #include "media/base/demuxer.h" #include "media/base/media_keys.h" @@ -25,6 +25,7 @@ class DecoderBuffer; class DecryptingDemuxerStream; class DemuxerStream; class MediaLog; +struct MediaPlayerHostMsg_DemuxerReady_Params; struct MediaPlayerHostMsg_ReadFromDemuxerAck_Params; } @@ -49,6 +50,7 @@ class MediaSourceDelegate : public media::DemuxerHost { MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy, int player_id, + const scoped_refptr<base::MessageLoopProxy>& media_loop, media::MediaLog* media_log); // Initialize the MediaSourceDelegate. |media_source| will be owned by @@ -89,6 +91,13 @@ class MediaSourceDelegate : public media::DemuxerHost { void Destroy(); private: + typedef base::Callback<void( + scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params)> + ReadFromDemuxerAckCB; + typedef base::Callback<void( + scoped_ptr<media::MediaPlayerHostMsg_DemuxerReady_Params> params)> + DemuxerReadyCB; + // This is private to enforce use of the Destroyer. virtual ~MediaSourceDelegate(); @@ -138,26 +147,54 @@ class MediaSourceDelegate : public media::DemuxerHost { const std::string& language); void NotifyDemuxerReady(); bool CanNotifyDemuxerReady(); + void SendDemuxerReady( + scoped_ptr<media::MediaPlayerHostMsg_DemuxerReady_Params> params); + void StopDemuxer(); + void InitializeDemuxer(); + void SeekInternal(base::TimeDelta time, unsigned seek_request_id); + void OnReadFromDemuxerInternal(media::DemuxerStream::Type type); // Reads an access unit from the demuxer stream |stream| and stores it in // the |index|th access unit in |params|. void ReadFromDemuxerStream( media::DemuxerStream::Type type, - media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params, + scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params, size_t index); void OnBufferReady( media::DemuxerStream::Type type, - media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params, + scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params, size_t index, media::DemuxerStream::Status status, const scoped_refptr<media::DecoderBuffer>& buffer); + void SendReadFromDemuxerAck( + scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params); + // Helper function for calculating duration. int GetDurationMs(); bool HasEncryptedStream(); - base::WeakPtrFactory<MediaSourceDelegate> weak_this_; + void SetSeeking(bool seeking); + bool IsSeeking() const; + + // Weak pointer must be dereferenced and invalidated on the same thread. + base::WeakPtrFactory<MediaSourceDelegate> main_weak_this_; + base::WeakPtrFactory<MediaSourceDelegate> media_weak_this_; + + // Message loop for main renderer thread. + const scoped_refptr<base::MessageLoopProxy> main_loop_; +#if defined(GOOGLE_TV) + // Message loop for the media thread. + // When there is high load in the render thread, the reading from |demuxer_| + // and its read-callback loops run very slowly. To improve the response time + // of the readings, we run tasks related to |demuxer_| in the media thread. + const scoped_refptr<base::MessageLoopProxy> media_loop_; + + ReadFromDemuxerAckCB send_read_from_demuxer_ack_cb_; + base::Closure send_seek_request_ack_cb_; + DemuxerReadyCB send_demuxer_ready_cb_; +#endif WebMediaPlayerProxyAndroid* proxy_; int player_id_; @@ -194,10 +231,10 @@ class MediaSourceDelegate : public media::DemuxerHost { // through GenerateKeyRequest() directly from WebKit. std::string init_data_type_; - media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params audio_params_; - media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params video_params_; - + // Lock used to serialize access for |seeking_|. + mutable base::Lock seeking_lock_; bool seeking_; + base::TimeDelta last_seek_time_; unsigned last_seek_request_id_; diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index 4c6b4aa..12e612f 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc @@ -65,12 +65,14 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid( RendererMediaPlayerManager* manager, WebMediaPlayerProxyAndroid* proxy, StreamTextureFactory* factory, + const scoped_refptr<base::MessageLoopProxy>& media_loop, media::MediaLog* media_log) : frame_(frame), client_(client), delegate_(delegate), buffered_(1u), main_loop_(base::MessageLoopProxy::current()), + media_loop_(media_loop), ignore_metadata_duration_change_(false), pending_seek_(0), seeking_(false), @@ -222,7 +224,7 @@ void WebMediaPlayerAndroid::load(const WebURL& url, if (source_type_ != MediaPlayerAndroid::SOURCE_TYPE_URL) { has_media_info_ = true; media_source_delegate_.reset( - new MediaSourceDelegate(proxy_, player_id_, media_log_)); + new MediaSourceDelegate(proxy_, player_id_, media_loop_, media_log_)); // |media_source_delegate_| is owned, so Unretained() is safe here. if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE) { media_source_delegate_->InitializeMediaSource( diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h index 1937536..6a5d24c 100644 --- a/content/renderer/media/android/webmediaplayer_android.h +++ b/content/renderer/media/android/webmediaplayer_android.h @@ -77,6 +77,7 @@ class WebMediaPlayerAndroid RendererMediaPlayerManager* manager, WebMediaPlayerProxyAndroid* proxy, StreamTextureFactory* factory, + const scoped_refptr<base::MessageLoopProxy>& media_loop, media::MediaLog* media_log); virtual ~WebMediaPlayerAndroid(); @@ -302,6 +303,9 @@ class WebMediaPlayerAndroid // Message loop for main renderer thread. const scoped_refptr<base::MessageLoopProxy> main_loop_; + // Message loop for media thread. + const scoped_refptr<base::MessageLoopProxy> media_loop_; + // URL of the media file to be fetched. GURL url_; diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 374b2b8..4cfea88 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -3038,6 +3038,7 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer( media_player_manager_.get(), media_player_proxy_, stream_texture_factory.release(), + RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy(), new RenderMediaLog())); #if defined(ENABLE_WEBRTC) && defined(GOOGLE_TV) if (media_stream_client_->IsMediaStream(url)) { |