Home | History | Annotate | Download | only in android
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/modules/video_render/android/video_render_android_native_opengl2.h"
     12 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     13 #include "webrtc/system_wrappers/interface/tick_util.h"
     14 
     15 #ifdef ANDROID_LOG
     16 #include <android/log.h>
     17 #include <stdio.h>
     18 
     19 #undef WEBRTC_TRACE
     20 #define WEBRTC_TRACE(a,b,c,...)  __android_log_print(ANDROID_LOG_DEBUG, "*WEBRTC*", __VA_ARGS__)
     21 #else
     22 #include "webrtc/system_wrappers/interface/trace.h"
     23 #endif
     24 
     25 namespace webrtc {
     26 
     27 AndroidNativeOpenGl2Renderer::AndroidNativeOpenGl2Renderer(
     28     const int32_t id,
     29     const VideoRenderType videoRenderType,
     30     void* window,
     31     const bool fullscreen) :
     32     VideoRenderAndroid(id, videoRenderType, window, fullscreen),
     33     _javaRenderObj(NULL),
     34     _javaRenderClass(NULL) {
     35 }
     36 
     37 bool AndroidNativeOpenGl2Renderer::UseOpenGL2(void* window) {
     38   if (!g_jvm) {
     39     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
     40                  "RendererAndroid():UseOpenGL No JVM set.");
     41     return false;
     42   }
     43   bool isAttached = false;
     44   JNIEnv* env = NULL;
     45   if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
     46     // try to attach the thread and get the env
     47     // Attach this thread to JVM
     48     jint res = g_jvm->AttachCurrentThread(&env, NULL);
     49 
     50     // Get the JNI env for this thread
     51     if ((res < 0) || !env) {
     52       WEBRTC_TRACE(
     53           kTraceError,
     54           kTraceVideoRenderer,
     55           -1,
     56           "RendererAndroid(): Could not attach thread to JVM (%d, %p)",
     57           res, env);
     58       return false;
     59     }
     60     isAttached = true;
     61   }
     62 
     63   // get the renderer class
     64   jclass javaRenderClassLocal =
     65       env->FindClass("org/webrtc/videoengine/ViEAndroidGLES20");
     66   if (!javaRenderClassLocal) {
     67     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
     68                  "%s: could not find ViEAndroidRenderer class",
     69                  __FUNCTION__);
     70     return false;
     71   }
     72 
     73   // get the method ID for UseOpenGL
     74   jmethodID cidUseOpenGL = env->GetStaticMethodID(javaRenderClassLocal,
     75                                                   "UseOpenGL2",
     76                                                   "(Ljava/lang/Object;)Z");
     77   if (cidUseOpenGL == NULL) {
     78     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
     79                  "%s: could not get UseOpenGL ID", __FUNCTION__);
     80     return false;
     81   }
     82   jboolean res = env->CallStaticBooleanMethod(javaRenderClassLocal,
     83                                               cidUseOpenGL, (jobject) window);
     84 
     85   // Detach this thread if it was attached
     86   if (isAttached) {
     87     if (g_jvm->DetachCurrentThread() < 0) {
     88       WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
     89                    "%s: Could not detach thread from JVM", __FUNCTION__);
     90     }
     91   }
     92   return res;
     93 }
     94 
     95 AndroidNativeOpenGl2Renderer::~AndroidNativeOpenGl2Renderer() {
     96   WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id,
     97                "AndroidNativeOpenGl2Renderer dtor");
     98   if (g_jvm) {
     99     // get the JNI env for this thread
    100     bool isAttached = false;
    101     JNIEnv* env = NULL;
    102     if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    103       // try to attach the thread and get the env
    104       // Attach this thread to JVM
    105       jint res = g_jvm->AttachCurrentThread(&env, NULL);
    106 
    107       // Get the JNI env for this thread
    108       if ((res < 0) || !env) {
    109         WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    110                      "%s: Could not attach thread to JVM (%d, %p)",
    111                      __FUNCTION__, res, env);
    112         env = NULL;
    113       }
    114       else {
    115         isAttached = true;
    116       }
    117     }
    118 
    119     env->DeleteGlobalRef(_javaRenderObj);
    120     env->DeleteGlobalRef(_javaRenderClass);
    121 
    122     if (isAttached) {
    123       if (g_jvm->DetachCurrentThread() < 0) {
    124         WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
    125                      "%s: Could not detach thread from JVM",
    126                      __FUNCTION__);
    127       }
    128     }
    129   }
    130 }
    131 
    132 int32_t AndroidNativeOpenGl2Renderer::Init() {
    133   WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s", __FUNCTION__);
    134   if (!g_jvm) {
    135     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    136                  "(%s): Not a valid Java VM pointer.", __FUNCTION__);
    137     return -1;
    138   }
    139   if (!_ptrWindow) {
    140     WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
    141                  "(%s): No window have been provided.", __FUNCTION__);
    142     return -1;
    143   }
    144 
    145   // get the JNI env for this thread
    146   bool isAttached = false;
    147   JNIEnv* env = NULL;
    148   if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    149     // try to attach the thread and get the env
    150     // Attach this thread to JVM
    151     jint res = g_jvm->AttachCurrentThread(&env, NULL);
    152 
    153     // Get the JNI env for this thread
    154     if ((res < 0) || !env) {
    155       WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    156                    "%s: Could not attach thread to JVM (%d, %p)",
    157                    __FUNCTION__, res, env);
    158       return -1;
    159     }
    160     isAttached = true;
    161   }
    162 
    163   // get the ViEAndroidGLES20 class
    164   jclass javaRenderClassLocal =
    165       env->FindClass("org/webrtc/videoengine/ViEAndroidGLES20");
    166   if (!javaRenderClassLocal) {
    167     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    168                  "%s: could not find ViEAndroidGLES20", __FUNCTION__);
    169     return -1;
    170   }
    171 
    172   // create a global reference to the class (to tell JNI that
    173   // we are referencing it after this function has returned)
    174   _javaRenderClass =
    175       reinterpret_cast<jclass> (env->NewGlobalRef(javaRenderClassLocal));
    176   if (!_javaRenderClass) {
    177     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    178                  "%s: could not create Java SurfaceHolder class reference",
    179                  __FUNCTION__);
    180     return -1;
    181   }
    182 
    183   // Delete local class ref, we only use the global ref
    184   env->DeleteLocalRef(javaRenderClassLocal);
    185 
    186   // create a reference to the object (to tell JNI that we are referencing it
    187   // after this function has returned)
    188   _javaRenderObj = env->NewGlobalRef(_ptrWindow);
    189   if (!_javaRenderObj) {
    190     WEBRTC_TRACE(
    191         kTraceError,
    192         kTraceVideoRenderer,
    193         _id,
    194         "%s: could not create Java SurfaceRender object reference",
    195         __FUNCTION__);
    196     return -1;
    197   }
    198 
    199   // Detach this thread if it was attached
    200   if (isAttached) {
    201     if (g_jvm->DetachCurrentThread() < 0) {
    202       WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
    203                    "%s: Could not detach thread from JVM", __FUNCTION__);
    204     }
    205   }
    206 
    207   WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s done",
    208                __FUNCTION__);
    209   return 0;
    210 
    211 }
    212 AndroidStream*
    213 AndroidNativeOpenGl2Renderer::CreateAndroidRenderChannel(
    214     int32_t streamId,
    215     int32_t zOrder,
    216     const float left,
    217     const float top,
    218     const float right,
    219     const float bottom,
    220     VideoRenderAndroid& renderer) {
    221   WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s: Id %d",
    222                __FUNCTION__, streamId);
    223   AndroidNativeOpenGl2Channel* stream =
    224       new AndroidNativeOpenGl2Channel(streamId, g_jvm, renderer,
    225                                       _javaRenderObj);
    226   if (stream && stream->Init(zOrder, left, top, right, bottom) == 0)
    227     return stream;
    228   else {
    229     delete stream;
    230   }
    231   return NULL;
    232 }
    233 
    234 AndroidNativeOpenGl2Channel::AndroidNativeOpenGl2Channel(
    235     uint32_t streamId,
    236     JavaVM* jvm,
    237     VideoRenderAndroid& renderer,jobject javaRenderObj):
    238     _id(streamId),
    239     _renderCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
    240     _renderer(renderer), _jvm(jvm), _javaRenderObj(javaRenderObj),
    241     _registerNativeCID(NULL), _deRegisterNativeCID(NULL),
    242     _openGLRenderer(streamId) {
    243 
    244 }
    245 AndroidNativeOpenGl2Channel::~AndroidNativeOpenGl2Channel() {
    246   WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id,
    247                "AndroidNativeOpenGl2Channel dtor");
    248   if (_jvm) {
    249     // get the JNI env for this thread
    250     bool isAttached = false;
    251     JNIEnv* env = NULL;
    252     if (_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    253       // try to attach the thread and get the env
    254       // Attach this thread to JVM
    255       jint res = _jvm->AttachCurrentThread(&env, NULL);
    256 
    257       // Get the JNI env for this thread
    258       if ((res < 0) || !env) {
    259         WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    260                      "%s: Could not attach thread to JVM (%d, %p)",
    261                      __FUNCTION__, res, env);
    262         env = NULL;
    263       } else {
    264         isAttached = true;
    265       }
    266     }
    267     if (env && _deRegisterNativeCID) {
    268       env->CallVoidMethod(_javaRenderObj, _deRegisterNativeCID);
    269     }
    270 
    271     if (isAttached) {
    272       if (_jvm->DetachCurrentThread() < 0) {
    273         WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
    274                      "%s: Could not detach thread from JVM",
    275                      __FUNCTION__);
    276       }
    277     }
    278   }
    279 
    280   delete &_renderCritSect;
    281 }
    282 
    283 int32_t AndroidNativeOpenGl2Channel::Init(int32_t zOrder,
    284                                           const float left,
    285                                           const float top,
    286                                           const float right,
    287                                           const float bottom)
    288 {
    289   WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id,
    290                "%s: AndroidNativeOpenGl2Channel", __FUNCTION__);
    291   if (!_jvm) {
    292     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    293                  "%s: Not a valid Java VM pointer", __FUNCTION__);
    294     return -1;
    295   }
    296 
    297   // get the JNI env for this thread
    298   bool isAttached = false;
    299   JNIEnv* env = NULL;
    300   if (_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    301     // try to attach the thread and get the env
    302     // Attach this thread to JVM
    303     jint res = _jvm->AttachCurrentThread(&env, NULL);
    304 
    305     // Get the JNI env for this thread
    306     if ((res < 0) || !env) {
    307       WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    308                    "%s: Could not attach thread to JVM (%d, %p)",
    309                    __FUNCTION__, res, env);
    310       return -1;
    311     }
    312     isAttached = true;
    313   }
    314 
    315   jclass javaRenderClass =
    316       env->FindClass("org/webrtc/videoengine/ViEAndroidGLES20");
    317   if (!javaRenderClass) {
    318     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    319                  "%s: could not find ViESurfaceRenderer", __FUNCTION__);
    320     return -1;
    321   }
    322 
    323   // get the method ID for the ReDraw function
    324   _redrawCid = env->GetMethodID(javaRenderClass, "ReDraw", "()V");
    325   if (_redrawCid == NULL) {
    326     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    327                  "%s: could not get ReDraw ID", __FUNCTION__);
    328     return -1;
    329   }
    330 
    331   _registerNativeCID = env->GetMethodID(javaRenderClass,
    332                                         "RegisterNativeObject", "(J)V");
    333   if (_registerNativeCID == NULL) {
    334     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    335                  "%s: could not get RegisterNativeObject ID", __FUNCTION__);
    336     return -1;
    337   }
    338 
    339   _deRegisterNativeCID = env->GetMethodID(javaRenderClass,
    340                                           "DeRegisterNativeObject", "()V");
    341   if (_deRegisterNativeCID == NULL) {
    342     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
    343                  "%s: could not get DeRegisterNativeObject ID",
    344                  __FUNCTION__);
    345     return -1;
    346   }
    347 
    348   JNINativeMethod nativeFunctions[2] = {
    349     { "DrawNative",
    350       "(J)V",
    351       (void*) &AndroidNativeOpenGl2Channel::DrawNativeStatic, },
    352     { "CreateOpenGLNative",
    353       "(JII)I",
    354       (void*) &AndroidNativeOpenGl2Channel::CreateOpenGLNativeStatic },
    355   };
    356   if (env->RegisterNatives(javaRenderClass, nativeFunctions, 2) == 0) {
    357     WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, -1,
    358                  "%s: Registered native functions", __FUNCTION__);
    359   }
    360   else {
    361     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
    362                  "%s: Failed to register native functions", __FUNCTION__);
    363     return -1;
    364   }
    365 
    366   env->CallVoidMethod(_javaRenderObj, _registerNativeCID, (jlong) this);
    367 
    368   // Detach this thread if it was attached
    369   if (isAttached) {
    370     if (_jvm->DetachCurrentThread() < 0) {
    371       WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,
    372                    "%s: Could not detach thread from JVM", __FUNCTION__);
    373     }
    374   }
    375 
    376   if (_openGLRenderer.SetCoordinates(zOrder, left, top, right, bottom) != 0) {
    377     return -1;
    378   }
    379   WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id,
    380                "%s: AndroidNativeOpenGl2Channel done", __FUNCTION__);
    381   return 0;
    382 }
    383 
    384 int32_t AndroidNativeOpenGl2Channel::RenderFrame(
    385     const uint32_t /*streamId*/,
    386     I420VideoFrame& videoFrame) {
    387   //   WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer,_id, "%s:" ,__FUNCTION__);
    388   _renderCritSect.Enter();
    389   _bufferToRender.SwapFrame(&videoFrame);
    390   _renderCritSect.Leave();
    391   _renderer.ReDraw();
    392   return 0;
    393 }
    394 
    395 /*Implements AndroidStream
    396  * Calls the Java object and render the buffer in _bufferToRender
    397  */
    398 void AndroidNativeOpenGl2Channel::DeliverFrame(JNIEnv* jniEnv) {
    399   //TickTime timeNow=TickTime::Now();
    400 
    401   //Draw the Surface
    402   jniEnv->CallVoidMethod(_javaRenderObj, _redrawCid);
    403 
    404   // WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer,_id,
    405   // "%s: time to deliver %lld" ,__FUNCTION__,
    406   // (TickTime::Now()-timeNow).Milliseconds());
    407 }
    408 
    409 /*
    410  * JNI callback from Java class. Called when the render
    411  * want to render a frame. Called from the GLRenderThread
    412  * Method:    DrawNative
    413  * Signature: (J)V
    414  */
    415 void JNICALL AndroidNativeOpenGl2Channel::DrawNativeStatic(
    416     JNIEnv * env, jobject, jlong context) {
    417   AndroidNativeOpenGl2Channel* renderChannel =
    418       reinterpret_cast<AndroidNativeOpenGl2Channel*>(context);
    419   renderChannel->DrawNative();
    420 }
    421 
    422 void AndroidNativeOpenGl2Channel::DrawNative() {
    423   _renderCritSect.Enter();
    424   _openGLRenderer.Render(_bufferToRender);
    425   _renderCritSect.Leave();
    426 }
    427 
    428 /*
    429  * JNI callback from Java class. Called when the GLSurfaceview
    430  * have created a surface. Called from the GLRenderThread
    431  * Method:    CreateOpenGLNativeStatic
    432  * Signature: (JII)I
    433  */
    434 jint JNICALL AndroidNativeOpenGl2Channel::CreateOpenGLNativeStatic(
    435     JNIEnv * env,
    436     jobject,
    437     jlong context,
    438     jint width,
    439     jint height) {
    440   AndroidNativeOpenGl2Channel* renderChannel =
    441       reinterpret_cast<AndroidNativeOpenGl2Channel*> (context);
    442   WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "%s:", __FUNCTION__);
    443   return renderChannel->CreateOpenGLNative(width, height);
    444 }
    445 
    446 jint AndroidNativeOpenGl2Channel::CreateOpenGLNative(
    447     int width, int height) {
    448   return _openGLRenderer.Setup(width, height);
    449 }
    450 
    451 }  // namespace webrtc
    452