Commit a561de6d authored by emircan's avatar emircan Committed by Commit bot

Fix errors in destruction sequence of GpuVideoEncodeAccelerator::OnWillDestroyStub()

On Windows, we can use GPU IO thread to filter some messages for GPUVEA.
In that case, while GpuVideoEncodeAccelerator::OnWillDestroyStub() is running
on main thread, GpuVideoEncodeAccelerator::OnEncodeFrameCreated() can run
on IO thread. If |encoder_| is reset on main thread and accessed on IO
thread, we see the crashes listed on the bug.
This CL solves the issue by:
- Checking |filter_removed_| which is signaled on IO thread before deciding
to continue with encode GpuVideoEncodeAccelerator::OnEncodeFrameCreated() on
IO thread.
- Making sure that |encoder_worker_thread_| tasks are completed before reset.

BUG=715759
TEST=Tested AppRTC loopback with H264.
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2849443003
Cr-Commit-Position: refs/heads/master@{#468457}
parent 221e92f4
...@@ -173,6 +173,9 @@ GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator( ...@@ -173,6 +173,9 @@ GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(
encode_task_runner_(main_task_runner_), encode_task_runner_(main_task_runner_),
weak_this_factory_for_encoder_worker_(this), weak_this_factory_for_encoder_worker_(this),
weak_this_factory_(this) { weak_this_factory_(this) {
weak_this_for_encoder_worker_ =
weak_this_factory_for_encoder_worker_.GetWeakPtr();
weak_this_ = weak_this_factory_.GetWeakPtr();
stub_->AddDestructionObserver(this); stub_->AddDestructionObserver(this);
make_context_current_ = make_context_current_ =
base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr()); base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr());
...@@ -182,13 +185,7 @@ GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() { ...@@ -182,13 +185,7 @@ GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
// This class can only be self-deleted from OnWillDestroyStub(), which means // This class can only be self-deleted from OnWillDestroyStub(), which means
// the VEA has already been destroyed in there. // the VEA has already been destroyed in there.
DCHECK(!encoder_); DCHECK(!encoder_);
if (encoder_worker_thread_.IsRunning()) { DCHECK(!encoder_worker_thread_.IsRunning());
encoder_worker_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuVideoEncodeAccelerator::DestroyOnEncoderWorker,
weak_this_factory_for_encoder_worker_.GetWeakPtr()));
encoder_worker_thread_.Stop();
}
} }
bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format, bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format,
...@@ -229,8 +226,8 @@ bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format, ...@@ -229,8 +226,8 @@ bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format,
input_visible_size_ = input_visible_size; input_visible_size_ = input_visible_size;
// Attempt to set up performing encoding tasks on IO thread, if supported // Attempt to set up performing encoding tasks on IO thread, if supported
// by the VEA. // by the VEA.
if (encoder_->TryToSetupEncodeOnSeparateThread( if (encoder_->TryToSetupEncodeOnSeparateThread(weak_this_,
weak_this_factory_.GetWeakPtr(), io_task_runner_)) { io_task_runner_)) {
filter_ = new MessageFilter(this, host_route_id_); filter_ = new MessageFilter(this, host_route_id_);
stub_->channel()->AddFilter(filter_.get()); stub_->channel()->AddFilter(filter_.get());
encode_task_runner_ = io_task_runner_; encode_task_runner_ = io_task_runner_;
...@@ -325,6 +322,16 @@ void GpuVideoEncodeAccelerator::OnWillDestroyStub() { ...@@ -325,6 +322,16 @@ void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
filter_removed_.Wait(); filter_removed_.Wait();
} }
// We should stop |encoder_worker_thread_| before releasing |encoder_|, see
// crbug.com/715759.
if (encoder_worker_thread_.IsRunning()) {
encoder_worker_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuVideoEncodeAccelerator::DestroyOnEncoderWorker,
weak_this_for_encoder_worker_));
encoder_worker_thread_.Stop();
}
stub_->channel()->RemoveRoute(host_route_id_); stub_->channel()->RemoveRoute(host_route_id_);
stub_->RemoveDestructionObserver(this); stub_->RemoveDestructionObserver(this);
encoder_.reset(); encoder_.reset();
...@@ -404,7 +411,7 @@ void GpuVideoEncodeAccelerator::OnEncode( ...@@ -404,7 +411,7 @@ void GpuVideoEncodeAccelerator::OnEncode(
encoder_worker_task_runner_->PostTask( encoder_worker_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker, base::Bind(&GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker,
weak_this_factory_for_encoder_worker_.GetWeakPtr(), params)); weak_this_for_encoder_worker_, params));
} }
void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer( void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
...@@ -465,18 +472,18 @@ void GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker( ...@@ -465,18 +472,18 @@ void GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker(
if (!map_offset.IsValid() || !map_size.IsValid()) { if (!map_offset.IsValid() || !map_size.IsValid()) {
DLOG(ERROR) << __func__ << " invalid map_offset or map_size"; DLOG(ERROR) << __func__ << " invalid map_offset or map_size";
encode_task_runner_->PostTask( encode_task_runner_->PostTask(
FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError, FROM_HERE,
weak_this_factory_.GetWeakPtr(), base::Bind(&GpuVideoEncodeAccelerator::NotifyError, weak_this_,
VideoEncodeAccelerator::kPlatformFailureError)); VideoEncodeAccelerator::kPlatformFailureError));
return; return;
} }
if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) { if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
DLOG(ERROR) << __func__ << " could not map frame_id=" << params.frame_id; DLOG(ERROR) << __func__ << " could not map frame_id=" << params.frame_id;
encode_task_runner_->PostTask( encode_task_runner_->PostTask(
FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError, FROM_HERE,
weak_this_factory_.GetWeakPtr(), base::Bind(&GpuVideoEncodeAccelerator::NotifyError, weak_this_,
VideoEncodeAccelerator::kPlatformFailureError)); VideoEncodeAccelerator::kPlatformFailureError));
return; return;
} }
...@@ -489,9 +496,9 @@ void GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker( ...@@ -489,9 +496,9 @@ void GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker(
if (!frame) { if (!frame) {
DLOG(ERROR) << __func__ << " could not create a frame"; DLOG(ERROR) << __func__ << " could not create a frame";
encode_task_runner_->PostTask( encode_task_runner_->PostTask(
FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError, FROM_HERE,
weak_this_factory_.GetWeakPtr(), base::Bind(&GpuVideoEncodeAccelerator::NotifyError, weak_this_,
VideoEncodeAccelerator::kPlatformFailureError)); VideoEncodeAccelerator::kPlatformFailureError));
return; return;
} }
...@@ -500,9 +507,9 @@ void GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker( ...@@ -500,9 +507,9 @@ void GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker(
frame->AddDestructionObserver( frame->AddDestructionObserver(
base::Bind(&DropSharedMemory, base::Passed(&shm))); base::Bind(&DropSharedMemory, base::Passed(&shm)));
encode_task_runner_->PostTask( encode_task_runner_->PostTask(
FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::OnEncodeFrameCreated, FROM_HERE,
weak_this_factory_.GetWeakPtr(), params.frame_id, base::Bind(&GpuVideoEncodeAccelerator::OnEncodeFrameCreated, weak_this_,
params.force_keyframe, frame)); params.frame_id, params.force_keyframe, frame));
} }
void GpuVideoEncodeAccelerator::DestroyOnEncoderWorker() { void GpuVideoEncodeAccelerator::DestroyOnEncoderWorker() {
...@@ -517,6 +524,9 @@ void GpuVideoEncodeAccelerator::OnEncodeFrameCreated( ...@@ -517,6 +524,9 @@ void GpuVideoEncodeAccelerator::OnEncodeFrameCreated(
DVLOG(3) << __func__; DVLOG(3) << __func__;
DCHECK(CheckIfCalledOnCorrectThread()); DCHECK(CheckIfCalledOnCorrectThread());
if (filter_removed_.IsSignaled())
return;
if (!frame) { if (!frame) {
DLOG(ERROR) << __func__ << " could not create a frame"; DLOG(ERROR) << __func__ << " could not create a frame";
NotifyError(VideoEncodeAccelerator::kPlatformFailureError); NotifyError(VideoEncodeAccelerator::kPlatformFailureError);
......
...@@ -159,12 +159,16 @@ class GpuVideoEncodeAccelerator ...@@ -159,12 +159,16 @@ class GpuVideoEncodeAccelerator
// otherwise |main_thread_task_runner_|. // otherwise |main_thread_task_runner_|.
scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner_;
base::WeakPtr<GpuVideoEncodeAccelerator> weak_this_for_encoder_worker_;
base::WeakPtr<GpuVideoEncodeAccelerator> weak_this_;
// Weak pointer for referring back to |this| on |encoder_worker_task_runner_|. // Weak pointer for referring back to |this| on |encoder_worker_task_runner_|.
base::WeakPtrFactory<GpuVideoEncodeAccelerator> base::WeakPtrFactory<GpuVideoEncodeAccelerator>
weak_this_factory_for_encoder_worker_; weak_this_factory_for_encoder_worker_;
// Weak pointer for VideoFrames that refer back to |this| on // Weak pointer for VideoFrames that refer back to |this| on
// |main_task_runner| or |io_task_runner_|. // |main_task_runner| or |io_task_runner_|. |io_task_runner_| is used if and
// only if |filter_| is applied.
base::WeakPtrFactory<GpuVideoEncodeAccelerator> weak_this_factory_; base::WeakPtrFactory<GpuVideoEncodeAccelerator> weak_this_factory_;
DISALLOW_COPY_AND_ASSIGN(GpuVideoEncodeAccelerator); DISALLOW_COPY_AND_ASSIGN(GpuVideoEncodeAccelerator);
......
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