tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

video_capture_android.cc (9094B)


      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 "video_capture_android.h"
     12 
     13 #include "AndroidBridge.h"
     14 #include "device_info_android.h"
     15 #include "modules/utility/include/helpers_android.h"
     16 #include "rtc_base/logging.h"
     17 #include "rtc_base/ref_counted_object.h"
     18 #include "rtc_base/time_utils.h"
     19 
     20 static JavaVM* g_jvm_capture = NULL;
     21 static jclass g_java_capturer_class = NULL;  // VideoCaptureAndroid.class.
     22 
     23 namespace webrtc {
     24 
     25 jobject JniCommon_allocateNativeByteBuffer(JNIEnv* env, jclass, jint size) {
     26  void* new_data = ::operator new(size);
     27  jobject byte_buffer = env->NewDirectByteBuffer(new_data, size);
     28  return byte_buffer;
     29 }
     30 
     31 void JniCommon_freeNativeByteBuffer(JNIEnv* env, jclass, jobject byte_buffer) {
     32  void* data = env->GetDirectBufferAddress(byte_buffer);
     33  ::operator delete(data);
     34 }
     35 
     36 // Called by Java when the camera has a new frame to deliver.
     37 void JNICALL ProvideCameraFrame(JNIEnv* env, jobject, jint width, jint height,
     38                                jobject javaDataY, jint strideY,
     39                                jobject javaDataU, jint strideU,
     40                                jobject javaDataV, jint strideV, jint rotation,
     41                                jlong timeStamp, jlong context) {
     42  if (!context) {
     43    return;
     44  }
     45 
     46  webrtc::videocapturemodule::VideoCaptureAndroid* captureModule =
     47      reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>(
     48          context);
     49  uint8_t* dataY =
     50      reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(javaDataY));
     51  uint8_t* dataU =
     52      reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(javaDataU));
     53  uint8_t* dataV =
     54      reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(javaDataV));
     55 
     56  webrtc::scoped_refptr<I420Buffer> i420Buffer = I420Buffer::Copy(
     57      width, height, dataY, strideY, dataU, strideU, dataV, strideV);
     58 
     59  captureModule->OnIncomingFrame(i420Buffer, rotation, timeStamp);
     60 }
     61 
     62 int32_t SetCaptureAndroidVM(JavaVM* javaVM) {
     63  if (g_java_capturer_class) {
     64    return 0;
     65  }
     66 
     67  if (javaVM) {
     68    assert(!g_jvm_capture);
     69    g_jvm_capture = javaVM;
     70    AttachThreadScoped ats(g_jvm_capture);
     71 
     72    videocapturemodule::DeviceInfoAndroid::Initialize(g_jvm_capture);
     73 
     74    {
     75      jclass clsRef = mozilla::jni::GetClassRef(
     76          ats.env(), "org/webrtc/videoengine/VideoCaptureAndroid");
     77      g_java_capturer_class =
     78          static_cast<jclass>(ats.env()->NewGlobalRef(clsRef));
     79      ats.env()->DeleteLocalRef(clsRef);
     80      assert(g_java_capturer_class);
     81 
     82      JNINativeMethod native_methods[] = {
     83          {"ProvideCameraFrame",
     84           "(IILjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;ILjava/nio/"
     85           "ByteBuffer;IIJJ)V",
     86           reinterpret_cast<void*>(&ProvideCameraFrame)}};
     87      if (ats.env()->RegisterNatives(g_java_capturer_class, native_methods,
     88                                     1) != 0)
     89        assert(false);
     90    }
     91 
     92    {
     93      jclass clsRef =
     94          mozilla::jni::GetClassRef(ats.env(), "org/webrtc/JniCommon");
     95 
     96      JNINativeMethod native_methods[] = {
     97          {"nativeAllocateByteBuffer", "(I)Ljava/nio/ByteBuffer;",
     98           reinterpret_cast<void*>(&JniCommon_allocateNativeByteBuffer)},
     99          {"nativeFreeByteBuffer", "(Ljava/nio/ByteBuffer;)V",
    100           reinterpret_cast<void*>(&JniCommon_freeNativeByteBuffer)}};
    101      if (ats.env()->RegisterNatives(clsRef, native_methods, 2) != 0)
    102        assert(false);
    103    }
    104  } else {
    105    if (g_jvm_capture) {
    106      AttachThreadScoped ats(g_jvm_capture);
    107      ats.env()->UnregisterNatives(g_java_capturer_class);
    108      ats.env()->DeleteGlobalRef(g_java_capturer_class);
    109      g_java_capturer_class = NULL;
    110      videocapturemodule::DeviceInfoAndroid::DeInitialize();
    111      g_jvm_capture = NULL;
    112    }
    113  }
    114 
    115  return 0;
    116 }
    117 
    118 namespace videocapturemodule {
    119 
    120 webrtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(
    121    Clock* clock, const char* deviceUniqueIdUTF8) {
    122  webrtc::scoped_refptr<VideoCaptureAndroid> implementation(
    123      new webrtc::RefCountedObject<VideoCaptureAndroid>(clock));
    124  if (implementation->Init(deviceUniqueIdUTF8) != 0) {
    125    implementation = nullptr;
    126  }
    127  return implementation;
    128 }
    129 
    130 void VideoCaptureAndroid::OnIncomingFrame(
    131    webrtc::scoped_refptr<I420Buffer> buffer, int32_t degrees,
    132    int64_t captureTime) {
    133  MutexLock lock(&api_lock_);
    134 
    135  VideoRotation rotation =
    136      (degrees <= 45 || degrees > 315)    ? kVideoRotation_0
    137      : (degrees > 45 && degrees <= 135)  ? kVideoRotation_90
    138      : (degrees > 135 && degrees <= 225) ? kVideoRotation_180
    139      : (degrees > 225 && degrees <= 315) ? kVideoRotation_270
    140                                          : kVideoRotation_0;  // Impossible.
    141 
    142  // Historically, we have ignored captureTime. Why?
    143  VideoFrame captureFrame(I420Buffer::Rotate(*buffer, rotation), 0,
    144                          webrtc::TimeMillis(), rotation);
    145 
    146  DeliverCapturedFrame(captureFrame);
    147 }
    148 
    149 VideoCaptureAndroid::VideoCaptureAndroid(Clock* clock)
    150    : VideoCaptureImpl(clock),
    151      _deviceInfo(),
    152      _jCapturer(NULL),
    153      _captureStarted(false) {}
    154 
    155 int32_t VideoCaptureAndroid::Init(const char* deviceUniqueIdUTF8) {
    156  const int nameLength = strlen(deviceUniqueIdUTF8);
    157  if (nameLength >= kVideoCaptureUniqueNameLength) return -1;
    158 
    159  RTC_DCHECK_RUN_ON(&api_checker_);
    160  // Store the device name
    161  RTC_LOG(LS_INFO) << "VideoCaptureAndroid::Init: " << deviceUniqueIdUTF8;
    162  _deviceUniqueId = new char[nameLength + 1];
    163  memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1);
    164 
    165  AttachThreadScoped ats(g_jvm_capture);
    166  JNIEnv* env = ats.env();
    167  jmethodID factory =
    168      env->GetStaticMethodID(g_java_capturer_class, "create",
    169                             "(Ljava/lang/String;)"
    170                             "Lorg/webrtc/videoengine/VideoCaptureAndroid;");
    171  assert(factory);
    172  jstring j_deviceName = env->NewStringUTF(_deviceUniqueId);
    173  _jCapturer = env->NewGlobalRef(env->CallStaticObjectMethod(
    174      g_java_capturer_class, factory, j_deviceName));
    175  assert(_jCapturer);
    176  return 0;
    177 }
    178 
    179 VideoCaptureAndroid::~VideoCaptureAndroid() {
    180  // Ensure Java camera is released even if our caller didn't explicitly Stop.
    181  if (_captureStarted) StopCapture();
    182  AttachThreadScoped ats(g_jvm_capture);
    183  JNIEnv* env = ats.env();
    184  env->DeleteGlobalRef(_jCapturer);
    185 }
    186 
    187 int32_t VideoCaptureAndroid::StartCapture(
    188    const VideoCaptureCapability& capability) {
    189  AttachThreadScoped ats(g_jvm_capture);
    190  JNIEnv* env = ats.env();
    191  int width = 0;
    192  int height = 0;
    193  int min_mfps = 0;
    194  int max_mfps = 0;
    195  {
    196    RTC_DCHECK_RUN_ON(&api_checker_);
    197    MutexLock lock(&api_lock_);
    198 
    199    if (_deviceInfo.GetBestMatchedCapability(_deviceUniqueId, capability,
    200                                             _captureCapability) < 0) {
    201      RTC_LOG(LS_ERROR) << __FUNCTION__
    202                        << "s: GetBestMatchedCapability failed: "
    203                        << capability.width << "x" << capability.height;
    204      return -1;
    205    }
    206 
    207    width = _captureCapability.width;
    208    height = _captureCapability.height;
    209    _deviceInfo.GetMFpsRange(_deviceUniqueId, _captureCapability.maxFPS,
    210                             &min_mfps, &max_mfps);
    211 
    212    // Exit critical section to avoid blocking camera thread inside
    213    // onIncomingFrame() call.
    214  }
    215 
    216  jmethodID j_start =
    217      env->GetMethodID(g_java_capturer_class, "startCapture", "(IIIIJ)Z");
    218  assert(j_start);
    219  jlong j_this = reinterpret_cast<intptr_t>(this);
    220  bool started = env->CallBooleanMethod(_jCapturer, j_start, width, height,
    221                                        min_mfps, max_mfps, j_this);
    222  if (started) {
    223    RTC_DCHECK_RUN_ON(&api_checker_);
    224    MutexLock lock(&api_lock_);
    225    _requestedCapability = capability;
    226    _captureStarted = true;
    227  }
    228  return started ? 0 : -1;
    229 }
    230 
    231 int32_t VideoCaptureAndroid::StopCapture() {
    232  AttachThreadScoped ats(g_jvm_capture);
    233  JNIEnv* env = ats.env();
    234  {
    235    RTC_DCHECK_RUN_ON(&api_checker_);
    236    MutexLock lock(&api_lock_);
    237 
    238    memset(&_requestedCapability, 0, sizeof(_requestedCapability));
    239    memset(&_captureCapability, 0, sizeof(_captureCapability));
    240    _captureStarted = false;
    241    // Exit critical section to avoid blocking camera thread inside
    242    // onIncomingFrame() call.
    243  }
    244 
    245  // try to stop the capturer.
    246  jmethodID j_stop =
    247      env->GetMethodID(g_java_capturer_class, "stopCapture", "()Z");
    248  return env->CallBooleanMethod(_jCapturer, j_stop) ? 0 : -1;
    249 }
    250 
    251 bool VideoCaptureAndroid::CaptureStarted() {
    252  MutexLock lock(&api_lock_);
    253  return _captureStarted;
    254 }
    255 
    256 int32_t VideoCaptureAndroid::CaptureSettings(VideoCaptureCapability& settings) {
    257  RTC_DCHECK_RUN_ON(&api_checker_);
    258  MutexLock lock(&api_lock_);
    259  settings = _requestedCapability;
    260  return 0;
    261 }
    262 
    263 }  // namespace videocapturemodule
    264 }  // namespace webrtc