OLD | NEW |
(Empty) | |
| 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/common_video/libyuv/include/webrtc_libyuv.h" |
| 12 #include "webrtc/modules/video_render/android/video_render_android_surface_view.
h" |
| 13 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
| 14 #include "webrtc/system_wrappers/include/tick_util.h" |
| 15 |
| 16 #ifdef ANDROID_LOG |
| 17 #include <android/log.h> |
| 18 #include <stdio.h> |
| 19 |
| 20 #undef WEBRTC_TRACE |
| 21 #define WEBRTC_TRACE(a,b,c,...) __android_log_print(ANDROID_LOG_DEBUG, "*WEBRTC
*", __VA_ARGS__) |
| 22 #else |
| 23 #include "webrtc/system_wrappers/include/trace.h" |
| 24 #endif |
| 25 |
| 26 namespace webrtc { |
| 27 |
| 28 AndroidSurfaceViewRenderer::AndroidSurfaceViewRenderer( |
| 29 const int32_t id, |
| 30 const VideoRenderType videoRenderType, |
| 31 void* window, |
| 32 const bool fullscreen) : |
| 33 VideoRenderAndroid(id,videoRenderType,window,fullscreen), |
| 34 _javaRenderObj(NULL), |
| 35 _javaRenderClass(NULL) { |
| 36 } |
| 37 |
| 38 AndroidSurfaceViewRenderer::~AndroidSurfaceViewRenderer() { |
| 39 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, |
| 40 "AndroidSurfaceViewRenderer dtor"); |
| 41 if(g_jvm) { |
| 42 // get the JNI env for this thread |
| 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(kTraceError, |
| 53 kTraceVideoRenderer, |
| 54 _id, |
| 55 "%s: Could not attach thread to JVM (%d, %p)", |
| 56 __FUNCTION__, |
| 57 res, |
| 58 env); |
| 59 env=NULL; |
| 60 } |
| 61 else { |
| 62 isAttached = true; |
| 63 } |
| 64 } |
| 65 env->DeleteGlobalRef(_javaRenderObj); |
| 66 env->DeleteGlobalRef(_javaRenderClass); |
| 67 |
| 68 if (isAttached) { |
| 69 if (g_jvm->DetachCurrentThread() < 0) { |
| 70 WEBRTC_TRACE(kTraceWarning, |
| 71 kTraceVideoRenderer, |
| 72 _id, |
| 73 "%s: Could not detach thread from JVM", |
| 74 __FUNCTION__); |
| 75 } |
| 76 } |
| 77 } |
| 78 } |
| 79 |
| 80 int32_t AndroidSurfaceViewRenderer::Init() { |
| 81 WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s", __FUNCTION__); |
| 82 if (!g_jvm) { |
| 83 WEBRTC_TRACE(kTraceError, |
| 84 kTraceVideoRenderer, |
| 85 _id, |
| 86 "(%s): Not a valid Java VM pointer.", |
| 87 __FUNCTION__); |
| 88 return -1; |
| 89 } |
| 90 if(!_ptrWindow) { |
| 91 WEBRTC_TRACE(kTraceWarning, |
| 92 kTraceVideoRenderer, |
| 93 _id, |
| 94 "(%s): No window have been provided.", |
| 95 __FUNCTION__); |
| 96 return -1; |
| 97 } |
| 98 |
| 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, |
| 110 kTraceVideoRenderer, |
| 111 _id, |
| 112 "%s: Could not attach thread to JVM (%d, %p)", |
| 113 __FUNCTION__, |
| 114 res, |
| 115 env); |
| 116 return -1; |
| 117 } |
| 118 isAttached = true; |
| 119 } |
| 120 |
| 121 // get the ViESurfaceRender class |
| 122 jclass javaRenderClassLocal = |
| 123 env->FindClass("org/webrtc/videoengine/ViESurfaceRenderer"); |
| 124 if (!javaRenderClassLocal) { |
| 125 WEBRTC_TRACE(kTraceError, |
| 126 kTraceVideoRenderer, |
| 127 _id, |
| 128 "%s: could not find ViESurfaceRenderer", |
| 129 __FUNCTION__); |
| 130 return -1; |
| 131 } |
| 132 |
| 133 // create a global reference to the class (to tell JNI that |
| 134 // we are referencing it after this function has returned) |
| 135 _javaRenderClass = |
| 136 reinterpret_cast<jclass>(env->NewGlobalRef(javaRenderClassLocal)); |
| 137 if (!_javaRenderClass) { |
| 138 WEBRTC_TRACE(kTraceError, |
| 139 kTraceVideoRenderer, |
| 140 _id, |
| 141 "%s: could not create Java ViESurfaceRenderer class reference", |
| 142 __FUNCTION__); |
| 143 return -1; |
| 144 } |
| 145 |
| 146 // Delete local class ref, we only use the global ref |
| 147 env->DeleteLocalRef(javaRenderClassLocal); |
| 148 |
| 149 // get the method ID for the constructor |
| 150 jmethodID cid = env->GetMethodID(_javaRenderClass, |
| 151 "<init>", |
| 152 "(Landroid/view/SurfaceView;)V"); |
| 153 if (cid == NULL) { |
| 154 WEBRTC_TRACE(kTraceError, |
| 155 kTraceVideoRenderer, |
| 156 _id, |
| 157 "%s: could not get constructor ID", |
| 158 __FUNCTION__); |
| 159 return -1; /* exception thrown */ |
| 160 } |
| 161 |
| 162 // construct the object |
| 163 jobject javaRenderObjLocal = env->NewObject(_javaRenderClass, |
| 164 cid, |
| 165 _ptrWindow); |
| 166 if (!javaRenderObjLocal) { |
| 167 WEBRTC_TRACE(kTraceError, |
| 168 kTraceVideoRenderer, |
| 169 _id, |
| 170 "%s: could not create Java Render", |
| 171 __FUNCTION__); |
| 172 return -1; |
| 173 } |
| 174 |
| 175 // create a reference to the object (to tell JNI that we are referencing it |
| 176 // after this function has returned) |
| 177 _javaRenderObj = env->NewGlobalRef(javaRenderObjLocal); |
| 178 if (!_javaRenderObj) { |
| 179 WEBRTC_TRACE(kTraceError, |
| 180 kTraceVideoRenderer, |
| 181 _id, |
| 182 "%s: could not create Java SurfaceRender object reference", |
| 183 __FUNCTION__); |
| 184 return -1; |
| 185 } |
| 186 |
| 187 // Detach this thread if it was attached |
| 188 if (isAttached) { |
| 189 if (g_jvm->DetachCurrentThread() < 0) { |
| 190 WEBRTC_TRACE(kTraceWarning, |
| 191 kTraceVideoRenderer, |
| 192 _id, |
| 193 "%s: Could not detach thread from JVM", __FUNCTION__); |
| 194 } |
| 195 } |
| 196 |
| 197 WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s done", __FUNCTION__); |
| 198 return 0; |
| 199 } |
| 200 |
| 201 AndroidStream* |
| 202 AndroidSurfaceViewRenderer::CreateAndroidRenderChannel( |
| 203 int32_t streamId, |
| 204 int32_t zOrder, |
| 205 const float left, |
| 206 const float top, |
| 207 const float right, |
| 208 const float bottom, |
| 209 VideoRenderAndroid& renderer) { |
| 210 WEBRTC_TRACE(kTraceDebug, |
| 211 kTraceVideoRenderer, |
| 212 _id, |
| 213 "%s: Id %d", |
| 214 __FUNCTION__, |
| 215 streamId); |
| 216 AndroidSurfaceViewChannel* stream = |
| 217 new AndroidSurfaceViewChannel(streamId, g_jvm, renderer, _javaRenderObj); |
| 218 if(stream && stream->Init(zOrder, left, top, right, bottom) == 0) |
| 219 return stream; |
| 220 else |
| 221 delete stream; |
| 222 return NULL; |
| 223 } |
| 224 |
| 225 AndroidSurfaceViewChannel::AndroidSurfaceViewChannel( |
| 226 uint32_t streamId, |
| 227 JavaVM* jvm, |
| 228 VideoRenderAndroid& renderer, |
| 229 jobject javaRenderObj) : |
| 230 _id(streamId), |
| 231 _renderCritSect(*CriticalSectionWrapper::CreateCriticalSection()), |
| 232 _renderer(renderer), |
| 233 _jvm(jvm), |
| 234 _javaRenderObj(javaRenderObj), |
| 235 #ifndef ANDROID_NDK_8_OR_ABOVE |
| 236 _javaByteBufferObj(NULL), |
| 237 _directBuffer(NULL), |
| 238 #endif |
| 239 _bitmapWidth(0), |
| 240 _bitmapHeight(0) { |
| 241 } |
| 242 |
| 243 AndroidSurfaceViewChannel::~AndroidSurfaceViewChannel() { |
| 244 WEBRTC_TRACE(kTraceInfo, |
| 245 kTraceVideoRenderer, |
| 246 _id, |
| 247 "AndroidSurfaceViewChannel dtor"); |
| 248 delete &_renderCritSect; |
| 249 if(_jvm) { |
| 250 // get the JNI env for this thread |
| 251 bool isAttached = false; |
| 252 JNIEnv* env = NULL; |
| 253 if ( _jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { |
| 254 // try to attach the thread and get the env |
| 255 // Attach this thread to JVM |
| 256 jint res = _jvm->AttachCurrentThread(&env, NULL); |
| 257 |
| 258 // Get the JNI env for this thread |
| 259 if ((res < 0) || !env) { |
| 260 WEBRTC_TRACE(kTraceError, |
| 261 kTraceVideoRenderer, |
| 262 _id, |
| 263 "%s: Could not attach thread to JVM (%d, %p)", |
| 264 __FUNCTION__, |
| 265 res, |
| 266 env); |
| 267 env=NULL; |
| 268 } |
| 269 else { |
| 270 isAttached = true; |
| 271 } |
| 272 } |
| 273 |
| 274 env->DeleteGlobalRef(_javaByteBufferObj); |
| 275 if (isAttached) { |
| 276 if (_jvm->DetachCurrentThread() < 0) { |
| 277 WEBRTC_TRACE(kTraceWarning, |
| 278 kTraceVideoRenderer, |
| 279 _id, |
| 280 "%s: Could not detach thread from JVM", |
| 281 __FUNCTION__); |
| 282 } |
| 283 } |
| 284 } |
| 285 } |
| 286 |
| 287 int32_t AndroidSurfaceViewChannel::Init( |
| 288 int32_t /*zOrder*/, |
| 289 const float left, |
| 290 const float top, |
| 291 const float right, |
| 292 const float bottom) { |
| 293 |
| 294 WEBRTC_TRACE(kTraceDebug, |
| 295 kTraceVideoRenderer, |
| 296 _id, |
| 297 "%s: AndroidSurfaceViewChannel", |
| 298 __FUNCTION__); |
| 299 if (!_jvm) { |
| 300 WEBRTC_TRACE(kTraceError, |
| 301 kTraceVideoRenderer, |
| 302 _id, |
| 303 "%s: Not a valid Java VM pointer", |
| 304 __FUNCTION__); |
| 305 return -1; |
| 306 } |
| 307 |
| 308 if( (top > 1 || top < 0) || |
| 309 (right > 1 || right < 0) || |
| 310 (bottom > 1 || bottom < 0) || |
| 311 (left > 1 || left < 0)) { |
| 312 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, |
| 313 "%s: Wrong coordinates", __FUNCTION__); |
| 314 return -1; |
| 315 } |
| 316 |
| 317 // get the JNI env for this thread |
| 318 bool isAttached = false; |
| 319 JNIEnv* env = NULL; |
| 320 if (_jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { |
| 321 // try to attach the thread and get the env |
| 322 // Attach this thread to JVM |
| 323 jint res = _jvm->AttachCurrentThread(&env, NULL); |
| 324 |
| 325 // Get the JNI env for this thread |
| 326 if ((res < 0) || !env) { |
| 327 WEBRTC_TRACE(kTraceError, |
| 328 kTraceVideoRenderer, |
| 329 _id, |
| 330 "%s: Could not attach thread to JVM (%d, %p)", |
| 331 __FUNCTION__, |
| 332 res, |
| 333 env); |
| 334 return -1; |
| 335 } |
| 336 isAttached = true; |
| 337 } |
| 338 |
| 339 jclass javaRenderClass = |
| 340 env->FindClass("org/webrtc/videoengine/ViESurfaceRenderer"); |
| 341 if (!javaRenderClass) { |
| 342 WEBRTC_TRACE(kTraceError, |
| 343 kTraceVideoRenderer, |
| 344 _id, |
| 345 "%s: could not find ViESurfaceRenderer", |
| 346 __FUNCTION__); |
| 347 return -1; |
| 348 } |
| 349 |
| 350 // get the method ID for the CreateIntArray |
| 351 _createByteBufferCid = |
| 352 env->GetMethodID(javaRenderClass, |
| 353 "CreateByteBuffer", |
| 354 "(II)Ljava/nio/ByteBuffer;"); |
| 355 if (_createByteBufferCid == NULL) { |
| 356 WEBRTC_TRACE(kTraceError, |
| 357 kTraceVideoRenderer, |
| 358 _id, |
| 359 "%s: could not get CreateByteBuffer ID", |
| 360 __FUNCTION__); |
| 361 return -1; /* exception thrown */ |
| 362 } |
| 363 |
| 364 // get the method ID for the DrawByteBuffer function |
| 365 _drawByteBufferCid = env->GetMethodID(javaRenderClass, |
| 366 "DrawByteBuffer", |
| 367 "()V"); |
| 368 if (_drawByteBufferCid == NULL) { |
| 369 WEBRTC_TRACE(kTraceError, |
| 370 kTraceVideoRenderer, |
| 371 _id, |
| 372 "%s: could not get DrawByteBuffer ID", |
| 373 __FUNCTION__); |
| 374 return -1; /* exception thrown */ |
| 375 } |
| 376 |
| 377 // get the method ID for the SetCoordinates function |
| 378 _setCoordinatesCid = env->GetMethodID(javaRenderClass, |
| 379 "SetCoordinates", |
| 380 "(FFFF)V"); |
| 381 if (_setCoordinatesCid == NULL) { |
| 382 WEBRTC_TRACE(kTraceError, |
| 383 kTraceVideoRenderer, |
| 384 _id, |
| 385 "%s: could not get SetCoordinates ID", |
| 386 __FUNCTION__); |
| 387 return -1; /* exception thrown */ |
| 388 } |
| 389 |
| 390 env->CallVoidMethod(_javaRenderObj, _setCoordinatesCid, |
| 391 left, top, right, bottom); |
| 392 |
| 393 // Detach this thread if it was attached |
| 394 if (isAttached) { |
| 395 if (_jvm->DetachCurrentThread() < 0) { |
| 396 WEBRTC_TRACE(kTraceWarning, |
| 397 kTraceVideoRenderer, |
| 398 _id, |
| 399 "%s: Could not detach thread from JVM", |
| 400 __FUNCTION__); |
| 401 } |
| 402 } |
| 403 |
| 404 WEBRTC_TRACE(kTraceDebug, |
| 405 kTraceVideoRenderer, |
| 406 _id, |
| 407 "%s: AndroidSurfaceViewChannel done", |
| 408 __FUNCTION__); |
| 409 return 0; |
| 410 } |
| 411 |
| 412 int32_t AndroidSurfaceViewChannel::RenderFrame(const uint32_t /*streamId*/, |
| 413 const VideoFrame& videoFrame) { |
| 414 // WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer,_id, "%s:" ,__FUNCTION__); |
| 415 _renderCritSect.Enter(); |
| 416 _bufferToRender = videoFrame; |
| 417 _renderCritSect.Leave(); |
| 418 _renderer.ReDraw(); |
| 419 return 0; |
| 420 } |
| 421 |
| 422 |
| 423 /*Implements AndroidStream |
| 424 * Calls the Java object and render the buffer in _bufferToRender |
| 425 */ |
| 426 void AndroidSurfaceViewChannel::DeliverFrame(JNIEnv* jniEnv) { |
| 427 _renderCritSect.Enter(); |
| 428 |
| 429 if (_bitmapWidth != _bufferToRender.width() || |
| 430 _bitmapHeight != _bufferToRender.height()) { |
| 431 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s: New render size %d " |
| 432 "%d",__FUNCTION__, |
| 433 _bufferToRender.width(), _bufferToRender.height()); |
| 434 if (_javaByteBufferObj) { |
| 435 jniEnv->DeleteGlobalRef(_javaByteBufferObj); |
| 436 _javaByteBufferObj = NULL; |
| 437 _directBuffer = NULL; |
| 438 } |
| 439 |
| 440 jobject javaByteBufferObj = |
| 441 jniEnv->CallObjectMethod(_javaRenderObj, _createByteBufferCid, |
| 442 _bufferToRender.width(), |
| 443 _bufferToRender.height()); |
| 444 _javaByteBufferObj = jniEnv->NewGlobalRef(javaByteBufferObj); |
| 445 if (!_javaByteBufferObj) { |
| 446 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s: could not " |
| 447 "create Java ByteBuffer object reference", __FUNCTION__); |
| 448 _renderCritSect.Leave(); |
| 449 return; |
| 450 } else { |
| 451 _directBuffer = static_cast<unsigned char*> |
| 452 (jniEnv->GetDirectBufferAddress(_javaByteBufferObj)); |
| 453 _bitmapWidth = _bufferToRender.width(); |
| 454 _bitmapHeight = _bufferToRender.height(); |
| 455 } |
| 456 } |
| 457 |
| 458 if(_javaByteBufferObj && _bitmapWidth && _bitmapHeight) { |
| 459 const int conversionResult = |
| 460 ConvertFromI420(_bufferToRender, kRGB565, 0, _directBuffer); |
| 461 |
| 462 if (conversionResult < 0) { |
| 463 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s: Color conversion" |
| 464 " failed.", __FUNCTION__); |
| 465 _renderCritSect.Leave(); |
| 466 return; |
| 467 } |
| 468 } |
| 469 _renderCritSect.Leave(); |
| 470 // Draw the Surface |
| 471 jniEnv->CallVoidMethod(_javaRenderObj, _drawByteBufferCid); |
| 472 } |
| 473 |
| 474 } // namespace webrtc |
OLD | NEW |