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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: talk/app/webrtc/java/jni/androidvideocapturer_jni.cc
diff --git a/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc b/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc
index 0b7a2efb2194fa3c88ddc74634adbb73a22e1369..43a60c3cecd9b9d8ff73ecfe407100ed1a927c71 100644
--- a/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc
+++ b/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc
@@ -29,6 +29,7 @@
#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
#include "webrtc/base/bind.h"
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
namespace webrtc_jni {
@@ -70,9 +71,7 @@ AndroidVideoCapturerJni::AndroidVideoCapturerJni(JNIEnv* jni,
jni,
FindClass(jni,
"org/webrtc/VideoCapturerAndroid$NativeObserver")),
- capturer_(nullptr),
- thread_(nullptr),
- valid_global_refs_(true) {
+ capturer_(nullptr) {
LOG(LS_INFO) << "AndroidVideoCapturerJni ctor";
thread_checker_.DetachFromThread();
}
@@ -88,30 +87,24 @@ bool AndroidVideoCapturerJni::Init(jstring device_name) {
}
AndroidVideoCapturerJni::~AndroidVideoCapturerJni() {
- valid_global_refs_ = false;
- if (thread_ != nullptr) {
- LOG(LS_INFO) << "AndroidVideoCapturerJni dtor - flush invoker";
- invoker_.Flush(thread_);
- }
- LOG(LS_INFO) << "AndroidVideoCapturerJni dtor done";
+ LOG(LS_INFO) << "AndroidVideoCapturerJni dtor";
}
void AndroidVideoCapturerJni::Start(int width, int height, int framerate,
webrtc::AndroidVideoCapturer* capturer) {
LOG(LS_INFO) << "AndroidVideoCapturerJni start";
- CHECK(thread_checker_.CalledOnValidThread());
- CHECK(capturer_ == nullptr);
- thread_ = rtc::Thread::Current();
- capturer_ = capturer;
-
- j_frame_observer_ = NewGlobalRef(
- jni(),
+ DCHECK(thread_checker_.CalledOnValidThread());
+ {
+ rtc::CritScope cs(&capturer_lock_);
+ CHECK(capturer_ == nullptr);
+ CHECK(invoker_.get() == nullptr);
+ capturer_ = capturer;
+ invoker_.reset(new rtc::GuardedAsyncInvoker());
+ }
+ jobject j_frame_observer =
jni()->NewObject(*j_observer_class_,
- GetMethodID(jni(),
- *j_observer_class_,
- "<init>",
- "(J)V"),
- jlongFromPointer(this)));
+ GetMethodID(jni(), *j_observer_class_, "<init>", "(J)V"),
+ jlongFromPointer(this));
CHECK_EXCEPTION(jni()) << "error during NewObject";
jmethodID m = GetMethodID(
@@ -122,33 +115,40 @@ void AndroidVideoCapturerJni::Start(int width, int height, int framerate,
m, width, height,
framerate,
application_context_,
- j_frame_observer_);
+ j_frame_observer);
CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture";
}
void AndroidVideoCapturerJni::Stop() {
LOG(LS_INFO) << "AndroidVideoCapturerJni stop";
- CHECK(thread_checker_.CalledOnValidThread());
- capturer_ = nullptr;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ {
+ rtc::CritScope cs(&capturer_lock_);
+ // Destroying |invoker_| will cancel all pending calls to |capturer_|.
+ invoker_ = nullptr;
+ capturer_ = nullptr;
+ }
jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
"stopCapture", "()V");
jni()->CallVoidMethod(*j_capturer_global_, m);
CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture";
- DeleteGlobalRef(jni(), j_frame_observer_);
LOG(LS_INFO) << "AndroidVideoCapturerJni stop done";
}
-void AndroidVideoCapturerJni::ReturnBuffer(int64 time_stamp) {
- invoker_.AsyncInvoke<void>(
- thread_,
- rtc::Bind(&AndroidVideoCapturerJni::ReturnBuffer_w, this, time_stamp));
-}
-
-void AndroidVideoCapturerJni::ReturnBuffer_w(int64 time_stamp) {
- if (!valid_global_refs_) {
- LOG(LS_ERROR) << "ReturnBuffer_w is called for invalid global refs.";
+template <typename... Args>
+void AndroidVideoCapturerJni::AsyncCapturerInvoke(
+ const char* method_name,
+ void (webrtc::AndroidVideoCapturer::*method)(Args...),
+ Args... args) {
+ rtc::CritScope cs(&capturer_lock_);
+ if (!invoker_) {
+ LOG(LS_WARNING) << method_name << "() called for closed capturer.";
return;
}
+ invoker_->AsyncInvoke<void>(rtc::Bind(method, capturer_, args...));
+}
+
+void AndroidVideoCapturerJni::ReturnBuffer(int64 time_stamp) {
jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
"returnBuffer", "(J)V");
jni()->CallVoidMethod(*j_capturer_global_, m, time_stamp);
@@ -166,10 +166,10 @@ std::string AndroidVideoCapturerJni::GetSupportedFormats() {
}
void AndroidVideoCapturerJni::OnCapturerStarted(bool success) {
- LOG(LS_INFO) << "AndroidVideoCapturerJni capture started: " << success;
- invoker_.AsyncInvoke<void>(
- thread_,
- rtc::Bind(&AndroidVideoCapturerJni::OnCapturerStarted_w, this, success));
+ LOG(LS_INFO) << "AndroidVideoCapturerJni capture started: " << success;
+ AsyncCapturerInvoke("OnCapturerStarted",
+ &webrtc::AndroidVideoCapturer::OnCapturerStarted,
+ success);
}
void AndroidVideoCapturerJni::OnIncomingFrame(void* video_frame,
@@ -178,57 +178,34 @@ void AndroidVideoCapturerJni::OnIncomingFrame(void* video_frame,
int height,
int rotation,
int64 time_stamp) {
- invoker_.AsyncInvoke<void>(
- thread_,
- rtc::Bind(&AndroidVideoCapturerJni::OnIncomingFrame_w, this, video_frame,
- length, width, height, rotation, time_stamp));
+ const uint8_t* y_plane = static_cast<uint8_t*>(video_frame);
+ // Android guarantees that the stride is a multiple of 16.
+ // http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat%28int%29
+ int y_stride;
+ int uv_stride;
+ webrtc::Calc16ByteAlignedStride(width, &y_stride, &uv_stride);
+ const uint8_t* v_plane = y_plane + y_stride * height;
+ const uint8_t* u_plane =
+ v_plane + uv_stride * webrtc::AlignInt(height, 2) / 2;
+
+ // Wrap the Java buffer, and call ReturnBuffer() in the wrapped
+ // VideoFrameBuffer destructor.
+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
+ new rtc::RefCountedObject<webrtc::WrappedI420Buffer>(
+ width, height, y_plane, y_stride, u_plane, uv_stride, v_plane,
+ uv_stride,
+ rtc::Bind(&AndroidVideoCapturerJni::ReturnBuffer, this, time_stamp)));
+ AsyncCapturerInvoke("OnIncomingFrame",
+ &webrtc::AndroidVideoCapturer::OnIncomingFrame,
+ buffer, rotation, time_stamp);
}
void AndroidVideoCapturerJni::OnOutputFormatRequest(int width,
int height,
int fps) {
- invoker_.AsyncInvoke<void>(
- thread_,
- rtc::Bind(&AndroidVideoCapturerJni::OnOutputFormatRequest_w,
- this, width, height, fps));
-}
-
-void AndroidVideoCapturerJni::OnCapturerStarted_w(bool success) {
- CHECK(thread_checker_.CalledOnValidThread());
- if (capturer_) {
- capturer_->OnCapturerStarted(success);
- } else {
- LOG(LS_WARNING) << "OnCapturerStarted_w is called for closed capturer.";
- }
-}
-
-void AndroidVideoCapturerJni::OnIncomingFrame_w(void* video_frame,
- int length,
- int width,
- int height,
- int rotation,
- int64 time_stamp) {
- CHECK(thread_checker_.CalledOnValidThread());
- if (capturer_) {
- capturer_->OnIncomingFrame(video_frame, length, width, height, rotation,
- time_stamp);
- } else {
- LOG(LS_INFO) <<
- "Frame arrived after camera has been stopped: " << time_stamp <<
- ". Valid global refs: " << valid_global_refs_;
- ReturnBuffer_w(time_stamp);
- }
-}
-
-void AndroidVideoCapturerJni::OnOutputFormatRequest_w(int width,
- int height,
- int fps) {
- CHECK(thread_checker_.CalledOnValidThread());
- if (capturer_) {
- capturer_->OnOutputFormatRequest(width, height, fps);
- } else {
- LOG(LS_WARNING) << "OnOutputFormatRequest_w is called for closed capturer.";
- }
+ AsyncCapturerInvoke("OnOutputFormatRequest",
+ &webrtc::AndroidVideoCapturer::OnOutputFormatRequest,
+ width, height, fps);
}
JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); }
@@ -238,16 +215,14 @@ JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnFrameCaptured)
jint width, jint height, jint rotation, jlong ts) {
jboolean is_copy = true;
jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy);
- if (!is_copy) {
- reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)
- ->OnIncomingFrame(bytes, length, width, height, rotation, ts);
- } else {
- // If this is a copy of the original frame, it means that the memory
- // is not direct memory and thus VideoCapturerAndroid does not guarantee
- // that the memory is valid when we have released |j_frame|.
- LOG(LS_ERROR) << "NativeObserver_nativeOnFrameCaptured: frame is a copy";
- CHECK(false) << "j_frame is a copy.";
- }
+ // If this is a copy of the original frame, it means that the memory
+ // is not direct memory and thus VideoCapturerAndroid does not guarantee
+ // that the memory is valid when we have released |j_frame|.
+ // TODO(magjed): Move ReleaseByteArrayElements() into ReturnBuffer() and
+ // remove this check.
+ CHECK(!is_copy) << "NativeObserver_nativeOnFrameCaptured: frame is a copy";
+ reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)
+ ->OnIncomingFrame(bytes, length, width, height, rotation, ts);
jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT);
}
@@ -267,4 +242,3 @@ JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnOutputFormatRequest)
}
} // namespace webrtc_jni
-
« 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