Index: media/base/android/media_source_player.cc |
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc |
index c7bc09ae2584d4160b7603c7c9809e034a6beab5..9b10b7850f86501619243712f01b1f66c56813e5 100644 |
--- a/media/base/android/media_source_player.cc |
+++ b/media/base/android/media_source_player.cc |
@@ -35,30 +35,30 @@ MediaSourcePlayer::MediaSourcePlayer( |
release_media_resources_cb), |
demuxer_(demuxer.Pass()), |
pending_event_(NO_EVENT_PENDING), |
- width_(0), |
- height_(0), |
- audio_codec_(kUnknownAudioCodec), |
- video_codec_(kUnknownVideoCodec), |
- num_channels_(0), |
- sampling_rate_(0), |
- reached_audio_eos_(false), |
- reached_video_eos_(false), |
playing_(false), |
- is_audio_encrypted_(false), |
- is_video_encrypted_(false), |
- volume_(-1.0), |
clock_(&default_tick_clock_), |
- next_video_data_is_iframe_(true), |
doing_browser_seek_(false), |
pending_seek_(false), |
- reconfig_audio_decoder_(false), |
- reconfig_video_decoder_(false), |
drm_bridge_(NULL), |
cdm_registration_id_(0), |
is_waiting_for_key_(false), |
- has_pending_audio_data_request_(false), |
- has_pending_video_data_request_(false), |
+ is_waiting_for_audio_decoder_(false), |
+ is_waiting_for_video_decoder_(false), |
weak_factory_(this) { |
+ audio_decoder_job_.reset(new AudioDecoderJob( |
+ base::Bind(&DemuxerAndroid::RequestDemuxerData, |
+ base::Unretained(demuxer_.get()), |
+ DemuxerStream::AUDIO), |
+ base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, |
+ weak_factory_.GetWeakPtr()))); |
+ video_decoder_job_.reset(new VideoDecoderJob( |
+ base::Bind(&DemuxerAndroid::RequestDemuxerData, |
+ base::Unretained(demuxer_.get()), |
+ DemuxerStream::VIDEO), |
+ base::Bind(request_media_resources_cb_, player_id), |
+ base::Bind(release_media_resources_cb_, player_id), |
+ base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, |
+ weak_factory_.GetWeakPtr()))); |
demuxer_->Initialize(this); |
clock_.SetMaxTime(base::TimeDelta()); |
weak_this_ = weak_factory_.GetWeakPtr(); |
@@ -74,38 +74,11 @@ MediaSourcePlayer::~MediaSourcePlayer() { |
} |
void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { |
- // For an empty surface, always pass it to the decoder job so that it |
- // can detach from the current one. Otherwise, don't pass an unprotected |
- // surface if the video content requires a protected one. |
- if (!surface.IsEmpty() && |
- IsProtectedSurfaceRequired() && !surface.is_protected()) { |
- return; |
- } |
- |
- surface_ = surface.Pass(); |
- is_surface_in_use_ = true; |
- |
- // If there is a pending surface change event, just wait for it to be |
- // processed. |
- if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING)) |
- return; |
- |
- // Eventual processing of surface change will take care of feeding the new |
- // video decoder initially with I-frame. See b/8950387. |
- SetPendingEvent(SURFACE_CHANGE_EVENT_PENDING); |
- |
- // If seek is already pending, processing of the pending surface change |
- // event will occur in OnDemuxerSeekDone(). |
- if (IsEventPending(SEEK_EVENT_PENDING)) |
- return; |
- |
- // If video config change is already pending, processing of the pending |
- // surface change event will occur in OnDemuxerConfigsAvailable(). |
- if (reconfig_video_decoder_ && IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) |
+ DVLOG(1) << __FUNCTION__; |
+ if (!video_decoder_job_->SetVideoSurface(surface.Pass())) |
return; |
- |
- // Otherwise we need to trigger pending event processing now. |
- ProcessPendingEvents(); |
+ // Retry video decoder creation. |
+ RetryDecoderCreation(false, true); |
} |
void MediaSourcePlayer::ScheduleSeekEventAndStopDecoding( |
@@ -117,9 +90,9 @@ void MediaSourcePlayer::ScheduleSeekEventAndStopDecoding( |
clock_.SetTime(seek_time, seek_time); |
- if (audio_decoder_job_ && audio_decoder_job_->is_decoding()) |
+ if (audio_decoder_job_->is_decoding()) |
audio_decoder_job_->StopDecode(); |
- if (video_decoder_job_ && video_decoder_job_->is_decoding()) |
+ if (video_decoder_job_->is_decoding()) |
video_decoder_job_->StopDecode(); |
SetPendingEvent(SEEK_EVENT_PENDING); |
@@ -171,11 +144,11 @@ bool MediaSourcePlayer::IsPlaying() { |
} |
int MediaSourcePlayer::GetVideoWidth() { |
- return width_; |
+ return video_decoder_job_->width(); |
} |
int MediaSourcePlayer::GetVideoHeight() { |
- return height_; |
+ return video_decoder_job_->height(); |
} |
void MediaSourcePlayer::SeekTo(base::TimeDelta timestamp) { |
@@ -208,42 +181,18 @@ base::TimeDelta MediaSourcePlayer::GetDuration() { |
void MediaSourcePlayer::Release() { |
DVLOG(1) << __FUNCTION__; |
- // Allow pending seeks and config changes to survive this Release(). |
- // If previously pending a prefetch done event, or a job was still decoding, |
- // then at end of Release() we need to ProcessPendingEvents() to process any |
- // seek or config change that was blocked by the prefetch or decode. |
- // TODO(qinmin/wolenetz): Maintain channel state to not double-request data |
- // or drop data received across Release()+Start(). See http://crbug.com/306314 |
- // and http://crbug.com/304234. |
- bool process_pending_events = false; |
- process_pending_events = IsEventPending(PREFETCH_DONE_EVENT_PENDING) || |
- (audio_decoder_job_ && audio_decoder_job_->is_decoding()) || |
- (video_decoder_job_ && video_decoder_job_->is_decoding()); |
- |
- // Clear all the pending events except seeks and config changes. |
- pending_event_ &= (SEEK_EVENT_PENDING | CONFIG_CHANGE_EVENT_PENDING); |
is_surface_in_use_ = false; |
- ResetAudioDecoderJob(); |
- ResetVideoDecoderJob(); |
- |
- // Prevent job re-creation attempts in OnDemuxerConfigsAvailable() |
- reconfig_audio_decoder_ = false; |
- reconfig_video_decoder_ = false; |
+ audio_decoder_job_->ReleaseDecoderResources(); |
+ video_decoder_job_->ReleaseDecoderResources(); |
// Prevent player restart, including job re-creation attempts. |
playing_ = false; |
decoder_starvation_callback_.Cancel(); |
- surface_ = gfx::ScopedJavaSurface(); |
- if (process_pending_events) { |
- DVLOG(1) << __FUNCTION__ << " : Resuming seek or config change processing"; |
- ProcessPendingEvents(); |
- } |
} |
void MediaSourcePlayer::SetVolume(double volume) { |
- volume_ = volume; |
- SetVolumeInternal(); |
+ audio_decoder_job_->SetVolume(volume); |
} |
bool MediaSourcePlayer::IsSurfaceInUse() const { |
@@ -277,16 +226,6 @@ void MediaSourcePlayer::StartInternal() { |
// |is_waiting_for_key_| condition may not be true anymore. |
is_waiting_for_key_ = false; |
- // Create decoder jobs if they are not created |
- ConfigureAudioDecoderJob(); |
- ConfigureVideoDecoderJob(); |
- |
- // If one of the decoder job is not ready, do nothing. |
- if ((HasAudio() && !audio_decoder_job_) || |
- (HasVideo() && !video_decoder_job_)) { |
- return; |
- } |
- |
SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
ProcessPendingEvents(); |
} |
@@ -298,11 +237,9 @@ void MediaSourcePlayer::OnDemuxerConfigsAvailable( |
duration_ = configs.duration; |
clock_.SetDuration(duration_); |
- SetDemuxerConfigs(configs, true); |
- SetDemuxerConfigs(configs, false); |
- |
- manager()->OnMediaMetadataChanged( |
- player_id(), duration_, width_, height_, true); |
+ audio_decoder_job_->SetDemuxerConfigs(configs); |
+ video_decoder_job_->SetDemuxerConfigs(configs); |
+ OnDemuxerConfigsChanged(); |
} |
void MediaSourcePlayer::OnDemuxerDataAvailable(const DemuxerData& data) { |
@@ -310,26 +247,10 @@ void MediaSourcePlayer::OnDemuxerDataAvailable(const DemuxerData& data) { |
DCHECK_LT(0u, data.access_units.size()); |
CHECK_GE(1u, data.demuxer_configs.size()); |
- if (has_pending_audio_data_request_ && data.type == DemuxerStream::AUDIO) { |
- has_pending_audio_data_request_ = false; |
- ProcessPendingEvents(); |
- return; |
- } |
- |
- if (has_pending_video_data_request_ && data.type == DemuxerStream::VIDEO) { |
- next_video_data_is_iframe_ = false; |
- has_pending_video_data_request_ = false; |
- ProcessPendingEvents(); |
- return; |
- } |
- |
- if (data.type == DemuxerStream::AUDIO && audio_decoder_job_) { |
+ if (data.type == DemuxerStream::AUDIO) |
audio_decoder_job_->OnDataReceived(data); |
- } else if (data.type == DemuxerStream::VIDEO) { |
- next_video_data_is_iframe_ = false; |
- if (video_decoder_job_) |
- video_decoder_job_->OnDataReceived(data); |
- } |
+ else if (data.type == DemuxerStream::VIDEO) |
+ video_decoder_job_->OnDataReceived(data); |
} |
void MediaSourcePlayer::OnDemuxerDurationChanged(base::TimeDelta duration) { |
@@ -337,19 +258,12 @@ void MediaSourcePlayer::OnDemuxerDurationChanged(base::TimeDelta duration) { |
clock_.SetDuration(duration_); |
} |
-base::android::ScopedJavaLocalRef<jobject> MediaSourcePlayer::GetMediaCrypto() { |
- base::android::ScopedJavaLocalRef<jobject> media_crypto; |
- if (drm_bridge_) |
- media_crypto = drm_bridge_->GetMediaCrypto(); |
- return media_crypto; |
-} |
- |
void MediaSourcePlayer::OnMediaCryptoReady() { |
DCHECK(!drm_bridge_->GetMediaCrypto().is_null()); |
drm_bridge_->SetMediaCryptoReadyCB(base::Closure()); |
- if (playing_) |
- StartInternal(); |
+ // Retry decoder creation if the decoders are waiting for MediaCrypto. |
+ RetryDecoderCreation(true, true); |
} |
void MediaSourcePlayer::SetCdm(BrowserCdm* cdm) { |
@@ -374,14 +288,17 @@ void MediaSourcePlayer::SetCdm(BrowserCdm* cdm) { |
base::Bind(&MediaSourcePlayer::OnKeyAdded, weak_this_), |
base::Bind(&MediaSourcePlayer::OnCdmUnset, weak_this_)); |
+ audio_decoder_job_->SetDrmBridge(drm_bridge_); |
wolenetz
2014/06/04 21:42:24
Should these two be done prior to registering the
qinmin
2014/06/04 22:34:03
This won't happen. RegisterPlayer() is a simple fu
|
+ video_decoder_job_->SetDrmBridge(drm_bridge_); |
+ |
if (drm_bridge_->GetMediaCrypto().is_null()) { |
drm_bridge_->SetMediaCryptoReadyCB( |
base::Bind(&MediaSourcePlayer::OnMediaCryptoReady, weak_this_)); |
return; |
} |
- if (playing_) |
- StartInternal(); |
+ // If the player is previously waiting for CDM, retry decoder creation. |
+ RetryDecoderCreation(true, true); |
} |
void MediaSourcePlayer::OnDemuxerSeekDone( |
@@ -392,8 +309,6 @@ void MediaSourcePlayer::OnDemuxerSeekDone( |
if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) |
ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
- next_video_data_is_iframe_ = true; |
- |
if (pending_seek_) { |
DVLOG(1) << __FUNCTION__ << "processing pending seek"; |
DCHECK(doing_browser_seek_); |
@@ -414,24 +329,20 @@ void MediaSourcePlayer::OnDemuxerSeekDone( |
DVLOG(1) << __FUNCTION__ << " : setting clock to actual browser seek time: " |
<< seek_time.InSecondsF(); |
clock_.SetTime(seek_time, seek_time); |
- if (audio_decoder_job_) |
- audio_decoder_job_->SetBaseTimestamp(seek_time); |
+ audio_decoder_job_->SetBaseTimestamp(seek_time); |
} else { |
DCHECK(actual_browser_seek_time == kNoTimestamp()); |
} |
- reached_audio_eos_ = false; |
- reached_video_eos_ = false; |
- |
base::TimeDelta current_time = GetCurrentTime(); |
// TODO(qinmin): Simplify the logic by using |start_presentation_timestamp_| |
// to preroll media decoder jobs. Currently |start_presentation_timestamp_| |
// is calculated from decoder output, while preroll relies on the access |
// unit's timestamp. There are some differences between the two. |
preroll_timestamp_ = current_time; |
- if (audio_decoder_job_) |
+ if (HasAudio()) |
audio_decoder_job_->BeginPrerolling(preroll_timestamp_); |
- if (video_decoder_job_) |
+ if (HasVideo()) |
video_decoder_job_->BeginPrerolling(preroll_timestamp_); |
if (!doing_browser_seek_) |
@@ -444,28 +355,22 @@ void MediaSourcePlayer::UpdateTimestamps( |
base::TimeDelta current_presentation_timestamp, |
base::TimeDelta max_presentation_timestamp) { |
clock_.SetTime(current_presentation_timestamp, max_presentation_timestamp); |
- |
manager()->OnTimeUpdate(player_id(), GetCurrentTime()); |
} |
void MediaSourcePlayer::ProcessPendingEvents() { |
DVLOG(1) << __FUNCTION__ << " : 0x" << std::hex << pending_event_; |
// Wait for all the decoding jobs to finish before processing pending tasks. |
- if (video_decoder_job_ && video_decoder_job_->is_decoding()) { |
+ if (video_decoder_job_->is_decoding()) { |
DVLOG(1) << __FUNCTION__ << " : A video job is still decoding."; |
return; |
} |
- if (audio_decoder_job_ && audio_decoder_job_->is_decoding()) { |
+ if (audio_decoder_job_->is_decoding()) { |
DVLOG(1) << __FUNCTION__ << " : An audio job is still decoding."; |
return; |
} |
- if (has_pending_audio_data_request_ || has_pending_video_data_request_) { |
- DVLOG(1) << __FUNCTION__ << " : has pending data request."; |
- return; |
- } |
- |
if (IsEventPending(PREFETCH_DONE_EVENT_PENDING)) { |
DVLOG(1) << __FUNCTION__ << " : PREFETCH_DONE still pending."; |
return; |
@@ -474,52 +379,20 @@ void MediaSourcePlayer::ProcessPendingEvents() { |
if (IsEventPending(SEEK_EVENT_PENDING)) { |
DVLOG(1) << __FUNCTION__ << " : Handling SEEK_EVENT"; |
ClearDecodingData(); |
- if (audio_decoder_job_) |
- audio_decoder_job_->SetBaseTimestamp(GetCurrentTime()); |
+ audio_decoder_job_->SetBaseTimestamp(GetCurrentTime()); |
demuxer_->RequestDemuxerSeek(GetCurrentTime(), doing_browser_seek_); |
return; |
} |
- start_time_ticks_ = base::TimeTicks(); |
- if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) { |
- DVLOG(1) << __FUNCTION__ << " : Handling CONFIG_CHANGE_EVENT."; |
- DCHECK(reconfig_audio_decoder_ || reconfig_video_decoder_); |
- manager()->OnMediaMetadataChanged( |
- player_id(), duration_, width_, height_, true); |
- |
- if (reconfig_audio_decoder_) |
- ConfigureAudioDecoderJob(); |
- |
- if (reconfig_video_decoder_) |
- ConfigureVideoDecoderJob(); |
- |
- ClearPendingEvent(CONFIG_CHANGE_EVENT_PENDING); |
- } |
- |
- if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING)) { |
- DVLOG(1) << __FUNCTION__ << " : Handling SURFACE_CHANGE_EVENT."; |
- // Setting a new surface will require a new MediaCodec to be created. |
- ResetVideoDecoderJob(); |
- ConfigureVideoDecoderJob(); |
- |
- // Return early if we can't successfully configure a new video decoder job |
- // yet. |
- if (HasVideo() && !video_decoder_job_) |
+ if (IsEventPending(DECODER_CREATION_EVENT_PENDING)) { |
+ // Don't continue if one of the decoder is not created. |
+ if (is_waiting_for_audio_decoder_ || is_waiting_for_video_decoder_) |
return; |
+ ClearPendingEvent(DECODER_CREATION_EVENT_PENDING); |
} |
if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) { |
DVLOG(1) << __FUNCTION__ << " : Handling PREFETCH_REQUEST_EVENT."; |
- // If one of the decoder is not initialized, cancel this event as it will be |
- // called later when Start() is called again. |
- if ((HasVideo() && !video_decoder_job_) || |
- (HasAudio() && !audio_decoder_job_)) { |
- ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
- return; |
- } |
- |
- DCHECK(audio_decoder_job_ || AudioFinished()); |
- DCHECK(video_decoder_job_ || VideoFinished()); |
int count = (AudioFinished() ? 0 : 1) + (VideoFinished() ? 0 : 1); |
// It is possible that all streams have finished decode, yet starvation |
@@ -597,10 +470,10 @@ void MediaSourcePlayer::MediaDecoderCallback( |
return; |
} |
- if (status == MEDIA_CODEC_OK && is_clock_manager && |
- current_presentation_timestamp != kNoTimestamp()) { |
- UpdateTimestamps( |
- current_presentation_timestamp, max_presentation_timestamp); |
+ if ((status == MEDIA_CODEC_OK || status == MEDIA_CODEC_INPUT_END_OF_STREAM) && |
+ is_clock_manager && current_presentation_timestamp != kNoTimestamp()) { |
+ UpdateTimestamps(current_presentation_timestamp, |
+ max_presentation_timestamp); |
} |
if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) |
@@ -646,9 +519,6 @@ void MediaSourcePlayer::MediaDecoderCallback( |
DecodeMoreAudio(); |
else |
DecodeMoreVideo(); |
- |
- if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) |
- ProcessPendingEvents(); |
} |
void MediaSourcePlayer::DecodeMoreAudio() { |
@@ -656,29 +526,18 @@ void MediaSourcePlayer::DecodeMoreAudio() { |
DCHECK(!audio_decoder_job_->is_decoding()); |
DCHECK(!AudioFinished()); |
- scoped_ptr<DemuxerConfigs> configs(audio_decoder_job_->Decode( |
+ if (audio_decoder_job_->Decode( |
start_time_ticks_, |
start_presentation_timestamp_, |
- base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, true))); |
- if (!configs) { |
+ base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, true))) { |
TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreAudio", |
audio_decoder_job_.get()); |
return; |
} |
- // Failed to start the next decode. |
- DCHECK(!reconfig_audio_decoder_); |
- reconfig_audio_decoder_ = true; |
- SetDemuxerConfigs(*configs, true); |
- |
- // Config change may have just been detected on the other stream. If so, |
- // don't send a duplicate demuxer config request. |
- if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) { |
- DCHECK(reconfig_video_decoder_); |
- return; |
- } |
- |
- SetPendingEvent(CONFIG_CHANGE_EVENT_PENDING); |
+ is_waiting_for_audio_decoder_ = true; |
+ if (!IsEventPending(DECODER_CREATION_EVENT_PENDING)) |
+ SetPendingEvent(DECODER_CREATION_EVENT_PENDING); |
} |
void MediaSourcePlayer::DecodeMoreVideo() { |
@@ -686,41 +545,29 @@ void MediaSourcePlayer::DecodeMoreVideo() { |
DCHECK(!video_decoder_job_->is_decoding()); |
DCHECK(!VideoFinished()); |
- scoped_ptr<DemuxerConfigs> configs(video_decoder_job_->Decode( |
+ if (video_decoder_job_->Decode( |
start_time_ticks_, |
start_presentation_timestamp_, |
- base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, false))); |
- if (!configs) { |
+ base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, |
+ false))) { |
TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreVideo", |
video_decoder_job_.get()); |
return; |
} |
- // Failed to start the next decode. |
- // After this detection of video config change, next video data received |
- // will begin with I-frame. |
- next_video_data_is_iframe_ = true; |
- |
- DCHECK(!reconfig_video_decoder_); |
- reconfig_video_decoder_ = true; |
- SetDemuxerConfigs(*configs, false); |
- |
- // Config change may have just been detected on the other stream. If so, |
- // don't send a duplicate demuxer config request. |
- if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) { |
- DCHECK(reconfig_audio_decoder_); |
+ // If the decoder is waiting for iframe, trigger a browser seek. |
+ if (!video_decoder_job_->next_video_data_is_iframe()) { |
+ BrowserSeekToCurrentTime(); |
return; |
} |
- SetPendingEvent(CONFIG_CHANGE_EVENT_PENDING); |
+ is_waiting_for_video_decoder_ = true; |
+ if (!IsEventPending(DECODER_CREATION_EVENT_PENDING)) |
+ SetPendingEvent(DECODER_CREATION_EVENT_PENDING); |
} |
void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { |
DVLOG(1) << __FUNCTION__ << "(" << is_audio << ")"; |
- if (is_audio) |
- reached_audio_eos_ = true; |
- else |
- reached_video_eos_ = true; |
if (AudioFinished() && VideoFinished()) { |
playing_ = false; |
@@ -732,154 +579,25 @@ void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { |
void MediaSourcePlayer::ClearDecodingData() { |
DVLOG(1) << __FUNCTION__; |
- if (audio_decoder_job_) |
- audio_decoder_job_->Flush(); |
- if (video_decoder_job_) |
- video_decoder_job_->Flush(); |
+ audio_decoder_job_->Flush(); |
+ video_decoder_job_->Flush(); |
start_time_ticks_ = base::TimeTicks(); |
} |
bool MediaSourcePlayer::HasVideo() { |
- return kUnknownVideoCodec != video_codec_; |
+ return video_decoder_job_->HasStream(); |
} |
bool MediaSourcePlayer::HasAudio() { |
- return kUnknownAudioCodec != audio_codec_; |
+ return audio_decoder_job_->HasStream(); |
} |
bool MediaSourcePlayer::AudioFinished() { |
- return reached_audio_eos_ || !HasAudio(); |
+ return audio_decoder_job_->OutputEOSReached() || !HasAudio(); |
} |
bool MediaSourcePlayer::VideoFinished() { |
- return reached_video_eos_ || !HasVideo(); |
-} |
- |
-void MediaSourcePlayer::ConfigureAudioDecoderJob() { |
- if (!HasAudio()) { |
- ResetAudioDecoderJob(); |
- return; |
- } |
- |
- // Create audio decoder job only if config changes. |
- if (audio_decoder_job_ && !reconfig_audio_decoder_) |
- return; |
- |
- base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto(); |
- if (is_audio_encrypted_ && media_crypto.is_null()) |
- return; |
- |
- DCHECK(!audio_decoder_job_ || !audio_decoder_job_->is_decoding()); |
- |
- ResetAudioDecoderJob(); |
- DVLOG(1) << __FUNCTION__ << " : creating new audio decoder job"; |
- audio_decoder_job_.reset(AudioDecoderJob::Create( |
- audio_codec_, sampling_rate_, num_channels_, &audio_extra_data_[0], |
- audio_extra_data_.size(), media_crypto.obj(), |
- base::Bind(&DemuxerAndroid::RequestDemuxerData, |
- base::Unretained(demuxer_.get()), DemuxerStream::AUDIO))); |
- |
- if (audio_decoder_job_) { |
- SetVolumeInternal(); |
- // Need to reset the base timestamp in |audio_decoder_job_|. |
- // TODO(qinmin): When reconfiguring the |audio_decoder_job_|, there might |
- // still be some audio frames in the decoder or in AudioTrack. Therefore, |
- // we are losing some time here. http://crbug.com/357726. |
- base::TimeDelta current_time = GetCurrentTime(); |
- audio_decoder_job_->SetBaseTimestamp(current_time); |
- clock_.SetTime(current_time, current_time); |
- audio_decoder_job_->BeginPrerolling(preroll_timestamp_); |
- reconfig_audio_decoder_ = false; |
- } |
-} |
- |
-void MediaSourcePlayer::ResetVideoDecoderJob() { |
- if (video_decoder_job_) { |
- has_pending_video_data_request_ = |
- video_decoder_job_->is_requesting_demuxer_data(); |
- } |
- video_decoder_job_.reset(); |
- |
- // Any eventual video decoder job re-creation will use the current |surface_|. |
- if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING)) |
- ClearPendingEvent(SURFACE_CHANGE_EVENT_PENDING); |
-} |
- |
-void MediaSourcePlayer::ResetAudioDecoderJob() { |
- if (audio_decoder_job_) { |
- has_pending_audio_data_request_ = |
- audio_decoder_job_->is_requesting_demuxer_data(); |
- } |
- audio_decoder_job_.reset(); |
-} |
- |
-void MediaSourcePlayer::ConfigureVideoDecoderJob() { |
- if (!HasVideo() || surface_.IsEmpty()) { |
- ResetVideoDecoderJob(); |
- return; |
- } |
- |
- // Create video decoder job only if config changes or we don't have a job. |
- if (video_decoder_job_ && !reconfig_video_decoder_) { |
- DCHECK(!IsEventPending(SURFACE_CHANGE_EVENT_PENDING)); |
- return; |
- } |
- |
- DCHECK(!video_decoder_job_ || !video_decoder_job_->is_decoding()); |
- |
- if (reconfig_video_decoder_) { |
- // No hack browser seek should be required. I-Frame must be next. |
- DCHECK(next_video_data_is_iframe_) << "Received video data between " |
- << "detecting video config change and reconfiguring video decoder"; |
- } |
- |
- // If uncertain that video I-frame data is next and there is no seek already |
- // in process, request browser demuxer seek so the new decoder will decode |
- // an I-frame first. Otherwise, the new MediaCodec might crash. See b/8950387. |
- // Eventual OnDemuxerSeekDone() will trigger ProcessPendingEvents() and |
- // continue from here. |
- // TODO(wolenetz): Instead of doing hack browser seek, replay cached data |
- // since last keyframe. See http://crbug.com/304234. |
- if (!next_video_data_is_iframe_ && !IsEventPending(SEEK_EVENT_PENDING)) { |
- BrowserSeekToCurrentTime(); |
- return; |
- } |
- |
- // Release the old VideoDecoderJob first so the surface can get released. |
- // Android does not allow 2 MediaCodec instances use the same surface. |
- ResetVideoDecoderJob(); |
- |
- base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto(); |
- if (is_video_encrypted_ && media_crypto.is_null()) |
- return; |
- |
- DVLOG(1) << __FUNCTION__ << " : creating new video decoder job"; |
- |
- // Create the new VideoDecoderJob. |
- bool is_secure = IsProtectedSurfaceRequired(); |
- video_decoder_job_.reset( |
- VideoDecoderJob::Create( |
- video_codec_, |
- is_secure, |
- gfx::Size(width_, height_), |
- surface_.j_surface().obj(), |
- media_crypto.obj(), |
- base::Bind(&DemuxerAndroid::RequestDemuxerData, |
- base::Unretained(demuxer_.get()), |
- DemuxerStream::VIDEO), |
- base::Bind(request_media_resources_cb_, player_id()), |
- base::Bind(release_media_resources_cb_, player_id()))); |
- if (!video_decoder_job_) |
- return; |
- |
- video_decoder_job_->BeginPrerolling(preroll_timestamp_); |
- reconfig_video_decoder_ = false; |
- |
- // Inform the fullscreen view the player is ready. |
- // TODO(qinmin): refactor MediaPlayerBridge so that we have a better way |
- // to inform ContentVideoView. |
- manager()->OnMediaMetadataChanged( |
- player_id(), duration_, width_, height_, true); |
+ return video_decoder_job_->OutputEOSReached() || !HasVideo(); |
} |
void MediaSourcePlayer::OnDecoderStarved() { |
@@ -920,20 +638,15 @@ void MediaSourcePlayer::StartStarvationCallback( |
FROM_HERE, decoder_starvation_callback_.callback(), timeout); |
} |
-void MediaSourcePlayer::SetVolumeInternal() { |
- if (audio_decoder_job_ && volume_ >= 0) |
- audio_decoder_job_->SetVolume(volume_); |
-} |
- |
bool MediaSourcePlayer::IsProtectedSurfaceRequired() { |
- return is_video_encrypted_ && |
+ return video_decoder_job_->is_content_encrypted() && |
drm_bridge_ && drm_bridge_->IsProtectedSurfaceRequired(); |
} |
void MediaSourcePlayer::OnPrefetchDone() { |
DVLOG(1) << __FUNCTION__; |
- DCHECK(!audio_decoder_job_ || !audio_decoder_job_->is_decoding()); |
- DCHECK(!video_decoder_job_ || !video_decoder_job_->is_decoding()); |
+ DCHECK(!audio_decoder_job_->is_decoding()); |
+ DCHECK(!video_decoder_job_->is_decoding()); |
// A previously posted OnPrefetchDone() could race against a Release(). If |
// Release() won the race, we should no longer have decoder jobs. |
@@ -942,7 +655,6 @@ void MediaSourcePlayer::OnPrefetchDone() { |
// and http://crbug.com/304234. |
if (!IsEventPending(PREFETCH_DONE_EVENT_PENDING)) { |
DVLOG(1) << __FUNCTION__ << " : aborting"; |
- DCHECK(!audio_decoder_job_ && !video_decoder_job_); |
return; |
} |
@@ -953,6 +665,9 @@ void MediaSourcePlayer::OnPrefetchDone() { |
return; |
} |
+ if (!playing_) |
+ return; |
+ |
start_time_ticks_ = base::TimeTicks::Now(); |
start_presentation_timestamp_ = GetCurrentTime(); |
if (!clock_.IsPlaying()) |
@@ -963,18 +678,20 @@ void MediaSourcePlayer::OnPrefetchDone() { |
if (!VideoFinished()) |
DecodeMoreVideo(); |
+} |
- if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) |
- ProcessPendingEvents(); |
+void MediaSourcePlayer::OnDemuxerConfigsChanged() { |
+ manager()->OnMediaMetadataChanged( |
+ player_id(), duration_, GetVideoWidth(), GetVideoHeight(), true); |
} |
const char* MediaSourcePlayer::GetEventName(PendingEventFlags event) { |
+ // Please keep this in sync with PendingEventFlags. |
static const char* kPendingEventNames[] = { |
+ "PREFETCH_DONE", |
"SEEK", |
- "SURFACE_CHANGE", |
- "CONFIG_CHANGE", |
+ "DECODER_CREATION", |
"PREFETCH_REQUEST", |
- "PREFETCH_DONE", |
}; |
int mask = 1; |
@@ -1006,20 +723,13 @@ void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { |
pending_event_ &= ~event; |
} |
-void MediaSourcePlayer::SetDemuxerConfigs(const DemuxerConfigs& configs, |
- bool is_audio) { |
- if (is_audio) { |
- audio_codec_ = configs.audio_codec; |
- num_channels_ = configs.audio_channels; |
- sampling_rate_ = configs.audio_sampling_rate; |
- is_audio_encrypted_ = configs.is_audio_encrypted; |
- audio_extra_data_ = configs.audio_extra_data; |
- } else { |
- video_codec_ = configs.video_codec; |
- width_ = configs.video_size.width(); |
- height_ = configs.video_size.height(); |
- is_video_encrypted_ = configs.is_video_encrypted; |
- } |
+void MediaSourcePlayer::RetryDecoderCreation(bool audio, bool video) { |
+ if (audio) |
+ is_waiting_for_audio_decoder_ = false; |
+ if (video) |
+ is_waiting_for_video_decoder_ = false; |
+ if (IsEventPending(DECODER_CREATION_EVENT_PENDING)) |
+ ProcessPendingEvents(); |
} |
void MediaSourcePlayer::OnKeyAdded() { |