blob: 286776e317ba0ea8978b3d62ede1361cd718dc32 [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/video_render/android/video_render_android_native_opengl2.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
#include "webrtc/system_wrappers/include/tick_util.h"
#ifdef ANDROID_LOG
#include <android/log.h>
#include <stdio.h>
#undef WEBRTC_TRACE
#define WEBRTC_TRACE(a,b,c,...) __android_log_print(ANDROID_LOG_DEBUG, "*WEBRTC*", __VA_ARGS__)
#else
#include "webrtc/system_wrappers/include/trace.h"
#endif
namespace webrtc {
AndroidNativeOpenGl2Renderer::AndroidNativeOpenGl2Renderer(
const int32_t id,
const VideoRenderType videoRenderType,
void* window,
const bool fullscreen) :
VideoRenderAndroid(id, videoRenderType, window, fullscreen),
_javaRenderObj(NULL),
_javaRenderClass(NULL) {
}
bool AndroidNativeOpenGl2Renderer::UseOpenGL2(void* window) {
if (!g_jvm) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
"RendererAndroid():UseOpenGL No JVM set.");
return false;
}
bool isAttached = false;
JNIEnv* env = NULL;
if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
// try to attach the thread and get the env
// Attach this thread to JVM
jint res = g_jvm->AttachCurrentThread(&env, NULL);
// Get the JNI env for this thread
if ((res < 0) || !env) {
WEBRTC_TRACE(
kTraceError,
kTraceVideoRenderer,
-1,
"RendererAndroid(): Could not attach thread to JVM (%d, %p)",
res, env);
return false;
}
isAttached = true;
}
// get the renderer class
jclass javaRenderClassLocal =
env->FindClass("org/webrtc/videoengine/ViEAndroidGLES20");
if (!javaRenderClassLocal) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
"%s: could not find ViEAndroidRenderer class",
__FUNCTION__);
return false;
}
// get the method ID for UseOpenGL
jmethodID cidUseOpenGL = env->GetStaticMethodID(javaRenderClassLocal,
"UseOpenGL2",
"(Ljava/lang/Object;)Z");
if (cidUseOpenGL == NULL) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
"%s: could not get UseOpenGL ID", __FUNCTION__);
return false;
}
jboolean res = env->CallStaticBooleanMethod(javaRenderClassLocal,
cidUseOpenGL, (jobject) window);
// Detach this thread if it was attached
if (isAttached) {
if (g_jvm->DetachCurrentThread() < 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
"%s: Could not detach thread from JVM", __FUNCTION__);
}
}
return res;
}
AndroidNativeOpenGl2Renderer::~AndroidNativeOpenGl2Renderer() {
WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id,
"AndroidNativeOpenGl2Renderer dtor");
if (g_jvm) {
// get the JNI env for this thread
bool isAttached = false;
JNIEnv* env = NULL;
if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
// try to attach the thread and get the env
// Attach this thread to JVM
jint res = g_jvm->AttachCurrentThread(&env, NULL);
// Get the JNI env for this thread
if ((res < 0) || !env) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: Could not attach thread to JVM (%d, %p)",
__FUNCTION__, res, env);
env = NULL;
}
else {
isAttached = true;
}
}
env->DeleteGlobalRef(_javaRenderObj);
env->DeleteGlobalRef(_javaRenderClass);
if (isAttached) {
if (g_jvm->DetachCurrentThread() < 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
"%s: Could not detach thread from JVM",
__FUNCTION__);
}
}
}
}
int32_t AndroidNativeOpenGl2Renderer::Init() {
WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s", __FUNCTION__);
if (!g_jvm) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"(%s): Not a valid Java VM pointer.", __FUNCTION__);
return -1;
}
if (!_ptrWindow) {
WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
"(%s): No window have been provided.", __FUNCTION__);
return -1;
}
// get the JNI env for this thread
bool isAttached = false;
JNIEnv* env = NULL;
if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
// try to attach the thread and get the env
// Attach this thread to JVM
jint res = g_jvm->AttachCurrentThread(&env, NULL);
// Get the JNI env for this thread
if ((res < 0) || !env) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: Could not attach thread to JVM (%d, %p)",
__FUNCTION__, res, env);
return -1;
}
isAttached = true;
}
// get the ViEAndroidGLES20 class
jclass javaRenderClassLocal =
env->FindClass("org/webrtc/videoengine/ViEAndroidGLES20");
if (!javaRenderClassLocal) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: could not find ViEAndroidGLES20", __FUNCTION__);
return -1;
}
// create a global reference to the class (to tell JNI that
// we are referencing it after this function has returned)
_javaRenderClass =
reinterpret_cast<jclass> (env->NewGlobalRef(javaRenderClassLocal));
if (!_javaRenderClass) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: could not create Java SurfaceHolder class reference",
__FUNCTION__);
return -1;
}
// Delete local class ref, we only use the global ref
env->DeleteLocalRef(javaRenderClassLocal);
// create a reference to the object (to tell JNI that we are referencing it
// after this function has returned)
_javaRenderObj = env->NewGlobalRef(_ptrWindow);
if (!_javaRenderObj) {
WEBRTC_TRACE(
kTraceError,
kTraceVideoRenderer,
_id,
"%s: could not create Java SurfaceRender object reference",
__FUNCTION__);
return -1;
}
// Detach this thread if it was attached
if (isAttached) {
if (g_jvm->DetachCurrentThread() < 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
"%s: Could not detach thread from JVM", __FUNCTION__);
}
}
WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s done",
__FUNCTION__);
return 0;
}
AndroidStream*
AndroidNativeOpenGl2Renderer::CreateAndroidRenderChannel(
int32_t streamId,
int32_t zOrder,
const float left,
const float top,
const float right,
const float bottom,
VideoRenderAndroid& renderer) {
WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s: Id %d",
__FUNCTION__, streamId);
AndroidNativeOpenGl2Channel* stream =
new AndroidNativeOpenGl2Channel(streamId, g_jvm, renderer,
_javaRenderObj);
if (stream && stream->Init(zOrder, left, top, right, bottom) == 0)
return stream;
else {
delete stream;
}
return NULL;
}
AndroidNativeOpenGl2Channel::AndroidNativeOpenGl2Channel(
uint32_t streamId,
JavaVM* jvm,
VideoRenderAndroid& renderer,jobject javaRenderObj):
_id(streamId),
_renderCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
_renderer(renderer), _jvm(jvm), _javaRenderObj(javaRenderObj),
_registerNativeCID(NULL), _deRegisterNativeCID(NULL),
_openGLRenderer(streamId) {
}
AndroidNativeOpenGl2Channel::~AndroidNativeOpenGl2Channel() {
WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id,
"AndroidNativeOpenGl2Channel dtor");
if (_jvm) {
// get the JNI env for this thread
bool isAttached = false;
JNIEnv* env = NULL;
if (_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
// try to attach the thread and get the env
// Attach this thread to JVM
jint res = _jvm->AttachCurrentThread(&env, NULL);
// Get the JNI env for this thread
if ((res < 0) || !env) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: Could not attach thread to JVM (%d, %p)",
__FUNCTION__, res, env);
env = NULL;
} else {
isAttached = true;
}
}
if (env && _deRegisterNativeCID) {
env->CallVoidMethod(_javaRenderObj, _deRegisterNativeCID);
}
if (isAttached) {
if (_jvm->DetachCurrentThread() < 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
"%s: Could not detach thread from JVM",
__FUNCTION__);
}
}
}
delete &_renderCritSect;
}
int32_t AndroidNativeOpenGl2Channel::Init(int32_t zOrder,
const float left,
const float top,
const float right,
const float bottom)
{
WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id,
"%s: AndroidNativeOpenGl2Channel", __FUNCTION__);
if (!_jvm) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: Not a valid Java VM pointer", __FUNCTION__);
return -1;
}
// get the JNI env for this thread
bool isAttached = false;
JNIEnv* env = NULL;
if (_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
// try to attach the thread and get the env
// Attach this thread to JVM
jint res = _jvm->AttachCurrentThread(&env, NULL);
// Get the JNI env for this thread
if ((res < 0) || !env) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: Could not attach thread to JVM (%d, %p)",
__FUNCTION__, res, env);
return -1;
}
isAttached = true;
}
jclass javaRenderClass =
env->FindClass("org/webrtc/videoengine/ViEAndroidGLES20");
if (!javaRenderClass) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: could not find ViESurfaceRenderer", __FUNCTION__);
return -1;
}
// get the method ID for the ReDraw function
_redrawCid = env->GetMethodID(javaRenderClass, "ReDraw", "()V");
if (_redrawCid == NULL) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: could not get ReDraw ID", __FUNCTION__);
return -1;
}
_registerNativeCID = env->GetMethodID(javaRenderClass,
"RegisterNativeObject", "(J)V");
if (_registerNativeCID == NULL) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: could not get RegisterNativeObject ID", __FUNCTION__);
return -1;
}
_deRegisterNativeCID = env->GetMethodID(javaRenderClass,
"DeRegisterNativeObject", "()V");
if (_deRegisterNativeCID == NULL) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: could not get DeRegisterNativeObject ID",
__FUNCTION__);
return -1;
}
JNINativeMethod nativeFunctions[2] = {
{ "DrawNative",
"(J)V",
(void*) &AndroidNativeOpenGl2Channel::DrawNativeStatic, },
{ "CreateOpenGLNative",
"(JII)I",
(void*) &AndroidNativeOpenGl2Channel::CreateOpenGLNativeStatic },
};
if (env->RegisterNatives(javaRenderClass, nativeFunctions, 2) == 0) {
WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, -1,
"%s: Registered native functions", __FUNCTION__);
}
else {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
"%s: Failed to register native functions", __FUNCTION__);
return -1;
}
env->CallVoidMethod(_javaRenderObj, _registerNativeCID, (jlong) this);
// Detach this thread if it was attached
if (isAttached) {
if (_jvm->DetachCurrentThread() < 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
"%s: Could not detach thread from JVM", __FUNCTION__);
}
}
if (_openGLRenderer.SetCoordinates(zOrder, left, top, right, bottom) != 0) {
return -1;
}
WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id,
"%s: AndroidNativeOpenGl2Channel done", __FUNCTION__);
return 0;
}
int32_t AndroidNativeOpenGl2Channel::RenderFrame(const uint32_t /*streamId*/,
const VideoFrame& videoFrame) {
// WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer,_id, "%s:" ,__FUNCTION__);
_renderCritSect.Enter();
_bufferToRender = videoFrame;
_renderCritSect.Leave();
_renderer.ReDraw();
return 0;
}
/*Implements AndroidStream
* Calls the Java object and render the buffer in _bufferToRender
*/
void AndroidNativeOpenGl2Channel::DeliverFrame(JNIEnv* jniEnv) {
//TickTime timeNow=TickTime::Now();
//Draw the Surface
jniEnv->CallVoidMethod(_javaRenderObj, _redrawCid);
// WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer,_id,
// "%s: time to deliver %lld" ,__FUNCTION__,
// (TickTime::Now()-timeNow).Milliseconds());
}
/*
* JNI callback from Java class. Called when the render
* want to render a frame. Called from the GLRenderThread
* Method: DrawNative
* Signature: (J)V
*/
void JNICALL AndroidNativeOpenGl2Channel::DrawNativeStatic(
JNIEnv * env, jobject, jlong context) {
AndroidNativeOpenGl2Channel* renderChannel =
reinterpret_cast<AndroidNativeOpenGl2Channel*>(context);
renderChannel->DrawNative();
}
void AndroidNativeOpenGl2Channel::DrawNative() {
_renderCritSect.Enter();
_openGLRenderer.Render(_bufferToRender);
_renderCritSect.Leave();
}
/*
* JNI callback from Java class. Called when the GLSurfaceview
* have created a surface. Called from the GLRenderThread
* Method: CreateOpenGLNativeStatic
* Signature: (JII)I
*/
jint JNICALL AndroidNativeOpenGl2Channel::CreateOpenGLNativeStatic(
JNIEnv * env,
jobject,
jlong context,
jint width,
jint height) {
AndroidNativeOpenGl2Channel* renderChannel =
reinterpret_cast<AndroidNativeOpenGl2Channel*> (context);
WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "%s:", __FUNCTION__);
return renderChannel->CreateOpenGLNative(width, height);
}
jint AndroidNativeOpenGl2Channel::CreateOpenGLNative(
int width, int height) {
return _openGLRenderer.Setup(width, height);
}
} // namespace webrtc