Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: talk/app/webrtc/java/jni/androidvideocapturer_jni.cc

Issue 1307973002: AndroidVideoCapturerJni: Fix threading issues (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Addressing tommi@s comments Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/jni/androidvideocapturer_jni.h ('k') | talk/app/webrtc/java/src/org/webrtc/VideoCapturerAndroid.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698