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