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 |