OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "media/base/android/media_codec_player.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/barrier_closure.h" | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/lazy_instance.h" | |
13 #include "base/logging.h" | |
14 #include "base/threading/thread.h" | |
15 #include "base/threading/thread_task_runner_handle.h" | |
16 #include "media/base/android/audio_media_codec_decoder.h" | |
17 #include "media/base/android/media_drm_bridge.h" | |
18 #include "media/base/android/media_player_manager.h" | |
19 #include "media/base/android/media_task_runner.h" | |
20 #include "media/base/android/video_media_codec_decoder.h" | |
21 #include "media/base/bind_to_current_loop.h" | |
22 #include "media/base/timestamp_constants.h" | |
23 | |
24 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \ | |
25 do { \ | |
26 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \ | |
27 DCHECK(ui_task_runner_->BelongsToCurrentThread()); \ | |
28 GetMediaTaskRunner()->PostTask( \ | |
29 FROM_HERE, base::Bind(&MediaCodecPlayer::METHOD, media_weak_this_, \ | |
30 ##__VA_ARGS__)); \ | |
31 return; \ | |
32 } \ | |
33 } while (0) | |
34 | |
35 namespace media { | |
36 | |
37 // MediaCodecPlayer implementation. | |
38 | |
39 MediaCodecPlayer::MediaCodecPlayer( | |
40 int player_id, | |
41 base::WeakPtr<MediaPlayerManager> manager, | |
42 const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb, | |
43 std::unique_ptr<DemuxerAndroid> demuxer, | |
44 const GURL& frame_url, | |
45 int media_session_id) | |
46 : MediaPlayerAndroid(player_id, | |
47 manager.get(), | |
48 on_decoder_resources_released_cb, | |
49 frame_url, | |
50 media_session_id), | |
51 ui_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
52 demuxer_(std::move(demuxer)), | |
53 state_(kStatePaused), | |
54 interpolator_(&default_tick_clock_), | |
55 pending_start_(false), | |
56 pending_seek_(kNoTimestamp), | |
57 cdm_registration_id_(0), | |
58 key_is_required_(false), | |
59 key_is_added_(false), | |
60 media_weak_factory_(this) { | |
61 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
62 | |
63 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id; | |
64 | |
65 completion_cb_ = | |
66 base::Bind(&MediaPlayerManager::OnPlaybackComplete, manager, player_id); | |
67 waiting_for_decryption_key_cb_ = base::Bind( | |
68 &MediaPlayerManager::OnWaitingForDecryptionKey, manager, player_id); | |
69 seek_done_cb_ = | |
70 base::Bind(&MediaPlayerManager::OnSeekComplete, manager, player_id); | |
71 error_cb_ = base::Bind(&MediaPlayerManager::OnError, manager, player_id); | |
72 | |
73 attach_listener_cb_ = base::Bind(&MediaPlayerAndroid::AttachListener, | |
74 WeakPtrForUIThread(), nullptr); | |
75 detach_listener_cb_ = | |
76 base::Bind(&MediaPlayerAndroid::DetachListener, WeakPtrForUIThread()); | |
77 metadata_changed_cb_ = base::Bind(&MediaPlayerAndroid::OnMediaMetadataChanged, | |
78 WeakPtrForUIThread()); | |
79 time_update_cb_ = | |
80 base::Bind(&MediaPlayerAndroid::OnTimeUpdate, WeakPtrForUIThread()); | |
81 | |
82 media_weak_this_ = media_weak_factory_.GetWeakPtr(); | |
83 | |
84 // Finish initializaton on Media thread | |
85 GetMediaTaskRunner()->PostTask( | |
86 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, media_weak_this_)); | |
87 } | |
88 | |
89 MediaCodecPlayer::~MediaCodecPlayer() | |
90 { | |
91 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer"; | |
92 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
93 | |
94 media_stat_->StopAndReport(GetInterpolatedTime()); | |
95 | |
96 // Currently the unit tests wait for the MediaCodecPlayer destruction by | |
97 // watching the demuxer, which is destroyed as one of the member variables. | |
98 // Release the codecs here, before any member variable is destroyed to make | |
99 // the unit tests happy. | |
100 | |
101 if (video_decoder_) | |
102 video_decoder_->ReleaseDecoderResources(); | |
103 if (audio_decoder_) | |
104 audio_decoder_->ReleaseDecoderResources(); | |
105 | |
106 if (cdm_) { | |
107 // Cancel previously registered callback (if any). | |
108 static_cast<MediaDrmBridge*>(cdm_.get()) | |
109 ->SetMediaCryptoReadyCB(MediaDrmBridge::MediaCryptoReadyCB()); | |
110 | |
111 DCHECK(cdm_registration_id_); | |
112 static_cast<MediaDrmBridge*>(cdm_.get()) | |
113 ->UnregisterPlayer(cdm_registration_id_); | |
114 } | |
115 } | |
116 | |
117 void MediaCodecPlayer::Initialize() { | |
118 DVLOG(1) << __FUNCTION__; | |
119 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
120 | |
121 interpolator_.SetUpperBound(base::TimeDelta()); | |
122 | |
123 CreateDecoders(); | |
124 | |
125 // This call might in turn call MediaCodecPlayer::OnDemuxerConfigsAvailable() | |
126 // which propagates configs into decoders. Therefore CreateDecoders() should | |
127 // be called first. | |
128 demuxer_->Initialize(this); | |
129 } | |
130 | |
131 // The implementation of MediaPlayerAndroid interface. | |
132 | |
133 void MediaCodecPlayer::DeleteOnCorrectThread() { | |
134 DVLOG(1) << __FUNCTION__; | |
135 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
136 | |
137 DetachListener(); | |
138 | |
139 // The base class part that deals with MediaPlayerListener | |
140 // has to be destroyed on UI thread. | |
141 DestroyListenerOnUIThread(); | |
142 | |
143 // Post deletion onto Media thread | |
144 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this); | |
145 } | |
146 | |
147 void MediaCodecPlayer::SetVideoSurface(gl::ScopedJavaSurface surface) { | |
148 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface)); | |
149 | |
150 DVLOG(1) << __FUNCTION__ << (surface.IsEmpty() ? " empty" : " non-empty"); | |
151 | |
152 // Save the empty-ness before we pass the surface to the decoder. | |
153 bool surface_is_empty = surface.IsEmpty(); | |
154 | |
155 // Apparently RemoveVideoSurface() can be called several times in a row, | |
156 // ignore the second and subsequent calls. | |
157 if (surface_is_empty && !video_decoder_->HasVideoSurface()) { | |
158 DVLOG(1) << __FUNCTION__ << ": surface already removed, ignoring"; | |
159 return; | |
160 } | |
161 | |
162 // Do not set unprotected surface if we know that we need a protected one. | |
163 // Empty surface means the surface removal and we always allow for it. | |
164 if (!surface_is_empty && video_decoder_->IsProtectedSurfaceRequired() && | |
165 !surface.is_protected()) { | |
166 DVLOG(0) << __FUNCTION__ << ": surface is not protected, ignoring"; | |
167 return; | |
168 } | |
169 | |
170 video_decoder_->SetVideoSurface(std::move(surface)); | |
171 | |
172 if (surface_is_empty) { | |
173 // Remove video surface. | |
174 switch (state_) { | |
175 case kStatePlaying: | |
176 if (VideoFinished()) | |
177 break; | |
178 | |
179 DVLOG(1) << __FUNCTION__ << ": stopping and restarting"; | |
180 // Stop decoders as quickly as possible. | |
181 StopDecoders(); // synchronous stop | |
182 | |
183 // Prefetch or wait for initial configuration. | |
184 if (HasAudio() || HasVideo()) { | |
185 SetState(kStatePrefetching); | |
186 StartPrefetchDecoders(); | |
187 } else { | |
188 SetState(kStateWaitingForConfig); | |
189 } | |
190 break; | |
191 | |
192 default: | |
193 break; // ignore | |
194 } | |
195 } else { | |
196 // Replace video surface. | |
197 switch (state_) { | |
198 case kStateWaitingForSurface: | |
199 SetState(kStatePlaying); | |
200 StartPlaybackOrBrowserSeek(); | |
201 break; | |
202 | |
203 case kStatePlaying: | |
204 if (VideoFinished()) | |
205 break; | |
206 | |
207 DVLOG(1) << __FUNCTION__ << ": requesting to stop and restart"; | |
208 SetState(kStateStopping); | |
209 RequestToStopDecoders(); | |
210 SetPendingStart(true); | |
211 break; | |
212 | |
213 default: | |
214 break; // ignore | |
215 } | |
216 } | |
217 } | |
218 | |
219 void MediaCodecPlayer::Start() { | |
220 RUN_ON_MEDIA_THREAD(Start); | |
221 | |
222 DVLOG(1) << __FUNCTION__; | |
223 | |
224 switch (state_) { | |
225 case kStatePaused: | |
226 // Request play permission or wait for initial configuration. | |
227 if (HasAudio() || HasVideo()) { | |
228 SetState(kStateWaitingForPermission); | |
229 RequestPlayPermission(); | |
230 } else { | |
231 SetState(kStateWaitingForConfig); | |
232 } | |
233 break; | |
234 case kStateStopping: | |
235 case kStateWaitingForSeek: | |
236 SetPendingStart(true); | |
237 break; | |
238 case kStateWaitingForConfig: | |
239 case kStateWaitingForPermission: | |
240 case kStatePrefetching: | |
241 case kStatePlaying: | |
242 case kStateWaitingForSurface: | |
243 case kStateWaitingForKey: | |
244 case kStateWaitingForMediaCrypto: | |
245 case kStateError: | |
246 break; // Ignore | |
247 default: | |
248 NOTREACHED(); | |
249 break; | |
250 } | |
251 } | |
252 | |
253 void MediaCodecPlayer::Pause(bool is_media_related_action) { | |
254 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action); | |
255 | |
256 DVLOG(1) << __FUNCTION__; | |
257 | |
258 media_stat_->StopAndReport(GetInterpolatedTime()); | |
259 | |
260 SetPendingStart(false); | |
261 | |
262 switch (state_) { | |
263 case kStateWaitingForConfig: | |
264 case kStateWaitingForPermission: | |
265 case kStatePrefetching: | |
266 case kStateWaitingForSurface: | |
267 case kStateWaitingForKey: | |
268 case kStateWaitingForMediaCrypto: | |
269 SetState(kStatePaused); | |
270 StopDecoders(); | |
271 break; | |
272 case kStatePlaying: | |
273 SetState(kStateStopping); | |
274 RequestToStopDecoders(); | |
275 break; | |
276 case kStatePaused: | |
277 case kStateStopping: | |
278 case kStateWaitingForSeek: | |
279 case kStateError: | |
280 break; // Ignore | |
281 default: | |
282 NOTREACHED(); | |
283 break; | |
284 } | |
285 } | |
286 | |
287 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) { | |
288 RUN_ON_MEDIA_THREAD(SeekTo, timestamp); | |
289 | |
290 DVLOG(1) << __FUNCTION__ << " " << timestamp; | |
291 | |
292 media_stat_->StopAndReport(GetInterpolatedTime()); | |
293 | |
294 switch (state_) { | |
295 case kStatePaused: | |
296 SetState(kStateWaitingForSeek); | |
297 RequestDemuxerSeek(timestamp); | |
298 break; | |
299 case kStateWaitingForConfig: | |
300 case kStateWaitingForPermission: | |
301 case kStatePrefetching: | |
302 case kStateWaitingForSurface: | |
303 case kStateWaitingForKey: | |
304 case kStateWaitingForMediaCrypto: | |
305 SetState(kStateWaitingForSeek); | |
306 StopDecoders(); | |
307 SetPendingStart(true); | |
308 RequestDemuxerSeek(timestamp); | |
309 break; | |
310 case kStatePlaying: | |
311 SetState(kStateStopping); | |
312 RequestToStopDecoders(); | |
313 SetPendingStart(true); | |
314 SetPendingSeek(timestamp); | |
315 break; | |
316 case kStateStopping: | |
317 SetPendingSeek(timestamp); | |
318 break; | |
319 case kStateWaitingForSeek: | |
320 SetPendingSeek(timestamp); | |
321 break; | |
322 case kStateError: | |
323 break; // ignore | |
324 default: | |
325 NOTREACHED(); | |
326 break; | |
327 } | |
328 } | |
329 | |
330 void MediaCodecPlayer::Release() { | |
331 // TODO(qinmin): the callback should be posted onto the UI thread when | |
332 // Release() finishes on media thread. However, the BrowserMediaPlayerManager | |
333 // could be gone in that case, which cause the MediaThrottler unable to | |
334 // track the active players. We should pass | |
335 // MediaThrottler::OnDecodeRequestFinished() to this class in the ctor, but | |
336 // also need a way for BrowserMediaPlayerManager to track active players. | |
337 if (ui_task_runner_->BelongsToCurrentThread()) | |
338 on_decoder_resources_released_cb_.Run(player_id()); | |
339 | |
340 RUN_ON_MEDIA_THREAD(Release); | |
341 | |
342 DVLOG(1) << __FUNCTION__; | |
343 | |
344 media_stat_->StopAndReport(GetInterpolatedTime()); | |
345 | |
346 // Stop decoding threads and delete MediaCodecs, but keep IPC between browser | |
347 // and renderer processes going. Seek should work across and after Release(). | |
348 | |
349 ReleaseDecoderResources(); | |
350 | |
351 SetPendingStart(false); | |
352 | |
353 if (state_ != kStateWaitingForSeek) | |
354 SetState(kStatePaused); | |
355 | |
356 // Crear encryption key related flags. | |
357 key_is_required_ = false; | |
358 key_is_added_ = false; | |
359 | |
360 base::TimeDelta pending_seek_time = GetPendingSeek(); | |
361 if (pending_seek_time != kNoTimestamp) { | |
362 SetPendingSeek(kNoTimestamp); | |
363 SetState(kStateWaitingForSeek); | |
364 RequestDemuxerSeek(pending_seek_time); | |
365 } | |
366 } | |
367 | |
368 void MediaCodecPlayer::UpdateEffectiveVolumeInternal(double effective_volume) { | |
369 RUN_ON_MEDIA_THREAD(UpdateEffectiveVolumeInternal, effective_volume); | |
370 | |
371 DVLOG(1) << __FUNCTION__ << " " << effective_volume; | |
372 audio_decoder_->SetVolume(effective_volume); | |
373 } | |
374 | |
375 bool MediaCodecPlayer::HasAudio() const { | |
376 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
377 return audio_decoder_->HasStream(); | |
378 } | |
379 | |
380 bool MediaCodecPlayer::HasVideo() const { | |
381 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
382 return video_decoder_->HasStream(); | |
383 } | |
384 | |
385 int MediaCodecPlayer::GetVideoWidth() { | |
386 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
387 return metadata_cache_.video_size.width(); | |
388 } | |
389 | |
390 int MediaCodecPlayer::GetVideoHeight() { | |
391 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
392 return metadata_cache_.video_size.height(); | |
393 } | |
394 | |
395 base::TimeDelta MediaCodecPlayer::GetCurrentTime() { | |
396 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
397 return current_time_cache_; | |
398 } | |
399 | |
400 base::TimeDelta MediaCodecPlayer::GetDuration() { | |
401 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
402 return metadata_cache_.duration; | |
403 } | |
404 | |
405 bool MediaCodecPlayer::IsPlaying() { | |
406 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
407 | |
408 // TODO(timav): Use another variable since |state_| should only be accessed on | |
409 // Media thread. | |
410 return state_ == kStatePlaying || state_ == kStateStopping; | |
411 } | |
412 | |
413 bool MediaCodecPlayer::CanPause() { | |
414 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
415 NOTIMPLEMENTED(); | |
416 return false; | |
417 } | |
418 | |
419 bool MediaCodecPlayer::CanSeekForward() { | |
420 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
421 NOTIMPLEMENTED(); | |
422 return false; | |
423 } | |
424 | |
425 bool MediaCodecPlayer::CanSeekBackward() { | |
426 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
427 NOTIMPLEMENTED(); | |
428 return false; | |
429 } | |
430 | |
431 bool MediaCodecPlayer::IsPlayerReady() { | |
432 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
433 // This method is called to check whether it's safe to release the player when | |
434 // the OS needs more resources. This class can be released at any time. | |
435 return true; | |
436 } | |
437 | |
438 void MediaCodecPlayer::SetCdm(const scoped_refptr<MediaKeys>& cdm) { | |
439 DCHECK(cdm); | |
440 RUN_ON_MEDIA_THREAD(SetCdm, cdm); | |
441 | |
442 DVLOG(1) << __FUNCTION__; | |
443 | |
444 // Currently we don't support DRM change during the middle of playback, even | |
445 // if the player is paused. There is no current plan to support it, see | |
446 // http://crbug.com/253792. | |
447 if (state_ != kStatePaused || GetInterpolatedTime() > base::TimeDelta()) { | |
448 VLOG(0) << "Setting DRM bridge after playback has started is not supported"; | |
449 return; | |
450 } | |
451 | |
452 if (cdm_) { | |
453 NOTREACHED() << "Currently we do not support resetting CDM."; | |
454 return; | |
455 } | |
456 | |
457 cdm_ = cdm; | |
458 | |
459 // Only MediaDrmBridge will be set on MediaCodecPlayer. | |
460 MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get()); | |
461 | |
462 // Register CDM callbacks. The callbacks registered will be posted back to the | |
463 // media thread via BindToCurrentLoop. | |
464 | |
465 // Since |this| holds a reference to the |cdm_|, by the time the CDM is | |
466 // destructed, UnregisterPlayer() must have been called and |this| has been | |
467 // destructed as well. So the |cdm_unset_cb| will never have a chance to be | |
468 // called. | |
469 // TODO(xhwang): Remove |cdm_unset_cb| after it's not used on all platforms. | |
470 cdm_registration_id_ = drm_bridge->RegisterPlayer( | |
471 BindToCurrentLoop( | |
472 base::Bind(&MediaCodecPlayer::OnKeyAdded, media_weak_this_)), | |
473 base::Bind(&base::DoNothing)); | |
474 | |
475 drm_bridge->SetMediaCryptoReadyCB(BindToCurrentLoop( | |
476 base::Bind(&MediaCodecPlayer::OnMediaCryptoReady, media_weak_this_))); | |
477 } | |
478 | |
479 // Callbacks from Demuxer. | |
480 | |
481 void MediaCodecPlayer::OnDemuxerConfigsAvailable( | |
482 const DemuxerConfigs& configs) { | |
483 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
484 | |
485 DVLOG(1) << __FUNCTION__; | |
486 | |
487 duration_ = configs.duration; | |
488 | |
489 SetDemuxerConfigs(configs); | |
490 | |
491 // Update cache and notify manager on UI thread | |
492 gfx::Size video_size = HasVideo() ? configs.video_size : gfx::Size(); | |
493 ui_task_runner_->PostTask( | |
494 FROM_HERE, base::Bind(metadata_changed_cb_, duration_, video_size)); | |
495 } | |
496 | |
497 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) { | |
498 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
499 | |
500 DCHECK_LT(0u, data.access_units.size()); | |
501 CHECK_GE(1u, data.demuxer_configs.size()); | |
502 | |
503 DVLOG(2) << "Player::" << __FUNCTION__; | |
504 | |
505 if (data.type == DemuxerStream::AUDIO) | |
506 audio_decoder_->OnDemuxerDataAvailable(data); | |
507 | |
508 if (data.type == DemuxerStream::VIDEO) | |
509 video_decoder_->OnDemuxerDataAvailable(data); | |
510 } | |
511 | |
512 void MediaCodecPlayer::OnDemuxerSeekDone( | |
513 base::TimeDelta actual_browser_seek_time) { | |
514 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
515 | |
516 DVLOG(1) << __FUNCTION__ << " actual_time:" << actual_browser_seek_time; | |
517 | |
518 DCHECK(seek_info_.get()); | |
519 DCHECK(seek_info_->seek_time != kNoTimestamp); | |
520 | |
521 // A browser seek must not jump into the past. Ideally, it seeks to the | |
522 // requested time, but it might jump into the future. | |
523 DCHECK(!seek_info_->is_browser_seek || | |
524 seek_info_->seek_time <= actual_browser_seek_time); | |
525 | |
526 // Restrict the current time to be equal to seek_time | |
527 // for the next StartPlaybackDecoders() call. | |
528 | |
529 base::TimeDelta seek_time = seek_info_->is_browser_seek | |
530 ? actual_browser_seek_time | |
531 : seek_info_->seek_time; | |
532 | |
533 interpolator_.SetBounds(seek_time, seek_time); | |
534 | |
535 audio_decoder_->SetBaseTimestamp(seek_time); | |
536 | |
537 audio_decoder_->SetPrerollTimestamp(seek_time); | |
538 video_decoder_->SetPrerollTimestamp(seek_time); | |
539 | |
540 // The Flush() might set the state to kStateError. | |
541 if (state_ == kStateError) { | |
542 // Notify the Renderer. | |
543 if (!seek_info_->is_browser_seek) | |
544 ui_task_runner_->PostTask(FROM_HERE, | |
545 base::Bind(seek_done_cb_, seek_time)); | |
546 | |
547 seek_info_.reset(); | |
548 return; | |
549 } | |
550 | |
551 DCHECK_EQ(kStateWaitingForSeek, state_); | |
552 | |
553 base::TimeDelta pending_seek_time = GetPendingSeek(); | |
554 if (pending_seek_time != kNoTimestamp) { | |
555 // Keep kStateWaitingForSeek | |
556 SetPendingSeek(kNoTimestamp); | |
557 RequestDemuxerSeek(pending_seek_time); | |
558 return; | |
559 } | |
560 | |
561 if (HasPendingStart()) { | |
562 SetPendingStart(false); | |
563 // Request play permission or wait for initial configuration. | |
564 if (HasAudio() || HasVideo()) { | |
565 SetState(kStateWaitingForPermission); | |
566 RequestPlayPermission(); | |
567 } else { | |
568 SetState(kStateWaitingForConfig); | |
569 } | |
570 } else { | |
571 SetState(kStatePaused); | |
572 } | |
573 | |
574 // Notify the Renderer. | |
575 if (!seek_info_->is_browser_seek) | |
576 ui_task_runner_->PostTask(FROM_HERE, base::Bind(seek_done_cb_, seek_time)); | |
577 | |
578 seek_info_.reset(); | |
579 } | |
580 | |
581 void MediaCodecPlayer::OnDemuxerDurationChanged( | |
582 base::TimeDelta duration) { | |
583 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
584 DVLOG(1) << __FUNCTION__ << " duration:" << duration; | |
585 | |
586 duration_ = duration; | |
587 } | |
588 | |
589 void MediaCodecPlayer::SetDecodersTimeCallbackForTests( | |
590 DecodersTimeCallback cb) { | |
591 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
592 decoders_time_cb_ = cb; | |
593 } | |
594 | |
595 void MediaCodecPlayer::SetCodecCreatedCallbackForTests( | |
596 CodecCreatedCallback cb) { | |
597 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
598 DCHECK(audio_decoder_ && video_decoder_); | |
599 | |
600 audio_decoder_->SetCodecCreatedCallbackForTests( | |
601 base::Bind(cb, DemuxerStream::AUDIO)); | |
602 video_decoder_->SetCodecCreatedCallbackForTests( | |
603 base::Bind(cb, DemuxerStream::VIDEO)); | |
604 } | |
605 | |
606 void MediaCodecPlayer::SetAlwaysReconfigureForTests(DemuxerStream::Type type) { | |
607 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
608 DCHECK(audio_decoder_ && video_decoder_); | |
609 | |
610 if (type == DemuxerStream::AUDIO) | |
611 audio_decoder_->SetAlwaysReconfigureForTests(); | |
612 else if (type == DemuxerStream::VIDEO) | |
613 video_decoder_->SetAlwaysReconfigureForTests(); | |
614 } | |
615 | |
616 bool MediaCodecPlayer::IsPrerollingForTests(DemuxerStream::Type type) const { | |
617 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
618 DCHECK(audio_decoder_ && video_decoder_); | |
619 | |
620 if (type == DemuxerStream::AUDIO) | |
621 return audio_decoder_->IsPrerollingForTests(); | |
622 else if (type == DemuxerStream::VIDEO) | |
623 return video_decoder_->IsPrerollingForTests(); | |
624 else | |
625 return false; | |
626 } | |
627 | |
628 // Events from Player, called on UI thread | |
629 | |
630 void MediaCodecPlayer::RequestPermissionAndPostResult(base::TimeDelta duration, | |
631 bool has_audio) { | |
632 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
633 DVLOG(1) << __FUNCTION__ << " duration:" << duration; | |
634 | |
635 bool granted = manager()->RequestPlay(player_id(), duration, has_audio); | |
636 GetMediaTaskRunner()->PostTask( | |
637 FROM_HERE, base::Bind(&MediaCodecPlayer::OnPermissionDecided, | |
638 media_weak_this_, granted)); | |
639 } | |
640 | |
641 void MediaCodecPlayer::OnMediaMetadataChanged(base::TimeDelta duration, | |
642 const gfx::Size& video_size) { | |
643 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
644 | |
645 if (duration != kNoTimestamp) | |
646 metadata_cache_.duration = duration; | |
647 | |
648 if (!video_size.IsEmpty()) | |
649 metadata_cache_.video_size = video_size; | |
650 | |
651 manager()->OnMediaMetadataChanged(player_id(), metadata_cache_.duration, | |
652 metadata_cache_.video_size.width(), | |
653 metadata_cache_.video_size.height(), true); | |
654 } | |
655 | |
656 void MediaCodecPlayer::OnTimeUpdate(base::TimeDelta current_timestamp, | |
657 base::TimeTicks current_time_ticks) { | |
658 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
659 | |
660 current_time_cache_ = current_timestamp; | |
661 manager()->OnTimeUpdate(player_id(), current_timestamp, current_time_ticks); | |
662 } | |
663 | |
664 // Event from manager, called on Media thread | |
665 | |
666 void MediaCodecPlayer::OnPermissionDecided(bool granted) { | |
667 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
668 | |
669 DVLOG(1) << __FUNCTION__ << ": " << (granted ? "granted" : "denied"); | |
670 | |
671 switch (state_) { | |
672 case kStateWaitingForPermission: | |
673 if (granted) { | |
674 SetState(kStatePrefetching); | |
675 StartPrefetchDecoders(); | |
676 } else { | |
677 SetState(kStatePaused); | |
678 StopDecoders(); | |
679 } | |
680 break; | |
681 | |
682 default: | |
683 break; // ignore | |
684 } | |
685 } | |
686 | |
687 // Events from Decoders, called on Media thread | |
688 | |
689 void MediaCodecPlayer::RequestDemuxerData(DemuxerStream::Type stream_type) { | |
690 DVLOG(2) << __FUNCTION__ << " streamType:" << stream_type; | |
691 | |
692 // Use this method instead of directly binding with | |
693 // DemuxerAndroid::RequestDemuxerData() to avoid the race condition on | |
694 // deletion: | |
695 // 1. DeleteSoon is posted from UI to Media thread. | |
696 // 2. RequestDemuxerData callback is posted from Decoder to Media thread. | |
697 // 3. DeleteSoon arrives, we delete the player and detach from | |
698 // BrowserDemuxerAndroid. | |
699 // 4. RequestDemuxerData is processed by the media thread queue. Since the | |
700 // weak_ptr was invalidated in (3), this is a no-op. If we used | |
701 // DemuxerAndroid::RequestDemuxerData() it would arrive and will try to | |
702 // call the client, but the client (i.e. this player) would not exist. | |
703 demuxer_->RequestDemuxerData(stream_type); | |
704 } | |
705 | |
706 void MediaCodecPlayer::OnPrefetchDone() { | |
707 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
708 | |
709 if (state_ != kStatePrefetching) { | |
710 DVLOG(1) << __FUNCTION__ << " wrong state " << AsString(state_) | |
711 << " ignoring"; | |
712 return; // Ignore | |
713 } | |
714 | |
715 DVLOG(1) << __FUNCTION__; | |
716 | |
717 if (!HasAudio() && !HasVideo()) { | |
718 // No configuration at all after prefetching. | |
719 // This is an error, initial configuration is expected | |
720 // before the first data chunk. | |
721 DCHECK(!internal_error_cb_.is_null()); | |
722 GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_); | |
723 return; | |
724 } | |
725 | |
726 if (HasVideo() && !video_decoder_->HasVideoSurface()) { | |
727 SetState(kStateWaitingForSurface); | |
728 return; | |
729 } | |
730 | |
731 if (key_is_required_ && !key_is_added_) { | |
732 SetState(kStateWaitingForKey); | |
733 ui_task_runner_->PostTask(FROM_HERE, waiting_for_decryption_key_cb_); | |
734 return; | |
735 } | |
736 | |
737 SetState(kStatePlaying); | |
738 StartPlaybackOrBrowserSeek(); | |
739 } | |
740 | |
741 void MediaCodecPlayer::OnPrerollDone() { | |
742 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
743 | |
744 if (state_ != kStatePlaying) { | |
745 DVLOG(1) << __FUNCTION__ << ": in state " << AsString(state_) | |
746 << ", ignoring"; | |
747 return; | |
748 } | |
749 | |
750 DVLOG(1) << __FUNCTION__; | |
751 | |
752 StartStatus status = StartDecoders(); | |
753 if (status != kStartOk) | |
754 GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_); | |
755 } | |
756 | |
757 void MediaCodecPlayer::OnDecoderDrained(DemuxerStream::Type type) { | |
758 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
759 DVLOG(1) << __FUNCTION__ << " " << type; | |
760 | |
761 // We expect that OnStopDone() comes next. | |
762 | |
763 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); | |
764 | |
765 // DCHECK(state_ == kStatePlaying || state_ == kStateStopping) | |
766 // << __FUNCTION__ << " illegal state: " << AsString(state_); | |
767 // | |
768 // With simultaneous reconfiguration of audio and video streams the state | |
769 // can be kStatePrefetching as well: | |
770 // OnLastFrameRendered VIDEO (VIDEO decoder is stopped) | |
771 // OnLastFrameRendered AUDIO (AUDIO decoder is stopped) | |
772 // OnDecoderDrained VIDEO (kStatePlaying -> kStateStopping) | |
773 // OnStopDone VIDEO (kStateStopping -> kStatePrefetching) | |
774 // OnDecoderDrained AUDIO | |
775 // OnStopDone AUDIO | |
776 // | |
777 // TODO(timav): combine OnDecoderDrained() and OnStopDone() ? | |
778 | |
779 switch (state_) { | |
780 case kStatePlaying: | |
781 SetState(kStateStopping); | |
782 SetPendingStart(true); | |
783 | |
784 if (type == DemuxerStream::AUDIO && !VideoFinished()) { | |
785 DVLOG(1) << __FUNCTION__ << " requesting to stop video"; | |
786 video_decoder_->RequestToStop(); | |
787 } else if (type == DemuxerStream::VIDEO && !AudioFinished()) { | |
788 DVLOG(1) << __FUNCTION__ << " requesting to stop audio"; | |
789 audio_decoder_->RequestToStop(); | |
790 } | |
791 break; | |
792 | |
793 default: | |
794 break; | |
795 } | |
796 } | |
797 | |
798 void MediaCodecPlayer::OnStopDone(DemuxerStream::Type type) { | |
799 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
800 DVLOG(1) << __FUNCTION__ << " " << type | |
801 << " interpolated time:" << GetInterpolatedTime(); | |
802 | |
803 if (!(audio_decoder_->IsStopped() && video_decoder_->IsStopped())) { | |
804 DVLOG(1) << __FUNCTION__ << " both audio and video has to be stopped" | |
805 << ", ignoring"; | |
806 return; // Wait until other stream is stopped | |
807 } | |
808 | |
809 // At this point decoder threads should not be running | |
810 if (interpolator_.interpolating()) | |
811 interpolator_.StopInterpolating(); | |
812 | |
813 base::TimeDelta seek_time; | |
814 switch (state_) { | |
815 case kStateStopping: { | |
816 base::TimeDelta seek_time = GetPendingSeek(); | |
817 if (seek_time != kNoTimestamp) { | |
818 SetState(kStateWaitingForSeek); | |
819 SetPendingSeek(kNoTimestamp); | |
820 RequestDemuxerSeek(seek_time); | |
821 } else if (HasPendingStart()) { | |
822 SetPendingStart(false); | |
823 SetState(kStateWaitingForPermission); | |
824 RequestPlayPermission(); | |
825 } else { | |
826 SetState(kStatePaused); | |
827 } | |
828 } break; | |
829 case kStatePlaying: | |
830 // Unexpected stop means completion | |
831 SetState(kStatePaused); | |
832 break; | |
833 default: | |
834 // DVLOG(0) << __FUNCTION__ << " illegal state: " << AsString(state_); | |
835 // NOTREACHED(); | |
836 // Ignore! There can be a race condition: audio posts OnStopDone, | |
837 // then video posts, then first OnStopDone arrives at which point | |
838 // both streams are already stopped, then second OnStopDone arrives. When | |
839 // the second one arrives, the state us not kStateStopping any more. | |
840 return; | |
841 } | |
842 | |
843 // DetachListener to UI thread | |
844 ui_task_runner_->PostTask(FROM_HERE, detach_listener_cb_); | |
845 | |
846 if (AudioFinished() && VideoFinished()) { | |
847 media_stat_->StopAndReport(GetInterpolatedTime()); | |
848 ui_task_runner_->PostTask(FROM_HERE, completion_cb_); | |
849 } | |
850 } | |
851 | |
852 void MediaCodecPlayer::OnMissingKeyReported(DemuxerStream::Type type) { | |
853 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
854 DVLOG(1) << __FUNCTION__ << " " << type; | |
855 | |
856 // Request stop and restart to pick up the key. | |
857 key_is_required_ = true; | |
858 | |
859 if (state_ == kStatePlaying) { | |
860 media_stat_->StopAndReport(GetInterpolatedTime()); | |
861 | |
862 SetState(kStateStopping); | |
863 RequestToStopDecoders(); | |
864 SetPendingStart(true); | |
865 } | |
866 } | |
867 | |
868 void MediaCodecPlayer::OnError() { | |
869 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
870 DVLOG(1) << __FUNCTION__; | |
871 | |
872 media_stat_->StopAndReport(GetInterpolatedTime()); | |
873 | |
874 // kStateError blocks all events | |
875 SetState(kStateError); | |
876 | |
877 ReleaseDecoderResources(); | |
878 | |
879 ui_task_runner_->PostTask(FROM_HERE, | |
880 base::Bind(error_cb_, MEDIA_ERROR_DECODE)); | |
881 } | |
882 | |
883 void MediaCodecPlayer::OnStarvation(DemuxerStream::Type type) { | |
884 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
885 DVLOG(1) << __FUNCTION__ << " stream type:" << type; | |
886 | |
887 if (state_ != kStatePlaying) | |
888 return; // Ignore | |
889 | |
890 SetState(kStateStopping); | |
891 RequestToStopDecoders(); | |
892 SetPendingStart(true); | |
893 | |
894 media_stat_->AddStarvation(); | |
895 } | |
896 | |
897 void MediaCodecPlayer::OnTimeIntervalUpdate(DemuxerStream::Type type, | |
898 base::TimeDelta now_playing, | |
899 base::TimeDelta last_buffered, | |
900 bool postpone) { | |
901 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
902 | |
903 DVLOG(2) << __FUNCTION__ << ": stream type:" << type << " [" << now_playing | |
904 << "," << last_buffered << "]" << (postpone ? " postpone" : ""); | |
905 | |
906 // For testing only: report time interval as we receive it from decoders | |
907 // as an indication of what is being rendered. Do not post this callback | |
908 // for postponed frames: although the PTS is correct, the tests also care | |
909 // about the wall clock time this callback arrives and deduce the rendering | |
910 // moment from it. | |
911 if (!decoders_time_cb_.is_null() && !postpone) { | |
912 ui_task_runner_->PostTask( | |
913 FROM_HERE, | |
914 base::Bind(decoders_time_cb_, type, now_playing, last_buffered)); | |
915 } | |
916 | |
917 // I assume that audio stream cannot be added after we get configs by | |
918 // OnDemuxerConfigsAvailable(), but that audio can finish early. | |
919 | |
920 if (type == DemuxerStream::VIDEO) { | |
921 // Ignore video PTS if there is audio stream or if it's behind current | |
922 // time as set by audio stream. | |
923 if (!AudioFinished() || | |
924 (HasAudio() && now_playing < interpolator_.GetInterpolatedTime())) | |
925 return; | |
926 } | |
927 | |
928 interpolator_.SetBounds(now_playing, last_buffered); | |
929 | |
930 // Post to UI thread | |
931 if (!postpone) { | |
932 ui_task_runner_->PostTask(FROM_HERE, | |
933 base::Bind(time_update_cb_, GetInterpolatedTime(), | |
934 base::TimeTicks::Now())); | |
935 } | |
936 } | |
937 | |
938 void MediaCodecPlayer::OnVideoResolutionChanged(const gfx::Size& size) { | |
939 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
940 | |
941 DVLOG(1) << __FUNCTION__ << " " << size.width() << "x" << size.height(); | |
942 | |
943 // Update cache and notify manager on UI thread | |
944 ui_task_runner_->PostTask( | |
945 FROM_HERE, base::Bind(metadata_changed_cb_, kNoTimestamp, size)); | |
946 } | |
947 | |
948 // Callbacks from MediaDrmBridge. | |
949 | |
950 void MediaCodecPlayer::OnMediaCryptoReady( | |
951 MediaDrmBridge::JavaObjectPtr media_crypto, | |
952 bool needs_protected_surface) { | |
953 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
954 DVLOG(1) << __FUNCTION__ << " protected surface is " | |
955 << (needs_protected_surface ? "required" : "not required"); | |
956 | |
957 // We use the parameters that come with this callback every time we call | |
958 // Configure(). This is possible only if the MediaCrypto object remains valid | |
959 // and the surface requirement does not change until new SetCdm() is called. | |
960 | |
961 DCHECK(media_crypto); | |
962 | |
963 if (media_crypto->is_null()) { | |
964 // TODO(timav): Fail playback nicely here if needed. Note that we could get | |
965 // here even though the stream to play is unencrypted and therefore | |
966 // MediaCrypto is not needed. In that case, we may ignore this error and | |
967 // continue playback, or fail the playback. | |
968 LOG(ERROR) << "MediaCrypto creation failed."; | |
969 return; | |
970 } | |
971 | |
972 media_crypto_ = std::move(media_crypto); | |
973 | |
974 if (audio_decoder_) { | |
975 audio_decoder_->SetNeedsReconfigure(); | |
976 } | |
977 | |
978 if (video_decoder_) { | |
979 video_decoder_->SetNeedsReconfigure(); | |
980 video_decoder_->SetProtectedSurfaceRequired(needs_protected_surface); | |
981 } | |
982 | |
983 if (state_ == kStateWaitingForMediaCrypto) { | |
984 // Resume start sequence (configure, etc.) | |
985 SetState(kStatePlaying); | |
986 StartPlaybackOrBrowserSeek(); | |
987 } | |
988 | |
989 DVLOG(1) << __FUNCTION__ << " end"; | |
990 } | |
991 | |
992 void MediaCodecPlayer::OnKeyAdded() { | |
993 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
994 DVLOG(1) << __FUNCTION__; | |
995 | |
996 key_is_added_ = true; | |
997 | |
998 if (state_ == kStateWaitingForKey) { | |
999 SetState(kStatePlaying); | |
1000 StartPlaybackOrBrowserSeek(); | |
1001 } | |
1002 } | |
1003 | |
1004 // State machine operations, called on Media thread | |
1005 | |
1006 void MediaCodecPlayer::SetState(PlayerState new_state) { | |
1007 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1008 | |
1009 DVLOG(1) << "SetState:" << AsString(state_) << " -> " << AsString(new_state); | |
1010 state_ = new_state; | |
1011 } | |
1012 | |
1013 void MediaCodecPlayer::SetPendingStart(bool need_to_start) { | |
1014 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1015 DVLOG(1) << __FUNCTION__ << ": " << need_to_start; | |
1016 pending_start_ = need_to_start; | |
1017 } | |
1018 | |
1019 bool MediaCodecPlayer::HasPendingStart() const { | |
1020 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1021 return pending_start_; | |
1022 } | |
1023 | |
1024 void MediaCodecPlayer::SetPendingSeek(base::TimeDelta timestamp) { | |
1025 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1026 DVLOG(1) << __FUNCTION__ << ": " << timestamp; | |
1027 pending_seek_ = timestamp; | |
1028 } | |
1029 | |
1030 base::TimeDelta MediaCodecPlayer::GetPendingSeek() const { | |
1031 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1032 return pending_seek_; | |
1033 } | |
1034 | |
1035 void MediaCodecPlayer::SetDemuxerConfigs(const DemuxerConfigs& configs) { | |
1036 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1037 DVLOG(1) << __FUNCTION__ << " " << configs; | |
1038 | |
1039 DCHECK(audio_decoder_); | |
1040 DCHECK(video_decoder_); | |
1041 | |
1042 // At least one valid codec must be present. | |
1043 DCHECK(configs.audio_codec != kUnknownAudioCodec || | |
1044 configs.video_codec != kUnknownVideoCodec); | |
1045 | |
1046 if (configs.audio_codec != kUnknownAudioCodec) | |
1047 audio_decoder_->SetDemuxerConfigs(configs); | |
1048 | |
1049 if (configs.video_codec != kUnknownVideoCodec) | |
1050 video_decoder_->SetDemuxerConfigs(configs); | |
1051 | |
1052 if (state_ == kStateWaitingForConfig) { | |
1053 SetState(kStateWaitingForPermission); | |
1054 RequestPlayPermission(); | |
1055 } | |
1056 } | |
1057 | |
1058 void MediaCodecPlayer::RequestPlayPermission() { | |
1059 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1060 DVLOG(1) << __FUNCTION__; | |
1061 | |
1062 // Check that we have received demuxer config hence we know the duration. | |
1063 DCHECK(HasAudio() || HasVideo()); | |
1064 | |
1065 ui_task_runner_->PostTask( | |
1066 FROM_HERE, base::Bind(&MediaPlayerAndroid::RequestPermissionAndPostResult, | |
1067 WeakPtrForUIThread(), duration_, HasAudio())); | |
1068 } | |
1069 | |
1070 void MediaCodecPlayer::StartPrefetchDecoders() { | |
1071 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1072 DVLOG(1) << __FUNCTION__; | |
1073 | |
1074 bool do_audio = false; | |
1075 bool do_video = false; | |
1076 int count = 0; | |
1077 if (!AudioFinished()) { | |
1078 do_audio = true; | |
1079 ++count; | |
1080 } | |
1081 if (!VideoFinished()) { | |
1082 do_video = true; | |
1083 ++count; | |
1084 } | |
1085 | |
1086 DCHECK_LT(0, count); // at least one decoder should be active | |
1087 | |
1088 base::Closure prefetch_cb = base::BarrierClosure( | |
1089 count, base::Bind(&MediaCodecPlayer::OnPrefetchDone, media_weak_this_)); | |
1090 | |
1091 if (do_audio) | |
1092 audio_decoder_->Prefetch(prefetch_cb); | |
1093 | |
1094 if (do_video) | |
1095 video_decoder_->Prefetch(prefetch_cb); | |
1096 } | |
1097 | |
1098 void MediaCodecPlayer::StartPlaybackOrBrowserSeek() { | |
1099 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1100 DVLOG(1) << __FUNCTION__; | |
1101 | |
1102 // TODO(timav): consider replacing this method with posting a | |
1103 // browser seek task (i.e. generate an event) from StartPlaybackDecoders(). | |
1104 | |
1105 // Clear encryption key related flags. | |
1106 key_is_required_ = false; | |
1107 key_is_added_ = false; | |
1108 | |
1109 StartStatus status = StartPlaybackDecoders(); | |
1110 | |
1111 switch (status) { | |
1112 case kStartBrowserSeekRequired: | |
1113 // Browser seek | |
1114 SetState(kStateWaitingForSeek); | |
1115 SetPendingStart(true); | |
1116 StopDecoders(); | |
1117 RequestDemuxerSeek(GetInterpolatedTime(), true); | |
1118 break; | |
1119 case kStartCryptoRequired: | |
1120 SetState(kStateWaitingForMediaCrypto); | |
1121 break; | |
1122 case kStartFailed: | |
1123 GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_); | |
1124 break; | |
1125 case kStartOk: | |
1126 break; | |
1127 } | |
1128 } | |
1129 | |
1130 MediaCodecPlayer::StartStatus MediaCodecPlayer::StartPlaybackDecoders() { | |
1131 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1132 DVLOG(1) << __FUNCTION__; | |
1133 | |
1134 // Configure all streams before the start since we may discover that browser | |
1135 // seek is required. | |
1136 MediaCodecPlayer::StartStatus status = ConfigureDecoders(); | |
1137 if (status != kStartOk) | |
1138 return status; | |
1139 | |
1140 bool preroll_required = false; | |
1141 status = MaybePrerollDecoders(&preroll_required); | |
1142 if (preroll_required) | |
1143 return status; | |
1144 | |
1145 return StartDecoders(); | |
1146 } | |
1147 | |
1148 MediaCodecPlayer::StartStatus MediaCodecPlayer::ConfigureDecoders() { | |
1149 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1150 DVLOG(1) << __FUNCTION__; | |
1151 | |
1152 const bool do_audio = !AudioFinished(); | |
1153 const bool do_video = !VideoFinished(); | |
1154 | |
1155 // If there is nothing to play, the state machine should determine this at the | |
1156 // prefetch state and never call this method. | |
1157 DCHECK(do_audio || do_video); | |
1158 | |
1159 const bool need_audio_crypto = | |
1160 do_audio && audio_decoder_->IsContentEncrypted(); | |
1161 const bool need_video_crypto = | |
1162 do_video && video_decoder_->IsContentEncrypted(); | |
1163 | |
1164 // Do we need to create a local ref from the global ref? | |
1165 jobject media_crypto = media_crypto_ ? media_crypto_->obj() : nullptr; | |
1166 | |
1167 if (need_audio_crypto || need_video_crypto) { | |
1168 DVLOG(1) << (need_audio_crypto ? " audio" : "") | |
1169 << (need_video_crypto ? " video" : "") << " need(s) encryption"; | |
1170 if (!media_crypto) { | |
1171 DVLOG(1) << __FUNCTION__ << ": MediaCrypto is not found, returning"; | |
1172 return kStartCryptoRequired; | |
1173 } | |
1174 } | |
1175 | |
1176 // Start with video: if browser seek is required it would not make sense to | |
1177 // configure audio. | |
1178 | |
1179 MediaCodecDecoder::ConfigStatus status = MediaCodecDecoder::kConfigOk; | |
1180 if (do_video) | |
1181 status = video_decoder_->Configure(media_crypto); | |
1182 | |
1183 if (status == MediaCodecDecoder::kConfigOk && do_audio) | |
1184 status = audio_decoder_->Configure(media_crypto); | |
1185 | |
1186 switch (status) { | |
1187 case MediaCodecDecoder::kConfigOk: | |
1188 break; | |
1189 case MediaCodecDecoder::kConfigKeyFrameRequired: | |
1190 return kStartBrowserSeekRequired; | |
1191 case MediaCodecDecoder::kConfigFailure: | |
1192 return kStartFailed; | |
1193 } | |
1194 return kStartOk; | |
1195 } | |
1196 | |
1197 MediaCodecPlayer::StartStatus MediaCodecPlayer::MaybePrerollDecoders( | |
1198 bool* preroll_required) { | |
1199 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1200 | |
1201 DVLOG(1) << __FUNCTION__ << " current_time:" << GetInterpolatedTime(); | |
1202 | |
1203 // If requested, preroll is always done in the beginning of the playback, | |
1204 // after prefetch. The request might not happen at all though, in which case | |
1205 // we won't have prerolling phase. We need the prerolling when we (re)create | |
1206 // the decoder, because its configuration and initialization (getting input, | |
1207 // but not making output) can take time, and after the seek because there | |
1208 // could be some data to be skipped and there is again initialization after | |
1209 // the flush. | |
1210 | |
1211 *preroll_required = false; | |
1212 | |
1213 int count = 0; | |
1214 const bool do_audio = audio_decoder_->NotCompletedAndNeedsPreroll(); | |
1215 if (do_audio) | |
1216 ++count; | |
1217 | |
1218 const bool do_video = video_decoder_->NotCompletedAndNeedsPreroll(); | |
1219 if (do_video) | |
1220 ++count; | |
1221 | |
1222 if (count == 0) { | |
1223 DVLOG(1) << __FUNCTION__ << ": preroll is not required, skipping"; | |
1224 return kStartOk; | |
1225 } | |
1226 | |
1227 *preroll_required = true; | |
1228 | |
1229 DCHECK(count > 0); | |
1230 DCHECK(do_audio || do_video); | |
1231 | |
1232 DVLOG(1) << __FUNCTION__ << ": preroll for " << count << " stream(s)"; | |
1233 | |
1234 base::Closure preroll_cb = base::BarrierClosure( | |
1235 count, base::Bind(&MediaCodecPlayer::OnPrerollDone, media_weak_this_)); | |
1236 | |
1237 if (do_audio && !audio_decoder_->Preroll(preroll_cb)) | |
1238 return kStartFailed; | |
1239 | |
1240 if (do_video && !video_decoder_->Preroll(preroll_cb)) | |
1241 return kStartFailed; | |
1242 | |
1243 return kStartOk; | |
1244 } | |
1245 | |
1246 MediaCodecPlayer::StartStatus MediaCodecPlayer::StartDecoders() { | |
1247 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1248 | |
1249 if (!interpolator_.interpolating()) | |
1250 interpolator_.StartInterpolating(); | |
1251 | |
1252 base::TimeDelta current_time = GetInterpolatedTime(); | |
1253 | |
1254 DVLOG(1) << __FUNCTION__ << " current_time:" << current_time; | |
1255 | |
1256 // At this point decoder threads are either not running at all or their | |
1257 // message pumps are in the idle state after the preroll is done. | |
1258 | |
1259 if (!AudioFinished()) { | |
1260 if (!audio_decoder_->Start(current_time)) | |
1261 return kStartFailed; | |
1262 | |
1263 // Attach listener on UI thread | |
1264 ui_task_runner_->PostTask(FROM_HERE, attach_listener_cb_); | |
1265 } | |
1266 | |
1267 if (!VideoFinished()) { | |
1268 if (!video_decoder_->Start(current_time)) | |
1269 return kStartFailed; | |
1270 } | |
1271 | |
1272 media_stat_->Start(current_time); | |
1273 | |
1274 return kStartOk; | |
1275 } | |
1276 | |
1277 void MediaCodecPlayer::StopDecoders() { | |
1278 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1279 DVLOG(1) << __FUNCTION__; | |
1280 | |
1281 video_decoder_->SyncStop(); | |
1282 audio_decoder_->SyncStop(); | |
1283 } | |
1284 | |
1285 void MediaCodecPlayer::RequestToStopDecoders() { | |
1286 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1287 DVLOG(1) << __FUNCTION__; | |
1288 | |
1289 bool do_audio = false; | |
1290 bool do_video = false; | |
1291 | |
1292 if (audio_decoder_->IsPrefetchingOrPlaying()) | |
1293 do_audio = true; | |
1294 if (video_decoder_->IsPrefetchingOrPlaying()) | |
1295 do_video = true; | |
1296 | |
1297 if (!do_audio && !do_video) { | |
1298 GetMediaTaskRunner()->PostTask( | |
1299 FROM_HERE, base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_, | |
1300 DemuxerStream::UNKNOWN)); | |
1301 return; | |
1302 } | |
1303 | |
1304 if (do_audio) | |
1305 audio_decoder_->RequestToStop(); | |
1306 if (do_video) | |
1307 video_decoder_->RequestToStop(); | |
1308 } | |
1309 | |
1310 void MediaCodecPlayer::RequestDemuxerSeek(base::TimeDelta seek_time, | |
1311 bool is_browser_seek) { | |
1312 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1313 DVLOG(1) << __FUNCTION__ << " " << seek_time | |
1314 << (is_browser_seek ? " BROWSER_SEEK" : ""); | |
1315 | |
1316 // Flush decoders before requesting demuxer. | |
1317 audio_decoder_->Flush(); | |
1318 video_decoder_->Flush(); | |
1319 | |
1320 // Save active seek data. Logically it is attached to kStateWaitingForSeek. | |
1321 DCHECK_EQ(kStateWaitingForSeek, state_); | |
1322 seek_info_.reset(new SeekInfo(seek_time, is_browser_seek)); | |
1323 | |
1324 demuxer_->RequestDemuxerSeek(seek_time, is_browser_seek); | |
1325 } | |
1326 | |
1327 void MediaCodecPlayer::ReleaseDecoderResources() { | |
1328 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1329 DVLOG(1) << __FUNCTION__; | |
1330 | |
1331 if (audio_decoder_) | |
1332 audio_decoder_->ReleaseDecoderResources(); | |
1333 | |
1334 if (video_decoder_) | |
1335 video_decoder_->ReleaseDecoderResources(); | |
1336 | |
1337 // At this point decoder threads should not be running | |
1338 if (interpolator_.interpolating()) | |
1339 interpolator_.StopInterpolating(); | |
1340 } | |
1341 | |
1342 void MediaCodecPlayer::CreateDecoders() { | |
1343 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1344 DVLOG(1) << __FUNCTION__; | |
1345 | |
1346 internal_error_cb_ = base::Bind(&MediaCodecPlayer::OnError, media_weak_this_); | |
1347 | |
1348 media_stat_.reset(new MediaStatistics()); | |
1349 | |
1350 audio_decoder_.reset(new AudioMediaCodecDecoder( | |
1351 GetMediaTaskRunner(), &media_stat_->audio_frame_stats(), | |
1352 base::Bind(&MediaCodecPlayer::RequestDemuxerData, media_weak_this_, | |
1353 DemuxerStream::AUDIO), | |
1354 base::Bind(&MediaCodecPlayer::OnStarvation, media_weak_this_, | |
1355 DemuxerStream::AUDIO), | |
1356 base::Bind(&MediaCodecPlayer::OnDecoderDrained, media_weak_this_, | |
1357 DemuxerStream::AUDIO), | |
1358 base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_, | |
1359 DemuxerStream::AUDIO), | |
1360 base::Bind(&MediaCodecPlayer::OnMissingKeyReported, media_weak_this_, | |
1361 DemuxerStream::AUDIO), | |
1362 internal_error_cb_, base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate, | |
1363 media_weak_this_, DemuxerStream::AUDIO))); | |
1364 | |
1365 video_decoder_.reset(new VideoMediaCodecDecoder( | |
1366 GetMediaTaskRunner(), &media_stat_->video_frame_stats(), | |
1367 base::Bind(&MediaCodecPlayer::RequestDemuxerData, media_weak_this_, | |
1368 DemuxerStream::VIDEO), | |
1369 base::Bind(&MediaCodecPlayer::OnStarvation, media_weak_this_, | |
1370 DemuxerStream::VIDEO), | |
1371 base::Bind(&MediaCodecPlayer::OnDecoderDrained, media_weak_this_, | |
1372 DemuxerStream::VIDEO), | |
1373 base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_, | |
1374 DemuxerStream::VIDEO), | |
1375 base::Bind(&MediaCodecPlayer::OnMissingKeyReported, media_weak_this_, | |
1376 DemuxerStream::VIDEO), | |
1377 internal_error_cb_, base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate, | |
1378 media_weak_this_, DemuxerStream::VIDEO), | |
1379 base::Bind(&MediaCodecPlayer::OnVideoResolutionChanged, | |
1380 media_weak_this_))); | |
1381 } | |
1382 | |
1383 bool MediaCodecPlayer::AudioFinished() const { | |
1384 return audio_decoder_->IsCompleted() || !audio_decoder_->HasStream(); | |
1385 } | |
1386 | |
1387 bool MediaCodecPlayer::VideoFinished() const { | |
1388 return video_decoder_->IsCompleted() || !video_decoder_->HasStream(); | |
1389 } | |
1390 | |
1391 base::TimeDelta MediaCodecPlayer::GetInterpolatedTime() { | |
1392 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | |
1393 | |
1394 base::TimeDelta interpolated_time = interpolator_.GetInterpolatedTime(); | |
1395 return std::min(interpolated_time, duration_); | |
1396 } | |
1397 | |
1398 #undef RETURN_STRING | |
1399 #define RETURN_STRING(x) \ | |
1400 case x: \ | |
1401 return #x; | |
1402 | |
1403 const char* MediaCodecPlayer::AsString(PlayerState state) { | |
1404 switch (state) { | |
1405 RETURN_STRING(kStatePaused); | |
1406 RETURN_STRING(kStateWaitingForConfig); | |
1407 RETURN_STRING(kStateWaitingForPermission); | |
1408 RETURN_STRING(kStatePrefetching); | |
1409 RETURN_STRING(kStatePlaying); | |
1410 RETURN_STRING(kStateStopping); | |
1411 RETURN_STRING(kStateWaitingForSurface); | |
1412 RETURN_STRING(kStateWaitingForKey); | |
1413 RETURN_STRING(kStateWaitingForMediaCrypto); | |
1414 RETURN_STRING(kStateWaitingForSeek); | |
1415 RETURN_STRING(kStateError); | |
1416 } | |
1417 return nullptr; // crash early | |
1418 } | |
1419 | |
1420 #undef RETURN_STRING | |
1421 | |
1422 } // namespace media | |
OLD | NEW |