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 |