2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-02-20 08:45:02 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-07-12 10:03:52 +00:00
|
|
|
#include "webrtc/modules/video_capture/android/video_capture_android.h"
|
2011-09-12 08:53:36 +00:00
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
#include "webrtc/modules/utility/interface/helpers_android.h"
|
|
|
|
|
#include "webrtc/modules/video_capture/android/device_info_android.h"
|
2013-07-12 10:03:52 +00:00
|
|
|
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
2013-10-03 18:23:13 +00:00
|
|
|
#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
|
2013-07-12 10:03:52 +00:00
|
|
|
#include "webrtc/system_wrappers/interface/ref_count.h"
|
|
|
|
|
#include "webrtc/system_wrappers/interface/trace.h"
|
2012-04-04 17:15:42 +00:00
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
static JavaVM* g_jvm = NULL;
|
|
|
|
|
static jclass g_java_capturer_class = NULL; // VideoCaptureAndroid.class.
|
|
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
|
|
|
|
// Called by Java when the camera has a new frame to deliver.
|
|
|
|
|
void JNICALL ProvideCameraFrame(
|
|
|
|
|
JNIEnv* env,
|
|
|
|
|
jobject,
|
|
|
|
|
jbyteArray javaCameraFrame,
|
|
|
|
|
jint length,
|
|
|
|
|
jlong context) {
|
|
|
|
|
webrtc::videocapturemodule::VideoCaptureAndroid* captureModule =
|
|
|
|
|
reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>(
|
|
|
|
|
context);
|
|
|
|
|
jbyte* cameraFrame = env->GetByteArrayElements(javaCameraFrame, NULL);
|
|
|
|
|
captureModule->OnIncomingFrame(
|
|
|
|
|
reinterpret_cast<uint8_t*>(cameraFrame), length, 0);
|
|
|
|
|
env->ReleaseByteArrayElements(javaCameraFrame, cameraFrame, JNI_ABORT);
|
2012-07-13 22:00:43 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
int32_t SetCaptureAndroidVM(JavaVM* javaVM) {
|
|
|
|
|
g_jvm = javaVM;
|
|
|
|
|
AttachThreadScoped ats(g_jvm);
|
|
|
|
|
|
|
|
|
|
videocapturemodule::DeviceInfoAndroid::Initialize(ats.env());
|
|
|
|
|
|
|
|
|
|
jclass j_capture_class =
|
|
|
|
|
ats.env()->FindClass("org/webrtc/videoengine/VideoCaptureAndroid");
|
|
|
|
|
assert(j_capture_class);
|
|
|
|
|
g_java_capturer_class =
|
|
|
|
|
reinterpret_cast<jclass>(ats.env()->NewGlobalRef(j_capture_class));
|
|
|
|
|
assert(g_java_capturer_class);
|
|
|
|
|
|
|
|
|
|
JNINativeMethod native_method = {
|
|
|
|
|
"ProvideCameraFrame", "([BIJ)V",
|
|
|
|
|
reinterpret_cast<void*>(&ProvideCameraFrame)
|
|
|
|
|
};
|
|
|
|
|
if (ats.env()->RegisterNatives(g_java_capturer_class, &native_method, 1) != 0)
|
|
|
|
|
assert(false);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace videocapturemodule {
|
2012-04-04 17:15:42 +00:00
|
|
|
|
2011-09-12 08:53:36 +00:00
|
|
|
VideoCaptureModule* VideoCaptureImpl::Create(
|
2013-04-10 08:23:13 +00:00
|
|
|
const int32_t id,
|
2012-04-04 17:15:42 +00:00
|
|
|
const char* deviceUniqueIdUTF8) {
|
|
|
|
|
RefCountImpl<videocapturemodule::VideoCaptureAndroid>* implementation =
|
|
|
|
|
new RefCountImpl<videocapturemodule::VideoCaptureAndroid>(id);
|
2013-10-03 18:23:13 +00:00
|
|
|
if (implementation->Init(id, deviceUniqueIdUTF8) != 0) {
|
2012-04-04 17:15:42 +00:00
|
|
|
delete implementation;
|
|
|
|
|
implementation = NULL;
|
|
|
|
|
}
|
|
|
|
|
return implementation;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
int32_t VideoCaptureAndroid::OnIncomingFrame(uint8_t* videoFrame,
|
|
|
|
|
int32_t videoFrameLength,
|
|
|
|
|
int64_t captureTime) {
|
|
|
|
|
return IncomingFrame(
|
|
|
|
|
videoFrame, videoFrameLength, _captureCapability, captureTime);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-10 08:23:13 +00:00
|
|
|
VideoCaptureAndroid::VideoCaptureAndroid(const int32_t id)
|
2013-10-03 18:23:13 +00:00
|
|
|
: VideoCaptureImpl(id),
|
|
|
|
|
_deviceInfo(id),
|
|
|
|
|
_jCapturer(NULL),
|
2012-04-04 17:15:42 +00:00
|
|
|
_captureStarted(false) {
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-04-04 17:15:42 +00:00
|
|
|
|
2013-04-10 08:23:13 +00:00
|
|
|
int32_t VideoCaptureAndroid::Init(const int32_t id,
|
|
|
|
|
const char* deviceUniqueIdUTF8) {
|
2012-04-04 17:15:42 +00:00
|
|
|
const int nameLength = strlen(deviceUniqueIdUTF8);
|
2013-10-03 18:23:13 +00:00
|
|
|
if (nameLength >= kVideoCaptureUniqueNameLength)
|
2012-04-04 17:15:42 +00:00
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-04-04 17:15:42 +00:00
|
|
|
// Store the device name
|
|
|
|
|
_deviceUniqueId = new char[nameLength + 1];
|
|
|
|
|
memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
AttachThreadScoped ats(g_jvm);
|
|
|
|
|
JNIEnv* env = ats.env();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
jmethodID ctor = env->GetMethodID(g_java_capturer_class, "<init>", "(IJ)V");
|
|
|
|
|
assert(ctor);
|
|
|
|
|
jlong j_this = reinterpret_cast<intptr_t>(this);
|
|
|
|
|
size_t camera_id = 0;
|
|
|
|
|
if (!_deviceInfo.FindCameraIndex(deviceUniqueIdUTF8, &camera_id))
|
2012-04-04 17:15:42 +00:00
|
|
|
return -1;
|
2013-10-03 18:23:13 +00:00
|
|
|
_jCapturer = env->NewGlobalRef(
|
|
|
|
|
env->NewObject(g_java_capturer_class, ctor, camera_id, j_this));
|
|
|
|
|
assert(_jCapturer);
|
2012-04-04 17:15:42 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-04-04 17:15:42 +00:00
|
|
|
VideoCaptureAndroid::~VideoCaptureAndroid() {
|
2013-10-03 18:23:13 +00:00
|
|
|
// Ensure Java camera is released even if our caller didn't explicitly Stop.
|
|
|
|
|
if (_captureStarted)
|
|
|
|
|
StopCapture();
|
|
|
|
|
AttachThreadScoped ats(g_jvm);
|
|
|
|
|
ats.env()->DeleteGlobalRef(_jCapturer);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-10 08:23:13 +00:00
|
|
|
int32_t VideoCaptureAndroid::StartCapture(
|
2012-04-04 17:15:42 +00:00
|
|
|
const VideoCaptureCapability& capability) {
|
|
|
|
|
CriticalSectionScoped cs(&_apiCs);
|
2013-10-03 18:23:13 +00:00
|
|
|
AttachThreadScoped ats(g_jvm);
|
|
|
|
|
JNIEnv* env = ats.env();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
if (_deviceInfo.GetBestMatchedCapability(
|
|
|
|
|
_deviceUniqueId, capability, _captureCapability) < 0) {
|
2012-04-04 17:15:42 +00:00
|
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
|
2013-10-03 18:23:13 +00:00
|
|
|
"%s: GetBestMatchedCapability failed: %dx%d",
|
2012-04-04 17:15:42 +00:00
|
|
|
__FUNCTION__, capability.width, capability.height);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
_captureDelay = _captureCapability.expectedCaptureDelay;
|
2012-04-04 17:15:42 +00:00
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
jmethodID j_start =
|
|
|
|
|
env->GetMethodID(g_java_capturer_class, "startCapture", "(IIII)Z");
|
|
|
|
|
assert(j_start);
|
|
|
|
|
int min_mfps = 0;
|
|
|
|
|
int max_mfps = 0;
|
|
|
|
|
_deviceInfo.GetFpsRange(_deviceUniqueId, &min_mfps, &max_mfps);
|
|
|
|
|
bool started = env->CallBooleanMethod(_jCapturer, j_start,
|
|
|
|
|
_captureCapability.width,
|
|
|
|
|
_captureCapability.height,
|
|
|
|
|
min_mfps, max_mfps);
|
|
|
|
|
if (started) {
|
2012-04-04 17:15:42 +00:00
|
|
|
_requestedCapability = capability;
|
|
|
|
|
_captureStarted = true;
|
|
|
|
|
}
|
2013-10-03 18:23:13 +00:00
|
|
|
return started ? 0 : -1;
|
2012-04-04 17:15:42 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-10 08:23:13 +00:00
|
|
|
int32_t VideoCaptureAndroid::StopCapture() {
|
2012-04-04 17:15:42 +00:00
|
|
|
CriticalSectionScoped cs(&_apiCs);
|
2013-10-03 18:23:13 +00:00
|
|
|
AttachThreadScoped ats(g_jvm);
|
|
|
|
|
JNIEnv* env = ats.env();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-04-04 17:15:42 +00:00
|
|
|
memset(&_requestedCapability, 0, sizeof(_requestedCapability));
|
2013-10-03 18:23:13 +00:00
|
|
|
memset(&_captureCapability, 0, sizeof(_captureCapability));
|
2012-04-04 17:15:42 +00:00
|
|
|
_captureStarted = false;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
jmethodID j_stop =
|
|
|
|
|
env->GetMethodID(g_java_capturer_class, "stopCapture", "()Z");
|
|
|
|
|
return env->CallBooleanMethod(_jCapturer, j_stop) ? 0 : -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-04 17:15:42 +00:00
|
|
|
bool VideoCaptureAndroid::CaptureStarted() {
|
|
|
|
|
CriticalSectionScoped cs(&_apiCs);
|
|
|
|
|
return _captureStarted;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-04-04 17:15:42 +00:00
|
|
|
|
2013-04-10 08:23:13 +00:00
|
|
|
int32_t VideoCaptureAndroid::CaptureSettings(
|
2012-04-04 17:15:42 +00:00
|
|
|
VideoCaptureCapability& settings) {
|
|
|
|
|
CriticalSectionScoped cs(&_apiCs);
|
|
|
|
|
settings = _requestedCapability;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-10 08:23:13 +00:00
|
|
|
int32_t VideoCaptureAndroid::SetCaptureRotation(
|
2012-04-04 17:15:42 +00:00
|
|
|
VideoCaptureRotation rotation) {
|
|
|
|
|
CriticalSectionScoped cs(&_apiCs);
|
2013-10-03 18:23:13 +00:00
|
|
|
if (VideoCaptureImpl::SetCaptureRotation(rotation) != 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
AttachThreadScoped ats(g_jvm);
|
|
|
|
|
JNIEnv* env = ats.env();
|
2012-04-04 17:15:42 +00:00
|
|
|
|
2013-10-03 18:23:13 +00:00
|
|
|
jmethodID j_spr =
|
|
|
|
|
env->GetMethodID(g_java_capturer_class, "setPreviewRotation", "(I)V");
|
|
|
|
|
assert(j_spr);
|
|
|
|
|
int rotation_degrees;
|
|
|
|
|
if (RotationInDegrees(rotation, &rotation_degrees) != 0) {
|
|
|
|
|
assert(false);
|
2012-04-04 17:15:42 +00:00
|
|
|
}
|
2013-10-03 18:23:13 +00:00
|
|
|
env->CallVoidMethod(_jCapturer, j_spr, rotation_degrees);
|
2012-04-04 17:15:42 +00:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-04-04 17:15:42 +00:00
|
|
|
|
|
|
|
|
} // namespace videocapturemodule
|
|
|
|
|
} // namespace webrtc
|