blob: 33e913c078541e61478e5cd5f663fdeff8ca4e7a [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/capture/video/android/video_capture_device_factory_android.h"
#include <utility>
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/containers/cxx20_erase.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "media/capture/video/android/capture_jni_headers/VideoCaptureFactory_jni.h"
#include "media/capture/video/android/video_capture_device_android.h"
using base::android::AttachCurrentThread;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
namespace media {
// static
ScopedJavaLocalRef<jobject>
VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid(
int id,
jlong nativeVideoCaptureDeviceAndroid) {
return (Java_VideoCaptureFactory_createVideoCapture(
AttachCurrentThread(), id, nativeVideoCaptureDeviceAndroid));
}
VideoCaptureDeviceFactoryAndroid::VideoCaptureDeviceFactoryAndroid() = default;
VideoCaptureDeviceFactoryAndroid::~VideoCaptureDeviceFactoryAndroid() = default;
std::unique_ptr<VideoCaptureDevice>
VideoCaptureDeviceFactoryAndroid::CreateDevice(
const VideoCaptureDeviceDescriptor& device_descriptor) {
DCHECK(thread_checker_.CalledOnValidThread());
int id;
if (!base::StringToInt(device_descriptor.device_id, &id))
return nullptr;
std::unique_ptr<VideoCaptureDeviceAndroid> video_capture_device(
new VideoCaptureDeviceAndroid(device_descriptor));
if (video_capture_device->Init()) {
if (test_mode_)
video_capture_device->ConfigureForTesting();
return std::move(video_capture_device);
}
DLOG(ERROR) << "Error creating Video Capture Device.";
return nullptr;
}
void VideoCaptureDeviceFactoryAndroid::GetDevicesInfo(
GetDevicesInfoCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
JNIEnv* env = AttachCurrentThread();
const int num_cameras = Java_VideoCaptureFactory_getNumberOfCameras(env);
DVLOG(1) << __func__ << ": num_cameras=" << num_cameras;
if (num_cameras <= 0) {
std::move(callback).Run({});
return;
}
std::vector<VideoCaptureDeviceInfo> devices_info;
for (int camera_index = num_cameras - 1; camera_index >= 0; --camera_index) {
base::android::ScopedJavaLocalRef<jstring> device_name =
Java_VideoCaptureFactory_getDeviceName(env, camera_index);
if (device_name.obj() == nullptr)
continue;
const std::string display_name =
base::android::ConvertJavaStringToUTF8(device_name);
base::android::ScopedJavaLocalRef<jstring> device_id_jstring =
Java_VideoCaptureFactory_getDeviceId(env, camera_index);
if (device_id_jstring.obj() == nullptr)
continue;
const std::string device_id =
base::android::ConvertJavaStringToUTF8(device_id_jstring);
const VideoCaptureApi capture_api_type = static_cast<VideoCaptureApi>(
Java_VideoCaptureFactory_getCaptureApiType(env, camera_index));
if (capture_api_type == VideoCaptureApi::UNKNOWN)
continue;
VideoCaptureControlSupport control_support;
const int facing_mode =
Java_VideoCaptureFactory_getFacingMode(env, camera_index);
auto zoom_it = zooms_cache_.find(device_id);
if (zoom_it != zooms_cache_.end()) {
control_support.zoom = zoom_it->second;
} else {
control_support.zoom =
Java_VideoCaptureFactory_isZoomSupported(env, camera_index);
zooms_cache_.emplace(device_id, control_support.zoom);
}
// Android cameras are not typically USB devices, and the model_id is
// currently only used for USB model identifiers, so this implementation
// just indicates an unknown device model (by not providing one).
VideoCaptureDeviceInfo device_info(VideoCaptureDeviceDescriptor(
display_name, device_id, "" /*model_id*/, capture_api_type,
control_support, VideoCaptureTransportType::OTHER_TRANSPORT,
static_cast<VideoFacingMode>(facing_mode)));
auto it = supported_formats_cache_.find(device_id);
if (it != supported_formats_cache_.end()) {
device_info.supported_formats = it->second;
} else {
device_info.supported_formats =
GetSupportedFormats(camera_index, display_name);
supported_formats_cache_.emplace(device_id,
device_info.supported_formats);
}
// We put user-facing devices to the front of the list in order to make
// them by-default preferred over environment-facing ones when no other
// constraints for device selection are given.
if (facing_mode == MEDIA_VIDEO_FACING_USER) {
devices_info.insert(devices_info.begin(), std::move(device_info));
} else {
devices_info.emplace_back(std::move(device_info));
}
DVLOG(1) << __func__ << ": camera "
<< "device_name=" << display_name << ", unique_id=" << device_id;
}
// Remove old entries from |supported_formats_cache_| if necessary.
if (supported_formats_cache_.size() > devices_info.size()) {
base::EraseIf(supported_formats_cache_, [&devices_info](const auto& entry) {
return base::ranges::none_of(
devices_info, [&entry](const VideoCaptureDeviceInfo& info) {
return entry.first == info.descriptor.device_id;
});
});
}
// Remove old entries from |zooms_cache_| if necessary.
if (zooms_cache_.size() > devices_info.size()) {
base::EraseIf(zooms_cache_, [&devices_info](const auto& entry) {
return base::ranges::none_of(
devices_info, [&entry](const VideoCaptureDeviceInfo& info) {
return entry.first == info.descriptor.device_id;
});
});
}
std::move(callback).Run(std::move(devices_info));
}
VideoCaptureFormats VideoCaptureDeviceFactoryAndroid::GetSupportedFormats(
int device_index,
const std::string& display_name) {
DCHECK(thread_checker_.CalledOnValidThread());
JNIEnv* env = AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobjectArray> collected_formats =
Java_VideoCaptureFactory_getDeviceSupportedFormats(env, device_index);
if (collected_formats.is_null())
return {};
VideoCaptureFormats capture_formats;
for (auto format : collected_formats.ReadElements<jobject>()) {
VideoPixelFormat pixel_format = PIXEL_FORMAT_UNKNOWN;
switch (Java_VideoCaptureFactory_getCaptureFormatPixelFormat(env, format)) {
case VideoCaptureDeviceAndroid::ANDROID_IMAGE_FORMAT_YV12:
pixel_format = PIXEL_FORMAT_YV12;
break;
case VideoCaptureDeviceAndroid::ANDROID_IMAGE_FORMAT_NV21:
pixel_format = PIXEL_FORMAT_NV21;
break;
case VideoCaptureDeviceAndroid::ANDROID_IMAGE_FORMAT_YUV_420_888:
pixel_format = PIXEL_FORMAT_I420;
break;
default:
// TODO(crbug.com/792260): break here and let the enumeration continue
// with UNKNOWN pixel format because the platform doesn't know until
// capture, but some unrelated tests timeout https://crbug.com/644910.
continue;
}
VideoCaptureFormat capture_format(
gfx::Size(Java_VideoCaptureFactory_getCaptureFormatWidth(env, format),
Java_VideoCaptureFactory_getCaptureFormatHeight(env, format)),
Java_VideoCaptureFactory_getCaptureFormatFramerate(env, format),
pixel_format);
DVLOG(1) << display_name << " "
<< VideoCaptureFormat::ToString(capture_format);
capture_formats.push_back(std::move(capture_format));
}
return capture_formats;
}
bool VideoCaptureDeviceFactoryAndroid::IsLegacyOrDeprecatedDevice(
const std::string& device_id) {
int id;
if (!base::StringToInt(device_id, &id))
return true;
return (Java_VideoCaptureFactory_isLegacyOrDeprecatedDevice(
AttachCurrentThread(), id));
}
} // namespace media