Commit ce491a0b authored by ricea@chromium.org's avatar ricea@chromium.org

Revert of Revert of Remove threading from RendererGpuVideoAcceleratorFactories...

Revert of Revert of Remove threading from RendererGpuVideoAcceleratorFactories (https://codereview.chromium.org/145103004/)

Reason for revert:
Reverting the revert as it did not fix the failures.

Original issue's description:
> Revert of Remove threading from RendererGpuVideoAcceleratorFactories (https://codereview.chromium.org/27420004/)
> 
> Reason for revert:
> Sorry, it looks like you broke the Win 7 Tests (dbg)(2) bot. http://build.chromium.org/p/chromium.win/builders/Win7%20Tests%20%28dbg%29%282%29/builds/19785
> 
> Original issue's description:
> > This change removes all the threading considerations from
> > GpuVideoAcceleratorFactories (and its implementation,
> > RendererGpuVideoAcceleratorFactories).  Most notably, it removes Abort() and
> > associated functions and state.  And with the removal of Abort() and friends,
> > we can also remove its Clone() interface.
> > 
> > All of the previously abortable operations on the RGVAF (with the exception of
> > ReadPixels()) can be made non-abortable, with no functional difference, due to
> > the way the users of RGVAF function.  These three users are
> > WebMediaPlayerImpl/GpuVideoDecoder, RTCVideoDecoder, and RTCVideoEncoder, and
> > they can be made non-abortable because:
> > 
> > WebMediaPlayerImpl/GpuVideoDecoder:
> > * Abort() is called from WebMediaPlayerImpl::Destroy().  It has no effect, as:
> >   * All the RGVAF entry points are called from the the RGVAF message loop
> >     from GpuVideoDecoder (except for ReadPixels()), so the Abort() has no
> >     effect on them.
> > 
> > RTCVideoDecoder:
> > * Abort() is called from RTCVideoDecoder::WillDestroyCurrentMessageLoop() for
> >   the RGVAF message loop.  It has no effect, as:
> >   * Amost all the RGVAF entry points are called from the RGVAF message loop
> >     (except for ReadPixels()), so Abort() has no effect on them.
> >   * The other exception is CreateVideoDecodeAccelerator(), which is called from
> >     RTC's main thread.  But as the Abort() is called from
> >     WillDestroyCurrentMessageLoop() for the RGVAF message loop itself, it is
> >     guaranteed to occur after any tasks posted to the RGVAF message loop by
> >     CreateVideoDecodeAccelerator() has completed, and so the Abort() has no
> >     effect.
> > 
> > RTCVideoEncoder:
> > * Abort() is called from RTCVideoDecoder::Release().  It has no effect, as:
> >   * All the RGVAF entry points are called from the RGVAF message loop.
> > 
> > The only functional difference remaining is that making ReadPixels()
> > non-abortable.  This is preferable, as as long as a completed video accelerator
> > texture is available, it should be readable.  We also specify that all calls to
> > ReadPixels must be made on the RGVAF message loop, like all other entry points,
> > and leave it up to the users of ReadPixels() to handle thread trampolining if
> > necessary.
> > 
> > BUG=306333
> > TEST=local build, run on CrOS snow; build, run unittests on desktop Linux
> > 
> > Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=247480
> 
> TBR=fischman@chromium.org,wuchengli@chromium.org,jamesr@chromium.org,jam@chromium.org,hshi@chromium.org,sheu@chromium.org
> NOTREECHECKS=true
> NOTRY=true
> BUG=306333
> 
> Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=247655

TBR=fischman@chromium.org,wuchengli@chromium.org,jamesr@chromium.org,jam@chromium.org,hshi@chromium.org,sheu@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=306333

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247662 0039d316-1c4b-4281-b951-d872f2087c98
parent 9597e9e0
......@@ -14,6 +14,7 @@
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixelRef.h"
namespace content {
......@@ -21,37 +22,12 @@ namespace content {
RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
GpuChannelHost* gpu_channel_host,
const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider)
: task_runner_(
RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()),
: task_runner_(message_loop_proxy),
gpu_channel_host_(gpu_channel_host),
context_provider_(context_provider),
thread_safe_sender_(ChildThread::current()->thread_safe_sender()),
aborted_waiter_(true, false),
task_runner_async_waiter_(false, false) {
// |context_provider_| is only required to support HW-accelerated decode.
if (!context_provider_)
return;
if (task_runner_->BelongsToCurrentThread()) {
AsyncBindContext();
task_runner_async_waiter_.Reset();
return;
}
// Wait for the context to be acquired.
task_runner_->PostTask(
FROM_HERE,
base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncBindContext,
// Unretained to avoid ref/deref'ing |*this|, which is not yet
// stored in a scoped_refptr. Safe because the Wait() below
// keeps us alive until this task completes.
base::Unretained(this)));
task_runner_async_waiter_.Wait();
}
RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories()
: aborted_waiter_(true, false),
task_runner_async_waiter_(false, false) {}
thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
WebGraphicsContext3DCommandBufferImpl*
RendererGpuVideoAcceleratorFactories::GetContext3d() {
......@@ -66,44 +42,19 @@ RendererGpuVideoAcceleratorFactories::GetContext3d() {
return context_provider_->WebContext3D();
}
void RendererGpuVideoAcceleratorFactories::AsyncBindContext() {
DCHECK(task_runner_->BelongsToCurrentThread());
if (!context_provider_->BindToCurrentThread())
context_provider_ = NULL;
task_runner_async_waiter_.Signal();
}
scoped_ptr<media::VideoDecodeAccelerator>
RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator(
media::VideoCodecProfile profile,
media::VideoDecodeAccelerator::Client* client) {
if (task_runner_->BelongsToCurrentThread()) {
AsyncCreateVideoDecodeAccelerator(profile, client);
task_runner_async_waiter_.Reset();
return vda_.Pass();
}
// The VDA is returned in the vda_ member variable by the
// AsyncCreateVideoDecodeAccelerator() function.
task_runner_->PostTask(FROM_HERE,
base::Bind(&RendererGpuVideoAcceleratorFactories::
AsyncCreateVideoDecodeAccelerator,
this,
profile,
client));
DCHECK(task_runner_->BelongsToCurrentThread());
base::WaitableEvent* objects[] = {&aborted_waiter_,
&task_runner_async_waiter_};
if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) {
// If we are aborting and the VDA is created by the
// AsyncCreateVideoDecodeAccelerator() function later we need to ensure
// that it is destroyed on the same thread.
task_runner_->PostTask(FROM_HERE,
base::Bind(&RendererGpuVideoAcceleratorFactories::
AsyncDestroyVideoDecodeAccelerator,
this));
return scoped_ptr<media::VideoDecodeAccelerator>();
WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
if (context && context->GetCommandBufferProxy()) {
return gpu_channel_host_->CreateVideoDecoder(
context->GetCommandBufferProxy()->GetRouteID(), profile, client);
}
return vda_.Pass();
return scoped_ptr<media::VideoDecodeAccelerator>();
}
scoped_ptr<media::VideoEncodeAccelerator>
......@@ -114,19 +65,6 @@ RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator(
return gpu_channel_host_->CreateVideoEncoder(client);
}
void RendererGpuVideoAcceleratorFactories::AsyncCreateVideoDecodeAccelerator(
media::VideoCodecProfile profile,
media::VideoDecodeAccelerator::Client* client) {
DCHECK(task_runner_->BelongsToCurrentThread());
WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
if (context && context->GetCommandBufferProxy()) {
vda_ = gpu_channel_host_->CreateVideoDecoder(
context->GetCommandBufferProxy()->GetRouteID(), profile, client);
}
task_runner_async_waiter_.Signal();
}
uint32 RendererGpuVideoAcceleratorFactories::CreateTextures(
int32 count,
const gfx::Size& size,
......@@ -204,42 +142,15 @@ void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
gles2->ShallowFlushCHROMIUM();
}
void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id,
const gfx::Size& size,
const SkBitmap& pixels) {
// SkBitmaps use the SkPixelRef object to refcount the underlying pixels.
// Multiple SkBitmaps can share a SkPixelRef instance. We use this to
// ensure that the underlying pixels in the SkBitmap passed in remain valid
// until the AsyncReadPixels() call completes.
read_pixels_bitmap_.setPixelRef(pixels.pixelRef());
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(
FROM_HERE,
base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncReadPixels,
this,
texture_id,
size));
base::WaitableEvent* objects[] = {&aborted_waiter_,
&task_runner_async_waiter_};
if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
return;
} else {
AsyncReadPixels(texture_id, size);
task_runner_async_waiter_.Reset();
}
read_pixels_bitmap_.setPixelRef(NULL);
}
void RendererGpuVideoAcceleratorFactories::AsyncReadPixels(
void RendererGpuVideoAcceleratorFactories::ReadPixels(
uint32 texture_id,
const gfx::Size& size) {
const gfx::Rect& visible_rect,
const SkBitmap& pixels) {
DCHECK(task_runner_->BelongsToCurrentThread());
WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
if (!context) {
task_runner_async_waiter_.Signal();
if (!context)
return;
}
gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
......@@ -268,17 +179,16 @@ void RendererGpuVideoAcceleratorFactories::AsyncReadPixels(
#else
#error Unexpected Skia ARGB_8888 layout!
#endif
gles2->ReadPixels(0,
0,
size.width(),
size.height(),
gles2->ReadPixels(visible_rect.x(),
visible_rect.y(),
visible_rect.width(),
visible_rect.height(),
skia_format,
GL_UNSIGNED_BYTE,
read_pixels_bitmap_.pixelRef()->pixels());
pixels.pixelRef()->pixels());
gles2->DeleteFramebuffers(1, &fb);
gles2->DeleteTextures(1, &tmp_texture);
DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
task_runner_async_waiter_.Signal();
}
base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
......@@ -292,28 +202,4 @@ RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
return task_runner_;
}
void RendererGpuVideoAcceleratorFactories::Abort() { aborted_waiter_.Signal(); }
bool RendererGpuVideoAcceleratorFactories::IsAborted() {
return aborted_waiter_.IsSignaled();
}
scoped_refptr<RendererGpuVideoAcceleratorFactories>
RendererGpuVideoAcceleratorFactories::Clone() {
scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
new RendererGpuVideoAcceleratorFactories();
factories->task_runner_ = task_runner_;
factories->gpu_channel_host_ = gpu_channel_host_;
factories->context_provider_ = context_provider_;
factories->thread_safe_sender_ = thread_safe_sender_;
return factories;
}
void
RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoDecodeAccelerator() {
// OK to release because Destroy() will delete the VDA instance.
if (vda_)
vda_.release()->Destroy();
}
} // namespace content
......@@ -14,7 +14,6 @@
#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"
#include "ui/gfx/size.h"
namespace base {
......@@ -31,12 +30,9 @@ class WebGraphicsContext3DCommandBufferImpl;
// RenderViewImpl and only has its own header to allow extraction of its
// implementation from render_view_impl.cc which is already far too large.
//
// The RendererGpuVideoAcceleratorFactories can be constructed on any thread.
// Most public methods of the class must be called from the media thread. The
// exceptions (which can be called from any thread, as they are internally
// trampolined) are:
// * CreateVideoDecodeAccelerator()
// * ReadPixels()
// The RendererGpuVideoAcceleratorFactories can be constructed on any thread,
// but subsequent calls to all public methods of the class must be called from
// the |message_loop_proxy_|, as provided during construction.
class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
: public media::GpuVideoAcceleratorFactories {
public:
......@@ -44,10 +40,10 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
// use. Safe to call from any thread.
RendererGpuVideoAcceleratorFactories(
GpuChannelHost* gpu_channel_host,
const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider);
// media::GpuVideoAcceleratorFactories implementation.
// CreateVideoDecodeAccelerator() is safe to call from any thread.
virtual scoped_ptr<media::VideoDecodeAccelerator>
CreateVideoDecodeAccelerator(
media::VideoCodecProfile profile,
......@@ -64,42 +60,21 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
uint32 texture_target) OVERRIDE;
virtual void DeleteTexture(uint32 texture_id) OVERRIDE;
virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE;
// ReadPixels() is safe to call from any thread.
virtual void ReadPixels(uint32 texture_id,
const gfx::Size& size,
const gfx::Rect& visible_rect,
const SkBitmap& pixels) OVERRIDE;
virtual base::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE;
virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() OVERRIDE;
virtual void Abort() OVERRIDE;
virtual bool IsAborted() OVERRIDE;
scoped_refptr<RendererGpuVideoAcceleratorFactories> Clone();
protected:
friend class base::RefCountedThreadSafe<RendererGpuVideoAcceleratorFactories>;
virtual ~RendererGpuVideoAcceleratorFactories();
private:
RendererGpuVideoAcceleratorFactories();
// Helper to get a pointer to the WebGraphicsContext3DCommandBufferImpl,
// if it has not been lost yet.
WebGraphicsContext3DCommandBufferImpl* GetContext3d();
// Helper for the constructor to acquire the ContentGLContext on
// |task_runner_|.
void AsyncBindContext();
// Async versions of the public methods, run on |task_runner_|.
// 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.
void AsyncCreateVideoDecodeAccelerator(
media::VideoCodecProfile profile,
media::VideoDecodeAccelerator::Client* client);
void AsyncReadPixels(uint32 texture_id, const gfx::Size& size);
void AsyncDestroyVideoDecodeAccelerator();
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
scoped_refptr<GpuChannelHost> gpu_channel_host_;
scoped_refptr<ContextProviderCommandBuffer> context_provider_;
......@@ -107,20 +82,6 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
// 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_;
// This event is signaled by asynchronous tasks posted to |task_runner_| to
// indicate their completion.
// e.g. AsyncCreateVideoDecodeAccelerator()/AsyncCreateTextures() etc.
base::WaitableEvent task_runner_async_waiter_;
// The vda returned by the CreateVideoDecodeAccelerator function.
scoped_ptr<media::VideoDecodeAccelerator> vda_;
// Bitmap returned by ReadPixels().
SkBitmap read_pixels_bitmap_;
DISALLOW_COPY_AND_ASSIGN(RendererGpuVideoAcceleratorFactories);
};
......
......@@ -11,11 +11,13 @@
#include "base/metrics/histogram.h"
#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/task_runner_util.h"
#include "content/child/child_thread.h"
#include "content/renderer/media/native_handle_impl.h"
#include "media/base/bind_to_current_loop.h"
#include "media/filters/gpu_video_accelerator_factories.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/webrtc/common_video/interface/texture_video_frame.h"
#include "third_party/webrtc/system_wrappers/interface/ref_count.h"
......@@ -85,28 +87,12 @@ RTCVideoDecoder::RTCVideoDecoder(
weak_factory_(this) {
DCHECK(!vda_task_runner_->BelongsToCurrentThread());
weak_this_ = weak_factory_.GetWeakPtr();
base::WaitableEvent message_loop_async_waiter(false, false);
// Waiting here is safe. The media thread is stopped in the child thread and
// the child thread is blocked when VideoDecoderFactory::CreateVideoDecoder
// runs.
vda_task_runner_->PostTask(FROM_HERE,
base::Bind(&RTCVideoDecoder::Initialize,
base::Unretained(this),
&message_loop_async_waiter));
message_loop_async_waiter.Wait();
}
RTCVideoDecoder::~RTCVideoDecoder() {
DVLOG(2) << "~RTCVideoDecoder";
// Destroy VDA and remove |this| from the observer if this is vda thread.
if (vda_task_runner_->BelongsToCurrentThread()) {
base::MessageLoop::current()->RemoveDestructionObserver(this);
DestroyVDA();
} else {
// VDA should have been destroyed in WillDestroyCurrentMessageLoop.
DCHECK(!vda_);
}
DCHECK(vda_task_runner_->BelongsToCurrentThread());
DestroyVDA();
// Delete all shared memories.
STLDeleteElements(&available_shm_segments_);
......@@ -124,6 +110,7 @@ RTCVideoDecoder::~RTCVideoDecoder() {
}
}
// static
scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create(
webrtc::VideoCodecType type,
const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) {
......@@ -139,9 +126,15 @@ scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create(
return decoder.Pass();
}
base::WaitableEvent waiter(true, false);
decoder.reset(new RTCVideoDecoder(factories));
decoder->vda_ =
factories->CreateVideoDecodeAccelerator(profile, decoder.get()).Pass();
decoder->vda_task_runner_->PostTask(
FROM_HERE,
base::Bind(&RTCVideoDecoder::CreateVDA,
base::Unretained(decoder.get()),
profile,
&waiter));
waiter.Wait();
// vda can be NULL if VP8 is not supported.
if (decoder->vda_ != NULL) {
decoder->state_ = INITIALIZED;
......@@ -406,6 +399,33 @@ void RTCVideoDecoder::PictureReady(const media::Picture& picture) {
}
}
static void ReadPixelsSyncInner(
const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
uint32 texture_id,
const gfx::Rect& visible_rect,
const SkBitmap& pixels,
base::WaitableEvent* event) {
factories->ReadPixels(texture_id, visible_rect, pixels);
event->Signal();
}
static void ReadPixelsSync(
const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
uint32 texture_id,
const gfx::Rect& visible_rect,
const SkBitmap& pixels) {
base::WaitableEvent event(true, false);
if (!factories->GetTaskRunner()->PostTask(FROM_HERE,
base::Bind(&ReadPixelsSyncInner,
factories,
texture_id,
visible_rect,
pixels,
&event)))
return;
event.Wait();
}
scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame(
const media::Picture& picture,
const media::PictureBuffer& pb,
......@@ -414,7 +434,6 @@ scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame(
uint32_t height,
size_t size) {
gfx::Rect visible_rect(width, height);
gfx::Size natural_size(width, height);
DCHECK(decoder_texture_target_);
// Convert timestamp from 90KHz to ms.
base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue(
......@@ -430,12 +449,9 @@ scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame(
decoder_texture_target_,
pb.size(),
visible_rect,
natural_size,
visible_rect.size(),
timestamp_ms,
base::Bind(&media::GpuVideoAcceleratorFactories::ReadPixels,
factories_,
pb.texture_id(),
natural_size),
base::Bind(&ReadPixelsSync, factories_, pb.texture_id(), visible_rect),
base::Closure());
}
......@@ -496,21 +512,6 @@ void RTCVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) {
state_ = DECODE_ERROR;
}
void RTCVideoDecoder::WillDestroyCurrentMessageLoop() {
DVLOG(2) << "WillDestroyCurrentMessageLoop";
DCHECK(vda_task_runner_->BelongsToCurrentThread());
factories_->Abort();
weak_factory_.InvalidateWeakPtrs();
DestroyVDA();
}
void RTCVideoDecoder::Initialize(base::WaitableEvent* waiter) {
DVLOG(2) << "Initialize";
DCHECK(vda_task_runner_->BelongsToCurrentThread());
base::MessageLoop::current()->AddDestructionObserver(this);
waiter->Signal();
}
void RTCVideoDecoder::RequestBufferDecode() {
DCHECK(vda_task_runner_->BelongsToCurrentThread());
if (!vda_)
......@@ -670,6 +671,13 @@ void RTCVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id,
vda_->ReusePictureBuffer(picture_buffer_id);
}
void RTCVideoDecoder::CreateVDA(media::VideoCodecProfile profile,
base::WaitableEvent* waiter) {
DCHECK(vda_task_runner_->BelongsToCurrentThread());
vda_ = factories_->CreateVideoDecodeAccelerator(profile, this);
waiter->Signal();
}
void RTCVideoDecoder::DestroyTextures() {
DCHECK(vda_task_runner_->BelongsToCurrentThread());
std::map<int32, media::PictureBuffer>::iterator it;
......
......@@ -6,6 +6,7 @@
#define CONTENT_RENDERER_MEDIA_RTC_VIDEO_DECODER_H_
#include <deque>
#include <list>
#include <map>
#include <set>
#include <utility>
......@@ -13,9 +14,7 @@
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
#include "media/base/bitstream_buffer.h"
......@@ -25,6 +24,7 @@
#include "third_party/webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
namespace base {
class WaitableEvent;
class MessageLoopProxy;
};
......@@ -43,8 +43,7 @@ namespace content {
// frames are delivered to WebRTC on |vda_message_loop_|.
class CONTENT_EXPORT RTCVideoDecoder
: NON_EXPORTED_BASE(public webrtc::VideoDecoder),
public media::VideoDecodeAccelerator::Client,
public base::MessageLoop::DestructionObserver {
public media::VideoDecodeAccelerator::Client {
public:
virtual ~RTCVideoDecoder();
......@@ -87,10 +86,6 @@ class CONTENT_EXPORT RTCVideoDecoder
virtual void NotifyResetDone() OVERRIDE;
virtual void NotifyError(media::VideoDecodeAccelerator::Error error) OVERRIDE;
// base::DestructionObserver implementation. Called when |vda_message_loop_|
// is stopped.
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
private:
class SHMBuffer;
// Metadata of a bitstream buffer.
......@@ -116,8 +111,6 @@ class CONTENT_EXPORT RTCVideoDecoder
RTCVideoDecoder(
const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories);
void Initialize(base::WaitableEvent* waiter);
// Requests a buffer to be decoded by VDA.
void RequestBufferDecode();
......@@ -158,6 +151,9 @@ class CONTENT_EXPORT RTCVideoDecoder
// Tells VDA that a picture buffer can be recycled.
void ReusePictureBuffer(int64 picture_buffer_id, uint32 sync_point);
// Create |vda_| on |vda_loop_proxy_|.
void CreateVDA(media::VideoCodecProfile profile, base::WaitableEvent* waiter);
void DestroyTextures();
void DestroyVDA();
......
......@@ -6,13 +6,13 @@
#include "base/location.h"
#include "base/memory/scoped_ptr.h"
#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
#include "content/renderer/media/rtc_video_decoder.h"
#include "media/filters/gpu_video_accelerator_factories.h"
namespace content {
RTCVideoDecoderFactory::RTCVideoDecoderFactory(
const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories)
: gpu_factories_(gpu_factories) {
DVLOG(2) << "RTCVideoDecoderFactory";
}
......@@ -24,12 +24,8 @@ RTCVideoDecoderFactory::~RTCVideoDecoderFactory() {
webrtc::VideoDecoder* RTCVideoDecoderFactory::CreateVideoDecoder(
webrtc::VideoCodecType type) {
DVLOG(2) << "CreateVideoDecoder";
// GpuVideoAcceleratorFactories is not thread safe. It cannot be shared
// by different decoders. This method runs on Chrome_libJingle_WorkerThread
// and the child thread is blocked while this runs. We cannot create new gpu
// factories here. Clone one instead.
scoped_ptr<RTCVideoDecoder> decoder =
RTCVideoDecoder::Create(type, gpu_factories_->Clone());
RTCVideoDecoder::Create(type, gpu_factories_);
return decoder.release();
}
......
......@@ -13,17 +13,20 @@
namespace webrtc {
class VideoDecoder;
}
} // namespace webrtc
namespace media {
class GpuVideoAcceleratorFactories;
} // namespace media
namespace content {
class RendererGpuVideoAcceleratorFactories;
// TODO(wuchengli): add unittest.
class CONTENT_EXPORT RTCVideoDecoderFactory
: NON_EXPORTED_BASE(public cricket::WebRtcVideoDecoderFactory) {
public:
explicit RTCVideoDecoderFactory(
const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories);
virtual ~RTCVideoDecoderFactory();
// Runs on Chrome_libJingle_WorkerThread. The child thread is blocked while
......@@ -36,7 +39,7 @@ class CONTENT_EXPORT RTCVideoDecoderFactory
virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
private:
scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderFactory);
};
......
......@@ -43,7 +43,6 @@ class RTCVideoDecoderTest : public ::testing::Test,
EXPECT_CALL(*mock_gpu_factories_,
DoCreateVideoDecodeAccelerator(media::VP8PROFILE_MAIN, _))
.WillRepeatedly(Return(mock_vda_));
EXPECT_CALL(*mock_gpu_factories_, Abort()).WillRepeatedly(Return());
EXPECT_CALL(*mock_gpu_factories_, CreateSharedMemory(_))
.WillRepeatedly(Return(static_cast<base::SharedMemory*>(NULL)));
EXPECT_CALL(*mock_vda_, Destroy());
......@@ -53,15 +52,12 @@ class RTCVideoDecoderTest : public ::testing::Test,
virtual void TearDown() OVERRIDE {
VLOG(2) << "TearDown";
if (vda_thread_.IsRunning()) {
RunUntilIdle(); // Wait until all callbascks complete.
vda_task_runner_->DeleteSoon(FROM_HERE, rtc_decoder_.release());
// Make sure the decoder is released before stopping the thread.
RunUntilIdle();
vda_thread_.Stop();
} else {
rtc_decoder_.reset();
}
EXPECT_TRUE(vda_thread_.IsRunning());
RunUntilIdle(); // Wait until all callbascks complete.
vda_task_runner_->DeleteSoon(FROM_HERE, rtc_decoder_.release());
// Make sure the decoder is released before stopping the thread.
RunUntilIdle();
vda_thread_.Stop();
}
virtual int32_t Decoded(webrtc::I420VideoFrame& decoded_image) OVERRIDE {
......@@ -166,8 +162,6 @@ TEST_F(RTCVideoDecoderTest, InitDecodeAfterRelease) {
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->Release());
}
TEST_F(RTCVideoDecoderTest, VdaThreadStops) { vda_thread_.Stop(); }
TEST_F(RTCVideoDecoderTest, IsBufferAfterReset) {
EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_INVALID));
EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST,
......
......@@ -11,7 +11,6 @@
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
#include "base/synchronization/waitable_event.h"
#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
......@@ -42,9 +41,8 @@ class RTCVideoEncoder::Impl
: public media::VideoEncodeAccelerator::Client,
public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> {
public:
Impl(
const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories);
// Create the VEA and call Initialize() on it. Called once per instantiation,
// and then the instance is bound forevermore to whichever thread made the
......@@ -119,7 +117,7 @@ class RTCVideoEncoder::Impl
const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
// Factory for creating VEAs, shared memory buffers, etc.
const scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
const scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
// webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous.
// Do this by waiting on the |async_waiter_| and returning the return value in
......@@ -155,7 +153,7 @@ class RTCVideoEncoder::Impl
RTCVideoEncoder::Impl::Impl(
const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories)
: weak_encoder_(weak_encoder),
encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
gpu_factories_(gpu_factories),
......@@ -471,7 +469,7 @@ void RTCVideoEncoder::Impl::SignalAsyncWaiter(int32_t retval) {
RTCVideoEncoder::RTCVideoEncoder(
webrtc::VideoCodecType type,
media::VideoCodecProfile profile,
const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories)
: video_codec_type_(type),
video_codec_profile_(profile),
gpu_factories_(gpu_factories),
......@@ -563,9 +561,6 @@ int32_t RTCVideoEncoder::Release() {
DVLOG(3) << "Release()";
DCHECK(thread_checker_.CalledOnValidThread());
// Reset the gpu_factory_, in case we reuse this encoder.
gpu_factories_->Abort();
gpu_factories_ = gpu_factories_->Clone();
if (impl_) {
gpu_factories_->GetTaskRunner()->PostTask(
FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
......
......@@ -23,9 +23,13 @@ class MessageLoopProxy;
} // namespace base
namespace content {
namespace media {
class GpuVideoAcceleratorFactories;
class RendererGpuVideoAcceleratorFactories;
} // namespace media
namespace content {
// RTCVideoEncoder uses a media::VideoEncodeAccelerator to implement a
// webrtc::VideoEncoder class for WebRTC. Internally, VEA methods are
......@@ -41,7 +45,7 @@ class CONTENT_EXPORT RTCVideoEncoder
RTCVideoEncoder(
webrtc::VideoCodecType type,
media::VideoCodecProfile profile,
const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories);
virtual ~RTCVideoEncoder();
// webrtc::VideoEncoder implementation. Tasks are posted to |impl_| using the
......@@ -80,7 +84,7 @@ class CONTENT_EXPORT RTCVideoEncoder
const media::VideoCodecProfile video_codec_profile_;
// Factory for creating VEAs, shared memory buffers, etc.
scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
// webrtc::VideoEncoder encode complete callback.
webrtc::EncodedImageCallback* encoded_image_callback_;
......
......@@ -5,8 +5,8 @@
#include "content/renderer/media/rtc_video_encoder_factory.h"
#include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
#include "content/renderer/media/rtc_video_encoder.h"
#include "media/filters/gpu_video_accelerator_factories.h"
#include "media/video/video_encode_accelerator.h"
namespace content {
......@@ -59,7 +59,7 @@ media::VideoCodecProfile WebRTCCodecToVideoCodecProfile(
} // anonymous namespace
RTCVideoEncoderFactory::RTCVideoEncoderFactory(
const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories)
: gpu_factories_(gpu_factories) {
// Query media::VideoEncodeAccelerator (statically) for our supported codecs.
std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles =
......@@ -84,11 +84,8 @@ webrtc::VideoEncoder* RTCVideoEncoderFactory::CreateVideoEncoder(
}
if (!found)
return NULL;
// GpuVideoAcceleratorFactories is not thread safe. It cannot be shared
// by different encoders. Since we aren't running on the child thread and
// cannot create a new factory, clone one instead.
return new RTCVideoEncoder(
type, WebRTCCodecToVideoCodecProfile(type), gpu_factories_->Clone());
type, WebRTCCodecToVideoCodecProfile(type), gpu_factories_);
}
void RTCVideoEncoderFactory::AddObserver(Observer* observer) {
......
......@@ -12,9 +12,13 @@
#include "content/common/content_export.h"
#include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoencoderfactory.h"
namespace content {
namespace media {
class GpuVideoAcceleratorFactories;
class RendererGpuVideoAcceleratorFactories;
} // namespace media
namespace content {
// This class creates RTCVideoEncoder instances (each wrapping a
// media::VideoEncodeAccelerator) on behalf of the WebRTC stack.
......@@ -22,7 +26,7 @@ class CONTENT_EXPORT RTCVideoEncoderFactory
: NON_EXPORTED_BASE(public cricket::WebRtcVideoEncoderFactory) {
public:
explicit RTCVideoEncoderFactory(
const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories);
virtual ~RTCVideoEncoderFactory();
// cricket::WebRtcVideoEncoderFactory implementation.
......@@ -34,7 +38,7 @@ class CONTENT_EXPORT RTCVideoEncoderFactory
virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
private:
const scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
const scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
// Codec support list of cricket::WebRtcVideoEncoderFactory::VideoCodec
// instances.
......
......@@ -1204,10 +1204,7 @@ void WebMediaPlayerImpl::Destroy() {
chunk_demuxer_ = NULL;
}
if (gpu_factories_.get()) {
gpu_factories_->Abort();
gpu_factories_ = NULL;
}
gpu_factories_ = NULL;
// Make sure to kill the pipeline so there's no more media threads running.
// Note: stopping the pipeline might block for a long time.
......
......@@ -895,6 +895,8 @@ RenderThreadImpl::GetGpuFactories() {
scoped_refptr<GpuChannelHost> gpu_channel_host = GetGpuChannel();
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories;
scoped_refptr<base::MessageLoopProxy> media_loop_proxy =
GetMediaThreadMessageLoopProxy();
if (!cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
if (!gpu_va_context_provider_ ||
gpu_va_context_provider_->DestroyedOnMainThread()) {
......@@ -910,11 +912,16 @@ RenderThreadImpl::GetGpuFactories() {
GURL("chrome://gpu/RenderThreadImpl::GetGpuVDAContext3D"),
WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits())),
"GPU-VideoAccelerator-Offscreen");
media_loop_proxy->PostTask(
FROM_HERE,
base::Bind(
base::IgnoreResult(&cc::ContextProvider::BindToCurrentThread),
gpu_va_context_provider_));
}
}
if (gpu_channel_host) {
gpu_factories = new RendererGpuVideoAcceleratorFactories(
gpu_channel_host.get(), gpu_va_context_provider_);
gpu_channel_host, media_loop_proxy, gpu_va_context_provider_);
}
return gpu_factories;
}
......
......@@ -58,10 +58,6 @@ FakeGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator(
static_cast<media::VideoDecodeAccelerator*>(NULL));
}
bool FakeGpuVideoAcceleratorFactories::IsAborted() {
return false;
}
} // namespace test
} // namespace cast
} // namespace media
......
......@@ -39,17 +39,13 @@ class FakeGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories {
virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE {}
virtual void ReadPixels(uint32 texture_id,
const gfx::Size& size,
const gfx::Rect& visible_rect,
const SkBitmap& pixels) OVERRIDE {};
virtual scoped_ptr<VideoDecodeAccelerator> CreateVideoDecodeAccelerator(
VideoCodecProfile profile,
VideoDecodeAccelerator::Client* client) OVERRIDE;
virtual void Abort() OVERRIDE {}
virtual bool IsAborted() OVERRIDE;
private:
friend class base::RefCountedThreadSafe<FakeGpuVideoAcceleratorFactories>;
virtual ~FakeGpuVideoAcceleratorFactories();
......
......@@ -21,6 +21,12 @@ namespace media {
// Helper interface for specifying factories needed to instantiate a hardware
// video accelerator.
// Threading model:
// * The GpuVideoAcceleratorFactories may be constructed on any thread.
// * The GpuVideoAcceleratorFactories has an associated message loop, which may
// be retrieved as |GetMessageLoop()|.
// * All calls to the Factories after construction must be made on its message
// loop.
class MEDIA_EXPORT GpuVideoAcceleratorFactories
: public base::RefCountedThreadSafe<GpuVideoAcceleratorFactories> {
public:
......@@ -43,9 +49,10 @@ class MEDIA_EXPORT GpuVideoAcceleratorFactories
virtual void WaitSyncPoint(uint32 sync_point) = 0;
// Read pixels from a native texture and store into |pixels| as RGBA.
// Read pixels within |visible_rect| boundaries from a native texture and
// store into |pixels| as RGBA.
virtual void ReadPixels(uint32 texture_id,
const gfx::Size& size,
const gfx::Rect& visible_rect,
const SkBitmap& pixels) = 0;
// Allocate & return a shared memory segment. Caller is responsible for
......@@ -55,13 +62,6 @@ class MEDIA_EXPORT GpuVideoAcceleratorFactories
// Returns the task runner the video accelerator runs on.
virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() = 0;
// Abort any outstanding factory operations and error any future
// attempts at factory operations
virtual void Abort() = 0;
// Returns true if Abort() has been called.
virtual bool IsAborted() = 0;
protected:
friend class base::RefCountedThreadSafe<GpuVideoAcceleratorFactories>;
virtual ~GpuVideoAcceleratorFactories();
......
......@@ -12,6 +12,7 @@
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/task_runner_util.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/decoder_buffer.h"
......@@ -20,6 +21,7 @@
#include "media/base/pipeline_status.h"
#include "media/base/video_decoder_config.h"
#include "media/filters/gpu_video_accelerator_factories.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace media {
......@@ -72,7 +74,7 @@ void GpuVideoDecoder::Reset(const base::Closure& closure) {
DVLOG(3) << "Reset()";
DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
if (state_ == kDrainingDecoder && !factories_->IsAborted()) {
if (state_ == kDrainingDecoder) {
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
&GpuVideoDecoder::Reset, weak_this_, closure));
// NOTE: if we're deferring Reset() until a Flush() completes, return
......@@ -420,6 +422,33 @@ void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
}
}
static void ReadPixelsSyncInner(
const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
uint32 texture_id,
const gfx::Rect& visible_rect,
const SkBitmap& pixels,
base::WaitableEvent* event) {
factories->ReadPixels(texture_id, visible_rect, pixels);
event->Signal();
}
static void ReadPixelsSync(
const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
uint32 texture_id,
const gfx::Rect& visible_rect,
const SkBitmap& pixels) {
base::WaitableEvent event(true, false);
if (!factories->GetTaskRunner()->PostTask(FROM_HERE,
base::Bind(&ReadPixelsSyncInner,
factories,
texture_id,
visible_rect,
pixels,
&event)))
return;
event.Wait();
}
void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
DVLOG(3) << "PictureReady()";
DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
......@@ -453,10 +482,7 @@ void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
visible_rect,
natural_size,
timestamp,
base::Bind(&GpuVideoAcceleratorFactories::ReadPixels,
factories_,
pb.texture_id(),
gfx::Size(visible_rect.width(), visible_rect.height())),
base::Bind(&ReadPixelsSync, factories_, pb.texture_id(), visible_rect),
base::Closure()));
CHECK_GT(available_pictures_, 0);
--available_pictures_;
......
......@@ -44,12 +44,10 @@ class MockGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories {
MOCK_METHOD1(WaitSyncPoint, void(uint32 sync_point));
MOCK_METHOD3(ReadPixels,
void(uint32 texture_id,
const gfx::Size& size,
const gfx::Rect& visible_rect,
const SkBitmap& pixels));
MOCK_METHOD1(CreateSharedMemory, base::SharedMemory*(size_t size));
MOCK_METHOD0(GetTaskRunner, scoped_refptr<base::SingleThreadTaskRunner>());
MOCK_METHOD0(Abort, void());
MOCK_METHOD0(IsAborted, bool());
virtual scoped_ptr<VideoDecodeAccelerator> CreateVideoDecodeAccelerator(
VideoCodecProfile profile,
......
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