| 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 "media/mojo/clients/mojo_renderer_impl.h" | 5 #include "media/mojo/clients/mojo_renderer_impl.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 video_overlay_factory_(std::move(video_overlay_factory)), | 27 video_overlay_factory_(std::move(video_overlay_factory)), |
| 28 video_renderer_sink_(video_renderer_sink), | 28 video_renderer_sink_(video_renderer_sink), |
| 29 remote_renderer_info_(remote_renderer.PassInterface()), | 29 remote_renderer_info_(remote_renderer.PassInterface()), |
| 30 binding_(this) { | 30 binding_(this) { |
| 31 DVLOG(1) << __FUNCTION__; | 31 DVLOG(1) << __FUNCTION__; |
| 32 } | 32 } |
| 33 | 33 |
| 34 MojoRendererImpl::~MojoRendererImpl() { | 34 MojoRendererImpl::~MojoRendererImpl() { |
| 35 DVLOG(1) << __FUNCTION__; | 35 DVLOG(1) << __FUNCTION__; |
| 36 DCHECK(task_runner_->BelongsToCurrentThread()); | 36 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 37 |
| 38 CancelPendingCallbacks(); |
| 37 } | 39 } |
| 38 | 40 |
| 39 void MojoRendererImpl::Initialize( | 41 void MojoRendererImpl::Initialize( |
| 40 DemuxerStreamProvider* demuxer_stream_provider, | 42 DemuxerStreamProvider* demuxer_stream_provider, |
| 41 media::RendererClient* client, | 43 media::RendererClient* client, |
| 42 const PipelineStatusCB& init_cb) { | 44 const PipelineStatusCB& init_cb) { |
| 43 DVLOG(1) << __FUNCTION__; | 45 DVLOG(1) << __FUNCTION__; |
| 44 DCHECK(task_runner_->BelongsToCurrentThread()); | 46 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 45 DCHECK(demuxer_stream_provider); | 47 DCHECK(demuxer_stream_provider); |
| 46 | 48 |
| 49 if (encountered_error_) { |
| 50 task_runner_->PostTask( |
| 51 FROM_HERE, base::Bind(init_cb, PIPELINE_ERROR_INITIALIZATION_FAILED)); |
| 52 return; |
| 53 } |
| 54 |
| 47 demuxer_stream_provider_ = demuxer_stream_provider; | 55 demuxer_stream_provider_ = demuxer_stream_provider; |
| 48 client_ = client; | |
| 49 init_cb_ = init_cb; | 56 init_cb_ = init_cb; |
| 50 | 57 |
| 51 // Create audio and video mojom::DemuxerStream and bind its lifetime to | 58 // Create audio and video mojom::DemuxerStream and bind its lifetime to |
| 52 // the pipe. | 59 // the pipe. |
| 53 DemuxerStream* const audio = | 60 DemuxerStream* const audio = |
| 54 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); | 61 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); |
| 55 DemuxerStream* const video = | 62 DemuxerStream* const video = |
| 56 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); | 63 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); |
| 57 | 64 |
| 58 mojom::DemuxerStreamPtr audio_stream; | 65 mojom::DemuxerStreamPtr audio_stream; |
| 59 if (audio) | 66 if (audio) |
| 60 new MojoDemuxerStreamImpl(audio, GetProxy(&audio_stream)); | 67 new MojoDemuxerStreamImpl(audio, GetProxy(&audio_stream)); |
| 61 | 68 |
| 62 mojom::DemuxerStreamPtr video_stream; | 69 mojom::DemuxerStreamPtr video_stream; |
| 63 if (video) | 70 if (video) |
| 64 new MojoDemuxerStreamImpl(video, GetProxy(&video_stream)); | 71 new MojoDemuxerStreamImpl(video, GetProxy(&video_stream)); |
| 65 | 72 |
| 66 BindRemoteRendererIfNeeded(); | 73 BindRemoteRendererIfNeeded(); |
| 67 | 74 |
| 68 // Using base::Unretained(this) is safe because |this| owns | 75 // Using base::Unretained(this) is safe because |this| owns |
| 69 // |remote_renderer_|, and the callback won't be dispatched if | 76 // |remote_renderer_|, and the callback won't be dispatched if |
| 70 // |remote_renderer_| is destroyed. | 77 // |remote_renderer_| is destroyed. |
| 71 remote_renderer_->Initialize( | 78 remote_renderer_->Initialize(binding_.CreateInterfacePtrAndBind(), |
| 72 binding_.CreateInterfacePtrAndBind(), std::move(audio_stream), | 79 std::move(audio_stream), std::move(video_stream), |
| 73 std::move(video_stream), | 80 base::Bind(&MojoRendererImpl::OnInitialized, |
| 74 base::Bind(&MojoRendererImpl::OnInitialized, base::Unretained(this))); | 81 base::Unretained(this), client)); |
| 75 } | 82 } |
| 76 | 83 |
| 77 void MojoRendererImpl::SetCdm(CdmContext* cdm_context, | 84 void MojoRendererImpl::SetCdm(CdmContext* cdm_context, |
| 78 const CdmAttachedCB& cdm_attached_cb) { | 85 const CdmAttachedCB& cdm_attached_cb) { |
| 79 DVLOG(1) << __FUNCTION__; | 86 DVLOG(1) << __FUNCTION__; |
| 80 DCHECK(task_runner_->BelongsToCurrentThread()); | 87 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 81 DCHECK(cdm_context); | 88 DCHECK(cdm_context); |
| 89 DCHECK(!cdm_attached_cb.is_null()); |
| 90 DCHECK(cdm_attached_cb_.is_null()); |
| 91 |
| 92 if (encountered_error_) { |
| 93 task_runner_->PostTask(FROM_HERE, base::Bind(cdm_attached_cb, false)); |
| 94 return; |
| 95 } |
| 82 | 96 |
| 83 int32_t cdm_id = cdm_context->GetCdmId(); | 97 int32_t cdm_id = cdm_context->GetCdmId(); |
| 84 if (cdm_id == CdmContext::kInvalidCdmId) { | 98 if (cdm_id == CdmContext::kInvalidCdmId) { |
| 85 DVLOG(2) << "MojoRendererImpl only works with remote CDMs but the CDM ID " | 99 DVLOG(2) << "MojoRendererImpl only works with remote CDMs but the CDM ID " |
| 86 "is invalid."; | 100 "is invalid."; |
| 87 cdm_attached_cb.Run(false); | 101 task_runner_->PostTask(FROM_HERE, base::Bind(cdm_attached_cb, false)); |
| 88 return; | 102 return; |
| 89 } | 103 } |
| 90 | 104 |
| 91 BindRemoteRendererIfNeeded(); | 105 BindRemoteRendererIfNeeded(); |
| 92 remote_renderer_->SetCdm(cdm_id, cdm_attached_cb); | 106 |
| 107 cdm_attached_cb_ = cdm_attached_cb; |
| 108 remote_renderer_->SetCdm(cdm_id, base::Bind(&MojoRendererImpl::OnCdmAttached, |
| 109 base::Unretained(this))); |
| 93 } | 110 } |
| 94 | 111 |
| 95 void MojoRendererImpl::Flush(const base::Closure& flush_cb) { | 112 void MojoRendererImpl::Flush(const base::Closure& flush_cb) { |
| 96 DVLOG(2) << __FUNCTION__; | 113 DVLOG(2) << __FUNCTION__; |
| 97 DCHECK(task_runner_->BelongsToCurrentThread()); | 114 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 98 DCHECK(remote_renderer_.is_bound()); | 115 DCHECK(remote_renderer_.is_bound()); |
| 99 remote_renderer_->Flush(flush_cb); | 116 DCHECK(!flush_cb.is_null()); |
| 117 DCHECK(flush_cb_.is_null()); |
| 118 |
| 119 if (encountered_error_) { |
| 120 task_runner_->PostTask(FROM_HERE, flush_cb); |
| 121 return; |
| 122 } |
| 123 |
| 124 flush_cb_ = flush_cb; |
| 125 remote_renderer_->Flush( |
| 126 base::Bind(&MojoRendererImpl::OnFlushed, base::Unretained(this))); |
| 100 } | 127 } |
| 101 | 128 |
| 102 void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time) { | 129 void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time) { |
| 103 DVLOG(2) << __FUNCTION__; | 130 DVLOG(2) << __FUNCTION__; |
| 104 DCHECK(task_runner_->BelongsToCurrentThread()); | 131 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 105 DCHECK(remote_renderer_.is_bound()); | 132 DCHECK(remote_renderer_.is_bound()); |
| 106 | 133 |
| 107 { | 134 { |
| 108 base::AutoLock auto_lock(lock_); | 135 base::AutoLock auto_lock(lock_); |
| 109 time_ = time; | 136 time_ = time; |
| 110 } | 137 } |
| 111 | 138 |
| 112 remote_renderer_->StartPlayingFrom(time.InMicroseconds()); | 139 remote_renderer_->StartPlayingFrom(time.InMicroseconds()); |
| 113 } | 140 } |
| 114 | 141 |
| 115 void MojoRendererImpl::SetPlaybackRate(double playback_rate) { | 142 void MojoRendererImpl::SetPlaybackRate(double playback_rate) { |
| 116 DVLOG(2) << __FUNCTION__; | 143 DVLOG(2) << __FUNCTION__; |
| 117 DCHECK(task_runner_->BelongsToCurrentThread()); | 144 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 118 DCHECK(remote_renderer_.is_bound()); | 145 DCHECK(remote_renderer_.is_bound()); |
| 146 |
| 119 remote_renderer_->SetPlaybackRate(playback_rate); | 147 remote_renderer_->SetPlaybackRate(playback_rate); |
| 120 } | 148 } |
| 121 | 149 |
| 122 void MojoRendererImpl::SetVolume(float volume) { | 150 void MojoRendererImpl::SetVolume(float volume) { |
| 123 DVLOG(2) << __FUNCTION__; | 151 DVLOG(2) << __FUNCTION__; |
| 124 DCHECK(task_runner_->BelongsToCurrentThread()); | 152 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 125 DCHECK(remote_renderer_.is_bound()); | 153 DCHECK(remote_renderer_.is_bound()); |
| 154 |
| 126 remote_renderer_->SetVolume(volume); | 155 remote_renderer_->SetVolume(volume); |
| 127 } | 156 } |
| 128 | 157 |
| 129 base::TimeDelta MojoRendererImpl::GetMediaTime() { | 158 base::TimeDelta MojoRendererImpl::GetMediaTime() { |
| 130 base::AutoLock auto_lock(lock_); | 159 base::AutoLock auto_lock(lock_); |
| 131 DVLOG(3) << __FUNCTION__ << ": " << time_.InMilliseconds() << " ms"; | 160 DVLOG(3) << __FUNCTION__ << ": " << time_.InMilliseconds() << " ms"; |
| 132 return time_; | 161 return time_; |
| 133 } | 162 } |
| 134 | 163 |
| 135 bool MojoRendererImpl::HasAudio() { | 164 bool MojoRendererImpl::HasAudio() { |
| 136 DVLOG(1) << __FUNCTION__; | 165 DVLOG(1) << __FUNCTION__; |
| 137 DCHECK(task_runner_->BelongsToCurrentThread()); | 166 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 138 DCHECK(remote_renderer_.get()); // We always bind the renderer. | 167 DCHECK(remote_renderer_.is_bound()); |
| 168 |
| 139 return !!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); | 169 return !!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); |
| 140 } | 170 } |
| 141 | 171 |
| 142 bool MojoRendererImpl::HasVideo() { | 172 bool MojoRendererImpl::HasVideo() { |
| 143 DVLOG(1) << __FUNCTION__; | 173 DVLOG(1) << __FUNCTION__; |
| 144 DCHECK(task_runner_->BelongsToCurrentThread()); | 174 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 175 DCHECK(remote_renderer_.is_bound()); |
| 176 |
| 145 return !!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); | 177 return !!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); |
| 146 } | 178 } |
| 147 | 179 |
| 148 void MojoRendererImpl::OnTimeUpdate(int64_t time_usec, int64_t max_time_usec) { | 180 void MojoRendererImpl::OnTimeUpdate(int64_t time_usec, int64_t max_time_usec) { |
| 149 DVLOG(3) << __FUNCTION__ << ": " << time_usec << ", " << max_time_usec; | 181 DVLOG(3) << __FUNCTION__ << ": " << time_usec << ", " << max_time_usec; |
| 150 DCHECK(task_runner_->BelongsToCurrentThread()); | 182 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 151 | 183 |
| 152 base::AutoLock auto_lock(lock_); | 184 base::AutoLock auto_lock(lock_); |
| 153 time_ = base::TimeDelta::FromMicroseconds(time_usec); | 185 time_ = base::TimeDelta::FromMicroseconds(time_usec); |
| 154 } | 186 } |
| 155 | 187 |
| 156 void MojoRendererImpl::OnBufferingStateChange(mojom::BufferingState state) { | 188 void MojoRendererImpl::OnBufferingStateChange(mojom::BufferingState state) { |
| 157 DVLOG(2) << __FUNCTION__; | 189 DVLOG(2) << __FUNCTION__; |
| 158 DCHECK(task_runner_->BelongsToCurrentThread()); | 190 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 159 client_->OnBufferingStateChange(static_cast<media::BufferingState>(state)); | 191 client_->OnBufferingStateChange(static_cast<media::BufferingState>(state)); |
| 160 } | 192 } |
| 161 | 193 |
| 162 void MojoRendererImpl::OnEnded() { | 194 void MojoRendererImpl::OnEnded() { |
| 163 DVLOG(1) << __FUNCTION__; | 195 DVLOG(1) << __FUNCTION__; |
| 164 DCHECK(task_runner_->BelongsToCurrentThread()); | 196 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 165 client_->OnEnded(); | 197 client_->OnEnded(); |
| 166 } | 198 } |
| 167 | 199 |
| 168 void MojoRendererImpl::OnError() { | 200 void MojoRendererImpl::OnError() { |
| 169 DVLOG(1) << __FUNCTION__; | 201 DVLOG(1) << __FUNCTION__; |
| 170 DCHECK(task_runner_->BelongsToCurrentThread()); | 202 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 171 DCHECK(init_cb_.is_null()); | 203 DCHECK(init_cb_.is_null()); |
| 172 | 204 |
| 205 encountered_error_ = true; |
| 206 |
| 173 // TODO(tim): Should we plumb error code from remote renderer? | 207 // TODO(tim): Should we plumb error code from remote renderer? |
| 174 // http://crbug.com/410451. | 208 // http://crbug.com/410451. |
| 175 client_->OnError(PIPELINE_ERROR_DECODE); | 209 client_->OnError(PIPELINE_ERROR_DECODE); |
| 176 } | 210 } |
| 177 | 211 |
| 178 void MojoRendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { | 212 void MojoRendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { |
| 179 DVLOG(2) << __FUNCTION__ << ": " << size.ToString(); | 213 DVLOG(2) << __FUNCTION__ << ": " << size.ToString(); |
| 180 DCHECK(task_runner_->BelongsToCurrentThread()); | 214 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 181 | 215 |
| 182 video_renderer_sink_->PaintSingleFrame( | 216 video_renderer_sink_->PaintSingleFrame( |
| 183 video_overlay_factory_->CreateFrame(size)); | 217 video_overlay_factory_->CreateFrame(size)); |
| 184 client_->OnVideoNaturalSizeChange(size); | 218 client_->OnVideoNaturalSizeChange(size); |
| 185 } | 219 } |
| 186 | 220 |
| 187 void MojoRendererImpl::OnVideoOpacityChange(bool opaque) { | 221 void MojoRendererImpl::OnVideoOpacityChange(bool opaque) { |
| 188 DVLOG(2) << __FUNCTION__ << ": " << opaque; | 222 DVLOG(2) << __FUNCTION__ << ": " << opaque; |
| 189 DCHECK(task_runner_->BelongsToCurrentThread()); | 223 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 190 client_->OnVideoOpacityChange(opaque); | 224 client_->OnVideoOpacityChange(opaque); |
| 191 } | 225 } |
| 192 | 226 |
| 193 void MojoRendererImpl::OnConnectionError() { | 227 void MojoRendererImpl::OnConnectionError() { |
| 194 DVLOG(1) << __FUNCTION__; | 228 DVLOG(1) << __FUNCTION__; |
| 195 DCHECK(task_runner_->BelongsToCurrentThread()); | 229 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 196 | 230 |
| 197 if (!init_cb_.is_null()) { | 231 encountered_error_ = true; |
| 198 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | 232 CancelPendingCallbacks(); |
| 199 return; | |
| 200 } | |
| 201 | 233 |
| 202 client_->OnError(PIPELINE_ERROR_DECODE); | 234 if (client_) |
| 235 client_->OnError(PIPELINE_ERROR_DECODE); |
| 203 } | 236 } |
| 204 | 237 |
| 205 void MojoRendererImpl::BindRemoteRendererIfNeeded() { | 238 void MojoRendererImpl::BindRemoteRendererIfNeeded() { |
| 206 DVLOG(2) << __FUNCTION__; | 239 DVLOG(2) << __FUNCTION__; |
| 207 DCHECK(task_runner_->BelongsToCurrentThread()); | 240 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 208 | 241 |
| 209 // If |remote_renderer_| has already been bound, do nothing. | 242 // If |remote_renderer_| has already been bound, do nothing. |
| 243 // Note that after Bind() is called, |remote_renderer_| is always bound even |
| 244 // after connection error. |
| 210 if (remote_renderer_.is_bound()) | 245 if (remote_renderer_.is_bound()) |
| 211 return; | 246 return; |
| 212 | 247 |
| 213 // Bind |remote_renderer_| to the |task_runner_|. | 248 // Bind |remote_renderer_| to the |task_runner_|. |
| 214 remote_renderer_.Bind(std::move(remote_renderer_info_)); | 249 remote_renderer_.Bind(std::move(remote_renderer_info_)); |
| 215 | 250 |
| 216 // Otherwise, set an error handler to catch the connection error. | 251 // Otherwise, set an error handler to catch the connection error. |
| 217 // Using base::Unretained(this) is safe because |this| owns | 252 // Using base::Unretained(this) is safe because |this| owns |
| 218 // |remote_renderer_|, and the error handler can't be invoked once | 253 // |remote_renderer_|, and the error handler can't be invoked once |
| 219 // |remote_renderer_| is destroyed. | 254 // |remote_renderer_| is destroyed. |
| 220 remote_renderer_.set_connection_error_handler( | 255 remote_renderer_.set_connection_error_handler( |
| 221 base::Bind(&MojoRendererImpl::OnConnectionError, base::Unretained(this))); | 256 base::Bind(&MojoRendererImpl::OnConnectionError, base::Unretained(this))); |
| 222 } | 257 } |
| 223 | 258 |
| 224 void MojoRendererImpl::OnInitialized(bool success) { | 259 void MojoRendererImpl::OnInitialized(media::RendererClient* client, |
| 260 bool success) { |
| 225 DVLOG(1) << __FUNCTION__; | 261 DVLOG(1) << __FUNCTION__; |
| 226 DCHECK(task_runner_->BelongsToCurrentThread()); | 262 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 227 DCHECK(!init_cb_.is_null()); | 263 DCHECK(!init_cb_.is_null()); |
| 228 | 264 |
| 265 // Only set |client_| after initialization succeeded. No client methods should |
| 266 // be called before this. |
| 267 if (success) |
| 268 client_ = client; |
| 269 |
| 229 base::ResetAndReturn(&init_cb_).Run( | 270 base::ResetAndReturn(&init_cb_).Run( |
| 230 success ? PIPELINE_OK : PIPELINE_ERROR_INITIALIZATION_FAILED); | 271 success ? PIPELINE_OK : PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 231 } | 272 } |
| 232 | 273 |
| 274 void MojoRendererImpl::OnFlushed() { |
| 275 DVLOG(1) << __FUNCTION__; |
| 276 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 277 DCHECK(!flush_cb_.is_null()); |
| 278 |
| 279 base::ResetAndReturn(&flush_cb_).Run(); |
| 280 } |
| 281 |
| 282 void MojoRendererImpl::OnCdmAttached(bool success) { |
| 283 DVLOG(1) << __FUNCTION__; |
| 284 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 285 DCHECK(!cdm_attached_cb_.is_null()); |
| 286 |
| 287 base::ResetAndReturn(&cdm_attached_cb_).Run(success); |
| 288 } |
| 289 |
| 290 void MojoRendererImpl::CancelPendingCallbacks() { |
| 291 DVLOG(1) << __FUNCTION__; |
| 292 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 293 |
| 294 if (!init_cb_.is_null()) |
| 295 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 296 |
| 297 if (!flush_cb_.is_null()) |
| 298 base::ResetAndReturn(&flush_cb_).Run(); |
| 299 |
| 300 if (!cdm_attached_cb_.is_null()) |
| 301 base::ResetAndReturn(&cdm_attached_cb_).Run(false); |
| 302 } |
| 303 |
| 233 } // namespace media | 304 } // namespace media |
| OLD | NEW |