blob: 3630ac4a0a13745d2c309463d3d1c1846a64decf [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,
magjed0dc23162016-03-14 03:59:38 -070036 jobject j_egl_context)
nissec490e012015-12-10 06:23:33 -080037 : 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>(
magjed0dc23162016-03-14 03:59:38 -070045 jni, j_egl_context)),
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()";
magjed0dc23162016-03-14 03:59:38 -070057 jni()->CallVoidMethod(
58 surface_texture_helper_->GetJavaSurfaceTextureHelper(),
59 GetMethodID(jni(), FindClass(jni(), "org/webrtc/SurfaceTextureHelper"),
60 "dispose", "()V"));
61 CHECK_EXCEPTION(jni()) << "error during SurfaceTextureHelper.dispose()";
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000062}
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000063
64void AndroidVideoCapturerJni::Start(int width, int height, int framerate,
65 webrtc::AndroidVideoCapturer* capturer) {
Alex Glaznev8c054152015-04-20 13:00:49 -070066 LOG(LS_INFO) << "AndroidVideoCapturerJni start";
henrikg91d6ede2015-09-17 00:24:34 -070067 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Magnus Jedvertc464f502015-08-25 23:22:08 +020068 {
69 rtc::CritScope cs(&capturer_lock_);
henrikg91d6ede2015-09-17 00:24:34 -070070 RTC_CHECK(capturer_ == nullptr);
71 RTC_CHECK(invoker_.get() == nullptr);
Magnus Jedvertc464f502015-08-25 23:22:08 +020072 capturer_ = capturer;
73 invoker_.reset(new rtc::GuardedAsyncInvoker());
74 }
75 jobject j_frame_observer =
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000076 jni()->NewObject(*j_observer_class_,
Magnus Jedvertc464f502015-08-25 23:22:08 +020077 GetMethodID(jni(), *j_observer_class_, "<init>", "(J)V"),
78 jlongFromPointer(this));
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000079 CHECK_EXCEPTION(jni()) << "error during NewObject";
80
81 jmethodID m = GetMethodID(
82 jni(), *j_video_capturer_class_, "startCapture",
magjed0dc23162016-03-14 03:59:38 -070083 "(IIILorg/webrtc/SurfaceTextureHelper;Landroid/content/Context;"
Magnus Jedvert5e7834e2016-02-12 17:05:29 +010084 "Lorg/webrtc/VideoCapturer$CapturerObserver;)V");
nissec490e012015-12-10 06:23:33 -080085 jni()->CallVoidMethod(*j_video_capturer_,
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000086 m, width, height,
87 framerate,
magjed0dc23162016-03-14 03:59:38 -070088 surface_texture_helper_->GetJavaSurfaceTextureHelper(),
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000089 application_context_,
Magnus Jedvertc464f502015-08-25 23:22:08 +020090 j_frame_observer);
Magnus Jedvert5e7834e2016-02-12 17:05:29 +010091 CHECK_EXCEPTION(jni()) << "error during VideoCapturer.startCapture";
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000092}
93
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000094void AndroidVideoCapturerJni::Stop() {
Alex Glaznev8c054152015-04-20 13:00:49 -070095 LOG(LS_INFO) << "AndroidVideoCapturerJni stop";
henrikg91d6ede2015-09-17 00:24:34 -070096 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Magnus Jedvertc464f502015-08-25 23:22:08 +020097 {
98 rtc::CritScope cs(&capturer_lock_);
99 // Destroying |invoker_| will cancel all pending calls to |capturer_|.
100 invoker_ = nullptr;
101 capturer_ = nullptr;
102 }
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000103 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000104 "stopCapture", "()V");
nissec490e012015-12-10 06:23:33 -0800105 jni()->CallVoidMethod(*j_video_capturer_, m);
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100106 CHECK_EXCEPTION(jni()) << "error during VideoCapturer.stopCapture";
Alex Glaznev8c054152015-04-20 13:00:49 -0700107 LOG(LS_INFO) << "AndroidVideoCapturerJni stop done";
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000108}
109
Magnus Jedvertc464f502015-08-25 23:22:08 +0200110template <typename... Args>
111void AndroidVideoCapturerJni::AsyncCapturerInvoke(
112 const char* method_name,
113 void (webrtc::AndroidVideoCapturer::*method)(Args...),
olka30a5b5e2015-10-20 11:04:56 -0700114 typename Identity<Args>::type... args) {
Magnus Jedvertc464f502015-08-25 23:22:08 +0200115 rtc::CritScope cs(&capturer_lock_);
116 if (!invoker_) {
117 LOG(LS_WARNING) << method_name << "() called for closed capturer.";
Alex Glaznevc4905fb2015-04-20 16:54:42 -0700118 return;
119 }
Magnus Jedvertc464f502015-08-25 23:22:08 +0200120 invoker_->AsyncInvoke<void>(rtc::Bind(method, capturer_, args...));
121}
122
Magnus Jedvert5199c742016-02-18 13:09:54 +0100123std::vector<cricket::VideoFormat>
124AndroidVideoCapturerJni::GetSupportedFormats() {
125 JNIEnv* jni = AttachCurrentThreadIfNeeded();
126 jobject j_list_of_formats = jni->CallObjectMethod(
127 *j_video_capturer_,
128 GetMethodID(jni, *j_video_capturer_class_, "getSupportedFormats",
129 "()Ljava/util/List;"));
130 CHECK_EXCEPTION(jni) << "error during getSupportedFormats";
131
132 // Extract Java List<CaptureFormat> to std::vector<cricket::VideoFormat>.
133 jclass j_list_class = jni->FindClass("java/util/List");
134 jclass j_format_class =
135 jni->FindClass("org/webrtc/CameraEnumerationAndroid$CaptureFormat");
136 const int size = jni->CallIntMethod(
137 j_list_of_formats, GetMethodID(jni, j_list_class, "size", "()I"));
138 jmethodID j_get =
139 GetMethodID(jni, j_list_class, "get", "(I)Ljava/lang/Object;");
140 jfieldID j_width_field = GetFieldID(jni, j_format_class, "width", "I");
141 jfieldID j_height_field = GetFieldID(jni, j_format_class, "height", "I");
142 jfieldID j_max_framerate_field =
143 GetFieldID(jni, j_format_class, "maxFramerate", "I");
144
145 std::vector<cricket::VideoFormat> formats;
146 formats.reserve(size);
147 for (int i = 0; i < size; ++i) {
148 jobject j_format = jni->CallObjectMethod(j_list_of_formats, j_get, i);
149 const int frame_interval = cricket::VideoFormat::FpsToInterval(
150 (GetIntField(jni, j_format, j_max_framerate_field) + 999) / 1000);
151 formats.emplace_back(GetIntField(jni, j_format, j_width_field),
152 GetIntField(jni, j_format, j_height_field),
153 frame_interval, cricket::FOURCC_NV21);
154 }
155 CHECK_EXCEPTION(jni) << "error while extracting formats";
156 return formats;
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000157}
158
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000159void AndroidVideoCapturerJni::OnCapturerStarted(bool success) {
Magnus Jedvertc464f502015-08-25 23:22:08 +0200160 LOG(LS_INFO) << "AndroidVideoCapturerJni capture started: " << success;
161 AsyncCapturerInvoke("OnCapturerStarted",
162 &webrtc::AndroidVideoCapturer::OnCapturerStarted,
163 success);
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000164}
165
perkjac306422015-10-08 15:32:38 +0200166void AndroidVideoCapturerJni::OnMemoryBufferFrame(void* video_frame,
167 int length,
168 int width,
169 int height,
170 int rotation,
171 int64_t timestamp_ns) {
magjedb5815c82015-09-29 01:13:43 -0700172 const uint8_t* y_plane = static_cast<uint8_t*>(video_frame);
perkj88518a22015-12-18 00:37:06 -0800173 const uint8_t* vu_plane = y_plane + width * height;
Magnus Jedvertc464f502015-08-25 23:22:08 +0200174
perkj88518a22015-12-18 00:37:06 -0800175 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer =
176 buffer_pool_.CreateBuffer(width, height);
177 libyuv::NV21ToI420(
178 y_plane, width,
179 vu_plane, width,
180 buffer->MutableData(webrtc::kYPlane), buffer->stride(webrtc::kYPlane),
181 buffer->MutableData(webrtc::kUPlane), buffer->stride(webrtc::kUPlane),
182 buffer->MutableData(webrtc::kVPlane), buffer->stride(webrtc::kVPlane),
183 width, height);
Magnus Jedvertc464f502015-08-25 23:22:08 +0200184 AsyncCapturerInvoke("OnIncomingFrame",
185 &webrtc::AndroidVideoCapturer::OnIncomingFrame,
perkjac306422015-10-08 15:32:38 +0200186 buffer, rotation, timestamp_ns);
187}
188
Per488e75f2015-11-19 10:43:36 +0100189void AndroidVideoCapturerJni::OnTextureFrame(int width,
190 int height,
Per71f5a9a2015-12-11 09:32:37 +0100191 int rotation,
Per488e75f2015-11-19 10:43:36 +0100192 int64_t timestamp_ns,
193 const NativeHandleImpl& handle) {
perkjac306422015-10-08 15:32:38 +0200194 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
perkj88518a22015-12-18 00:37:06 -0800195 surface_texture_helper_->CreateTextureFrame(width, height, handle));
196
perkjac306422015-10-08 15:32:38 +0200197 AsyncCapturerInvoke("OnIncomingFrame",
198 &webrtc::AndroidVideoCapturer::OnIncomingFrame,
Per71f5a9a2015-12-11 09:32:37 +0100199 buffer, rotation, timestamp_ns);
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000200}
201
Åsa Persson2b679252015-06-15 09:53:05 +0200202void AndroidVideoCapturerJni::OnOutputFormatRequest(int width,
203 int height,
204 int fps) {
Magnus Jedvertc464f502015-08-25 23:22:08 +0200205 AsyncCapturerInvoke("OnOutputFormatRequest",
206 &webrtc::AndroidVideoCapturer::OnOutputFormatRequest,
207 width, height, fps);
Åsa Persson2b679252015-06-15 09:53:05 +0200208}
209
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000210JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); }
211
perkj3d06eca2015-10-08 12:53:33 +0200212JOW(void,
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100213 VideoCapturer_00024NativeObserver_nativeOnByteBufferFrameCaptured)
magjedb5815c82015-09-29 01:13:43 -0700214 (JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame, jint length,
perkjac306422015-10-08 15:32:38 +0200215 jint width, jint height, jint rotation, jlong timestamp) {
magjedb5815c82015-09-29 01:13:43 -0700216 jboolean is_copy = true;
217 jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy);
Magnus Jedvertc464f502015-08-25 23:22:08 +0200218 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)
perkjac306422015-10-08 15:32:38 +0200219 ->OnMemoryBufferFrame(bytes, length, width, height, rotation, timestamp);
magjedb5815c82015-09-29 01:13:43 -0700220 jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000221}
222
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100223JOW(void, VideoCapturer_00024NativeObserver_nativeOnTextureFrameCaptured)
perkjac306422015-10-08 15:32:38 +0200224 (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height,
225 jint j_oes_texture_id, jfloatArray j_transform_matrix,
Per71f5a9a2015-12-11 09:32:37 +0100226 jint j_rotation, jlong j_timestamp) {
perkjac306422015-10-08 15:32:38 +0200227 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)
Per71f5a9a2015-12-11 09:32:37 +0100228 ->OnTextureFrame(j_width, j_height, j_rotation, j_timestamp,
Per488e75f2015-11-19 10:43:36 +0100229 NativeHandleImpl(jni, j_oes_texture_id,
230 j_transform_matrix));
perkjac306422015-10-08 15:32:38 +0200231}
232
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100233JOW(void, VideoCapturer_00024NativeObserver_nativeCapturerStarted)
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000234 (JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) {
Alex Glaznev8c054152015-04-20 13:00:49 -0700235 LOG(LS_INFO) << "NativeObserver_nativeCapturerStarted";
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000236 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnCapturerStarted(
237 j_success);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000238}
239
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100240JOW(void, VideoCapturer_00024NativeObserver_nativeOnOutputFormatRequest)
Åsa Persson2b679252015-06-15 09:53:05 +0200241 (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height,
242 jint j_fps) {
243 LOG(LS_INFO) << "NativeObserver_nativeOnOutputFormatRequest";
244 reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnOutputFormatRequest(
245 j_width, j_height, j_fps);
246}
247
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000248} // namespace webrtc_jni