blob: d22c8b16ba9b88781d54c2f04fbe751c41d68722 [file] [log] [blame]
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00009 */
10
Henrik Kjellander15583c12016-02-10 10:53:12 +010011#include "webrtc/api/java/jni/androidvideocapturer_jni.h"
12#include "webrtc/api/java/jni/classreferenceholder.h"
13#include "webrtc/api/java/jni/native_handle_impl.h"
14#include "webrtc/api/java/jni/surfacetexturehelper_jni.h"
perkj88518a22015-12-18 00:37:06 -080015#include "third_party/libyuv/include/libyuv/convert.h"
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000016#include "webrtc/base/bind.h"
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000017
18namespace webrtc_jni {
19
20jobject AndroidVideoCapturerJni::application_context_ = nullptr;
21
22// static
23int AndroidVideoCapturerJni::SetAndroidObjects(JNIEnv* jni,
24 jobject appliction_context) {
25 if (application_context_) {
26 jni->DeleteGlobalRef(application_context_);
27 }
28 application_context_ = NewGlobalRef(jni, appliction_context);
29
30 return 0;
31}
32
nissec490e012015-12-10 06:23:33 -080033AndroidVideoCapturerJni::AndroidVideoCapturerJni(
34 JNIEnv* jni,
35 jobject j_video_capturer,
36 jobject j_surface_texture_helper)
37 : j_video_capturer_(jni, j_video_capturer),
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000038 j_video_capturer_class_(
Magnus Jedvert5e7834e2016-02-12 17:05:29 +010039 jni, FindClass(jni, "org/webrtc/VideoCapturer")),
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000040 j_observer_class_(
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000041 jni,
42 FindClass(jni,
Magnus Jedvert5e7834e2016-02-12 17:05:29 +010043 "org/webrtc/VideoCapturer$NativeObserver")),
perkj88518a22015-12-18 00:37:06 -080044 surface_texture_helper_(new rtc::RefCountedObject<SurfaceTextureHelper>(
45 jni, j_surface_texture_helper)),
Magnus Jedvertc464f502015-08-25 23:22:08 +020046 capturer_(nullptr) {
Alex Glaznev8c054152015-04-20 13:00:49 -070047 LOG(LS_INFO) << "AndroidVideoCapturerJni ctor";
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000048 thread_checker_.DetachFromThread();
49}
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000050
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000051AndroidVideoCapturerJni::~AndroidVideoCapturerJni() {
Magnus Jedvertc464f502015-08-25 23:22:08 +020052 LOG(LS_INFO) << "AndroidVideoCapturerJni dtor";
Magnus Jedvertf706c8a2015-09-23 12:01:28 +020053 jni()->CallVoidMethod(
nissec490e012015-12-10 06:23:33 -080054 *j_video_capturer_,
Magnus Jedvert5e7834e2016-02-12 17:05:29 +010055 GetMethodID(jni(), *j_video_capturer_class_, "dispose", "()V"));
56 CHECK_EXCEPTION(jni()) << "error during VideoCapturer.dispose()";
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000057}
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000058
59void AndroidVideoCapturerJni::Start(int width, int height, int framerate,
60 webrtc::AndroidVideoCapturer* capturer) {
Alex Glaznev8c054152015-04-20 13:00:49 -070061 LOG(LS_INFO) << "AndroidVideoCapturerJni start";
henrikg91d6ede2015-09-17 00:24:34 -070062 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Magnus Jedvertc464f502015-08-25 23:22:08 +020063 {
64 rtc::CritScope cs(&capturer_lock_);
henrikg91d6ede2015-09-17 00:24:34 -070065 RTC_CHECK(capturer_ == nullptr);
66 RTC_CHECK(invoker_.get() == nullptr);
Magnus Jedvertc464f502015-08-25 23:22:08 +020067 capturer_ = capturer;
68 invoker_.reset(new rtc::GuardedAsyncInvoker());
69 }
70 jobject j_frame_observer =
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000071 jni()->NewObject(*j_observer_class_,
Magnus Jedvertc464f502015-08-25 23:22:08 +020072 GetMethodID(jni(), *j_observer_class_, "<init>", "(J)V"),
73 jlongFromPointer(this));
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000074 CHECK_EXCEPTION(jni()) << "error during NewObject";
75
76 jmethodID m = GetMethodID(
77 jni(), *j_video_capturer_class_, "startCapture",
78 "(IIILandroid/content/Context;"
Magnus Jedvert5e7834e2016-02-12 17:05:29 +010079 "Lorg/webrtc/VideoCapturer$CapturerObserver;)V");
nissec490e012015-12-10 06:23:33 -080080 jni()->CallVoidMethod(*j_video_capturer_,
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000081 m, width, height,
82 framerate,
83 application_context_,
Magnus Jedvertc464f502015-08-25 23:22:08 +020084 j_frame_observer);
Magnus Jedvert5e7834e2016-02-12 17:05:29 +010085 CHECK_EXCEPTION(jni()) << "error during VideoCapturer.startCapture";
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000086}
87
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000088void AndroidVideoCapturerJni::Stop() {
Alex Glaznev8c054152015-04-20 13:00:49 -070089 LOG(LS_INFO) << "AndroidVideoCapturerJni stop";
henrikg91d6ede2015-09-17 00:24:34 -070090 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Magnus Jedvertc464f502015-08-25 23:22:08 +020091 {
92 rtc::CritScope cs(&capturer_lock_);
93 // Destroying |invoker_| will cancel all pending calls to |capturer_|.
94 invoker_ = nullptr;
95 capturer_ = nullptr;
96 }
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000097 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000098 "stopCapture", "()V");
nissec490e012015-12-10 06:23:33 -080099 jni()->CallVoidMethod(*j_video_capturer_, m);
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100100 CHECK_EXCEPTION(jni()) << "error during VideoCapturer.stopCapture";
Alex Glaznev8c054152015-04-20 13:00:49 -0700101 LOG(LS_INFO) << "AndroidVideoCapturerJni stop done";
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000102}
103
Magnus Jedvertc464f502015-08-25 23:22:08 +0200104template <typename... Args>
105void AndroidVideoCapturerJni::AsyncCapturerInvoke(
106 const char* method_name,
107 void (webrtc::AndroidVideoCapturer::*method)(Args...),
olka30a5b5e2015-10-20 11:04:56 -0700108 typename Identity<Args>::type... args) {
Magnus Jedvertc464f502015-08-25 23:22:08 +0200109 rtc::CritScope cs(&capturer_lock_);
110 if (!invoker_) {
111 LOG(LS_WARNING) << method_name << "() called for closed capturer.";
Alex Glaznevc4905fb2015-04-20 16:54:42 -0700112 return;
113 }
Magnus Jedvertc464f502015-08-25 23:22:08 +0200114 invoker_->AsyncInvoke<void>(rtc::Bind(method, capturer_, args...));
115}
116
Magnus Jedvert5199c742016-02-18 13:09:54 +0100117std::vector<cricket::VideoFormat>
118AndroidVideoCapturerJni::GetSupportedFormats() {
119 JNIEnv* jni = AttachCurrentThreadIfNeeded();
120 jobject j_list_of_formats = jni->CallObjectMethod(
121 *j_video_capturer_,
122 GetMethodID(jni, *j_video_capturer_class_, "getSupportedFormats",
123 "()Ljava/util/List;"));
124 CHECK_EXCEPTION(jni) << "error during getSupportedFormats";
125
126 // Extract Java List<CaptureFormat> to std::vector<cricket::VideoFormat>.
127 jclass j_list_class = jni->FindClass("java/util/List");
128 jclass j_format_class =
129 jni->FindClass("org/webrtc/CameraEnumerationAndroid$CaptureFormat");
130 const int size = jni->CallIntMethod(
131 j_list_of_formats, GetMethodID(jni, j_list_class, "size", "()I"));
132 jmethodID j_get =
133 GetMethodID(jni, j_list_class, "get", "(I)Ljava/lang/Object;");
134 jfieldID j_width_field = GetFieldID(jni, j_format_class, "width", "I");
135 jfieldID j_height_field = GetFieldID(jni, j_format_class, "height", "I");
136 jfieldID j_max_framerate_field =
137 GetFieldID(jni, j_format_class, "maxFramerate", "I");
138
139 std::vector<cricket::VideoFormat> formats;
140 formats.reserve(size);
141 for (int i = 0; i < size; ++i) {
142 jobject j_format = jni->CallObjectMethod(j_list_of_formats, j_get, i);
143 const int frame_interval = cricket::VideoFormat::FpsToInterval(
144 (GetIntField(jni, j_format, j_max_framerate_field) + 999) / 1000);
145 formats.emplace_back(GetIntField(jni, j_format, j_width_field),
146 GetIntField(jni, j_format, j_height_field),
147 frame_interval, cricket::FOURCC_NV21);
148 }
149 CHECK_EXCEPTION(jni) << "error while extracting formats";
150 return formats;
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000151}
152
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000153void AndroidVideoCapturerJni::OnCapturerStarted(bool success) {
Magnus Jedvertc464f502015-08-25 23:22:08 +0200154 LOG(LS_INFO) << "AndroidVideoCapturerJni capture started: " << success;
155 AsyncCapturerInvoke("OnCapturerStarted",
156 &webrtc::AndroidVideoCapturer::OnCapturerStarted,
157 success);
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000158}
159
perkjac306422015-10-08 15:32:38 +0200160void AndroidVideoCapturerJni::OnMemoryBufferFrame(void* video_frame,
161 int length,
162 int width,
163 int height,
164 int rotation,
165 int64_t timestamp_ns) {
magjedb5815c82015-09-29 01:13:43 -0700166 const uint8_t* y_plane = static_cast<uint8_t*>(video_frame);
perkj88518a22015-12-18 00:37:06 -0800167 const uint8_t* vu_plane = y_plane + width * height;
Magnus Jedvertc464f502015-08-25 23:22:08 +0200168
perkj88518a22015-12-18 00:37:06 -0800169 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer =
170 buffer_pool_.CreateBuffer(width, height);
171 libyuv::NV21ToI420(
172 y_plane, width,
173 vu_plane, width,
174 buffer->MutableData(webrtc::kYPlane), buffer->stride(webrtc::kYPlane),
175 buffer->MutableData(webrtc::kUPlane), buffer->stride(webrtc::kUPlane),
176 buffer->MutableData(webrtc::kVPlane), buffer->stride(webrtc::kVPlane),
177 width, height);
Magnus Jedvertc464f502015-08-25 23:22:08 +0200178 AsyncCapturerInvoke("OnIncomingFrame",
179 &webrtc::AndroidVideoCapturer::OnIncomingFrame,
perkjac306422015-10-08 15:32:38 +0200180 buffer, rotation, timestamp_ns);
181}
182
Per488e75f2015-11-19 10:43:36 +0100183void AndroidVideoCapturerJni::OnTextureFrame(int width,
184 int height,
Per71f5a9a2015-12-11 09:32:37 +0100185 int rotation,
Per488e75f2015-11-19 10:43:36 +0100186 int64_t timestamp_ns,
187 const NativeHandleImpl& handle) {
perkjac306422015-10-08 15:32:38 +0200188 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
perkj88518a22015-12-18 00:37:06 -0800189 surface_texture_helper_->CreateTextureFrame(width, height, handle));
190
perkjac306422015-10-08 15:32:38 +0200191 AsyncCapturerInvoke("OnIncomingFrame",
192 &webrtc::AndroidVideoCapturer::OnIncomingFrame,
Per71f5a9a2015-12-11 09:32:37 +0100193 buffer, rotation, timestamp_ns);
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000194}
195
Åsa Persson2b679252015-06-15 09:53:05 +0200196void AndroidVideoCapturerJni::OnOutputFormatRequest(int width,
197 int height,
198 int fps) {
Magnus Jedvertc464f502015-08-25 23:22:08 +0200199 AsyncCapturerInvoke("OnOutputFormatRequest",
200 &webrtc::AndroidVideoCapturer::OnOutputFormatRequest,
201 width, height, fps);
Åsa Persson2b679252015-06-15 09:53:05 +0200202}
203
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000204JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); }
205
perkj3d06eca2015-10-08 12:53:33 +0200206JOW(void,
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100207 VideoCapturer_00024NativeObserver_nativeOnByteBufferFrameCaptured)
magjedb5815c82015-09-29 01:13:43 -0700208 (JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame, jint length,
perkjac306422015-10-08 15:32:38 +0200209 jint width, jint height, jint rotation, jlong timestamp) {
magjedb5815c82015-09-29 01:13:43 -0700210 jboolean is_copy = true;
211 jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy);
Magnus Jedvertc464f502015-08-25 23:22:08 +0200212 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)
perkjac306422015-10-08 15:32:38 +0200213 ->OnMemoryBufferFrame(bytes, length, width, height, rotation, timestamp);
magjedb5815c82015-09-29 01:13:43 -0700214 jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000215}
216
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100217JOW(void, VideoCapturer_00024NativeObserver_nativeOnTextureFrameCaptured)
perkjac306422015-10-08 15:32:38 +0200218 (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height,
219 jint j_oes_texture_id, jfloatArray j_transform_matrix,
Per71f5a9a2015-12-11 09:32:37 +0100220 jint j_rotation, jlong j_timestamp) {
perkjac306422015-10-08 15:32:38 +0200221 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)
Per71f5a9a2015-12-11 09:32:37 +0100222 ->OnTextureFrame(j_width, j_height, j_rotation, j_timestamp,
Per488e75f2015-11-19 10:43:36 +0100223 NativeHandleImpl(jni, j_oes_texture_id,
224 j_transform_matrix));
perkjac306422015-10-08 15:32:38 +0200225}
226
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100227JOW(void, VideoCapturer_00024NativeObserver_nativeCapturerStarted)
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000228 (JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) {
Alex Glaznev8c054152015-04-20 13:00:49 -0700229 LOG(LS_INFO) << "NativeObserver_nativeCapturerStarted";
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000230 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnCapturerStarted(
231 j_success);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000232}
233
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100234JOW(void, VideoCapturer_00024NativeObserver_nativeOnOutputFormatRequest)
Åsa Persson2b679252015-06-15 09:53:05 +0200235 (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height,
236 jint j_fps) {
237 LOG(LS_INFO) << "NativeObserver_nativeOnOutputFormatRequest";
238 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnOutputFormatRequest(
239 j_width, j_height, j_fps);
240}
241
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000242} // namespace webrtc_jni