OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 11 matching lines...) Expand all Loading... |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | 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 | 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 * | 26 * |
27 */ | 27 */ |
28 | 28 |
29 #include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h" | 29 #include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h" |
30 #include "talk/app/webrtc/java/jni/classreferenceholder.h" | 30 #include "talk/app/webrtc/java/jni/classreferenceholder.h" |
31 #include "webrtc/base/bind.h" | 31 #include "webrtc/base/bind.h" |
| 32 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
32 | 33 |
33 namespace webrtc_jni { | 34 namespace webrtc_jni { |
34 | 35 |
35 jobject AndroidVideoCapturerJni::application_context_ = nullptr; | 36 jobject AndroidVideoCapturerJni::application_context_ = nullptr; |
36 | 37 |
37 // static | 38 // static |
38 int AndroidVideoCapturerJni::SetAndroidObjects(JNIEnv* jni, | 39 int AndroidVideoCapturerJni::SetAndroidObjects(JNIEnv* jni, |
39 jobject appliction_context) { | 40 jobject appliction_context) { |
40 if (application_context_) { | 41 if (application_context_) { |
41 jni->DeleteGlobalRef(application_context_); | 42 jni->DeleteGlobalRef(application_context_); |
(...skipping 21 matching lines...) Expand all Loading... |
63 | 64 |
64 AndroidVideoCapturerJni::AndroidVideoCapturerJni(JNIEnv* jni, | 65 AndroidVideoCapturerJni::AndroidVideoCapturerJni(JNIEnv* jni, |
65 jobject j_video_capturer) | 66 jobject j_video_capturer) |
66 : j_capturer_global_(jni, j_video_capturer), | 67 : j_capturer_global_(jni, j_video_capturer), |
67 j_video_capturer_class_( | 68 j_video_capturer_class_( |
68 jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")), | 69 jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")), |
69 j_observer_class_( | 70 j_observer_class_( |
70 jni, | 71 jni, |
71 FindClass(jni, | 72 FindClass(jni, |
72 "org/webrtc/VideoCapturerAndroid$NativeObserver")), | 73 "org/webrtc/VideoCapturerAndroid$NativeObserver")), |
73 capturer_(nullptr), | 74 capturer_(nullptr) { |
74 thread_(nullptr), | |
75 valid_global_refs_(true) { | |
76 LOG(LS_INFO) << "AndroidVideoCapturerJni ctor"; | 75 LOG(LS_INFO) << "AndroidVideoCapturerJni ctor"; |
77 thread_checker_.DetachFromThread(); | 76 thread_checker_.DetachFromThread(); |
78 } | 77 } |
79 | 78 |
80 bool AndroidVideoCapturerJni::Init(jstring device_name) { | 79 bool AndroidVideoCapturerJni::Init(jstring device_name) { |
81 const jmethodID m(GetMethodID( | 80 const jmethodID m(GetMethodID( |
82 jni(), *j_video_capturer_class_, "init", "(Ljava/lang/String;)Z")); | 81 jni(), *j_video_capturer_class_, "init", "(Ljava/lang/String;)Z")); |
83 if (!jni()->CallBooleanMethod(*j_capturer_global_, m, device_name)) { | 82 if (!jni()->CallBooleanMethod(*j_capturer_global_, m, device_name)) { |
84 return false; | 83 return false; |
85 } | 84 } |
86 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; | 85 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
87 return true; | 86 return true; |
88 } | 87 } |
89 | 88 |
90 AndroidVideoCapturerJni::~AndroidVideoCapturerJni() { | 89 AndroidVideoCapturerJni::~AndroidVideoCapturerJni() { |
91 valid_global_refs_ = false; | 90 LOG(LS_INFO) << "AndroidVideoCapturerJni dtor"; |
92 if (thread_ != nullptr) { | |
93 LOG(LS_INFO) << "AndroidVideoCapturerJni dtor - flush invoker"; | |
94 invoker_.Flush(thread_); | |
95 } | |
96 LOG(LS_INFO) << "AndroidVideoCapturerJni dtor done"; | |
97 } | 91 } |
98 | 92 |
99 void AndroidVideoCapturerJni::Start(int width, int height, int framerate, | 93 void AndroidVideoCapturerJni::Start(int width, int height, int framerate, |
100 webrtc::AndroidVideoCapturer* capturer) { | 94 webrtc::AndroidVideoCapturer* capturer) { |
101 LOG(LS_INFO) << "AndroidVideoCapturerJni start"; | 95 LOG(LS_INFO) << "AndroidVideoCapturerJni start"; |
102 CHECK(thread_checker_.CalledOnValidThread()); | 96 DCHECK(thread_checker_.CalledOnValidThread()); |
103 CHECK(capturer_ == nullptr); | 97 { |
104 thread_ = rtc::Thread::Current(); | 98 rtc::CritScope cs(&capturer_lock_); |
105 capturer_ = capturer; | 99 CHECK(capturer_ == nullptr); |
106 | 100 CHECK(invoker_.get() == nullptr); |
107 j_frame_observer_ = NewGlobalRef( | 101 capturer_ = capturer; |
108 jni(), | 102 invoker_.reset(new rtc::GuardedAsyncInvoker()); |
| 103 } |
| 104 jobject j_frame_observer = |
109 jni()->NewObject(*j_observer_class_, | 105 jni()->NewObject(*j_observer_class_, |
110 GetMethodID(jni(), | 106 GetMethodID(jni(), *j_observer_class_, "<init>", "(J)V"), |
111 *j_observer_class_, | 107 jlongFromPointer(this)); |
112 "<init>", | |
113 "(J)V"), | |
114 jlongFromPointer(this))); | |
115 CHECK_EXCEPTION(jni()) << "error during NewObject"; | 108 CHECK_EXCEPTION(jni()) << "error during NewObject"; |
116 | 109 |
117 jmethodID m = GetMethodID( | 110 jmethodID m = GetMethodID( |
118 jni(), *j_video_capturer_class_, "startCapture", | 111 jni(), *j_video_capturer_class_, "startCapture", |
119 "(IIILandroid/content/Context;" | 112 "(IIILandroid/content/Context;" |
120 "Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V"); | 113 "Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V"); |
121 jni()->CallVoidMethod(*j_capturer_global_, | 114 jni()->CallVoidMethod(*j_capturer_global_, |
122 m, width, height, | 115 m, width, height, |
123 framerate, | 116 framerate, |
124 application_context_, | 117 application_context_, |
125 j_frame_observer_); | 118 j_frame_observer); |
126 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture"; | 119 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture"; |
127 } | 120 } |
128 | 121 |
129 void AndroidVideoCapturerJni::Stop() { | 122 void AndroidVideoCapturerJni::Stop() { |
130 LOG(LS_INFO) << "AndroidVideoCapturerJni stop"; | 123 LOG(LS_INFO) << "AndroidVideoCapturerJni stop"; |
131 CHECK(thread_checker_.CalledOnValidThread()); | 124 DCHECK(thread_checker_.CalledOnValidThread()); |
132 capturer_ = nullptr; | 125 { |
| 126 rtc::CritScope cs(&capturer_lock_); |
| 127 // Destroying |invoker_| will cancel all pending calls to |capturer_|. |
| 128 invoker_ = nullptr; |
| 129 capturer_ = nullptr; |
| 130 } |
133 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, | 131 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, |
134 "stopCapture", "()V"); | 132 "stopCapture", "()V"); |
135 jni()->CallVoidMethod(*j_capturer_global_, m); | 133 jni()->CallVoidMethod(*j_capturer_global_, m); |
136 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture"; | 134 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture"; |
137 DeleteGlobalRef(jni(), j_frame_observer_); | |
138 LOG(LS_INFO) << "AndroidVideoCapturerJni stop done"; | 135 LOG(LS_INFO) << "AndroidVideoCapturerJni stop done"; |
139 } | 136 } |
140 | 137 |
141 void AndroidVideoCapturerJni::ReturnBuffer(int64 time_stamp) { | 138 template <typename... Args> |
142 invoker_.AsyncInvoke<void>( | 139 void AndroidVideoCapturerJni::AsyncCapturerInvoke( |
143 thread_, | 140 const char* method_name, |
144 rtc::Bind(&AndroidVideoCapturerJni::ReturnBuffer_w, this, time_stamp)); | 141 void (webrtc::AndroidVideoCapturer::*method)(Args...), |
| 142 Args... args) { |
| 143 rtc::CritScope cs(&capturer_lock_); |
| 144 if (!invoker_) { |
| 145 LOG(LS_WARNING) << method_name << "() called for closed capturer."; |
| 146 return; |
| 147 } |
| 148 invoker_->AsyncInvoke<void>(rtc::Bind(method, capturer_, args...)); |
145 } | 149 } |
146 | 150 |
147 void AndroidVideoCapturerJni::ReturnBuffer_w(int64 time_stamp) { | 151 void AndroidVideoCapturerJni::ReturnBuffer(int64 time_stamp) { |
148 if (!valid_global_refs_) { | |
149 LOG(LS_ERROR) << "ReturnBuffer_w is called for invalid global refs."; | |
150 return; | |
151 } | |
152 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, | 152 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, |
153 "returnBuffer", "(J)V"); | 153 "returnBuffer", "(J)V"); |
154 jni()->CallVoidMethod(*j_capturer_global_, m, time_stamp); | 154 jni()->CallVoidMethod(*j_capturer_global_, m, time_stamp); |
155 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.returnBuffer"; | 155 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.returnBuffer"; |
156 } | 156 } |
157 | 157 |
158 std::string AndroidVideoCapturerJni::GetSupportedFormats() { | 158 std::string AndroidVideoCapturerJni::GetSupportedFormats() { |
159 jmethodID m = | 159 jmethodID m = |
160 GetMethodID(jni(), *j_video_capturer_class_, | 160 GetMethodID(jni(), *j_video_capturer_class_, |
161 "getSupportedFormatsAsJson", "()Ljava/lang/String;"); | 161 "getSupportedFormatsAsJson", "()Ljava/lang/String;"); |
162 jstring j_json_caps = | 162 jstring j_json_caps = |
163 (jstring) jni()->CallObjectMethod(*j_capturer_global_, m); | 163 (jstring) jni()->CallObjectMethod(*j_capturer_global_, m); |
164 CHECK_EXCEPTION(jni()) << "error during supportedFormatsAsJson"; | 164 CHECK_EXCEPTION(jni()) << "error during supportedFormatsAsJson"; |
165 return JavaToStdString(jni(), j_json_caps); | 165 return JavaToStdString(jni(), j_json_caps); |
166 } | 166 } |
167 | 167 |
168 void AndroidVideoCapturerJni::OnCapturerStarted(bool success) { | 168 void AndroidVideoCapturerJni::OnCapturerStarted(bool success) { |
169 LOG(LS_INFO) << "AndroidVideoCapturerJni capture started: " << success; | 169 LOG(LS_INFO) << "AndroidVideoCapturerJni capture started: " << success; |
170 invoker_.AsyncInvoke<void>( | 170 AsyncCapturerInvoke("OnCapturerStarted", |
171 thread_, | 171 &webrtc::AndroidVideoCapturer::OnCapturerStarted, |
172 rtc::Bind(&AndroidVideoCapturerJni::OnCapturerStarted_w, this, success)); | 172 success); |
173 } | 173 } |
174 | 174 |
175 void AndroidVideoCapturerJni::OnIncomingFrame(void* video_frame, | 175 void AndroidVideoCapturerJni::OnIncomingFrame(void* video_frame, |
176 int length, | 176 int length, |
177 int width, | 177 int width, |
178 int height, | 178 int height, |
179 int rotation, | 179 int rotation, |
180 int64 time_stamp) { | 180 int64 time_stamp) { |
181 invoker_.AsyncInvoke<void>( | 181 const uint8_t* y_plane = static_cast<uint8_t*>(video_frame); |
182 thread_, | 182 // Android guarantees that the stride is a multiple of 16. |
183 rtc::Bind(&AndroidVideoCapturerJni::OnIncomingFrame_w, this, video_frame, | 183 // http://developer.android.com/reference/android/hardware/Camera.Parameters.h
tml#setPreviewFormat%28int%29 |
184 length, width, height, rotation, time_stamp)); | 184 int y_stride; |
| 185 int uv_stride; |
| 186 webrtc::Calc16ByteAlignedStride(width, &y_stride, &uv_stride); |
| 187 const uint8_t* v_plane = y_plane + y_stride * height; |
| 188 const uint8_t* u_plane = |
| 189 v_plane + uv_stride * webrtc::AlignInt(height, 2) / 2; |
| 190 |
| 191 // Wrap the Java buffer, and call ReturnBuffer() in the wrapped |
| 192 // VideoFrameBuffer destructor. |
| 193 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer( |
| 194 new rtc::RefCountedObject<webrtc::WrappedI420Buffer>( |
| 195 width, height, y_plane, y_stride, u_plane, uv_stride, v_plane, |
| 196 uv_stride, |
| 197 rtc::Bind(&AndroidVideoCapturerJni::ReturnBuffer, this, time_stamp))); |
| 198 AsyncCapturerInvoke("OnIncomingFrame", |
| 199 &webrtc::AndroidVideoCapturer::OnIncomingFrame, |
| 200 buffer, rotation, time_stamp); |
185 } | 201 } |
186 | 202 |
187 void AndroidVideoCapturerJni::OnOutputFormatRequest(int width, | 203 void AndroidVideoCapturerJni::OnOutputFormatRequest(int width, |
188 int height, | 204 int height, |
189 int fps) { | 205 int fps) { |
190 invoker_.AsyncInvoke<void>( | 206 AsyncCapturerInvoke("OnOutputFormatRequest", |
191 thread_, | 207 &webrtc::AndroidVideoCapturer::OnOutputFormatRequest, |
192 rtc::Bind(&AndroidVideoCapturerJni::OnOutputFormatRequest_w, | 208 width, height, fps); |
193 this, width, height, fps)); | |
194 } | |
195 | |
196 void AndroidVideoCapturerJni::OnCapturerStarted_w(bool success) { | |
197 CHECK(thread_checker_.CalledOnValidThread()); | |
198 if (capturer_) { | |
199 capturer_->OnCapturerStarted(success); | |
200 } else { | |
201 LOG(LS_WARNING) << "OnCapturerStarted_w is called for closed capturer."; | |
202 } | |
203 } | |
204 | |
205 void AndroidVideoCapturerJni::OnIncomingFrame_w(void* video_frame, | |
206 int length, | |
207 int width, | |
208 int height, | |
209 int rotation, | |
210 int64 time_stamp) { | |
211 CHECK(thread_checker_.CalledOnValidThread()); | |
212 if (capturer_) { | |
213 capturer_->OnIncomingFrame(video_frame, length, width, height, rotation, | |
214 time_stamp); | |
215 } else { | |
216 LOG(LS_INFO) << | |
217 "Frame arrived after camera has been stopped: " << time_stamp << | |
218 ". Valid global refs: " << valid_global_refs_; | |
219 ReturnBuffer_w(time_stamp); | |
220 } | |
221 } | |
222 | |
223 void AndroidVideoCapturerJni::OnOutputFormatRequest_w(int width, | |
224 int height, | |
225 int fps) { | |
226 CHECK(thread_checker_.CalledOnValidThread()); | |
227 if (capturer_) { | |
228 capturer_->OnOutputFormatRequest(width, height, fps); | |
229 } else { | |
230 LOG(LS_WARNING) << "OnOutputFormatRequest_w is called for closed capturer."; | |
231 } | |
232 } | 209 } |
233 | 210 |
234 JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); } | 211 JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); } |
235 | 212 |
236 JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnFrameCaptured) | 213 JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnFrameCaptured) |
237 (JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame, jint length, | 214 (JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame, jint length, |
238 jint width, jint height, jint rotation, jlong ts) { | 215 jint width, jint height, jint rotation, jlong ts) { |
239 jboolean is_copy = true; | 216 jboolean is_copy = true; |
240 jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy); | 217 jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy); |
241 if (!is_copy) { | 218 // If this is a copy of the original frame, it means that the memory |
242 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer) | 219 // is not direct memory and thus VideoCapturerAndroid does not guarantee |
243 ->OnIncomingFrame(bytes, length, width, height, rotation, ts); | 220 // that the memory is valid when we have released |j_frame|. |
244 } else { | 221 // TODO(magjed): Move ReleaseByteArrayElements() into ReturnBuffer() and |
245 // If this is a copy of the original frame, it means that the memory | 222 // remove this check. |
246 // is not direct memory and thus VideoCapturerAndroid does not guarantee | 223 CHECK(!is_copy) << "NativeObserver_nativeOnFrameCaptured: frame is a copy"; |
247 // that the memory is valid when we have released |j_frame|. | 224 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer) |
248 LOG(LS_ERROR) << "NativeObserver_nativeOnFrameCaptured: frame is a copy"; | 225 ->OnIncomingFrame(bytes, length, width, height, rotation, ts); |
249 CHECK(false) << "j_frame is a copy."; | |
250 } | |
251 jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT); | 226 jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT); |
252 } | 227 } |
253 | 228 |
254 JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted) | 229 JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted) |
255 (JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) { | 230 (JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) { |
256 LOG(LS_INFO) << "NativeObserver_nativeCapturerStarted"; | 231 LOG(LS_INFO) << "NativeObserver_nativeCapturerStarted"; |
257 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnCapturerStarted( | 232 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnCapturerStarted( |
258 j_success); | 233 j_success); |
259 } | 234 } |
260 | 235 |
261 JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnOutputFormatRequest) | 236 JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnOutputFormatRequest) |
262 (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height, | 237 (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height, |
263 jint j_fps) { | 238 jint j_fps) { |
264 LOG(LS_INFO) << "NativeObserver_nativeOnOutputFormatRequest"; | 239 LOG(LS_INFO) << "NativeObserver_nativeOnOutputFormatRequest"; |
265 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnOutputFormatRequest( | 240 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnOutputFormatRequest( |
266 j_width, j_height, j_fps); | 241 j_width, j_height, j_fps); |
267 } | 242 } |
268 | 243 |
269 } // namespace webrtc_jni | 244 } // namespace webrtc_jni |
270 | |
OLD | NEW |