Home | History | Annotate | Download | only in android
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  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.
      9  */
     10 
     11 #include "webrtc/modules/video_capture/android/video_capture_android.h"
     12 
     13 #include "webrtc/base/common.h"
     14 #include "webrtc/modules/utility/interface/helpers_android.h"
     15 #include "webrtc/modules/video_capture/android/device_info_android.h"
     16 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     17 #include "webrtc/system_wrappers/interface/logcat_trace_context.h"
     18 #include "webrtc/system_wrappers/interface/logging.h"
     19 #include "webrtc/system_wrappers/interface/ref_count.h"
     20 #include "webrtc/system_wrappers/interface/trace.h"
     21 
     22 static JavaVM* g_jvm = NULL;
     23 static jclass g_java_capturer_class = NULL;  // VideoCaptureAndroid.class.
     24 static jobject g_context = NULL;  // Owned android.content.Context.
     25 
     26 namespace webrtc {
     27 
     28 // Called by Java to get the global application context.
     29 jobject JNICALL GetContext(JNIEnv* env, jclass) {
     30   assert(g_context);
     31   return g_context;
     32 }
     33 
     34 // Called by Java when the camera has a new frame to deliver.
     35 void JNICALL ProvideCameraFrame(
     36     JNIEnv* env,
     37     jobject,
     38     jbyteArray javaCameraFrame,
     39     jint length,
     40     jlong timeStamp,
     41     jlong context) {
     42   webrtc::videocapturemodule::VideoCaptureAndroid* captureModule =
     43       reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>(
     44           context);
     45   jbyte* cameraFrame = env->GetByteArrayElements(javaCameraFrame, NULL);
     46   captureModule->OnIncomingFrame(
     47       reinterpret_cast<uint8_t*>(cameraFrame), length, 0);
     48   env->ReleaseByteArrayElements(javaCameraFrame, cameraFrame, JNI_ABORT);
     49 }
     50 
     51 // Called by Java when the device orientation has changed.
     52 void JNICALL OnOrientationChanged(
     53     JNIEnv* env, jobject, jlong context, jint degrees) {
     54   webrtc::videocapturemodule::VideoCaptureAndroid* captureModule =
     55       reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>(
     56           context);
     57   degrees = (360 + degrees) % 360;
     58   assert(degrees >= 0 && degrees < 360);
     59   VideoCaptureRotation rotation =
     60       (degrees <= 45 || degrees > 315) ? kCameraRotate0 :
     61       (degrees > 45 && degrees <= 135) ? kCameraRotate90 :
     62       (degrees > 135 && degrees <= 225) ? kCameraRotate180 :
     63       (degrees > 225 && degrees <= 315) ? kCameraRotate270 :
     64       kCameraRotate0;  // Impossible.
     65   int32_t status =
     66       captureModule->VideoCaptureImpl::SetCaptureRotation(rotation);
     67   RTC_UNUSED(status);
     68   assert(status == 0);
     69 }
     70 
     71 int32_t SetCaptureAndroidVM(JavaVM* javaVM, jobject context) {
     72   if (javaVM) {
     73     assert(!g_jvm);
     74     g_jvm = javaVM;
     75     AttachThreadScoped ats(g_jvm);
     76     g_context = ats.env()->NewGlobalRef(context);
     77 
     78     videocapturemodule::DeviceInfoAndroid::Initialize(ats.env());
     79 
     80     jclass j_capture_class =
     81         ats.env()->FindClass("org/webrtc/videoengine/VideoCaptureAndroid");
     82     assert(j_capture_class);
     83     g_java_capturer_class =
     84         reinterpret_cast<jclass>(ats.env()->NewGlobalRef(j_capture_class));
     85     assert(g_java_capturer_class);
     86 
     87     JNINativeMethod native_methods[] = {
     88         {"GetContext",
     89          "()Landroid/content/Context;",
     90          reinterpret_cast<void*>(&GetContext)},
     91         {"OnOrientationChanged",
     92          "(JI)V",
     93          reinterpret_cast<void*>(&OnOrientationChanged)},
     94         {"ProvideCameraFrame",
     95          "([BIJJ)V",
     96          reinterpret_cast<void*>(&ProvideCameraFrame)}};
     97     if (ats.env()->RegisterNatives(g_java_capturer_class,
     98                                    native_methods, 3) != 0)
     99       assert(false);
    100   } else {
    101     if (g_jvm) {
    102       AttachThreadScoped ats(g_jvm);
    103       ats.env()->UnregisterNatives(g_java_capturer_class);
    104       ats.env()->DeleteGlobalRef(g_java_capturer_class);
    105       g_java_capturer_class = NULL;
    106       ats.env()->DeleteGlobalRef(g_context);
    107       g_context = NULL;
    108       videocapturemodule::DeviceInfoAndroid::DeInitialize();
    109       g_jvm = NULL;
    110     }
    111   }
    112 
    113   return 0;
    114 }
    115 
    116 namespace videocapturemodule {
    117 
    118 VideoCaptureModule* VideoCaptureImpl::Create(
    119     const int32_t id,
    120     const char* deviceUniqueIdUTF8) {
    121   RefCountImpl<videocapturemodule::VideoCaptureAndroid>* implementation =
    122       new RefCountImpl<videocapturemodule::VideoCaptureAndroid>(id);
    123   if (implementation->Init(id, deviceUniqueIdUTF8) != 0) {
    124     delete implementation;
    125     implementation = NULL;
    126   }
    127   return implementation;
    128 }
    129 
    130 int32_t VideoCaptureAndroid::OnIncomingFrame(uint8_t* videoFrame,
    131                                              int32_t videoFrameLength,
    132                                              int64_t captureTime) {
    133   if (!_captureStarted)
    134     return 0;
    135   return IncomingFrame(
    136       videoFrame, videoFrameLength, _captureCapability, captureTime);
    137 }
    138 
    139 VideoCaptureAndroid::VideoCaptureAndroid(const int32_t id)
    140     : VideoCaptureImpl(id),
    141       _deviceInfo(id),
    142       _jCapturer(NULL),
    143       _captureStarted(false) {
    144 }
    145 
    146 int32_t VideoCaptureAndroid::Init(const int32_t id,
    147                                   const char* deviceUniqueIdUTF8) {
    148   const int nameLength = strlen(deviceUniqueIdUTF8);
    149   if (nameLength >= kVideoCaptureUniqueNameLength)
    150     return -1;
    151 
    152   // Store the device name
    153   LOG(LS_INFO) << "VideoCaptureAndroid::Init: " << deviceUniqueIdUTF8;
    154   size_t camera_id = 0;
    155   if (!_deviceInfo.FindCameraIndex(deviceUniqueIdUTF8, &camera_id))
    156     return -1;
    157   _deviceUniqueId = new char[nameLength + 1];
    158   memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1);
    159 
    160   AttachThreadScoped ats(g_jvm);
    161   JNIEnv* env = ats.env();
    162   jmethodID ctor = env->GetMethodID(g_java_capturer_class, "<init>", "(IJ)V");
    163   assert(ctor);
    164   jlong j_this = reinterpret_cast<intptr_t>(this);
    165   _jCapturer = env->NewGlobalRef(
    166       env->NewObject(g_java_capturer_class, ctor, camera_id, j_this));
    167   assert(_jCapturer);
    168   return 0;
    169 }
    170 
    171 VideoCaptureAndroid::~VideoCaptureAndroid() {
    172   // Ensure Java camera is released even if our caller didn't explicitly Stop.
    173   if (_captureStarted)
    174     StopCapture();
    175   AttachThreadScoped ats(g_jvm);
    176   ats.env()->DeleteGlobalRef(_jCapturer);
    177 }
    178 
    179 int32_t VideoCaptureAndroid::StartCapture(
    180     const VideoCaptureCapability& capability) {
    181   CriticalSectionScoped cs(&_apiCs);
    182   AttachThreadScoped ats(g_jvm);
    183   JNIEnv* env = ats.env();
    184 
    185   if (_deviceInfo.GetBestMatchedCapability(
    186           _deviceUniqueId, capability, _captureCapability) < 0) {
    187     WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
    188                  "%s: GetBestMatchedCapability failed: %dx%d",
    189                  __FUNCTION__, capability.width, capability.height);
    190     return -1;
    191   }
    192 
    193   _captureDelay = _captureCapability.expectedCaptureDelay;
    194 
    195   jmethodID j_start =
    196       env->GetMethodID(g_java_capturer_class, "startCapture", "(IIII)Z");
    197   assert(j_start);
    198   int min_mfps = 0;
    199   int max_mfps = 0;
    200   _deviceInfo.GetMFpsRange(_deviceUniqueId, _captureCapability.maxFPS,
    201                            &min_mfps, &max_mfps);
    202   bool started = env->CallBooleanMethod(_jCapturer, j_start,
    203                                         _captureCapability.width,
    204                                         _captureCapability.height,
    205                                         min_mfps, max_mfps);
    206   if (started) {
    207     _requestedCapability = capability;
    208     _captureStarted = true;
    209   }
    210   return started ? 0 : -1;
    211 }
    212 
    213 int32_t VideoCaptureAndroid::StopCapture() {
    214   _apiCs.Enter();
    215   AttachThreadScoped ats(g_jvm);
    216   JNIEnv* env = ats.env();
    217 
    218   memset(&_requestedCapability, 0, sizeof(_requestedCapability));
    219   memset(&_captureCapability, 0, sizeof(_captureCapability));
    220   _captureStarted = false;
    221   // Exit critical section to avoid blocking camera thread inside
    222   // onIncomingFrame() call.
    223   _apiCs.Leave();
    224 
    225   jmethodID j_stop =
    226       env->GetMethodID(g_java_capturer_class, "stopCapture", "()Z");
    227   return env->CallBooleanMethod(_jCapturer, j_stop) ? 0 : -1;
    228 }
    229 
    230 bool VideoCaptureAndroid::CaptureStarted() {
    231   CriticalSectionScoped cs(&_apiCs);
    232   return _captureStarted;
    233 }
    234 
    235 int32_t VideoCaptureAndroid::CaptureSettings(
    236     VideoCaptureCapability& settings) {
    237   CriticalSectionScoped cs(&_apiCs);
    238   settings = _requestedCapability;
    239   return 0;
    240 }
    241 
    242 int32_t VideoCaptureAndroid::SetCaptureRotation(
    243     VideoCaptureRotation rotation) {
    244   int32_t status = VideoCaptureImpl::SetCaptureRotation(rotation);
    245   if (status != 0)
    246     return status;
    247 
    248   AttachThreadScoped ats(g_jvm);
    249   JNIEnv* env = ats.env();
    250 
    251   jmethodID j_spr =
    252       env->GetMethodID(g_java_capturer_class, "setPreviewRotation", "(I)V");
    253   assert(j_spr);
    254   int rotation_degrees;
    255   if (RotationInDegrees(rotation, &rotation_degrees) != 0) {
    256     assert(false);
    257   }
    258   env->CallVoidMethod(_jCapturer, j_spr, rotation_degrees);
    259   return 0;
    260 }
    261 
    262 }  // namespace videocapturemodule
    263 }  // namespace webrtc
    264