Commit 05681d39 authored by Chris Watkins's avatar Chris Watkins Committed by Commit Bot

media: Make SurfaceTextureGLOwner mockable and add a mock.

This converts STGLO to be a pure virtual interface so we can mock it.
It will be used in a coming CL.

Bug: 660942
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: Ief880307a7ea47d9284fdd26f624de6bf39a6c86
Reviewed-on: https://chromium-review.googlesource.com/520662Reviewed-by: default avatarJohn Bauman <jbauman@chromium.org>
Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Commit-Queue: Chris Watkins <watk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#476537}
parent b71f6a8e
......@@ -459,6 +459,8 @@ source_set("android_video_decode_accelerator_unittests") {
"android_video_surface_chooser_impl_unittest.cc",
"avda_codec_allocator_unittest.cc",
"content_video_view_overlay_allocator_unittest.cc",
"mock_surface_texture_gl_owner.cc",
"mock_surface_texture_gl_owner.h",
"surface_texture_gl_owner_unittest.cc",
]
if (enable_media_codec_video_decoder) {
......
......@@ -27,15 +27,17 @@ class FakeCodecAllocator : public testing::NiceMock<AVDACodecAllocator> {
// implementation of their respective functions. This allows tests to set
// expectations on them.
MOCK_METHOD2(MockCreateMediaCodecSync,
void(AndroidOverlay*, gl::SurfaceTexture*));
void(AndroidOverlay*, SurfaceTextureGLOwner*));
MOCK_METHOD2(MockCreateMediaCodecAsync,
void(AndroidOverlay*, gl::SurfaceTexture*));
void(AndroidOverlay*, SurfaceTextureGLOwner*));
// Note that this doesn't exactly match the signature, since unique_ptr
// doesn't work. plus, we expand |surface_bundle| a bit to make it more
// convenient to set expectations.
MOCK_METHOD3(MockReleaseMediaCodec,
void(MediaCodecBridge*, AndroidOverlay*, gl::SurfaceTexture*));
void(MediaCodecBridge*,
AndroidOverlay*,
SurfaceTextureGLOwner*));
std::unique_ptr<MediaCodecBridge> CreateMediaCodecSync(
scoped_refptr<CodecConfig> codec_config) override;
......@@ -69,7 +71,7 @@ class FakeCodecAllocator : public testing::NiceMock<AVDACodecAllocator> {
// Returns the most recent overlay / etc. that we were given during codec
// allocation (sync or async).
AndroidOverlay* most_recent_overlay() { return most_recent_overlay_; }
gl::SurfaceTexture* most_recent_surface_texture() {
SurfaceTextureGLOwner* most_recent_surface_texture() {
return most_recent_surface_texture_;
}
......@@ -90,7 +92,7 @@ class FakeCodecAllocator : public testing::NiceMock<AVDACodecAllocator> {
AndroidOverlay* most_recent_overlay_ = nullptr;
// The most recent surface texture provided during codec allocation.
gl::SurfaceTexture* most_recent_surface_texture_ = nullptr;
SurfaceTextureGLOwner* most_recent_surface_texture_ = nullptr;
// Whether CreateMediaCodecSync() is allowed to succeed.
bool allow_sync_creation = true;
......
......@@ -150,7 +150,7 @@ void MediaCodecVideoDecoder::StartLazyInit() {
DVLOG(2) << __func__;
lazy_init_pending_ = false;
// TODO(watk): Initialize surface_texture_ properly.
surface_texture_ = SurfaceTextureGLOwner::Create();
surface_texture_ = SurfaceTextureGLOwnerImpl::Create();
InitializeSurfaceChooser();
}
......
......@@ -54,12 +54,12 @@ bool AVDAPictureBufferManager::Initialize(
if (!surface_bundle->overlay) {
// Create the surface texture.
surface_texture_ = SurfaceTextureGLOwner::Create();
surface_texture_ = SurfaceTextureGLOwnerImpl::Create();
if (!surface_texture_)
return false;
surface_bundle->surface_texture_surface =
gl::ScopedJavaSurface(surface_texture_.get());
surface_texture_->CreateJavaSurface();
surface_bundle->surface_texture = surface_texture_;
}
......
......@@ -29,7 +29,7 @@ class AVDASharedState : public base::RefCounted<AVDASharedState> {
AVDASharedState(scoped_refptr<AVDASurfaceBundle> surface_bundle);
GLuint surface_texture_service_id() const {
return surface_texture() ? surface_texture()->texture_id() : 0;
return surface_texture() ? surface_texture()->GetTextureId() : 0;
}
SurfaceTextureGLOwner* surface_texture() const {
......@@ -43,11 +43,11 @@ class AVDASharedState : public base::RefCounted<AVDASharedState> {
// Context and surface that |surface_texture_| is bound to, if
// |surface_texture_| is not null.
gl::GLContext* context() const {
return surface_texture() ? surface_texture()->context() : nullptr;
return surface_texture() ? surface_texture()->GetContext() : nullptr;
}
gl::GLSurface* surface() const {
return surface_texture() ? surface_texture()->surface() : nullptr;
return surface_texture() ? surface_texture()->GetSurface() : nullptr;
}
// Helper method for coordinating the interactions between
......
......@@ -16,7 +16,7 @@ AVDASurfaceBundle::AVDASurfaceBundle(std::unique_ptr<AndroidOverlay> overlay)
AVDASurfaceBundle::AVDASurfaceBundle(
scoped_refptr<SurfaceTextureGLOwner> surface_texture_owner)
: surface_texture(std::move(surface_texture_owner)),
surface_texture_surface(gl::ScopedJavaSurface(surface_texture.get())) {}
surface_texture_surface(surface_texture->CreateJavaSurface()) {}
AVDASurfaceBundle::~AVDASurfaceBundle() {
// Explicitly free the surface first, just to be sure that it's deleted before
......@@ -25,7 +25,7 @@ AVDASurfaceBundle::~AVDASurfaceBundle() {
// Also release the back buffers.
if (surface_texture)
surface_texture->ReleaseSurfaceTexture();
surface_texture->ReleaseBackBuffers();
surface_texture = nullptr;
}
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/gpu/mock_surface_texture_gl_owner.h"
namespace media {
MockSurfaceTextureGLOwner::MockSurfaceTextureGLOwner() = default;
MockSurfaceTextureGLOwner::~MockSurfaceTextureGLOwner() = default;
} // namespace media
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_MOCK_SURFACE_TEXTURE_GL_OWNER_H_
#define MEDIA_GPU_MOCK_SURFACE_TEXTURE_GL_OWNER_H_
#include "media/gpu/surface_texture_gl_owner.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
class MockSurfaceTextureGLOwner : public SurfaceTextureGLOwner {
public:
MockSurfaceTextureGLOwner();
MOCK_CONST_METHOD0(GetTextureId, GLuint());
MOCK_CONST_METHOD0(GetContext, gl::GLContext*());
MOCK_CONST_METHOD0(GetSurface, gl::GLSurface*());
MOCK_CONST_METHOD0(CreateJavaSurface, gl::ScopedJavaSurface());
MOCK_METHOD0(UpdateTexImage, void());
MOCK_METHOD1(GetTransformMatrix, void(float mtx[16]));
MOCK_METHOD0(ReleaseBackBuffers, void());
MOCK_METHOD0(SetReleaseTimeToNow, void());
MOCK_METHOD0(IgnorePendingRelease, void());
MOCK_METHOD0(IsExpectingFrameAvailable, bool());
MOCK_METHOD0(WaitForFrameAvailable, void());
protected:
~MockSurfaceTextureGLOwner();
};
} // namespace media
#endif // MEDIA_GPU_MOCK_SURFACE_TEXTURE_GL_OWNER_H_
......@@ -14,7 +14,7 @@
namespace media {
// FrameAvailableEvent is a RefCounted wrapper for a WaitableEvent
// because it's not possible to put one in RefCountedData.
// (it's not possible to put one in RefCountedData).
// This lets us safely signal an event on any thread.
struct FrameAvailableEvent
: public base::RefCountedThreadSafe<FrameAvailableEvent> {
......@@ -29,7 +29,7 @@ struct FrameAvailableEvent
~FrameAvailableEvent() = default;
};
scoped_refptr<SurfaceTextureGLOwner> SurfaceTextureGLOwner::Create() {
scoped_refptr<SurfaceTextureGLOwner> SurfaceTextureGLOwnerImpl::Create() {
GLuint texture_id;
glGenTextures(1, &texture_id);
if (!texture_id)
......@@ -44,25 +44,25 @@ scoped_refptr<SurfaceTextureGLOwner> SurfaceTextureGLOwner::Create() {
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
return new SurfaceTextureGLOwner(texture_id);
return new SurfaceTextureGLOwnerImpl(texture_id);
}
SurfaceTextureGLOwner::SurfaceTextureGLOwner(GLuint texture_id)
: SurfaceTexture(CreateJavaSurfaceTexture(texture_id)),
SurfaceTextureGLOwnerImpl::SurfaceTextureGLOwnerImpl(GLuint texture_id)
: surface_texture_(gl::SurfaceTexture::Create(texture_id)),
texture_id_(texture_id),
context_(gl::GLContext::GetCurrent()),
surface_(gl::GLSurface::GetCurrent()),
texture_id_(texture_id),
frame_available_event_(new FrameAvailableEvent()) {
DCHECK(context_);
DCHECK(surface_);
SetFrameAvailableCallbackOnAnyThread(
surface_texture_->SetFrameAvailableCallbackOnAnyThread(
base::Bind(&FrameAvailableEvent::Signal, frame_available_event_));
}
SurfaceTextureGLOwner::~SurfaceTextureGLOwner() {
SurfaceTextureGLOwnerImpl::~SurfaceTextureGLOwnerImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
// Make sure that the SurfaceTexture isn't using the GL objects.
DestroyJavaObject();
surface_texture_ = nullptr;
ui::ScopedMakeCurrent scoped_make_current(context_.get(), surface_.get());
if (scoped_make_current.Succeeded()) {
......@@ -71,19 +71,47 @@ SurfaceTextureGLOwner::~SurfaceTextureGLOwner() {
}
}
void SurfaceTextureGLOwner::SetReleaseTimeToNow() {
GLuint SurfaceTextureGLOwnerImpl::GetTextureId() const {
return texture_id_;
}
gl::ScopedJavaSurface SurfaceTextureGLOwnerImpl::CreateJavaSurface() const {
return gl::ScopedJavaSurface(surface_texture_.get());
}
void SurfaceTextureGLOwnerImpl::UpdateTexImage() {
surface_texture_->UpdateTexImage();
}
void SurfaceTextureGLOwnerImpl::GetTransformMatrix(float mtx[]) {
surface_texture_->GetTransformMatrix(mtx);
}
void SurfaceTextureGLOwnerImpl::ReleaseBackBuffers() {
surface_texture_->ReleaseBackBuffers();
}
gl::GLContext* SurfaceTextureGLOwnerImpl::GetContext() const {
return context_.get();
}
gl::GLSurface* SurfaceTextureGLOwnerImpl::GetSurface() const {
return surface_.get();
}
void SurfaceTextureGLOwnerImpl::SetReleaseTimeToNow() {
release_time_ = base::TimeTicks::Now();
}
void SurfaceTextureGLOwner::IgnorePendingRelease() {
void SurfaceTextureGLOwnerImpl::IgnorePendingRelease() {
release_time_ = base::TimeTicks();
}
bool SurfaceTextureGLOwner::IsExpectingFrameAvailable() {
bool SurfaceTextureGLOwnerImpl::IsExpectingFrameAvailable() {
return !release_time_.is_null();
}
void SurfaceTextureGLOwner::WaitForFrameAvailable() {
void SurfaceTextureGLOwnerImpl::WaitForFrameAvailable() {
DCHECK(!release_time_.is_null());
// 5msec covers >99.9% of cases, so just wait for up to that much before
......@@ -113,12 +141,4 @@ void SurfaceTextureGLOwner::WaitForFrameAvailable() {
}
}
void SurfaceTextureGLOwner::AttachToGLContext() {
NOTIMPLEMENTED();
}
void SurfaceTextureGLOwner::DetachFromGLContext() {
NOTIMPLEMENTED();
}
} // namespace media
......@@ -9,6 +9,7 @@
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_checker.h"
#include "media/gpu/media_gpu_export.h"
#include "ui/gl/android/scoped_java_surface.h"
#include "ui/gl/android/surface_texture.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
......@@ -18,57 +19,88 @@ namespace media {
struct FrameAvailableEvent;
// Handy subclass of SurfaceTexture which creates and maintains ownership of the
// GL texture also. This texture is only destroyed with the object; one may
// ReleaseSurfaceTexture without destroying the GL texture. It must be deleted
// on the same thread on which it is constructed.
class MEDIA_GPU_EXPORT SurfaceTextureGLOwner : public gl::SurfaceTexture {
// A SurfaceTexture wrapper that creates and maintains ownership of the
// attached GL texture. The texture is destroyed with the object but it's
// possible to call ReleaseSurfaceTexture() without destroying the GL texture.
// It must be deleted on the thread it was constructed on.
// This is a virtual interface to make it mockable; see
// SurfaceTextureGLOwnerImpl.
class MEDIA_GPU_EXPORT SurfaceTextureGLOwner
: public base::RefCountedThreadSafe<SurfaceTextureGLOwner> {
public:
// Must be called with a platform gl context current. Creates the GL texture
// using this context, and memorizes it to delete the texture later.
static scoped_refptr<SurfaceTextureGLOwner> Create();
SurfaceTextureGLOwner() = default;
// Returns the GL texture id that the SurfaceTexture is attached to.
virtual GLuint GetTextureId() const = 0;
virtual gl::GLContext* GetContext() const = 0;
virtual gl::GLSurface* GetSurface() const = 0;
// Return the GL texture id that we created.
GLuint texture_id() const { return texture_id_; }
// Create a java surface for the SurfaceTexture.
virtual gl::ScopedJavaSurface CreateJavaSurface() const = 0;
gl::GLContext* context() const { return context_.get(); }
gl::GLSurface* surface() const { return surface_.get(); }
// See gl::SurfaceTexture for the following.
virtual void UpdateTexImage() = 0;
virtual void GetTransformMatrix(float mtx[16]) = 0;
virtual void ReleaseBackBuffers() = 0;
// Start expecting a new frame because a buffer was just released to this
// surface.
void SetReleaseTimeToNow();
// Sets the expectation of onFrameAVailable for a new frame because a buffer
// was just released to this surface.
virtual void SetReleaseTimeToNow() = 0;
// Ignores a pending release that was previously indicated with
// SetReleaseTimeToNow().
// TODO(watk): This doesn't seem necessary. It actually may be detrimental
// because the next time we release a buffer we may confuse its
// onFrameAvailable with the one we're ignoring.
void IgnorePendingRelease();
virtual void IgnorePendingRelease() = 0;
// Whether we're expecting onFrameAvailable. True when SetReleaseTimeToNow()
// was called but neither IgnorePendingRelease() nor WaitForFrameAvailable()
// have been called since.
bool IsExpectingFrameAvailable();
virtual bool IsExpectingFrameAvailable() = 0;
// Waits for onFrameAvailable until it's been 5ms since the buffer was
// released. This must only be called if IsExpectingFrameAvailable().
void WaitForFrameAvailable();
virtual void WaitForFrameAvailable() = 0;
// We don't support these. In principle, we could, but they're fairly buggy
// anyway on many devices.
void AttachToGLContext() override;
void DetachFromGLContext() override;
protected:
friend class base::RefCountedThreadSafe<SurfaceTextureGLOwner>;
virtual ~SurfaceTextureGLOwner() = default;
private:
SurfaceTextureGLOwner(GLuint texture_id);
~SurfaceTextureGLOwner() override;
DISALLOW_COPY_AND_ASSIGN(SurfaceTextureGLOwner);
};
// Context and surface that were used to create |texture_id_|.
scoped_refptr<gl::GLContext> context_;
scoped_refptr<gl::GLSurface> surface_;
class MEDIA_GPU_EXPORT SurfaceTextureGLOwnerImpl
: public SurfaceTextureGLOwner {
public:
// Creates a GL texture using the current platform GL context and returns a
// new SurfaceTextureGLOwnerImpl attached to it. Returns null on failure.
static scoped_refptr<SurfaceTextureGLOwner> Create();
GLuint GetTextureId() const override;
gl::GLContext* GetContext() const override;
gl::GLSurface* GetSurface() const override;
gl::ScopedJavaSurface CreateJavaSurface() const override;
void UpdateTexImage() override;
void GetTransformMatrix(float mtx[16]) override;
void ReleaseBackBuffers() override;
void SetReleaseTimeToNow() override;
void IgnorePendingRelease() override;
bool IsExpectingFrameAvailable() override;
void WaitForFrameAvailable() override;
private:
SurfaceTextureGLOwnerImpl(GLuint texture_id);
~SurfaceTextureGLOwnerImpl() override;
scoped_refptr<gl::SurfaceTexture> surface_texture_;
GLuint texture_id_;
// The context and surface that were used to create |texture_id_|.
scoped_refptr<gl::GLContext> context_;
scoped_refptr<gl::GLSurface> surface_;
// When SetReleaseTimeToNow() was last called. i.e., when the last
// codec buffer was released to this surface. Or null if
// IgnorePendingRelease() or WaitForFrameAvailable() have been called since.
......@@ -76,6 +108,7 @@ class MEDIA_GPU_EXPORT SurfaceTextureGLOwner : public gl::SurfaceTexture {
scoped_refptr<FrameAvailableEvent> frame_available_event_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(SurfaceTextureGLOwnerImpl);
};
} // namespace media
......
......@@ -43,8 +43,8 @@ class SurfaceTextureGLOwnerTest : public testing::Test {
context_->Initialize(surface_.get(), gl::GLContextAttribs());
ASSERT_TRUE(context_->MakeCurrent(surface_.get()));
surface_texture_ = SurfaceTextureGLOwner::Create();
texture_id_ = surface_texture_->texture_id();
surface_texture_ = SurfaceTextureGLOwnerImpl::Create();
texture_id_ = surface_texture_->GetTextureId();
// Bind and un-bind the texture, since that's required for glIsTexture to
// return true.
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
......@@ -77,16 +77,16 @@ TEST_F(SurfaceTextureGLOwnerTest, GLTextureIsCreatedAndDestroyed) {
ASSERT_FALSE(glIsTexture(texture_id_));
}
// Calling ReleaseSurfaceTexture shouldn't deallocate the texture handle.
// Calling ReleaseBackBuffers shouldn't deallocate the texture handle.
TEST_F(SurfaceTextureGLOwnerTest, ReleaseDoesntDestroyTexture) {
surface_texture_->ReleaseSurfaceTexture();
surface_texture_->ReleaseBackBuffers();
ASSERT_TRUE(glIsTexture(texture_id_));
}
// Make sure that |surface_texture_| remembers the correct context and surface.
TEST_F(SurfaceTextureGLOwnerTest, ContextAndSurfaceAreCaptured) {
ASSERT_EQ(context_, surface_texture_->context());
ASSERT_EQ(surface_, surface_texture_->surface());
ASSERT_EQ(context_, surface_texture_->GetContext());
ASSERT_EQ(surface_, surface_texture_->GetSurface());
}
// Verify that destruction works even if some other context is current.
......
......@@ -16,13 +16,9 @@
namespace gl {
scoped_refptr<SurfaceTexture> SurfaceTexture::Create(int texture_id) {
return new SurfaceTexture(CreateJavaSurfaceTexture(texture_id));
}
base::android::ScopedJavaLocalRef<jobject>
SurfaceTexture::CreateJavaSurfaceTexture(int texture_id) {
JNIEnv* env = base::android::AttachCurrentThread();
return Java_SurfaceTexturePlatformWrapper_create(env, texture_id);
return new SurfaceTexture(
Java_SurfaceTexturePlatformWrapper_create(env, texture_id));
}
SurfaceTexture::SurfaceTexture(
......@@ -31,20 +27,11 @@ SurfaceTexture::SurfaceTexture(
}
SurfaceTexture::~SurfaceTexture() {
DestroyJavaObject();
}
void SurfaceTexture::DestroyJavaObject() {
if (j_surface_texture_.is_null())
return;
JNIEnv* env = base::android::AttachCurrentThread();
Java_SurfaceTexturePlatformWrapper_destroy(env, j_surface_texture_);
j_surface_texture_.Reset();
}
void SurfaceTexture::SetFrameAvailableCallback(
const base::Closure& callback) {
void SurfaceTexture::SetFrameAvailableCallback(const base::Closure& callback) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_SurfaceTexturePlatformWrapper_setFrameAvailableCallback(
env, j_surface_texture_,
......@@ -102,12 +89,12 @@ ANativeWindow* SurfaceTexture::CreateSurface() {
// ANativeWindow_fromSurface are released immediately. This is needed as a
// workaround for https://code.google.com/p/android/issues/detail?id=68174
base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
ANativeWindow* native_window = ANativeWindow_fromSurface(
env, surface.j_surface().obj());
ANativeWindow* native_window =
ANativeWindow_fromSurface(env, surface.j_surface().obj());
return native_window;
}
void SurfaceTexture::ReleaseSurfaceTexture() {
void SurfaceTexture::ReleaseBackBuffers() {
JNIEnv* env = base::android::AttachCurrentThread();
Java_SurfaceTexturePlatformWrapper_release(env, j_surface_texture_);
}
......
......@@ -20,7 +20,7 @@ namespace gl {
// This class serves as a bridge for native code to call java functions inside
// android SurfaceTexture class.
class GL_EXPORT SurfaceTexture
: public base::RefCountedThreadSafe<SurfaceTexture>{
: public base::RefCountedThreadSafe<SurfaceTexture> {
public:
static scoped_refptr<SurfaceTexture> Create(int texture_id);
......@@ -46,11 +46,11 @@ class GL_EXPORT SurfaceTexture
// Attach the SurfaceTexture to the texture currently bound to
// GL_TEXTURE_EXTERNAL_OES.
virtual void AttachToGLContext();
void AttachToGLContext();
// Detaches the SurfaceTexture from the context that owns its current GL
// texture. Must be called with that context current on the calling thread.
virtual void DetachFromGLContext();
void DetachFromGLContext();
// Creates a native render surface for this surface texture.
// The caller must release the underlying reference when done with the handle
......@@ -58,9 +58,10 @@ class GL_EXPORT SurfaceTexture
ANativeWindow* CreateSurface();
// Release the SurfaceTexture back buffers. The SurfaceTexture is no longer
// usable after calling this. Note that this is not called 'Release', like
// the android API, because scoped_refptr<> calls that quite a bit.
void ReleaseSurfaceTexture();
// usable after calling this but the front buffer is still valid. Note that
// this is not called 'Release', like the Android API, because scoped_refptr
// calls that quite a bit.
void ReleaseBackBuffers();
// Set the default buffer size for the surface texture.
void SetDefaultBufferSize(int width, int height);
......@@ -70,19 +71,12 @@ class GL_EXPORT SurfaceTexture
}
protected:
static base::android::ScopedJavaLocalRef<jobject> CreateJavaSurfaceTexture(
int texture_id);
explicit SurfaceTexture(
const base::android::ScopedJavaLocalRef<jobject>& j_surface_texture);
virtual ~SurfaceTexture();
// Destroy |j_surface_texture| if it hasn't been destroyed already.
void DestroyJavaObject();
private:
friend class base::RefCountedThreadSafe<SurfaceTexture>;
virtual ~SurfaceTexture();
// Java SurfaceTexture instance.
base::android::ScopedJavaGlobalRef<jobject> j_surface_texture_;
......
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