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 FireAllPendingCallbacks(); | |
sandersd (OOO until July 31)
2016/06/16 18:10:06
Why does the destructor need to call this?
xhwang
2016/06/17 06:59:00
The Renderer API says all pending callbacks should
| |
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 FireAllPendingCallbacks(); |
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::FireAllPendingCallbacks() { | |
sandersd (OOO until July 31)
2016/06/16 18:10:06
This name should probably indicate that the callba
xhwang
2016/06/17 06:59:00
Done.
| |
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 |