Commit ae2b37fe authored by qinmin's avatar qinmin Committed by Commit bot

Use cached Key frames to avoid browser seek

This change allows MediaSourcePlayer to skip browser seek if a key frame is found in cache.
Key frames can be identified by an empty data buffer, a config change or is_key_frame field.

BUG=304234

Review URL: https://codereview.chromium.org/898843002

Cr-Commit-Position: refs/heads/master@{#314699}
parent 903fdfd7
...@@ -135,16 +135,17 @@ bool AudioDecoderJob::AreDemuxerConfigsChanged( ...@@ -135,16 +135,17 @@ bool AudioDecoderJob::AreDemuxerConfigsChanged(
configs.audio_extra_data.begin()); configs.audio_extra_data.begin());
} }
bool AudioDecoderJob::CreateMediaCodecBridgeInternal() { MediaDecoderJob::MediaDecoderJobStatus
AudioDecoderJob::CreateMediaCodecBridgeInternal() {
media_codec_bridge_.reset(AudioCodecBridge::Create(audio_codec_)); media_codec_bridge_.reset(AudioCodecBridge::Create(audio_codec_));
if (!media_codec_bridge_) if (!media_codec_bridge_)
return false; return STATUS_FAILURE;
if (!(static_cast<AudioCodecBridge*>(media_codec_bridge_.get()))->Start( if (!(static_cast<AudioCodecBridge*>(media_codec_bridge_.get()))->Start(
audio_codec_, config_sampling_rate_, num_channels_, &audio_extra_data_[0], audio_codec_, config_sampling_rate_, num_channels_, &audio_extra_data_[0],
audio_extra_data_.size(), true, GetMediaCrypto().obj())) { audio_extra_data_.size(), true, GetMediaCrypto().obj())) {
media_codec_bridge_.reset(); media_codec_bridge_.reset();
return false; return STATUS_FAILURE;
} }
SetVolumeInternal(); SetVolumeInternal();
...@@ -153,7 +154,7 @@ bool AudioDecoderJob::CreateMediaCodecBridgeInternal() { ...@@ -153,7 +154,7 @@ bool AudioDecoderJob::CreateMediaCodecBridgeInternal() {
frame_count_ = 0; frame_count_ = 0;
ResetTimestampHelper(); ResetTimestampHelper();
return true; return STATUS_SUCCESS;
} }
void AudioDecoderJob::SetVolumeInternal() { void AudioDecoderJob::SetVolumeInternal() {
......
...@@ -49,7 +49,7 @@ class AudioDecoderJob : public MediaDecoderJob { ...@@ -49,7 +49,7 @@ class AudioDecoderJob : public MediaDecoderJob {
virtual bool ComputeTimeToRender() const override; virtual bool ComputeTimeToRender() const override;
virtual bool AreDemuxerConfigsChanged( virtual bool AreDemuxerConfigsChanged(
const DemuxerConfigs& configs) const override; const DemuxerConfigs& configs) const override;
virtual bool CreateMediaCodecBridgeInternal() override; virtual MediaDecoderJobStatus CreateMediaCodecBridgeInternal() override;
virtual void OnOutputFormatChanged() override; virtual void OnOutputFormatChanged() override;
// Helper method to set the audio output volume. // Helper method to set the audio output volume.
......
...@@ -110,7 +110,7 @@ void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { ...@@ -110,7 +110,7 @@ void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) {
RequestData(prefetch_cb); RequestData(prefetch_cb);
} }
bool MediaDecoderJob::Decode( MediaDecoderJob::MediaDecoderJobStatus MediaDecoderJob::Decode(
base::TimeTicks start_time_ticks, base::TimeTicks start_time_ticks,
base::TimeDelta start_presentation_timestamp, base::TimeDelta start_presentation_timestamp,
const DecoderCallback& callback) { const DecoderCallback& callback) {
...@@ -120,10 +120,11 @@ bool MediaDecoderJob::Decode( ...@@ -120,10 +120,11 @@ bool MediaDecoderJob::Decode(
if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) { if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) {
if (drain_decoder_) if (drain_decoder_)
OnDecoderDrained(); OnDecoderDrained();
need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge(); MediaDecoderJobStatus status = CreateMediaCodecBridge();
need_to_reconfig_decoder_job_ = (status != STATUS_SUCCESS);
skip_eos_enqueue_ = true; skip_eos_enqueue_ = true;
if (need_to_reconfig_decoder_job_) if (need_to_reconfig_decoder_job_)
return false; return status;
} }
decode_cb_ = callback; decode_cb_ = callback;
...@@ -133,11 +134,11 @@ bool MediaDecoderJob::Decode( ...@@ -133,11 +134,11 @@ bool MediaDecoderJob::Decode(
base::Unretained(this), base::Unretained(this),
start_time_ticks, start_time_ticks,
start_presentation_timestamp)); start_presentation_timestamp));
return true; return STATUS_SUCCESS;
} }
DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp); DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp);
return true; return STATUS_SUCCESS;
} }
void MediaDecoderJob::StopDecode() { void MediaDecoderJob::StopDecode() {
...@@ -205,6 +206,32 @@ base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() { ...@@ -205,6 +206,32 @@ base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() {
return media_crypto; return media_crypto;
} }
bool MediaDecoderJob::SetCurrentFrameToPreviouslyCachedKeyFrame() {
const std::vector<AccessUnit>& access_units =
received_data_[current_demuxer_data_index_].access_units;
// If the current data chunk is empty, the player must be in an initial or
// seek state. The next access unit will always be a key frame.
if (access_units.size() == 0)
return true;
// Find key frame in all the access units the decoder have decoded,
// or is about to decode.
int i = std::min(access_unit_index_[current_demuxer_data_index_],
access_units.size() - 1);
for (; i >= 0; --i) {
// Config change is always the last access unit, and it always come with
// a key frame afterwards.
if (access_units[i].status == DemuxerStream::kConfigChanged)
return true;
if (access_units[i].is_key_frame) {
access_unit_index_[current_demuxer_data_index_] = i;
return true;
}
}
return false;
}
void MediaDecoderJob::Release() { void MediaDecoderJob::Release() {
DCHECK(ui_task_runner_->BelongsToCurrentThread()); DCHECK(ui_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
...@@ -518,11 +545,8 @@ void MediaDecoderJob::OnDecodeCompleted( ...@@ -518,11 +545,8 @@ void MediaDecoderJob::OnDecodeCompleted(
case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
case MEDIA_CODEC_OUTPUT_END_OF_STREAM: case MEDIA_CODEC_OUTPUT_END_OF_STREAM:
if (!input_eos_encountered_) { if (!input_eos_encountered_)
CurrentDataConsumed(
CurrentAccessUnit().status == DemuxerStream::kConfigChanged);
access_unit_index_[current_demuxer_data_index_]++; access_unit_index_[current_demuxer_data_index_]++;
}
break; break;
case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
...@@ -589,7 +613,7 @@ void MediaDecoderJob::RequestCurrentChunkIfEmpty() { ...@@ -589,7 +613,7 @@ void MediaDecoderJob::RequestCurrentChunkIfEmpty() {
// Requests new data if the the last access unit of the next chunk is not EOS. // Requests new data if the the last access unit of the next chunk is not EOS.
current_demuxer_data_index_ = inactive_demuxer_data_index(); current_demuxer_data_index_ = inactive_demuxer_data_index();
const AccessUnit last_access_unit = const AccessUnit& last_access_unit =
received_data_[current_demuxer_data_index_].access_units.back(); received_data_[current_demuxer_data_index_].access_units.back();
if (!last_access_unit.is_end_of_stream && if (!last_access_unit.is_end_of_stream &&
last_access_unit.status != DemuxerStream::kAborted) { last_access_unit.status != DemuxerStream::kAborted) {
...@@ -616,26 +640,26 @@ void MediaDecoderJob::OnDecoderDrained() { ...@@ -616,26 +640,26 @@ void MediaDecoderJob::OnDecoderDrained() {
// Increase the access unit index so that the new decoder will not handle // Increase the access unit index so that the new decoder will not handle
// the config change again. // the config change again.
access_unit_index_[current_demuxer_data_index_]++; access_unit_index_[current_demuxer_data_index_]++;
CurrentDataConsumed(true);
} }
bool MediaDecoderJob::CreateMediaCodecBridge() { MediaDecoderJob::MediaDecoderJobStatus
MediaDecoderJob::CreateMediaCodecBridge() {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
DCHECK(ui_task_runner_->BelongsToCurrentThread()); DCHECK(ui_task_runner_->BelongsToCurrentThread());
DCHECK(decode_cb_.is_null()); DCHECK(decode_cb_.is_null());
if (!HasStream()) { if (!HasStream()) {
ReleaseMediaCodecBridge(); ReleaseMediaCodecBridge();
return false; return STATUS_FAILURE;
} }
// Create |media_codec_bridge_| only if config changes. // Create |media_codec_bridge_| only if config changes.
if (media_codec_bridge_ && !need_to_reconfig_decoder_job_) if (media_codec_bridge_ && !need_to_reconfig_decoder_job_)
return true; return STATUS_SUCCESS;
base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto(); base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto();
if (is_content_encrypted_ && media_crypto.is_null()) if (is_content_encrypted_ && media_crypto.is_null())
return false; return STATUS_FAILURE;
ReleaseMediaCodecBridge(); ReleaseMediaCodecBridge();
DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge"; DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge";
......
...@@ -27,6 +27,13 @@ class MediaDrmBridge; ...@@ -27,6 +27,13 @@ class MediaDrmBridge;
// data request will be sent to the renderer. // data request will be sent to the renderer.
class MediaDecoderJob { class MediaDecoderJob {
public: public:
// Return value when Decode() is called.
enum MediaDecoderJobStatus {
STATUS_SUCCESS,
STATUS_KEY_FRAME_REQUIRED,
STATUS_FAILURE,
};
struct Deleter { struct Deleter {
inline void operator()(MediaDecoderJob* ptr) const { ptr->Release(); } inline void operator()(MediaDecoderJob* ptr) const { ptr->Release(); }
}; };
...@@ -57,11 +64,10 @@ class MediaDecoderJob { ...@@ -57,11 +64,10 @@ class MediaDecoderJob {
// Called by MediaSourcePlayer to decode some data. // Called by MediaSourcePlayer to decode some data.
// |callback| - Run when decode operation has completed. // |callback| - Run when decode operation has completed.
// //
// Returns true if the next decode was started and |callback| will be // Returns STATUS_SUCCESS on success, or STATUS_FAILURE on failure, or
// called when the decode operation is complete. // STATUS_KEY_FRAME_REQUIRED if a browser seek is required. |callback| is
// Returns false if |media_codec_bridge_| cannot be created; |callback| is // ignored and will not be called for the latter 2 cases.
// ignored and will not be called. MediaDecoderJobStatus Decode(base::TimeTicks start_time_ticks,
bool Decode(base::TimeTicks start_time_ticks,
base::TimeDelta start_presentation_timestamp, base::TimeDelta start_presentation_timestamp,
const DecoderCallback& callback); const DecoderCallback& callback);
...@@ -132,6 +138,11 @@ class MediaDecoderJob { ...@@ -132,6 +138,11 @@ class MediaDecoderJob {
// Releases the |media_codec_bridge_|. // Releases the |media_codec_bridge_|.
void ReleaseMediaCodecBridge(); void ReleaseMediaCodecBridge();
// Sets the current frame to a previously cached key frame. Returns true if
// a key frame is found, or false otherwise.
// TODO(qinmin): add UMA to study the cache hit ratio for key frames.
bool SetCurrentFrameToPreviouslyCachedKeyFrame();
MediaDrmBridge* drm_bridge() { return drm_bridge_; } MediaDrmBridge* drm_bridge() { return drm_bridge_; }
void set_is_content_encrypted(bool is_content_encrypted) { void set_is_content_encrypted(bool is_content_encrypted) {
...@@ -209,18 +220,16 @@ class MediaDecoderJob { ...@@ -209,18 +220,16 @@ class MediaDecoderJob {
// Called when the decoder is completely drained and is ready to be released. // Called when the decoder is completely drained and is ready to be released.
void OnDecoderDrained(); void OnDecoderDrained();
// Creates |media_codec_bridge_| for decoding purpose. Returns true if it is // Creates |media_codec_bridge_| for decoding purpose.
// created, or false otherwise. // Returns STATUS_SUCCESS on success, or STATUS_FAILURE on failure, or
bool CreateMediaCodecBridge(); // STATUS_KEY_FRAME_REQUIRED if a browser seek is required.
MediaDecoderJobStatus CreateMediaCodecBridge();
// Called when an access unit is consumed by the decoder. |is_config_change|
// indicates whether the current access unit is a config change. If it is
// true, the next access unit is guarateed to be an I-frame.
virtual void CurrentDataConsumed(bool is_config_change) {}
// Implemented by the child class to create |media_codec_bridge_| for a // Implemented by the child class to create |media_codec_bridge_| for a
// particular stream. Returns true if it is created, or false otherwise. // particular stream.
virtual bool CreateMediaCodecBridgeInternal() = 0; // Returns STATUS_SUCCESS on success, or STATUS_FAILURE on failure, or
// STATUS_KEY_FRAME_REQUIRED if a browser seek is required.
virtual MediaDecoderJobStatus CreateMediaCodecBridgeInternal() = 0;
// Returns true if the |configs| doesn't match the current demuxer configs // Returns true if the |configs| doesn't match the current demuxer configs
// the decoder job has. // the decoder job has.
......
...@@ -564,18 +564,25 @@ void MediaSourcePlayer::DecodeMoreAudio() { ...@@ -564,18 +564,25 @@ void MediaSourcePlayer::DecodeMoreAudio() {
DCHECK(!audio_decoder_job_->is_decoding()); DCHECK(!audio_decoder_job_->is_decoding());
DCHECK(!AudioFinished()); DCHECK(!AudioFinished());
if (audio_decoder_job_->Decode( MediaDecoderJob::MediaDecoderJobStatus status = audio_decoder_job_->Decode(
start_time_ticks_, start_time_ticks_,
start_presentation_timestamp_, start_presentation_timestamp_,
base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, true))) { base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, true));
switch (status) {
case MediaDecoderJob::STATUS_SUCCESS:
TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreAudio", TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreAudio",
audio_decoder_job_.get()); audio_decoder_job_.get());
return; break;
} case MediaDecoderJob::STATUS_KEY_FRAME_REQUIRED:
NOTREACHED();
break;
case MediaDecoderJob::STATUS_FAILURE:
is_waiting_for_audio_decoder_ = true; is_waiting_for_audio_decoder_ = true;
if (!IsEventPending(DECODER_CREATION_EVENT_PENDING)) if (!IsEventPending(DECODER_CREATION_EVENT_PENDING))
SetPendingEvent(DECODER_CREATION_EVENT_PENDING); SetPendingEvent(DECODER_CREATION_EVENT_PENDING);
break;
}
} }
void MediaSourcePlayer::DecodeMoreVideo() { void MediaSourcePlayer::DecodeMoreVideo() {
...@@ -583,25 +590,26 @@ void MediaSourcePlayer::DecodeMoreVideo() { ...@@ -583,25 +590,26 @@ void MediaSourcePlayer::DecodeMoreVideo() {
DCHECK(!video_decoder_job_->is_decoding()); DCHECK(!video_decoder_job_->is_decoding());
DCHECK(!VideoFinished()); DCHECK(!VideoFinished());
if (video_decoder_job_->Decode( MediaDecoderJob::MediaDecoderJobStatus status = video_decoder_job_->Decode(
start_time_ticks_, start_time_ticks_,
start_presentation_timestamp_, start_presentation_timestamp_,
base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_,
false))) { false));
switch (status) {
case MediaDecoderJob::STATUS_SUCCESS:
TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreVideo", TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreVideo",
video_decoder_job_.get()); video_decoder_job_.get());
return; break;
} case MediaDecoderJob::STATUS_KEY_FRAME_REQUIRED:
// If the decoder is waiting for iframe, trigger a browser seek.
if (!video_decoder_job_->next_video_data_is_iframe()) {
BrowserSeekToCurrentTime(); BrowserSeekToCurrentTime();
return; break;
} case MediaDecoderJob::STATUS_FAILURE:
is_waiting_for_video_decoder_ = true; is_waiting_for_video_decoder_ = true;
if (!IsEventPending(DECODER_CREATION_EVENT_PENDING)) if (!IsEventPending(DECODER_CREATION_EVENT_PENDING))
SetPendingEvent(DECODER_CREATION_EVENT_PENDING); SetPendingEvent(DECODER_CREATION_EVENT_PENDING);
break;
}
} }
void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { void MediaSourcePlayer::PlaybackCompleted(bool is_audio) {
......
...@@ -435,6 +435,10 @@ class MediaSourcePlayerTest : public testing::Test { ...@@ -435,6 +435,10 @@ class MediaSourcePlayerTest : public testing::Test {
return data; return data;
} }
bool HasData(bool is_audio) {
return GetMediaDecoderJob(is_audio)->HasData();
}
// Helper method for use at test start. It starts an audio decoder job and // Helper method for use at test start. It starts an audio decoder job and
// immediately feeds it some data to decode. Then, without letting the decoder // immediately feeds it some data to decode. Then, without letting the decoder
// job complete a decode cycle, it also starts player SeekTo(). Upon return, // job complete a decode cycle, it also starts player SeekTo(). Upon return,
...@@ -1043,7 +1047,9 @@ TEST_F(MediaSourcePlayerTest, SetEmptySurfaceAndStarveWhileDecoding) { ...@@ -1043,7 +1047,9 @@ TEST_F(MediaSourcePlayerTest, SetEmptySurfaceAndStarveWhileDecoding) {
// Playback resumes once a non-empty surface is passed. // Playback resumes once a non-empty surface is passed.
CreateNextTextureAndSetVideoSurface(); CreateNextTextureAndSetVideoSurface();
EXPECT_EQ(1, demuxer_->num_browser_seek_requests()); EXPECT_EQ(0, demuxer_->num_browser_seek_requests());
while(demuxer_->num_browser_seek_requests() != 1)
message_loop_.RunUntilIdle();
WaitForVideoDecodeDone(); WaitForVideoDecodeDone();
} }
...@@ -1534,6 +1540,34 @@ TEST_F(MediaSourcePlayerTest, BrowserSeek_MidStreamReleaseAndStart) { ...@@ -1534,6 +1540,34 @@ TEST_F(MediaSourcePlayerTest, BrowserSeek_MidStreamReleaseAndStart) {
EXPECT_EQ(1, demuxer_->num_seek_requests()); EXPECT_EQ(1, demuxer_->num_seek_requests());
} }
TEST_F(MediaSourcePlayerTest, NoBrowserSeekWithKeyFrameInCache) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
// Test that browser seek is not needed if a key frame is found in data
// cache.
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob();
DemuxerData data = CreateReadFromDemuxerAckForVideo(false);
data.access_units[0].is_key_frame = true;
// Simulate demuxer's response to the video data request.
player_.OnDemuxerDataAvailable(data);
// Trigger decoder recreation later by changing surfaces.
CreateNextTextureAndSetVideoSurface();
// Wait for the media codec bridge to finish decoding and be reset.
WaitForVideoDecodeDone();
EXPECT_FALSE(HasData(false));
// Send a non key frame to decoder so that decoder can continue. This will
// not trigger any browser seeks as the previous key frame is still in the
// buffer.
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
WaitForVideoDecodeDone();
EXPECT_EQ(0, demuxer_->num_browser_seek_requests());
}
TEST_F(MediaSourcePlayerTest, PrerollAudioAfterSeek) { TEST_F(MediaSourcePlayerTest, PrerollAudioAfterSeek) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
......
...@@ -37,8 +37,7 @@ VideoDecoderJob::VideoDecoderJob( ...@@ -37,8 +37,7 @@ VideoDecoderJob::VideoDecoderJob(
config_height_(0), config_height_(0),
output_width_(0), output_width_(0),
output_height_(0), output_height_(0),
request_resources_cb_(request_resources_cb), request_resources_cb_(request_resources_cb) {
next_video_data_is_iframe_(true) {
} }
VideoDecoderJob::~VideoDecoderJob() {} VideoDecoderJob::~VideoDecoderJob() {}
...@@ -61,11 +60,6 @@ bool VideoDecoderJob::HasStream() const { ...@@ -61,11 +60,6 @@ bool VideoDecoderJob::HasStream() const {
return video_codec_ != kUnknownVideoCodec; return video_codec_ != kUnknownVideoCodec;
} }
void VideoDecoderJob::Flush() {
MediaDecoderJob::Flush();
next_video_data_is_iframe_ = true;
}
void VideoDecoderJob::ReleaseDecoderResources() { void VideoDecoderJob::ReleaseDecoderResources() {
MediaDecoderJob::ReleaseDecoderResources(); MediaDecoderJob::ReleaseDecoderResources();
surface_ = gfx::ScopedJavaSurface(); surface_ = gfx::ScopedJavaSurface();
...@@ -124,16 +118,17 @@ bool VideoDecoderJob::AreDemuxerConfigsChanged( ...@@ -124,16 +118,17 @@ bool VideoDecoderJob::AreDemuxerConfigsChanged(
config_height_ != configs.video_size.height(); config_height_ != configs.video_size.height();
} }
bool VideoDecoderJob::CreateMediaCodecBridgeInternal() { MediaDecoderJob::MediaDecoderJobStatus
VideoDecoderJob::CreateMediaCodecBridgeInternal() {
if (surface_.IsEmpty()) { if (surface_.IsEmpty()) {
ReleaseMediaCodecBridge(); ReleaseMediaCodecBridge();
return false; return STATUS_FAILURE;
} }
// If the next data is not iframe, return false so that the player need to // If we cannot find a key frame in cache, browser seek is needed.
// perform a browser seek. bool next_video_data_is_iframe = SetCurrentFrameToPreviouslyCachedKeyFrame();
if (!next_video_data_is_iframe_) if (!next_video_data_is_iframe)
return false; return STATUS_KEY_FRAME_REQUIRED;
bool is_secure = is_content_encrypted() && drm_bridge() && bool is_secure = is_content_encrypted() && drm_bridge() &&
drm_bridge()->IsProtectedSurfaceRequired(); drm_bridge()->IsProtectedSurfaceRequired();
...@@ -143,14 +138,10 @@ bool VideoDecoderJob::CreateMediaCodecBridgeInternal() { ...@@ -143,14 +138,10 @@ bool VideoDecoderJob::CreateMediaCodecBridgeInternal() {
surface_.j_surface().obj(), GetMediaCrypto().obj())); surface_.j_surface().obj(), GetMediaCrypto().obj()));
if (!media_codec_bridge_) if (!media_codec_bridge_)
return false; return STATUS_FAILURE;
request_resources_cb_.Run(); request_resources_cb_.Run();
return true; return STATUS_SUCCESS;
}
void VideoDecoderJob::CurrentDataConsumed(bool is_config_change) {
next_video_data_is_iframe_ = is_config_change;
} }
bool VideoDecoderJob::UpdateOutputFormat() { bool VideoDecoderJob::UpdateOutputFormat() {
......
...@@ -33,14 +33,9 @@ class VideoDecoderJob : public MediaDecoderJob { ...@@ -33,14 +33,9 @@ class VideoDecoderJob : public MediaDecoderJob {
// MediaDecoderJob implementation. // MediaDecoderJob implementation.
virtual bool HasStream() const override; virtual bool HasStream() const override;
virtual void Flush() override;
virtual void ReleaseDecoderResources() override; virtual void ReleaseDecoderResources() override;
virtual void SetDemuxerConfigs(const DemuxerConfigs& configs) override; virtual void SetDemuxerConfigs(const DemuxerConfigs& configs) override;
bool next_video_data_is_iframe() {
return next_video_data_is_iframe_;
}
int output_width() const { return output_width_; } int output_width() const { return output_width_; }
int output_height() const { return output_height_; } int output_height() const { return output_height_; }
...@@ -57,8 +52,7 @@ class VideoDecoderJob : public MediaDecoderJob { ...@@ -57,8 +52,7 @@ class VideoDecoderJob : public MediaDecoderJob {
const DemuxerConfigs& configs) const override; const DemuxerConfigs& configs) const override;
virtual bool AreDemuxerConfigsChanged( virtual bool AreDemuxerConfigsChanged(
const DemuxerConfigs& configs) const override; const DemuxerConfigs& configs) const override;
virtual bool CreateMediaCodecBridgeInternal() override; virtual MediaDecoderJobStatus CreateMediaCodecBridgeInternal() override;
virtual void CurrentDataConsumed(bool is_config_change) override;
virtual bool UpdateOutputFormat() override; virtual bool UpdateOutputFormat() override;
// Returns true if a protected surface is required for video playback. // Returns true if a protected surface is required for video playback.
...@@ -80,11 +74,6 @@ class VideoDecoderJob : public MediaDecoderJob { ...@@ -80,11 +74,6 @@ class VideoDecoderJob : public MediaDecoderJob {
base::Closure request_resources_cb_; base::Closure request_resources_cb_;
base::Closure release_resources_cb_; base::Closure release_resources_cb_;
// Track whether the next access unit is an I-frame. The first access
// unit after Flush() and CurrentDataConsumed(true) is guaranteed to be an
// I-frame.
bool next_video_data_is_iframe_;
DISALLOW_COPY_AND_ASSIGN(VideoDecoderJob); DISALLOW_COPY_AND_ASSIGN(VideoDecoderJob);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment