| Index: webrtc/modules/video_render/android/video_render_android_native_opengl2.cc
|
| diff --git a/webrtc/modules/video_render/android/video_render_android_native_opengl2.cc b/webrtc/modules/video_render/android/video_render_android_native_opengl2.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..286776e317ba0ea8978b3d62ede1361cd718dc32
|
| --- /dev/null
|
| +++ b/webrtc/modules/video_render/android/video_render_android_native_opengl2.cc
|
| @@ -0,0 +1,450 @@
|
| +/*
|
| + * 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
|
|
|