Commit 6dbf2686 authored by liberato's avatar liberato Committed by Commit bot

Release MediaCodec on another thread more often.

Since MediaCodec::release() can hang, this CL moves more cases of
it to a separate thread when needed.  Previously, we did this only
during AVDA destruction.  This CL adds support for other cases in
which we replace or clear |media_codec_|.

BUG=613238

Review-Url: https://codereview.chromium.org/2116573002
Cr-Commit-Position: refs/heads/master@{#403345}
parent 7561063a
...@@ -1088,11 +1088,13 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() { ...@@ -1088,11 +1088,13 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() {
// might access that surface while the main thread is drawing. Telling the // might access that surface while the main thread is drawing. Telling the
// strategy to forget the codec avoids this. // strategy to forget the codec avoids this.
if (media_codec_) { if (media_codec_) {
media_codec_.reset(); ReleaseMediaCodec();
strategy_->CodecChanged(nullptr); strategy_->CodecChanged(nullptr);
} }
// Choose whether to autodetect the codec type. // Choose whether to autodetect the codec type. Note that we do this after
// releasing any outgoing codec, so that |codec_config_| still matches the
// outgoing codec for ReleaseMediaCodec().
codec_config_->allow_autodetection_ = codec_config_->allow_autodetection_ =
g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe(); g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe();
codec_config_->notify_completion_ = codec_config_->allow_autodetection_; codec_config_->notify_completion_ = codec_config_->allow_autodetection_;
...@@ -1126,6 +1128,7 @@ bool AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() { ...@@ -1126,6 +1128,7 @@ bool AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() {
g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe(); g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe();
codec_config_->notify_completion_ = false; codec_config_->notify_completion_ = false;
ReleaseMediaCodec();
std::unique_ptr<VideoCodecBridge> media_codec = std::unique_ptr<VideoCodecBridge> media_codec =
ConfigureMediaCodecOnAnyThread(codec_config_); ConfigureMediaCodecOnAnyThread(codec_config_);
OnCodecConfigured(std::move(media_codec)); OnCodecConfigured(std::move(media_codec));
...@@ -1183,6 +1186,7 @@ void AndroidVideoDecodeAccelerator::OnCodecConfigured( ...@@ -1183,6 +1186,7 @@ void AndroidVideoDecodeAccelerator::OnCodecConfigured(
if (state_ == SURFACE_DESTROYED) if (state_ == SURFACE_DESTROYED)
return; return;
DCHECK(!media_codec_);
media_codec_ = std::move(media_codec); media_codec_ = std::move(media_codec);
strategy_->CodecChanged(media_codec_.get()); strategy_->CodecChanged(media_codec_.get());
if (!media_codec_) { if (!media_codec_) {
...@@ -1412,20 +1416,7 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() { ...@@ -1412,20 +1416,7 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() {
weak_this_factory_.InvalidateWeakPtrs(); weak_this_factory_.InvalidateWeakPtrs();
if (media_codec_) { if (media_codec_) {
manager->StopTimer(this); manager->StopTimer(this);
// If codec construction is broken, then we can't release this codec if it's ReleaseMediaCodec();
// backed by hardware, else it may hang too. Post it to the construction
// thread, and it'll get freed if things start working. If things are
// already working, then it'll be freed soon.
//
// We require software codecs when |allow_autodetection_| is false, so use
// the stored value as a proxy for whether the MediaCodec is software backed
// or not.
if (!codec_config_->allow_autodetection_) {
media_codec_.reset();
} else {
manager->ConstructionTaskRunner()->DeleteSoon(FROM_HERE,
media_codec_.release());
}
} }
delete this; delete this;
} }
...@@ -1513,7 +1504,7 @@ void AndroidVideoDecodeAccelerator::OnDestroyingSurface(int surface_id) { ...@@ -1513,7 +1504,7 @@ void AndroidVideoDecodeAccelerator::OnDestroyingSurface(int surface_id) {
// SURFACE_DESTROYED. // SURFACE_DESTROYED.
state_ = SURFACE_DESTROYED; state_ = SURFACE_DESTROYED;
if (media_codec_) { if (media_codec_) {
media_codec_.reset(); ReleaseMediaCodec();
strategy_->CodecChanged(media_codec_.get()); strategy_->CodecChanged(media_codec_.get());
} }
// If we're draining, signal completion now because the drain can no longer // If we're draining, signal completion now because the drain can no longer
...@@ -1669,6 +1660,26 @@ void AndroidVideoDecodeAccelerator::ManageTimer(bool did_work) { ...@@ -1669,6 +1660,26 @@ void AndroidVideoDecodeAccelerator::ManageTimer(bool did_work) {
g_avda_timer.Pointer()->StopTimer(this); g_avda_timer.Pointer()->StopTimer(this);
} }
void AndroidVideoDecodeAccelerator::ReleaseMediaCodec() {
if (!media_codec_)
return;
// If codec construction is broken, then we can't release this codec if it's
// backed by hardware, else it may hang too. Post it to the construction
// thread, and it'll get freed if things start working. If things are
// already working, then it'll be freed soon.
//
// We require software codecs when |allow_autodetection_| is false, so use
// the stored value as a proxy for whether the MediaCodec is software backed
// or not.
if (!codec_config_->allow_autodetection_) {
media_codec_.reset();
} else {
g_avda_timer.Pointer()->ConstructionTaskRunner()->DeleteSoon(
FROM_HERE, media_codec_.release());
}
}
// static // static
bool AndroidVideoDecodeAccelerator::UseDeferredRenderingStrategy( bool AndroidVideoDecodeAccelerator::UseDeferredRenderingStrategy(
const gpu::GpuPreferences& gpu_preferences) { const gpu::GpuPreferences& gpu_preferences) {
......
...@@ -326,6 +326,12 @@ class MEDIA_GPU_EXPORT AndroidVideoDecodeAccelerator ...@@ -326,6 +326,12 @@ class MEDIA_GPU_EXPORT AndroidVideoDecodeAccelerator
// start the timer. Calling it with false may stop the timer. // start the timer. Calling it with false may stop the timer.
void ManageTimer(bool did_work); void ManageTimer(bool did_work);
// Safely clear |media_codec_|. Do this instead of calling reset() / assign.
// Otherwise, the destructor can hang if mediaserver is in a bad state. This
// will release immediately if safe, else post to a separate thread. Either
// way, |media_codec_| will be null upon return.
void ReleaseMediaCodec();
// Start the MediaCodec drain process by adding end_of_stream() buffer to the // Start the MediaCodec drain process by adding end_of_stream() buffer to the
// encoded buffers queue. When we receive EOS from the output buffer the drain // encoded buffers queue. When we receive EOS from the output buffer the drain
// process completes and we perform the action depending on the |drain_type|. // process completes and we perform the action depending on the |drain_type|.
......
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