OLD | NEW |
| (Empty) |
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 | |
36 namespace webrtc_jni { | |
37 | |
38 jobject AndroidVideoCapturerJni::application_context_ = nullptr; | |
39 | |
40 // static | |
41 int 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 | |
51 AndroidVideoCapturerJni::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 | |
69 AndroidVideoCapturerJni::~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 | |
77 void 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 | |
106 void 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 | |
122 template <typename... Args> | |
123 void 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 | |
135 std::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 | |
145 void AndroidVideoCapturerJni::OnCapturerStarted(bool success) { | |
146 LOG(LS_INFO) << "AndroidVideoCapturerJni capture started: " << success; | |
147 AsyncCapturerInvoke("OnCapturerStarted", | |
148 &webrtc::AndroidVideoCapturer::OnCapturerStarted, | |
149 success); | |
150 } | |
151 | |
152 void 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 | |
175 void 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 | |
188 void AndroidVideoCapturerJni::OnOutputFormatRequest(int width, | |
189 int height, | |
190 int fps) { | |
191 AsyncCapturerInvoke("OnOutputFormatRequest", | |
192 &webrtc::AndroidVideoCapturer::OnOutputFormatRequest, | |
193 width, height, fps); | |
194 } | |
195 | |
196 JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); } | |
197 | |
198 JOW(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 | |
209 JOW(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 | |
219 JOW(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 | |
226 JOW(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 | |
234 JOW(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 | |
OLD | NEW |