| 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 |