| Index: media/base/android/media_codec_player.cc
|
| diff --git a/media/base/android/media_codec_player.cc b/media/base/android/media_codec_player.cc
|
| index 4e1e8ff4fb9a52269e0eb4037f2d5bba5938883d..b7538875b31933fa188c3a6c52622dec15a7e085 100644
|
| --- a/media/base/android/media_codec_player.cc
|
| +++ b/media/base/android/media_codec_player.cc
|
| @@ -12,6 +12,8 @@
|
| #include "base/threading/thread.h"
|
| #include "media/base/android/media_codec_audio_decoder.h"
|
| #include "media/base/android/media_codec_video_decoder.h"
|
| +#include "media/base/android/media_drm_bridge.h"
|
| +#include "media/base/android/media_drm_proxy.h"
|
| #include "media/base/android/media_player_manager.h"
|
| #include "media/base/timestamp_constants.h"
|
|
|
| @@ -62,6 +64,10 @@ MediaCodecPlayer::MediaCodecPlayer(
|
| interpolator_(&default_tick_clock_),
|
| pending_start_(false),
|
| pending_seek_(kNoTimestamp()),
|
| + drm_bridge_(nullptr),
|
| + cdm_registration_id_(0),
|
| + key_is_required_(false),
|
| + key_is_added_(false),
|
| media_weak_factory_(this) {
|
| DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
|
|
| @@ -104,6 +110,11 @@ MediaCodecPlayer::~MediaCodecPlayer()
|
| video_decoder_->ReleaseDecoderResources();
|
| if (audio_decoder_)
|
| audio_decoder_->ReleaseDecoderResources();
|
| +
|
| + if (drm_bridge_) {
|
| + DCHECK(cdm_registration_id_);
|
| + drm_bridge_->UnregisterPlayer(cdm_registration_id_);
|
| + }
|
| }
|
|
|
| void MediaCodecPlayer::Initialize() {
|
| @@ -223,6 +234,8 @@ void MediaCodecPlayer::Start() {
|
| case kStatePrefetching:
|
| case kStatePlaying:
|
| case kStateWaitingForSurface:
|
| + case kStateWaitingForKey:
|
| + case kStateWaitingForCrypto:
|
| case kStateError:
|
| break; // Ignore
|
| default:
|
| @@ -242,6 +255,8 @@ void MediaCodecPlayer::Pause(bool is_media_related_action) {
|
| case kStateWaitingForConfig:
|
| case kStatePrefetching:
|
| case kStateWaitingForSurface:
|
| + case kStateWaitingForKey:
|
| + case kStateWaitingForCrypto:
|
| SetState(kStatePaused);
|
| StopDecoders();
|
| break;
|
| @@ -273,6 +288,8 @@ void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) {
|
| case kStateWaitingForConfig:
|
| case kStatePrefetching:
|
| case kStateWaitingForSurface:
|
| + case kStateWaitingForKey:
|
| + case kStateWaitingForCrypto:
|
| SetState(kStateWaitingForSeek);
|
| StopDecoders();
|
| SetPendingStart(true);
|
| @@ -313,6 +330,10 @@ void MediaCodecPlayer::Release() {
|
| if (state_ != kStateWaitingForSeek)
|
| SetState(kStatePaused);
|
|
|
| + // Crear encryption key related flags.
|
| + key_is_required_ = false;
|
| + key_is_added_ = false;
|
| +
|
| base::TimeDelta pending_seek_time = GetPendingSeek();
|
| if (pending_seek_time != kNoTimestamp()) {
|
| SetPendingSeek(kNoTimestamp());
|
| @@ -382,8 +403,42 @@ bool MediaCodecPlayer::IsPlayerReady() {
|
| }
|
|
|
| void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) {
|
| - DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
| - NOTIMPLEMENTED();
|
| + RUN_ON_MEDIA_THREAD(SetCdm, cdm);
|
| +
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| + // Currently we don't support DRM change during the middle of playback, even
|
| + // if the player is paused. There is no current plan to support it, see
|
| + // http://crbug.com/253792.
|
| + if (state_ != kStatePaused || GetInterpolatedTime() > base::TimeDelta()) {
|
| + VLOG(0) << "Setting DRM bridge after playback has started is not supported";
|
| + return;
|
| + }
|
| +
|
| + if (drm_bridge_) {
|
| + NOTREACHED() << "Currently we do not support resetting CDM.";
|
| + return;
|
| + }
|
| +
|
| + DCHECK(cdm);
|
| + MediaDrmProxy* drm_proxy = static_cast<MediaDrmProxy*>(cdm);
|
| + drm_bridge_ = drm_proxy->GetDrmBridge();
|
| +
|
| + DCHECK(drm_bridge_);
|
| +
|
| + DCHECK(audio_decoder_);
|
| + DCHECK(video_decoder_);
|
| + audio_decoder_->SetDrmBridge(drm_bridge_);
|
| + video_decoder_->SetDrmBridge(drm_bridge_);
|
| +
|
| + cdm_registration_id_ = drm_bridge_->RegisterPlayer(
|
| + base::Bind(&MediaCodecPlayer::OnKeyAdded, media_weak_this_),
|
| + base::Bind(&MediaCodecPlayer::OnCdmUnset, media_weak_this_));
|
| +
|
| + // If the crypto is ready by this time, OnMediaCryptoReady will be posted
|
| + // immediately, otherwise it will be posted when the crypro is ready.
|
| + drm_bridge_->SetMediaCryptoReadyCB(
|
| + base::Bind(&MediaCodecPlayer::OnMediaCryptoReady, media_weak_this_));
|
| }
|
|
|
| // Callbacks from Demuxer.
|
| @@ -604,6 +659,11 @@ void MediaCodecPlayer::OnPrefetchDone() {
|
| return;
|
| }
|
|
|
| + if (key_is_required_ && !key_is_added_) {
|
| + SetState(kStateWaitingForKey);
|
| + return;
|
| + }
|
| +
|
| SetState(kStatePlaying);
|
| StartPlaybackOrBrowserSeek();
|
| }
|
| @@ -717,6 +777,20 @@ void MediaCodecPlayer::OnStopDone(DemuxerStream::Type type) {
|
| ui_task_runner_->PostTask(FROM_HERE, completion_cb_);
|
| }
|
|
|
| +void MediaCodecPlayer::OnKeyRequired(DemuxerStream::Type type) {
|
| + DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
|
| + DVLOG(1) << __FUNCTION__ << " " << type;
|
| +
|
| + // Request stop and restart to pick up the key.
|
| + key_is_required_ = true;
|
| +
|
| + if (state_ == kStatePlaying) {
|
| + SetState(kStateStopping);
|
| + RequestToStopDecoders();
|
| + SetPendingStart(true);
|
| + }
|
| +}
|
| +
|
| void MediaCodecPlayer::OnError() {
|
| DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
|
| DVLOG(1) << __FUNCTION__;
|
| @@ -800,6 +874,57 @@ void MediaCodecPlayer::OnVideoResolutionChanged(const gfx::Size& size) {
|
| FROM_HERE, base::Bind(metadata_changed_cb_, kNoTimestamp(), size));
|
| }
|
|
|
| +// Callbacks from DRM
|
| +
|
| +void MediaCodecPlayer::OnMediaCryptoReady() {
|
| + DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| + DCHECK(drm_bridge_);
|
| + DCHECK(!drm_bridge_->GetMediaCrypto().is_null());
|
| + drm_bridge_->SetMediaCryptoReadyCB(base::Closure());
|
| +
|
| + if (state_ == kStateWaitingForCrypto) {
|
| + // Resume decoders creation.
|
| + SetState(kStatePlaying);
|
| + StartPlaybackOrBrowserSeek();
|
| + }
|
| +
|
| + DVLOG(1) << __FUNCTION__ << " end";
|
| +}
|
| +
|
| +void MediaCodecPlayer::OnKeyAdded() {
|
| + DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| + key_is_added_ = true;
|
| +
|
| + if (state_ == kStateWaitingForKey) {
|
| + SetState(kStatePlaying);
|
| + StartPlaybackOrBrowserSeek();
|
| + }
|
| +}
|
| +
|
| +void MediaCodecPlayer::OnCdmUnset() {
|
| + DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| + // This comment is copied from MediaSourcePlayer::OnCdmUnset().
|
| + // TODO(xhwang): Currently this is only called during teardown. Support full
|
| + // detachment of CDM during playback. This will be needed when we start to
|
| + // support setMediaKeys(0) (see http://crbug.com/330324), or when we release
|
| + // MediaDrm when the video is paused, or when the device goes to sleep (see
|
| + // http://crbug.com/272421).
|
| +
|
| + if (audio_decoder_)
|
| + audio_decoder_->SetDrmBridge(nullptr);
|
| + if (video_decoder_)
|
| + video_decoder_->SetDrmBridge(nullptr);
|
| +
|
| + cdm_registration_id_ = 0;
|
| + drm_bridge_ = nullptr;
|
| +}
|
| +
|
| // State machine operations, called on Media thread
|
|
|
| void MediaCodecPlayer::SetState(PlayerState new_state) {
|
| @@ -899,6 +1024,10 @@ void MediaCodecPlayer::StartPlaybackOrBrowserSeek() {
|
| // TODO(timav): consider replacing this method with posting a
|
| // browser seek task (i.e. generate an event) from StartPlaybackDecoders().
|
|
|
| + // Clear encryption key related flags.
|
| + key_is_required_ = false;
|
| + key_is_added_ = false;
|
| +
|
| StartStatus status = StartPlaybackDecoders();
|
|
|
| switch (status) {
|
| @@ -909,6 +1038,9 @@ void MediaCodecPlayer::StartPlaybackOrBrowserSeek() {
|
| StopDecoders();
|
| RequestDemuxerSeek(GetInterpolatedTime(), true);
|
| break;
|
| + case kStartCryptoRequired:
|
| + SetState(kStateWaitingForCrypto);
|
| + break;
|
| case kStartFailed:
|
| GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_);
|
| break;
|
| @@ -946,29 +1078,26 @@ MediaCodecPlayer::StartStatus MediaCodecPlayer::ConfigureDecoders() {
|
| // prefetch state and never call this method.
|
| DCHECK(do_audio || do_video);
|
|
|
| - // Start with video: if browser seek is required it would
|
| - // not make sense to configure audio.
|
| + // Start with video: if browser seek is required it would not make sense to
|
| + // configure audio.
|
|
|
| - if (do_video) {
|
| - MediaCodecDecoder::ConfigStatus status = video_decoder_->Configure();
|
| - switch (status) {
|
| - case MediaCodecDecoder::kConfigOk:
|
| - break;
|
| - case MediaCodecDecoder::kConfigKeyFrameRequired:
|
| - // TODO(timav): post a task or return the status?
|
| - return kStartBrowserSeekRequired;
|
| - case MediaCodecDecoder::kConfigFailure:
|
| - return kStartFailed;
|
| - }
|
| - }
|
| + MediaCodecDecoder::ConfigStatus status = MediaCodecDecoder::kConfigOk;
|
| + if (do_video)
|
| + status = video_decoder_->Configure();
|
| +
|
| + if (status == MediaCodecDecoder::kConfigOk && do_audio)
|
| + status = audio_decoder_->Configure();
|
|
|
| - if (do_audio) {
|
| - MediaCodecDecoder::ConfigStatus status = audio_decoder_->Configure();
|
| - if (status != MediaCodecDecoder::kConfigOk) {
|
| + switch (status) {
|
| + case MediaCodecDecoder::kConfigOk:
|
| + break;
|
| + case MediaCodecDecoder::kConfigKeyFrameRequired:
|
| + return kStartBrowserSeekRequired;
|
| + case MediaCodecDecoder::kConfigNoCrypto:
|
| + return kStartCryptoRequired;
|
| + case MediaCodecDecoder::kConfigFailure:
|
| return kStartFailed;
|
| - }
|
| }
|
| -
|
| return kStartOk;
|
| }
|
|
|
| @@ -1127,6 +1256,8 @@ void MediaCodecPlayer::CreateDecoders() {
|
| DemuxerStream::AUDIO),
|
| base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_,
|
| DemuxerStream::AUDIO),
|
| + base::Bind(&MediaCodecPlayer::OnKeyRequired, media_weak_this_,
|
| + DemuxerStream::AUDIO),
|
| internal_error_cb_,
|
| base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate, media_weak_this_,
|
| DemuxerStream::AUDIO)));
|
| @@ -1140,6 +1271,8 @@ void MediaCodecPlayer::CreateDecoders() {
|
| DemuxerStream::VIDEO),
|
| base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_,
|
| DemuxerStream::VIDEO),
|
| + base::Bind(&MediaCodecPlayer::OnKeyRequired, media_weak_this_,
|
| + DemuxerStream::VIDEO),
|
| internal_error_cb_,
|
| base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate, media_weak_this_,
|
| DemuxerStream::VIDEO),
|
| @@ -1175,6 +1308,8 @@ const char* MediaCodecPlayer::AsString(PlayerState state) {
|
| RETURN_STRING(kStatePlaying);
|
| RETURN_STRING(kStateStopping);
|
| RETURN_STRING(kStateWaitingForSurface);
|
| + RETURN_STRING(kStateWaitingForKey);
|
| + RETURN_STRING(kStateWaitingForCrypto);
|
| RETURN_STRING(kStateWaitingForSeek);
|
| RETURN_STRING(kStateError);
|
| }
|
|
|