tor-browser

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

device_info_android.cc (10868B)


      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 "device_info_android.h"
     12 
     13 #include <sstream>
     14 #include <string>
     15 #include <vector>
     16 
     17 #include "modules/utility/include/helpers_android.h"
     18 #include "mozilla/jni/Utils.h"
     19 #include "rtc_base/logging.h"
     20 
     21 namespace webrtc {
     22 
     23 namespace videocapturemodule {
     24 
     25 // Helper for storing lists of pairs of ints.  Used e.g. for resolutions & FPS
     26 // ranges.
     27 typedef std::pair<int, int> IntPair;
     28 typedef std::vector<IntPair> IntPairs;
     29 
     30 static std::string IntPairsToString(const IntPairs& pairs, char separator) {
     31  std::stringstream stream;
     32  for (size_t i = 0; i < pairs.size(); ++i) {
     33    if (i > 0) {
     34      stream << ", ";
     35    }
     36    stream << "(" << pairs[i].first << separator << pairs[i].second << ")";
     37  }
     38  return stream.str();
     39 }
     40 
     41 struct AndroidCameraInfo {
     42  std::string name;
     43  bool front_facing;
     44  int orientation;
     45  IntPairs resolutions;  // Pairs are: (width,height).
     46  // Pairs are (min,max) in units of FPS*1000 ("milli-frame-per-second").
     47  IntPairs mfpsRanges;
     48 
     49  std::string ToString() {
     50    std::stringstream stream;
     51    stream << "Name: [" << name << "], MFPS ranges: ["
     52           << IntPairsToString(mfpsRanges, ':')
     53           << "], front_facing: " << front_facing
     54           << ", orientation: " << orientation << ", resolutions: ["
     55           << IntPairsToString(resolutions, 'x') << "]";
     56    return stream.str();
     57  }
     58 };
     59 
     60 // Camera info; populated during DeviceInfoAndroid::Refresh()
     61 static std::vector<AndroidCameraInfo>* g_camera_info = NULL;
     62 
     63 static JavaVM* g_jvm_dev_info = NULL;
     64 
     65 // Set |*index| to the index of |name| in g_camera_info or return false if no
     66 // match found.
     67 static bool FindCameraIndexByName(const std::string& name, size_t* index) {
     68  for (size_t i = 0; i < g_camera_info->size(); ++i) {
     69    if (g_camera_info->at(i).name == name) {
     70      *index = i;
     71      return true;
     72    }
     73  }
     74  return false;
     75 }
     76 
     77 // Returns a pointer to the named member of g_camera_info, or NULL if no match
     78 // is found.
     79 static AndroidCameraInfo* FindCameraInfoByName(const std::string& name) {
     80  size_t index = 0;
     81  if (FindCameraIndexByName(name, &index)) {
     82    return &g_camera_info->at(index);
     83  }
     84  return NULL;
     85 }
     86 
     87 // static
     88 void DeviceInfoAndroid::Initialize(JavaVM* javaVM) {
     89  // TODO(henrike): this "if" would make a lot more sense as an assert, but
     90  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine() and
     91  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Terminate() conspire to
     92  // prevent this.  Once that code is made to only
     93  // VideoEngine::SetAndroidObjects() once per process, this can turn into an
     94  // assert.
     95  if (g_camera_info) {
     96    return;
     97  }
     98 
     99  g_jvm_dev_info = javaVM;
    100  BuildDeviceList();
    101 }
    102 
    103 void DeviceInfoAndroid::BuildDeviceList() {
    104  if (!g_jvm_dev_info) {
    105    return;
    106  }
    107 
    108  AttachThreadScoped ats(g_jvm_dev_info);
    109  JNIEnv* jni = ats.env();
    110 
    111  g_camera_info = new std::vector<AndroidCameraInfo>();
    112  jclass j_info_class = mozilla::jni::GetClassRef(
    113      jni, "org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid");
    114  jclass j_cap_class = mozilla::jni::GetClassRef(
    115      jni, "org/webrtc/videoengine/CaptureCapabilityAndroid");
    116  assert(j_info_class);
    117  jmethodID j_get_device_info = jni->GetStaticMethodID(
    118      j_info_class, "getDeviceInfo",
    119      "()[Lorg/webrtc/videoengine/CaptureCapabilityAndroid;");
    120  jarray j_camera_caps = static_cast<jarray>(
    121      jni->CallStaticObjectMethod(j_info_class, j_get_device_info));
    122  if (jni->ExceptionCheck()) {
    123    jni->ExceptionClear();
    124    RTC_LOG(LS_INFO) << __FUNCTION__ << ": Failed to get camera capabilities.";
    125    return;
    126  }
    127  if (j_camera_caps == nullptr) {
    128    RTC_LOG(LS_INFO) << __FUNCTION__ << ": Failed to get camera capabilities.";
    129    return;
    130  }
    131 
    132  const jsize capLength = jni->GetArrayLength(j_camera_caps);
    133 
    134  jfieldID widthField = jni->GetFieldID(j_cap_class, "width", "[I");
    135  jfieldID heightField = jni->GetFieldID(j_cap_class, "height", "[I");
    136  jfieldID maxFpsField = jni->GetFieldID(j_cap_class, "maxMilliFPS", "I");
    137  jfieldID minFpsField = jni->GetFieldID(j_cap_class, "minMilliFPS", "I");
    138  jfieldID orientationField = jni->GetFieldID(j_cap_class, "orientation", "I");
    139  jfieldID frontFacingField = jni->GetFieldID(j_cap_class, "frontFacing", "Z");
    140  jfieldID nameField =
    141      jni->GetFieldID(j_cap_class, "name", "Ljava/lang/String;");
    142  if (widthField == NULL || heightField == NULL || maxFpsField == NULL ||
    143      minFpsField == NULL || orientationField == NULL ||
    144      frontFacingField == NULL || nameField == NULL) {
    145    RTC_LOG(LS_INFO) << __FUNCTION__ << ": Failed to get field Id.";
    146    return;
    147  }
    148 
    149  for (jsize i = 0; i < capLength; i++) {
    150    jobject capabilityElement =
    151        jni->GetObjectArrayElement((jobjectArray)j_camera_caps, i);
    152 
    153    AndroidCameraInfo info;
    154    jstring camName =
    155        static_cast<jstring>(jni->GetObjectField(capabilityElement, nameField));
    156    const char* camChars = jni->GetStringUTFChars(camName, nullptr);
    157    info.name = std::string(camChars);
    158    jni->ReleaseStringUTFChars(camName, camChars);
    159 
    160    info.orientation = jni->GetIntField(capabilityElement, orientationField);
    161    info.front_facing =
    162        jni->GetBooleanField(capabilityElement, frontFacingField);
    163    jint min_mfps = jni->GetIntField(capabilityElement, minFpsField);
    164    jint max_mfps = jni->GetIntField(capabilityElement, maxFpsField);
    165 
    166    jintArray widthResArray = static_cast<jintArray>(
    167        jni->GetObjectField(capabilityElement, widthField));
    168    jintArray heightResArray = static_cast<jintArray>(
    169        jni->GetObjectField(capabilityElement, heightField));
    170 
    171    const jsize numRes = jni->GetArrayLength(widthResArray);
    172 
    173    jint* widths = jni->GetIntArrayElements(widthResArray, nullptr);
    174    jint* heights = jni->GetIntArrayElements(heightResArray, nullptr);
    175 
    176    for (jsize j = 0; j < numRes; ++j) {
    177      info.resolutions.push_back(std::make_pair(widths[j], heights[j]));
    178    }
    179 
    180    info.mfpsRanges.push_back(std::make_pair(min_mfps, max_mfps));
    181    g_camera_info->push_back(info);
    182 
    183    jni->ReleaseIntArrayElements(widthResArray, widths, JNI_ABORT);
    184    jni->ReleaseIntArrayElements(heightResArray, heights, JNI_ABORT);
    185  }
    186 
    187  jni->DeleteLocalRef(j_info_class);
    188  jni->DeleteLocalRef(j_cap_class);
    189 }
    190 
    191 void DeviceInfoAndroid::DeInitialize() {
    192  if (g_camera_info) {
    193    delete g_camera_info;
    194    g_camera_info = NULL;
    195  }
    196 }
    197 
    198 int32_t DeviceInfoAndroid::Refresh() {
    199  if (!g_camera_info || g_camera_info->size() == 0) {
    200    DeviceInfoAndroid::BuildDeviceList();
    201 #ifdef DEBUG
    202    int frontFacingIndex = -1;
    203    for (uint32_t i = 0; i < g_camera_info->size(); i++) {
    204      if (g_camera_info->at(i).front_facing) {
    205        frontFacingIndex = i;
    206      }
    207    }
    208    // Either there is a front-facing camera, and it's first in the list, or
    209    // there is no front-facing camera.
    210    MOZ_ASSERT(frontFacingIndex == 0 || frontFacingIndex == -1);
    211 #endif
    212  }
    213  return 0;
    214 }
    215 
    216 VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
    217  return new videocapturemodule::DeviceInfoAndroid();
    218 }
    219 
    220 DeviceInfoAndroid::DeviceInfoAndroid() : DeviceInfoImpl() {}
    221 
    222 DeviceInfoAndroid::~DeviceInfoAndroid() {}
    223 
    224 bool DeviceInfoAndroid::FindCameraIndex(const char* deviceUniqueIdUTF8,
    225                                        size_t* index) {
    226  return FindCameraIndexByName(deviceUniqueIdUTF8, index);
    227 }
    228 
    229 int32_t DeviceInfoAndroid::Init() { return 0; }
    230 
    231 uint32_t DeviceInfoAndroid::NumberOfDevices() {
    232  Refresh();
    233  return g_camera_info->size();
    234 }
    235 
    236 int32_t DeviceInfoAndroid::GetDeviceName(
    237    uint32_t deviceNumber, char* deviceNameUTF8, uint32_t deviceNameLength,
    238    char* deviceUniqueIdUTF8, uint32_t deviceUniqueIdUTF8Length,
    239    char* /*productUniqueIdUTF8*/, uint32_t /*productUniqueIdUTF8Length*/,
    240    pid_t* /*pid*/, bool* /*deviceIsPlaceholder*/) {
    241  if (deviceNumber >= g_camera_info->size()) {
    242    return -1;
    243  }
    244  const AndroidCameraInfo& info = g_camera_info->at(deviceNumber);
    245  if (info.name.length() + 1 > deviceNameLength ||
    246      info.name.length() + 1 > deviceUniqueIdUTF8Length) {
    247    return -1;
    248  }
    249  memcpy(deviceNameUTF8, info.name.c_str(), info.name.length() + 1);
    250  memcpy(deviceUniqueIdUTF8, info.name.c_str(), info.name.length() + 1);
    251  return 0;
    252 }
    253 
    254 int32_t DeviceInfoAndroid::CreateCapabilityMap(const char* deviceUniqueIdUTF8) {
    255  _captureCapabilities.clear();
    256  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
    257  if (info == NULL) {
    258    return -1;
    259  }
    260 
    261  for (size_t i = 0; i < info->resolutions.size(); ++i) {
    262    for (size_t j = 0; j < info->mfpsRanges.size(); ++j) {
    263      const IntPair& size = info->resolutions[i];
    264      const IntPair& mfpsRange = info->mfpsRanges[j];
    265      VideoCaptureCapability cap;
    266      cap.width = size.first;
    267      cap.height = size.second;
    268      cap.maxFPS = mfpsRange.second / 1000;
    269      cap.videoType = VideoType::kNV21;
    270      _captureCapabilities.push_back(cap);
    271    }
    272  }
    273  return _captureCapabilities.size();
    274 }
    275 
    276 int32_t DeviceInfoAndroid::GetOrientation(const char* deviceUniqueIdUTF8,
    277                                          VideoRotation& orientation) {
    278  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
    279  if (info == NULL || VideoCaptureImpl::RotationFromDegrees(
    280                          info->orientation, &orientation) != 0) {
    281    return -1;
    282  }
    283  return 0;
    284 }
    285 
    286 void DeviceInfoAndroid::GetMFpsRange(const char* deviceUniqueIdUTF8,
    287                                     int max_fps_to_match, int* min_mfps,
    288                                     int* max_mfps) {
    289  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
    290  if (info == NULL) {
    291    return;
    292  }
    293  int desired_mfps = max_fps_to_match * 1000;
    294  int best_diff_mfps = 0;
    295  RTC_LOG(LS_INFO) << "Search for best target mfps " << desired_mfps;
    296  // Search for best fps range with preference shifted to constant fps modes.
    297  for (size_t i = 0; i < info->mfpsRanges.size(); ++i) {
    298    int diff_mfps =
    299        abs(info->mfpsRanges[i].first - desired_mfps) +
    300        abs(info->mfpsRanges[i].second - desired_mfps) +
    301        (info->mfpsRanges[i].second - info->mfpsRanges[i].first) / 2;
    302    RTC_LOG(LS_INFO) << "Fps range " << info->mfpsRanges[i].first << ":"
    303                     << info->mfpsRanges[i].second
    304                     << ". Distance: " << diff_mfps;
    305    if (i == 0 || diff_mfps < best_diff_mfps) {
    306      best_diff_mfps = diff_mfps;
    307      *min_mfps = info->mfpsRanges[i].first;
    308      *max_mfps = info->mfpsRanges[i].second;
    309    }
    310  }
    311 }
    312 
    313 }  // namespace videocapturemodule
    314 }  // namespace webrtc