2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/video_capture/android/device_info_android.h"
17 #include "json/json.h"
18 #include "third_party/icu/source/common/unicode/unistr.h"
19 #include "webrtc/modules/video_capture/android/video_capture_android.h"
20 #include "webrtc/system_wrappers/interface/logging.h"
21 #include "webrtc/system_wrappers/interface/ref_count.h"
22 #include "webrtc/system_wrappers/interface/trace.h"
26 namespace videocapturemodule {
28 // Helper for storing lists of pairs of ints. Used e.g. for resolutions & FPS
30 typedef std::pair<int, int> IntPair;
31 typedef std::vector<IntPair> IntPairs;
33 static std::string IntPairsToString(const IntPairs& pairs, char separator) {
34 std::stringstream stream;
35 for (size_t i = 0; i < pairs.size(); ++i) {
38 stream << "(" << pairs[i].first << separator << pairs[i].second << ")";
43 struct AndroidCameraInfo {
47 IntPairs resolutions; // Pairs are: (width,height).
48 // Pairs are (min,max) in units of FPS*1000 ("milli-frame-per-second").
51 std::string ToString() {
52 std::stringstream stream;
53 stream << "Name: [" << name << "], MFPS ranges: ["
54 << IntPairsToString(mfpsRanges, ':')
55 << "], front_facing: " << front_facing
56 << ", orientation: " << orientation << ", resolutions: ["
57 << IntPairsToString(resolutions, 'x') << "]";
62 // Camera info; populated during DeviceInfoAndroid::Initialize() and immutable
64 static std::vector<AndroidCameraInfo>* g_camera_info = NULL;
66 // Set |*index| to the index of |name| in g_camera_info or return false if no
68 static bool FindCameraIndexByName(const std::string& name, size_t* index) {
69 for (size_t i = 0; i < g_camera_info->size(); ++i) {
70 if (g_camera_info->at(i).name == name) {
78 // Returns a pointer to the named member of g_camera_info, or NULL if no match
80 static AndroidCameraInfo* FindCameraInfoByName(const std::string& name) {
82 if (FindCameraIndexByName(name, &index))
83 return &g_camera_info->at(index);
88 void DeviceInfoAndroid::Initialize(JNIEnv* jni) {
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
98 g_camera_info = new std::vector<AndroidCameraInfo>();
100 jni->FindClass("org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid");
101 assert(j_info_class);
102 jmethodID j_initialize = jni->GetStaticMethodID(
103 j_info_class, "getDeviceInfo", "()Ljava/lang/String;");
104 jstring j_json_info = static_cast<jstring>(
105 jni->CallStaticObjectMethod(j_info_class, j_initialize));
107 const jchar* jchars = jni->GetStringChars(j_json_info, NULL);
108 icu::UnicodeString ustr(jchars, jni->GetStringLength(j_json_info));
109 jni->ReleaseStringChars(j_json_info, jchars);
110 std::string json_info;
111 ustr.toUTF8String(json_info);
114 Json::Reader reader(Json::Features::strictMode());
115 bool parsed = reader.parse(json_info, cameras);
117 std::stringstream stream;
118 stream << "Failed to parse configuration:\n"
119 << reader.getFormattedErrorMessages();
123 for (Json::ArrayIndex i = 0; i < cameras.size(); ++i) {
124 const Json::Value& camera = cameras[i];
125 AndroidCameraInfo info;
126 info.name = camera["name"].asString();
127 info.front_facing = camera["front_facing"].asBool();
128 info.orientation = camera["orientation"].asInt();
129 Json::Value sizes = camera["sizes"];
130 for (Json::ArrayIndex j = 0; j < sizes.size(); ++j) {
131 const Json::Value& size = sizes[j];
132 info.resolutions.push_back(std::make_pair(
133 size["width"].asInt(), size["height"].asInt()));
135 Json::Value mfpsRanges = camera["mfpsRanges"];
136 for (Json::ArrayIndex j = 0; j < mfpsRanges.size(); ++j) {
137 const Json::Value& mfpsRange = mfpsRanges[j];
138 info.mfpsRanges.push_back(std::make_pair(mfpsRange["min_mfps"].asInt(),
139 mfpsRange["max_mfps"].asInt()));
141 g_camera_info->push_back(info);
145 void DeviceInfoAndroid::DeInitialize() {
147 delete g_camera_info;
148 g_camera_info = NULL;
152 VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo(
154 return new videocapturemodule::DeviceInfoAndroid(id);
157 DeviceInfoAndroid::DeviceInfoAndroid(const int32_t id) :
161 DeviceInfoAndroid::~DeviceInfoAndroid() {
164 bool DeviceInfoAndroid::FindCameraIndex(const char* deviceUniqueIdUTF8,
166 return FindCameraIndexByName(deviceUniqueIdUTF8, index);
169 int32_t DeviceInfoAndroid::Init() {
173 uint32_t DeviceInfoAndroid::NumberOfDevices() {
174 return g_camera_info->size();
177 int32_t DeviceInfoAndroid::GetDeviceName(
178 uint32_t deviceNumber,
179 char* deviceNameUTF8,
180 uint32_t deviceNameLength,
181 char* deviceUniqueIdUTF8,
182 uint32_t deviceUniqueIdUTF8Length,
183 char* /*productUniqueIdUTF8*/,
184 uint32_t /*productUniqueIdUTF8Length*/) {
185 if (deviceNumber >= g_camera_info->size())
187 const AndroidCameraInfo& info = g_camera_info->at(deviceNumber);
188 if (info.name.length() + 1 > deviceNameLength ||
189 info.name.length() + 1 > deviceUniqueIdUTF8Length) {
192 memcpy(deviceNameUTF8, info.name.c_str(), info.name.length() + 1);
193 memcpy(deviceUniqueIdUTF8, info.name.c_str(), info.name.length() + 1);
197 int32_t DeviceInfoAndroid::CreateCapabilityMap(
198 const char* deviceUniqueIdUTF8) {
199 _captureCapabilities.clear();
200 const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
204 for (size_t i = 0; i < info->resolutions.size(); ++i) {
205 for (size_t j = 0; j < info->mfpsRanges.size(); ++j) {
206 const IntPair& size = info->resolutions[i];
207 const IntPair& mfpsRange = info->mfpsRanges[j];
208 VideoCaptureCapability cap;
209 cap.width = size.first;
210 cap.height = size.second;
211 cap.maxFPS = mfpsRange.second / 1000;
212 cap.expectedCaptureDelay = kExpectedCaptureDelay;
213 cap.rawType = kVideoNV21;
214 _captureCapabilities.push_back(cap);
217 return _captureCapabilities.size();
220 int32_t DeviceInfoAndroid::GetOrientation(
221 const char* deviceUniqueIdUTF8,
222 VideoCaptureRotation& orientation) {
223 const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
225 !VideoCaptureImpl::RotationFromDegrees(info->orientation, &orientation)) {
231 void DeviceInfoAndroid::GetMFpsRange(const char* deviceUniqueIdUTF8,
232 int max_fps_to_match,
233 int* min_mfps, int* max_mfps) {
234 const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
237 int desired_mfps = max_fps_to_match * 1000;
238 int best_diff_mfps = 0;
239 LOG(LS_INFO) << "Search for best target mfps " << desired_mfps;
240 // Search for best fps range with preference shifted to constant fps modes.
241 for (size_t i = 0; i < info->mfpsRanges.size(); ++i) {
242 int diff_mfps = abs(info->mfpsRanges[i].first - desired_mfps) +
243 abs(info->mfpsRanges[i].second - desired_mfps) +
244 (info->mfpsRanges[i].second - info->mfpsRanges[i].first) / 2;
245 LOG(LS_INFO) << "Fps range " << info->mfpsRanges[i].first << ":" <<
246 info->mfpsRanges[i].second << ". Distance: " << diff_mfps;
247 if (i == 0 || diff_mfps < best_diff_mfps) {
248 best_diff_mfps = diff_mfps;
249 *min_mfps = info->mfpsRanges[i].first;
250 *max_mfps = info->mfpsRanges[i].second;
255 } // namespace videocapturemodule
256 } // namespace webrtc