Commit 89f5a178 authored by posciak@chromium.org's avatar posciak@chromium.org

Fix webrtc HW encode deadlock scenarios.

    
Webrtc unfortunately likes to sleep in BaseChannel::Send on the renderer's
ChildThread while directly or indirectly calling into HW encoder and we end 
up in a number of deadlocks of varying complexity in one way or another,
while trying to also use the ChildThread to allocate shared memory to service 
those calls.
The only way to avoid this is to not get onto the ChildThread while servicing
webrtc requests, so we use the static ChildThread::AllocateSharedMemory()
to send the request directly from the current thread.
    
Also add VEA::RequireBitstreamBuffers() to the initialization sequence, so that
RTCVideoEncoder::InitEncode() will only return after we've allocated requested
buffers. VEA::RequireBitstreamBuffers() is effectively a part of initialization
sequence anyway, because we can't really call VEA::Encode() without knowing the
VEA impl's coded size requirements. This could also potentially reduce
the latency of the first Encode() call.

And separately, zero out header structures sent to the client.

TEST=apprtc.appspot.com with HW encoding
BUG=260210

Review URL: https://chromiumcodereview.appspot.com/23440015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221395 0039d316-1c4b-4281-b951-d872f2087c98
parent 2af0d65f
......@@ -23,11 +23,10 @@ RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
WebGraphicsContext3DCommandBufferImpl* context)
: message_loop_(message_loop),
main_message_loop_(base::MessageLoopProxy::current()),
gpu_channel_host_(gpu_channel_host),
thread_safe_sender_(ChildThread::current()->thread_safe_sender()),
aborted_waiter_(true, false),
message_loop_async_waiter_(false, false),
render_thread_async_waiter_(false, false) {
message_loop_async_waiter_(false, false) {
// |context| is only required to support HW-accelerated decode.
if (!context)
return;
......@@ -55,8 +54,7 @@ RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories()
: aborted_waiter_(true, false),
message_loop_async_waiter_(false, false),
render_thread_async_waiter_(false, false) {}
message_loop_async_waiter_(false, false) {}
void RendererGpuVideoAcceleratorFactories::AsyncGetContext(
WebGraphicsContext3DCommandBufferImpl* context) {
......@@ -365,30 +363,7 @@ void RendererGpuVideoAcceleratorFactories::AsyncReadPixels(
base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
size_t size) {
if (main_message_loop_->BelongsToCurrentThread()) {
return ChildThread::current()->AllocateSharedMemory(size);
}
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncCreateSharedMemory,
this,
size));
base::WaitableEvent* objects[] = {&aborted_waiter_,
&render_thread_async_waiter_};
if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
return NULL;
return shared_memory_segment_.release();
}
void RendererGpuVideoAcceleratorFactories::AsyncCreateSharedMemory(
size_t size) {
DCHECK_EQ(base::MessageLoop::current(),
ChildThread::current()->message_loop());
shared_memory_segment_.reset(
ChildThread::current()->AllocateSharedMemory(size));
render_thread_async_waiter_.Signal();
return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
}
scoped_refptr<base::MessageLoopProxy>
......@@ -407,9 +382,9 @@ RendererGpuVideoAcceleratorFactories::Clone() {
scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
new RendererGpuVideoAcceleratorFactories();
factories->message_loop_ = message_loop_;
factories->main_message_loop_ = main_message_loop_;
factories->gpu_channel_host_ = gpu_channel_host_;
factories->context_ = context_;
factories->thread_safe_sender_ = thread_safe_sender_;
return factories;
}
......
......@@ -11,6 +11,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "content/child/thread_safe_sender.h"
#include "content/common/content_export.h"
#include "media/filters/gpu_video_accelerator_factories.h"
#include "third_party/skia/include/core/SkBitmap.h"
......@@ -32,8 +33,7 @@ class WebGraphicsContext3DCommandBufferImpl;
//
// The public methods of the class can be called from any thread, and are
// internally trampolined to the appropriate thread. GPU/GL-related calls go to
// the constructor-argument loop (the media thread), and shmem-related calls go
// to the render thread.
// the constructor-argument loop (the media thread).
class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
: public media::GpuVideoAcceleratorFactories {
public:
......@@ -82,11 +82,10 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
// |message_loop_|.
void AsyncGetContext(WebGraphicsContext3DCommandBufferImpl* context);
// Async versions of the public methods. They use output parameters instead
// of return values and each takes a WaitableEvent* param to signal completion
// (except for DeleteTexture, which is fire-and-forget).
// AsyncCreateSharedMemory runs on the renderer thread and the rest run on
// |message_loop_|.
// Async versions of the public methods, run on |message_loop_|.
// They use output parameters instead of return values and each takes
// a WaitableEvent* param to signal completion (except for DeleteTexture,
// which is fire-and-forget).
// AsyncCreateVideoDecodeAccelerator returns its output in the |vda_| member.
// AsyncCreateVideoEncodeAccelerator returns its output in the |vea_| member.
void AsyncCreateVideoDecodeAccelerator(
......@@ -103,15 +102,16 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
void AsyncReadPixels(uint32 texture_id,
uint32 texture_target,
const gfx::Size& size);
void AsyncCreateSharedMemory(size_t size);
void AsyncDestroyVideoDecodeAccelerator();
void AsyncDestroyVideoEncodeAccelerator();
scoped_refptr<base::MessageLoopProxy> message_loop_;
scoped_refptr<base::MessageLoopProxy> main_message_loop_;
scoped_refptr<GpuChannelHost> gpu_channel_host_;
base::WeakPtr<WebGraphicsContext3DCommandBufferImpl> context_;
// For sending requests to allocate shared memory in the Browser process.
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
// This event is signaled if we have been asked to Abort().
base::WaitableEvent aborted_waiter_;
......@@ -120,20 +120,12 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
// e.g. AsyncCreateVideoDecodeAccelerator()/AsyncCreateTextures() etc.
base::WaitableEvent message_loop_async_waiter_;
// This event is signaled by asynchronous tasks posted to the renderer thread
// message loop to indicate their completion. e.g. AsyncCreateSharedMemory.
base::WaitableEvent render_thread_async_waiter_;
// The vda returned by the CreateVideoDecodeAccelerator function.
scoped_ptr<media::VideoDecodeAccelerator> vda_;
// The vea returned by the CreateVideoEncodeAccelerator function.
scoped_ptr<media::VideoEncodeAccelerator> vea_;
// Shared memory segment which is returned by the CreateSharedMemory()
// function.
scoped_ptr<base::SharedMemory> shared_memory_segment_;
// Bitmap returned by ReadPixels().
SkBitmap read_pixels_bitmap_;
......
......@@ -250,7 +250,6 @@ void RTCVideoEncoder::Impl::Destroy() {
void RTCVideoEncoder::Impl::NotifyInitializeDone() {
DVLOG(3) << "Impl::NotifyInitializeDone()";
DCHECK(thread_checker_.CalledOnValidThread());
SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
}
void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
......@@ -298,6 +297,7 @@ void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size()));
}
SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
}
void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id,
......@@ -614,10 +614,12 @@ void RTCVideoEncoder::ReturnEncodedImage(scoped_ptr<webrtc::EncodedImage> image,
return;
webrtc::CodecSpecificInfo info;
memset(&info, 0, sizeof(info));
info.codecType = video_codec_type_;
// Generate a header describing a single fragment.
webrtc::RTPFragmentationHeader header;
memset(&header, 0, sizeof(header));
header.VerifyAndAllocateFragmentationHeader(1);
header.fragmentationOffset[0] = 0;
header.fragmentationLength[0] = image->_length;
......
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