1/* 2 * libjingle 3 * Copyright 2015 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h" 30#include "talk/app/webrtc/java/jni/classreferenceholder.h" 31#include "talk/app/webrtc/java/jni/native_handle_impl.h" 32#include "talk/app/webrtc/java/jni/surfacetexturehelper_jni.h" 33#include "third_party/libyuv/include/libyuv/convert.h" 34#include "webrtc/base/bind.h" 35 36namespace webrtc_jni { 37 38jobject AndroidVideoCapturerJni::application_context_ = nullptr; 39 40// static 41int AndroidVideoCapturerJni::SetAndroidObjects(JNIEnv* jni, 42 jobject appliction_context) { 43 if (application_context_) { 44 jni->DeleteGlobalRef(application_context_); 45 } 46 application_context_ = NewGlobalRef(jni, appliction_context); 47 48 return 0; 49} 50 51AndroidVideoCapturerJni::AndroidVideoCapturerJni( 52 JNIEnv* jni, 53 jobject j_video_capturer, 54 jobject j_surface_texture_helper) 55 : j_video_capturer_(jni, j_video_capturer), 56 j_video_capturer_class_( 57 jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")), 58 j_observer_class_( 59 jni, 60 FindClass(jni, 61 "org/webrtc/VideoCapturerAndroid$NativeObserver")), 62 surface_texture_helper_(new rtc::RefCountedObject<SurfaceTextureHelper>( 63 jni, j_surface_texture_helper)), 64 capturer_(nullptr) { 65 LOG(LS_INFO) << "AndroidVideoCapturerJni ctor"; 66 thread_checker_.DetachFromThread(); 67} 68 69AndroidVideoCapturerJni::~AndroidVideoCapturerJni() { 70 LOG(LS_INFO) << "AndroidVideoCapturerJni dtor"; 71 jni()->CallVoidMethod( 72 *j_video_capturer_, 73 GetMethodID(jni(), *j_video_capturer_class_, "release", "()V")); 74 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.release()"; 75} 76 77void AndroidVideoCapturerJni::Start(int width, int height, int framerate, 78 webrtc::AndroidVideoCapturer* capturer) { 79 LOG(LS_INFO) << "AndroidVideoCapturerJni start"; 80 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 81 { 82 rtc::CritScope cs(&capturer_lock_); 83 RTC_CHECK(capturer_ == nullptr); 84 RTC_CHECK(invoker_.get() == nullptr); 85 capturer_ = capturer; 86 invoker_.reset(new rtc::GuardedAsyncInvoker()); 87 } 88 jobject j_frame_observer = 89 jni()->NewObject(*j_observer_class_, 90 GetMethodID(jni(), *j_observer_class_, "<init>", "(J)V"), 91 jlongFromPointer(this)); 92 CHECK_EXCEPTION(jni()) << "error during NewObject"; 93 94 jmethodID m = GetMethodID( 95 jni(), *j_video_capturer_class_, "startCapture", 96 "(IIILandroid/content/Context;" 97 "Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V"); 98 jni()->CallVoidMethod(*j_video_capturer_, 99 m, width, height, 100 framerate, 101 application_context_, 102 j_frame_observer); 103 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture"; 104} 105 106void AndroidVideoCapturerJni::Stop() { 107 LOG(LS_INFO) << "AndroidVideoCapturerJni stop"; 108 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 109 { 110 rtc::CritScope cs(&capturer_lock_); 111 // Destroying |invoker_| will cancel all pending calls to |capturer_|. 112 invoker_ = nullptr; 113 capturer_ = nullptr; 114 } 115 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, 116 "stopCapture", "()V"); 117 jni()->CallVoidMethod(*j_video_capturer_, m); 118 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture"; 119 LOG(LS_INFO) << "AndroidVideoCapturerJni stop done"; 120} 121 122template <typename... Args> 123void AndroidVideoCapturerJni::AsyncCapturerInvoke( 124 const char* method_name, 125 void (webrtc::AndroidVideoCapturer::*method)(Args...), 126 typename Identity<Args>::type... args) { 127 rtc::CritScope cs(&capturer_lock_); 128 if (!invoker_) { 129 LOG(LS_WARNING) << method_name << "() called for closed capturer."; 130 return; 131 } 132 invoker_->AsyncInvoke<void>(rtc::Bind(method, capturer_, args...)); 133} 134 135std::string AndroidVideoCapturerJni::GetSupportedFormats() { 136 jmethodID m = 137 GetMethodID(jni(), *j_video_capturer_class_, 138 "getSupportedFormatsAsJson", "()Ljava/lang/String;"); 139 jstring j_json_caps = 140 (jstring) jni()->CallObjectMethod(*j_video_capturer_, m); 141 CHECK_EXCEPTION(jni()) << "error during supportedFormatsAsJson"; 142 return JavaToStdString(jni(), j_json_caps); 143} 144 145void AndroidVideoCapturerJni::OnCapturerStarted(bool success) { 146 LOG(LS_INFO) << "AndroidVideoCapturerJni capture started: " << success; 147 AsyncCapturerInvoke("OnCapturerStarted", 148 &webrtc::AndroidVideoCapturer::OnCapturerStarted, 149 success); 150} 151 152void AndroidVideoCapturerJni::OnMemoryBufferFrame(void* video_frame, 153 int length, 154 int width, 155 int height, 156 int rotation, 157 int64_t timestamp_ns) { 158 const uint8_t* y_plane = static_cast<uint8_t*>(video_frame); 159 const uint8_t* vu_plane = y_plane + width * height; 160 161 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer = 162 buffer_pool_.CreateBuffer(width, height); 163 libyuv::NV21ToI420( 164 y_plane, width, 165 vu_plane, width, 166 buffer->MutableData(webrtc::kYPlane), buffer->stride(webrtc::kYPlane), 167 buffer->MutableData(webrtc::kUPlane), buffer->stride(webrtc::kUPlane), 168 buffer->MutableData(webrtc::kVPlane), buffer->stride(webrtc::kVPlane), 169 width, height); 170 AsyncCapturerInvoke("OnIncomingFrame", 171 &webrtc::AndroidVideoCapturer::OnIncomingFrame, 172 buffer, rotation, timestamp_ns); 173} 174 175void AndroidVideoCapturerJni::OnTextureFrame(int width, 176 int height, 177 int rotation, 178 int64_t timestamp_ns, 179 const NativeHandleImpl& handle) { 180 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer( 181 surface_texture_helper_->CreateTextureFrame(width, height, handle)); 182 183 AsyncCapturerInvoke("OnIncomingFrame", 184 &webrtc::AndroidVideoCapturer::OnIncomingFrame, 185 buffer, rotation, timestamp_ns); 186} 187 188void AndroidVideoCapturerJni::OnOutputFormatRequest(int width, 189 int height, 190 int fps) { 191 AsyncCapturerInvoke("OnOutputFormatRequest", 192 &webrtc::AndroidVideoCapturer::OnOutputFormatRequest, 193 width, height, fps); 194} 195 196JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); } 197 198JOW(void, 199 VideoCapturerAndroid_00024NativeObserver_nativeOnByteBufferFrameCaptured) 200 (JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame, jint length, 201 jint width, jint height, jint rotation, jlong timestamp) { 202 jboolean is_copy = true; 203 jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy); 204 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer) 205 ->OnMemoryBufferFrame(bytes, length, width, height, rotation, timestamp); 206 jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT); 207} 208 209JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnTextureFrameCaptured) 210 (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height, 211 jint j_oes_texture_id, jfloatArray j_transform_matrix, 212 jint j_rotation, jlong j_timestamp) { 213 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer) 214 ->OnTextureFrame(j_width, j_height, j_rotation, j_timestamp, 215 NativeHandleImpl(jni, j_oes_texture_id, 216 j_transform_matrix)); 217} 218 219JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted) 220 (JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) { 221 LOG(LS_INFO) << "NativeObserver_nativeCapturerStarted"; 222 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnCapturerStarted( 223 j_success); 224} 225 226JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnOutputFormatRequest) 227 (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height, 228 jint j_fps) { 229 LOG(LS_INFO) << "NativeObserver_nativeOnOutputFormatRequest"; 230 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnOutputFormatRequest( 231 j_width, j_height, j_fps); 232} 233 234JOW(jlong, VideoCapturerAndroid_nativeCreateVideoCapturer) 235 (JNIEnv* jni, jclass, 236 jobject j_video_capturer, jobject j_surface_texture_helper) { 237 rtc::scoped_refptr<webrtc::AndroidVideoCapturerDelegate> delegate = 238 new rtc::RefCountedObject<AndroidVideoCapturerJni>( 239 jni, j_video_capturer, j_surface_texture_helper); 240 rtc::scoped_ptr<cricket::VideoCapturer> capturer( 241 new webrtc::AndroidVideoCapturer(delegate)); 242 // Caller takes ownership of the cricket::VideoCapturer* pointer. 243 return jlongFromPointer(capturer.release()); 244} 245 246} // namespace webrtc_jni 247