Chromium Code Reviews| Index: content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc |
| diff --git a/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc b/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc |
| index 88878d552107a537219f3b445877df4923849adc..5a8bf07c2e7534c6e87103f2a89b4f2af5762c37 100644 |
| --- a/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc |
| +++ b/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc |
| @@ -4,31 +4,180 @@ |
| #include "content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h" |
| +#include <algorithm> |
| + |
| +#include "base/bind.h" |
| +#include "base/callback.h" |
| +#include "base/location.h" |
| +#include "base/memory/weak_ptr.h" |
| +#include "base/message_loop/message_loop_proxy.h" |
| +#include "base/process/process.h" |
| +#include "base/synchronization/lock.h" |
| +#include "cc/output/context_provider.h" |
| +#include "content/common/android/surface_texture_peer.h" |
| +#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" |
| +#include "ui/gl/android/surface_texture_bridge.h" |
| + |
| namespace content { |
| -StreamTextureFactorySynchronousImpl::StreamTextureFactorySynchronousImpl() {} |
| +namespace { |
| + |
| +class StreamTextureProxyImpl |
| + : public StreamTextureProxy, |
| + public base::SupportsWeakPtr<StreamTextureProxyImpl> { |
| + public: |
| + explicit StreamTextureProxyImpl( |
| + StreamTextureFactorySynchronousImpl::ContextProvider* provider); |
| + virtual ~StreamTextureProxyImpl(); |
| + |
| + // StreamTextureProxy implementation: |
| + virtual void BindToCurrentThread(int32 stream_id) OVERRIDE; |
| + virtual bool IsBoundToThread() OVERRIDE { return loop_.get() != NULL; } |
| + virtual void SetClient(cc::VideoFrameProvider::Client* client) OVERRIDE; |
| + virtual void Release() OVERRIDE; |
| + |
| + private: |
| + void OnFrameAvailable(); |
| + |
| + scoped_refptr<base::MessageLoopProxy> loop_; |
| + base::Lock client_lock_; |
| + cc::VideoFrameProvider::Client* client_; |
| + base::Closure callback_; |
| + |
| + scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider> |
| + context_provider_; |
| + scoped_refptr<gfx::SurfaceTextureBridge> surface_texture_; |
| + |
| + float current_matrix_[16]; |
| + bool has_updated_; |
| + |
| + DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureProxyImpl); |
| +}; |
| + |
| +StreamTextureProxyImpl::StreamTextureProxyImpl( |
| + StreamTextureFactorySynchronousImpl::ContextProvider* provider) |
| + : context_provider_(provider), has_updated_(false) { |
| + std::fill(current_matrix_, current_matrix_ + 16, 0); |
| +} |
| + |
| +StreamTextureProxyImpl::~StreamTextureProxyImpl() {} |
| + |
| +void StreamTextureProxyImpl::Release() { |
| + SetClient(NULL); |
| + if (loop_.get() && loop_.get() != base::MessageLoopProxy::current()) |
| + loop_->DeleteSoon(FROM_HERE, this); |
| + else |
| + delete this; |
| +} |
| + |
| +void StreamTextureProxyImpl::SetClient(cc::VideoFrameProvider::Client* client) { |
| + base::AutoLock lock(client_lock_); |
| + client_ = client; |
| +} |
| + |
| +void StreamTextureProxyImpl::BindToCurrentThread(int stream_id) { |
| + if (loop_) { |
| + LOG(ERROR) << "Already bound to thread."; |
|
boliu
2013/08/20 21:33:49
I think this can be called multiple times if the v
no sievers
2013/08/20 21:59:58
Argh, that was never intended, but ok.
|
| + return; |
| + } |
| + loop_ = base::MessageLoopProxy::current(); |
|
boliu
2013/08/20 21:33:49
Hmm...should we have two thread checkers, one for
no sievers
2013/08/20 21:59:58
Constructor, Release and SetClient can be called o
|
| + DCHECK(callback_.is_null()); |
| + |
| + surface_texture_ = context_provider_->GetSurfaceTexture(stream_id); |
| + if (!surface_texture_) { |
| + LOG(ERROR) << "Failed to get SurfaceTexture for stream."; |
| + return; |
| + } |
| + |
| + callback_ = |
| + base::Bind(&StreamTextureProxyImpl::OnFrameAvailable, AsWeakPtr()); |
| + surface_texture_->SetFrameAvailableCallback(callback_); |
| +} |
| + |
| +void StreamTextureProxyImpl::OnFrameAvailable() { |
| + // GetTransformMatrix only returns something valid after both is true: |
| + // - OnFrameAvailable was called |
| + // - we called UpdateTexImage |
| + if (has_updated_) { |
| + float matrix[16]; |
| + surface_texture_->GetTransformMatrix(matrix); |
| + |
| + if (memcmp(current_matrix_, matrix, sizeof(matrix)) != 0) { |
| + memcpy(current_matrix_, matrix, sizeof(matrix)); |
| + |
| + base::AutoLock lock(client_lock_); |
| + if (client_) |
| + client_->DidUpdateMatrix(current_matrix_); |
| + } |
| + } |
| + // OnFrameAvailable being called a second time implies that we called |
| + // updateTexImage since after we received the first frame. |
| + has_updated_ = true; |
| + |
| + base::AutoLock lock(client_lock_); |
| + if (client_) |
| + client_->DidReceiveFrame(); |
| +} |
| + |
| +} // namespace |
| + |
| +StreamTextureFactorySynchronousImpl::StreamTextureFactorySynchronousImpl( |
| + ContextProvider* context_provider, |
| + int view_id) |
| + : context_provider_(context_provider), view_id_(view_id) {} |
| + |
| StreamTextureFactorySynchronousImpl::~StreamTextureFactorySynchronousImpl() {} |
| StreamTextureProxy* StreamTextureFactorySynchronousImpl::CreateProxy() { |
| - return NULL; |
| + return new StreamTextureProxyImpl(context_provider_); |
| } |
| void StreamTextureFactorySynchronousImpl::EstablishPeer(int32 stream_id, |
| - int player_id) {} |
| + int player_id) { |
| + scoped_refptr<gfx::SurfaceTextureBridge> surface_texture = |
| + context_provider_->GetSurfaceTexture(stream_id); |
| + if (surface_texture) { |
| + SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer( |
| + base::Process::Current().handle(), |
| + surface_texture, |
| + view_id_, |
| + player_id); |
| + } |
| +} |
| unsigned StreamTextureFactorySynchronousImpl::CreateStreamTexture( |
| unsigned texture_target, |
| unsigned* texture_id, |
| gpu::Mailbox* texture_mailbox, |
| unsigned* texture_mailbox_sync_point) { |
| - return 0; |
| + WebKit::WebGraphicsContext3D* context = context_provider_->Context3d(); |
| + unsigned stream_id = 0; |
| + if (context->makeContextCurrent()) { |
| + *texture_id = context->createTexture(); |
| + stream_id = context->createStreamTextureCHROMIUM(*texture_id); |
| + |
| + context->genMailboxCHROMIUM(texture_mailbox->name); |
| + context->bindTexture(texture_target, *texture_id); |
| + context->produceTextureCHROMIUM(texture_target, texture_mailbox->name); |
| + |
| + context->flush(); |
| + *texture_mailbox_sync_point = context->insertSyncPoint(); |
| + } |
| + return stream_id; |
| } |
| void StreamTextureFactorySynchronousImpl::DestroyStreamTexture( |
| - unsigned texture_id) {} |
| + unsigned texture_id) { |
| + WebKit::WebGraphicsContext3D* context = context_provider_->Context3d(); |
| + if (context->makeContextCurrent()) { |
| + context->destroyStreamTextureCHROMIUM(texture_id); |
| + context->deleteTexture(texture_id); |
| + context->flush(); |
| + } |
| +} |
| void StreamTextureFactorySynchronousImpl::SetStreamTextureSize( |
| - int32 texture_id, |
| + int32 stream_id, |
| const gfx::Size& size) {} |
| } // namespace content |