Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(986)

Unified Diff: media/filters/gpu_video_decoder.cc

Issue 12989009: Remove reference counting from media::VideoDecoder and friends. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: client proxy :( Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/gpu_video_decoder.h ('k') | media/filters/pipeline_integration_test_base.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/gpu_video_decoder.cc
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 71994156880483ffe34186e97aa6ec1715b8c972..9c7ddb2ae05c5fb86d9d6525b9c70e3dfa01cafd 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -9,6 +9,7 @@
#include "base/cpu.h"
#include "base/message_loop.h"
#include "base/stl_util.h"
+#include "base/task_runner_util.h"
#include "media/base/bind_to_loop.h"
#include "media/base/decoder_buffer.h"
#include "media/base/demuxer_stream.h"
@@ -18,6 +19,108 @@
namespace media {
+// Proxies calls to a VideoDecodeAccelerator::Client from the calling thread to
+// a thread of the client's choice.
Ami GONE FROM CHROMIUM 2013/04/05 21:05:48 Crazy Question Time(tm): What would happen if you
scherkus (not reviewing) 2013/04/05 21:16:12 I don't think it's too crazy but let's make sure I
+class VDAClientProxy
+ : public base::RefCountedThreadSafe<VDAClientProxy>,
+ public VideoDecodeAccelerator::Client {
+ public:
+ VDAClientProxy(const scoped_refptr<base::MessageLoopProxy>& client_loop,
Ami GONE FROM CHROMIUM 2013/04/05 21:05:48 This is always MessageLoopProxy::current() so I'd
scherkus (not reviewing) 2013/04/17 16:54:54 Done.
+ VideoDecodeAccelerator::Client* client);
+
+ // Detaches the proxy. |client| will no longer be called and can be safely
+ // deleted. Any pending/future calls will be discarded.
+ //
+ // Must be called on |client_loop|.
+ void Detach();
+
+ // VideoDecodeAccelerator::Client implementation.
+ virtual void NotifyInitializeDone() OVERRIDE;
+ virtual void ProvidePictureBuffers(uint32 count,
+ const gfx::Size& size,
+ uint32 texture_target) OVERRIDE;
+ virtual void DismissPictureBuffer(int32 id) OVERRIDE;
+ virtual void PictureReady(const media::Picture& picture) OVERRIDE;
+ virtual void NotifyEndOfBitstreamBuffer(int32 id) OVERRIDE;
+ virtual void NotifyFlushDone() OVERRIDE;
+ virtual void NotifyResetDone() OVERRIDE;
+ virtual void NotifyError(media::VideoDecodeAccelerator::Error error) OVERRIDE;
+
+ private:
+ friend class base::RefCountedThreadSafe<VDAClientProxy>;
+ virtual ~VDAClientProxy();
+
+ scoped_refptr<base::MessageLoopProxy> client_loop_;
+
+ // Weak pointers are used to invalidate tasks posted to |client_loop_| that
+ // Detach() has been called.
+ base::WeakPtrFactory<VideoDecodeAccelerator::Client> weak_client_factory_;
+ base::WeakPtr<VideoDecodeAccelerator::Client> weak_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(VDAClientProxy);
+};
+
+VDAClientProxy::VDAClientProxy(
+ const scoped_refptr<base::MessageLoopProxy>& client_loop,
+ VideoDecodeAccelerator::Client* client)
+ : client_loop_(client_loop),
+ weak_client_factory_(client),
+ weak_client_(weak_client_factory_.GetWeakPtr()) {
+}
+
+VDAClientProxy::~VDAClientProxy() {}
Ami GONE FROM CHROMIUM 2013/04/05 21:05:48 DCHECK already Detach()d
scherkus (not reviewing) 2013/04/17 16:54:54 Done.
+
+void VDAClientProxy::Detach() {
+ DCHECK(client_loop_->BelongsToCurrentThread());
Ami GONE FROM CHROMIUM 2013/04/05 21:05:48 DCHECK not already detached to catch programming e
scherkus (not reviewing) 2013/04/17 16:54:54 Done.
+ weak_client_factory_.InvalidateWeakPtrs();
+ DCHECK(!weak_client_);
+}
+
+void VDAClientProxy::NotifyInitializeDone() {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyInitializeDone, weak_client_));
+}
+
+void VDAClientProxy::ProvidePictureBuffers(uint32 count,
+ const gfx::Size& size,
+ uint32 texture_target) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::ProvidePictureBuffers, weak_client_,
+ count, size, texture_target));
+}
+
+void VDAClientProxy::DismissPictureBuffer(int32 id) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::DismissPictureBuffer, weak_client_, id));
+}
+
+void VDAClientProxy::PictureReady(const media::Picture& picture) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::PictureReady, weak_client_, picture));
+}
+
+void VDAClientProxy::NotifyEndOfBitstreamBuffer(int32 id) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer, weak_client_,
+ id));
+}
+
+void VDAClientProxy::NotifyFlushDone() {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyFlushDone, weak_client_));
+}
+
+void VDAClientProxy::NotifyResetDone() {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyResetDone, weak_client_));
+}
+
+void VDAClientProxy::NotifyError(media::VideoDecodeAccelerator::Error error) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyError, weak_client_, error));
+}
+
+
// Maximum number of concurrent VDA::Decode() operations GVD will maintain.
// Higher values allow better pipelining in the GPU, but also require more
// resources.
@@ -54,6 +157,7 @@ GpuVideoDecoder::GpuVideoDecoder(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
const scoped_refptr<Factories>& factories)
: gvd_loop_proxy_(message_loop),
+ weak_factory_(this),
vda_loop_proxy_(factories->GetMessageLoop()),
factories_(factories),
state_(kNormal),
@@ -71,7 +175,7 @@ void GpuVideoDecoder::Reset(const base::Closure& closure) {
if (state_ == kDrainingDecoder && !factories_->IsAborted()) {
gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::Reset, this, closure));
+ &GpuVideoDecoder::Reset, weak_this_, closure));
// NOTE: if we're deferring Reset() until a Flush() completes, return
// queued pictures to the VDA so they can be used to finish that Flush().
if (pending_read_cb_.is_null())
@@ -114,6 +218,8 @@ void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
const PipelineStatusCB& orig_status_cb,
const StatisticsCB& statistics_cb) {
DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
+ weak_this_ = weak_factory_.GetWeakPtr();
+
PipelineStatusCB status_cb = CreateUMAReportingPipelineCB(
"Media.GpuVideoDecoderInitializeStatus",
BindToCurrentLoop(orig_status_cb));
@@ -151,8 +257,9 @@ void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
}
}
+ client_proxy_ = new VDAClientProxy(gvd_loop_proxy_, this);
VideoDecodeAccelerator* vda =
- factories_->CreateVideoDecodeAccelerator(config.profile(), this);
+ factories_->CreateVideoDecodeAccelerator(config.profile(), client_proxy_);
if (!vda) {
status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
return;
@@ -165,17 +272,21 @@ void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
statistics_cb_ = statistics_cb;
DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded.";
- vda_loop_proxy_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&GpuVideoDecoder::SetVDA, this, vda),
- base::Bind(status_cb, PIPELINE_OK));
+ PostTaskAndReplyWithResult(
+ vda_loop_proxy_, FROM_HERE,
+ base::Bind(&VideoDecodeAccelerator::AsWeakPtr, base::Unretained(vda)),
+ base::Bind(&GpuVideoDecoder::SetVDA, weak_this_, status_cb, vda));
}
-void GpuVideoDecoder::SetVDA(VideoDecodeAccelerator* vda) {
- DCHECK(vda_loop_proxy_->BelongsToCurrentThread());
+void GpuVideoDecoder::SetVDA(
+ const PipelineStatusCB& status_cb,
+ VideoDecodeAccelerator* vda,
+ base::WeakPtr<VideoDecodeAccelerator> weak_vda) {
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
DCHECK(!vda_.get());
vda_.reset(vda);
- weak_vda_ = vda->AsWeakPtr();
+ weak_vda_ = weak_vda;
+ status_cb.Run(PIPELINE_OK);
}
void GpuVideoDecoder::DestroyTextures() {
@@ -187,17 +298,23 @@ void GpuVideoDecoder::DestroyTextures() {
picture_buffers_in_decoder_.clear();
}
+static void DestroyVDAWithClientProxy(
+ const scoped_refptr<VDAClientProxy>& client_proxy,
Ami GONE FROM CHROMIUM 2013/04/05 21:05:48 so this is only here to keep the proxy alive until
scherkus (not reviewing) 2013/04/17 16:54:54 Done.
+ base::WeakPtr<VideoDecodeAccelerator> weak_vda) {
+ if (weak_vda)
+ weak_vda->Destroy();
+}
+
void GpuVideoDecoder::DestroyVDA() {
DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
+
+ // |client_proxy| must stay alive until |weak_vda_| has been destroyed.
+ vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
+ &DestroyVDAWithClientProxy, client_proxy_, weak_vda_));
+
VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release();
- // Tricky: |this| needs to stay alive until after VDA::Destroy is actually
- // called, not just posted, so we take an artificial ref to |this| and release
- // it as |reply| after VDA::Destroy() returns.
- AddRef();
- vda_loop_proxy_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&VideoDecodeAccelerator::Destroy, weak_vda_),
- base::Bind(&GpuVideoDecoder::Release, this));
+ client_proxy_->Detach();
+ client_proxy_ = NULL;
DestroyTextures();
}
@@ -245,13 +362,9 @@ bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() {
void GpuVideoDecoder::RequestBufferDecode(
DemuxerStream::Status status,
const scoped_refptr<DecoderBuffer>& buffer) {
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status;
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::RequestBufferDecode, this, status, buffer));
- return;
- }
demuxer_read_in_progress_ = false;
if (status != DemuxerStream::kOk) {
@@ -356,12 +469,7 @@ void GpuVideoDecoder::NotifyInitializeDone() {
void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
const gfx::Size& size,
uint32 texture_target) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::ProvidePictureBuffers, this, count, size,
- texture_target));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
std::vector<uint32> texture_ids;
decoder_texture_target_ = texture_target;
@@ -391,11 +499,8 @@ void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
}
void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::DismissPictureBuffer, this, id));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
+
std::map<int32, PictureBuffer>::iterator it =
picture_buffers_in_decoder_.find(id);
if (it == picture_buffers_in_decoder_.end()) {
@@ -407,11 +512,8 @@ void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
}
void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::PictureReady, this, picture));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
+
std::map<int32, PictureBuffer>::iterator it =
picture_buffers_in_decoder_.find(picture.picture_buffer_id());
if (it == picture_buffers_in_decoder_.end()) {
@@ -435,8 +537,9 @@ void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(),
decoder_texture_target_,
gfx::Size(visible_rect.width(), visible_rect.height())),
- base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this,
- picture.picture_buffer_id())));
+ BindToCurrentLoop(base::Bind(
+ &GpuVideoDecoder::ReusePictureBuffer, weak_this_,
+ picture.picture_buffer_id()))));
CHECK_GT(available_pictures_, 0);
available_pictures_--;
@@ -465,11 +568,7 @@ void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery(
}
void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::ReusePictureBuffer, this, picture_buffer_id));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
CHECK_GE(available_pictures_, 0);
available_pictures_++;
@@ -502,11 +601,7 @@ void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) {
}
void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyEndOfBitstreamBuffer, this, id));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
std::map<int32, BufferPair>::iterator it =
bitstream_buffers_in_decoder_.find(id);
@@ -556,27 +651,18 @@ void GpuVideoDecoder::EnsureDemuxOrDecode() {
demuxer_read_in_progress_ = true;
gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
&DemuxerStream::Read, demuxer_stream_.get(),
- base::Bind(&GpuVideoDecoder::RequestBufferDecode, this)));
+ base::Bind(&GpuVideoDecoder::RequestBufferDecode, weak_this_)));
}
void GpuVideoDecoder::NotifyFlushDone() {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyFlushDone, this));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
DCHECK_EQ(state_, kDrainingDecoder);
state_ = kDecoderDrained;
EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
}
void GpuVideoDecoder::NotifyResetDone() {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyResetDone, this));
- return;
- }
-
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
DCHECK(ready_video_frames_.empty());
// This needs to happen after the Reset() on vda_ is done to ensure pictures
@@ -591,11 +677,7 @@ void GpuVideoDecoder::NotifyResetDone() {
}
void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyError, this, error));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
if (!vda_.get())
return;
« no previous file with comments | « media/filters/gpu_video_decoder.h ('k') | media/filters/pipeline_integration_test_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698