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_impl.h" 12 13 #include "webrtc/modules/video_render/video_render_internal.h" 14 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" 15 #include "webrtc/system_wrappers/include/event_wrapper.h" 16 #include "webrtc/system_wrappers/include/tick_util.h" 17 18 #ifdef ANDROID 19 #include <android/log.h> 20 #include <stdio.h> 21 22 #undef WEBRTC_TRACE 23 #define WEBRTC_TRACE(a,b,c,...) __android_log_print(ANDROID_LOG_DEBUG, "*WEBRTCN*", __VA_ARGS__) 24 #else 25 #include "webrtc/system_wrappers/include/trace.h" 26 #endif 27 28 namespace webrtc { 29 30 JavaVM* VideoRenderAndroid::g_jvm = NULL; 31 32 int32_t SetRenderAndroidVM(JavaVM* javaVM) { 33 WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, -1, "%s", __FUNCTION__); 34 VideoRenderAndroid::g_jvm = javaVM; 35 return 0; 36 } 37 38 VideoRenderAndroid::VideoRenderAndroid( 39 const int32_t id, 40 const VideoRenderType videoRenderType, 41 void* window, 42 const bool /*fullscreen*/): 43 _id(id), 44 _critSect(*CriticalSectionWrapper::CreateCriticalSection()), 45 _renderType(videoRenderType), 46 _ptrWindow((jobject)(window)), 47 _javaShutDownFlag(false), 48 _javaShutdownEvent(*EventWrapper::Create()), 49 _javaRenderEvent(*EventWrapper::Create()), 50 _lastJavaRenderEvent(0), 51 _javaRenderJniEnv(NULL) { 52 } 53 54 VideoRenderAndroid::~VideoRenderAndroid() { 55 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, 56 "VideoRenderAndroid dtor"); 57 58 if (_javaRenderThread) 59 StopRender(); 60 61 for (AndroidStreamMap::iterator it = _streamsMap.begin(); 62 it != _streamsMap.end(); 63 ++it) { 64 delete it->second; 65 } 66 delete &_javaShutdownEvent; 67 delete &_javaRenderEvent; 68 delete &_critSect; 69 } 70 71 int32_t VideoRenderAndroid::ChangeWindow(void* /*window*/) { 72 return -1; 73 } 74 75 VideoRenderCallback* 76 VideoRenderAndroid::AddIncomingRenderStream(const uint32_t streamId, 77 const uint32_t zOrder, 78 const float left, const float top, 79 const float right, 80 const float bottom) { 81 CriticalSectionScoped cs(&_critSect); 82 83 AndroidStream* renderStream = NULL; 84 AndroidStreamMap::iterator item = _streamsMap.find(streamId); 85 if (item != _streamsMap.end() && item->second != NULL) { 86 WEBRTC_TRACE(kTraceInfo, 87 kTraceVideoRenderer, 88 -1, 89 "%s: Render stream already exists", 90 __FUNCTION__); 91 return renderStream; 92 } 93 94 renderStream = CreateAndroidRenderChannel(streamId, zOrder, left, top, 95 right, bottom, *this); 96 if (renderStream) { 97 _streamsMap[streamId] = renderStream; 98 } 99 else { 100 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 101 "(%s:%d): renderStream is NULL", __FUNCTION__, __LINE__); 102 return NULL; 103 } 104 return renderStream; 105 } 106 107 int32_t VideoRenderAndroid::DeleteIncomingRenderStream( 108 const uint32_t streamId) { 109 CriticalSectionScoped cs(&_critSect); 110 111 AndroidStreamMap::iterator item = _streamsMap.find(streamId); 112 if (item == _streamsMap.end()) { 113 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 114 "(%s:%d): renderStream is NULL", __FUNCTION__, __LINE__); 115 return -1; 116 } 117 delete item->second; 118 _streamsMap.erase(item); 119 return 0; 120 } 121 122 int32_t VideoRenderAndroid::GetIncomingRenderStreamProperties( 123 const uint32_t streamId, 124 uint32_t& zOrder, 125 float& left, 126 float& top, 127 float& right, 128 float& bottom) const { 129 return -1; 130 } 131 132 int32_t VideoRenderAndroid::StartRender() { 133 CriticalSectionScoped cs(&_critSect); 134 135 if (_javaRenderThread) { 136 // StartRender is called when this stream should start render. 137 // However StopRender is not called when the streams stop rendering. 138 // Thus the the thread is only deleted when the renderer is removed. 139 WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, 140 "%s, Render thread already exist", __FUNCTION__); 141 return 0; 142 } 143 144 _javaRenderThread.reset(new rtc::PlatformThread(JavaRenderThreadFun, this, 145 "AndroidRenderThread")); 146 147 _javaRenderThread->Start(); 148 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s: thread started", 149 __FUNCTION__); 150 _javaRenderThread->SetPriority(rtc::kRealtimePriority); 151 return 0; 152 } 153 154 int32_t VideoRenderAndroid::StopRender() { 155 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:", __FUNCTION__); 156 { 157 CriticalSectionScoped cs(&_critSect); 158 if (!_javaRenderThread) 159 { 160 return -1; 161 } 162 _javaShutDownFlag = true; 163 _javaRenderEvent.Set(); 164 } 165 166 _javaShutdownEvent.Wait(3000); 167 CriticalSectionScoped cs(&_critSect); 168 _javaRenderThread->Stop(); 169 _javaRenderThread.reset(); 170 171 return 0; 172 } 173 174 void VideoRenderAndroid::ReDraw() { 175 CriticalSectionScoped cs(&_critSect); 176 // Allow redraw if it was more than 20ms since last. 177 if (_lastJavaRenderEvent < TickTime::MillisecondTimestamp() - 20) { 178 _lastJavaRenderEvent = TickTime::MillisecondTimestamp(); 179 _javaRenderEvent.Set(); 180 } 181 } 182 183 bool VideoRenderAndroid::JavaRenderThreadFun(void* obj) { 184 return static_cast<VideoRenderAndroid*> (obj)->JavaRenderThreadProcess(); 185 } 186 187 bool VideoRenderAndroid::JavaRenderThreadProcess() 188 { 189 _javaRenderEvent.Wait(1000); 190 191 CriticalSectionScoped cs(&_critSect); 192 if (!_javaRenderJniEnv) { 193 // try to attach the thread and get the env 194 // Attach this thread to JVM 195 jint res = g_jvm->AttachCurrentThread(&_javaRenderJniEnv, NULL); 196 197 // Get the JNI env for this thread 198 if ((res < 0) || !_javaRenderJniEnv) { 199 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 200 "%s: Could not attach thread to JVM (%d, %p)", 201 __FUNCTION__, res, _javaRenderJniEnv); 202 return false; 203 } 204 } 205 206 for (AndroidStreamMap::iterator it = _streamsMap.begin(); 207 it != _streamsMap.end(); 208 ++it) { 209 it->second->DeliverFrame(_javaRenderJniEnv); 210 } 211 212 if (_javaShutDownFlag) { 213 if (g_jvm->DetachCurrentThread() < 0) 214 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id, 215 "%s: Could not detach thread from JVM", __FUNCTION__); 216 else { 217 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, 218 "%s: Java thread detached", __FUNCTION__); 219 } 220 _javaRenderJniEnv = NULL; 221 _javaShutDownFlag = false; 222 _javaShutdownEvent.Set(); 223 return false; // Do not run this thread again. 224 } 225 return true; 226 } 227 228 VideoRenderType VideoRenderAndroid::RenderType() { 229 return _renderType; 230 } 231 232 RawVideoType VideoRenderAndroid::PerferedVideoType() { 233 return kVideoI420; 234 } 235 236 bool VideoRenderAndroid::FullScreen() { 237 return false; 238 } 239 240 int32_t VideoRenderAndroid::GetGraphicsMemory( 241 uint64_t& /*totalGraphicsMemory*/, 242 uint64_t& /*availableGraphicsMemory*/) const { 243 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 244 "%s - not supported on Android", __FUNCTION__); 245 return -1; 246 } 247 248 int32_t VideoRenderAndroid::GetScreenResolution( 249 uint32_t& /*screenWidth*/, 250 uint32_t& /*screenHeight*/) const { 251 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 252 "%s - not supported on Android", __FUNCTION__); 253 return -1; 254 } 255 256 uint32_t VideoRenderAndroid::RenderFrameRate( 257 const uint32_t /*streamId*/) { 258 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 259 "%s - not supported on Android", __FUNCTION__); 260 return -1; 261 } 262 263 int32_t VideoRenderAndroid::SetStreamCropping( 264 const uint32_t /*streamId*/, 265 const float /*left*/, 266 const float /*top*/, 267 const float /*right*/, 268 const float /*bottom*/) { 269 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 270 "%s - not supported on Android", __FUNCTION__); 271 return -1; 272 } 273 274 int32_t VideoRenderAndroid::SetTransparentBackground(const bool enable) { 275 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 276 "%s - not supported on Android", __FUNCTION__); 277 return -1; 278 } 279 280 int32_t VideoRenderAndroid::ConfigureRenderer( 281 const uint32_t streamId, 282 const unsigned int zOrder, 283 const float left, 284 const float top, 285 const float right, 286 const float bottom) { 287 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 288 "%s - not supported on Android", __FUNCTION__); 289 return -1; 290 } 291 292 int32_t VideoRenderAndroid::SetText( 293 const uint8_t textId, 294 const uint8_t* text, 295 const int32_t textLength, 296 const uint32_t textColorRef, 297 const uint32_t backgroundColorRef, 298 const float left, const float top, 299 const float rigth, const float bottom) { 300 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 301 "%s - not supported on Android", __FUNCTION__); 302 return -1; 303 } 304 305 int32_t VideoRenderAndroid::SetBitmap(const void* bitMap, 306 const uint8_t pictureId, 307 const void* colorKey, 308 const float left, const float top, 309 const float right, 310 const float bottom) { 311 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, 312 "%s - not supported on Android", __FUNCTION__); 313 return -1; 314 } 315 316 } // namespace webrtc 317