blob: df045ddc22d48de3d101c555d92f537cbf79c502 [file] [log] [blame]
// Copyright 2019 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/chromeos/reprocess_manager.h"
#include <functional>
#include <utility>
#include "media/capture/video/chromeos/camera_metadata_utils.h"
namespace media {
namespace {
void OnStillCaptureDone(media::mojom::ImageCapture::TakePhotoCallback callback,
int status,
mojom::BlobPtr blob) {
std::move(callback).Run(std::move(blob));
}
} // namespace
ReprocessTask::ReprocessTask() = default;
ReprocessTask::ReprocessTask(ReprocessTask&& other)
: effect(other.effect),
callback(std::move(other.callback)),
extra_metadata(std::move(other.extra_metadata)) {}
ReprocessTask::~ReprocessTask() = default;
// static
int ReprocessManager::GetReprocessReturnCode(
cros::mojom::Effect effect,
const cros::mojom::CameraMetadataPtr* metadata) {
if (effect == cros::mojom::Effect::PORTRAIT_MODE) {
auto* portrait_mode_segmentation_result = GetMetadataEntry(
*metadata, static_cast<cros::mojom::CameraMetadataTag>(
kPortraitModeSegmentationResultVendorKey));
CHECK(portrait_mode_segmentation_result);
return static_cast<int>((*portrait_mode_segmentation_result)->data[0]);
}
return kReprocessSuccess;
}
ReprocessManager::ReprocessManager(CameraInfoGetter get_camera_info)
: sequenced_task_runner_(base::CreateSequencedTaskRunner(
{base::ThreadPool(), base::TaskPriority::USER_VISIBLE})),
impl(std::make_unique<ReprocessManager::ReprocessManagerImpl>(
std::move(get_camera_info))) {}
ReprocessManager::~ReprocessManager() {
sequenced_task_runner_->DeleteSoon(FROM_HERE, std::move(impl));
}
void ReprocessManager::SetReprocessOption(
const std::string& device_id,
cros::mojom::Effect effect,
cros::mojom::CrosImageCapture::SetReprocessOptionCallback
reprocess_result_callback) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ReprocessManager::ReprocessManagerImpl::SetReprocessOption,
base::Unretained(impl.get()), device_id, effect,
std::move(reprocess_result_callback)));
}
void ReprocessManager::ConsumeReprocessOptions(
const std::string& device_id,
media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ReprocessManager::ReprocessManagerImpl::ConsumeReprocessOptions,
base::Unretained(impl.get()), device_id,
std::move(take_photo_callback), std::move(consumption_callback)));
}
void ReprocessManager::Flush(const std::string& device_id) {
sequenced_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&ReprocessManager::ReprocessManagerImpl::Flush,
base::Unretained(impl.get()), device_id));
}
void ReprocessManager::GetCameraInfo(const std::string& device_id,
GetCameraInfoCallback callback) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&ReprocessManager::ReprocessManagerImpl::GetCameraInfo,
base::Unretained(impl.get()), device_id,
std::move(callback)));
}
void ReprocessManager::SetFpsRange(
const std::string& device_id,
const uint32_t stream_width,
const uint32_t stream_height,
const int32_t min_fps,
const int32_t max_fps,
cros::mojom::CrosImageCapture::SetFpsRangeCallback callback) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&ReprocessManager::ReprocessManagerImpl::SetFpsRange,
base::Unretained(impl.get()), device_id, stream_width,
stream_height, min_fps, max_fps, std::move(callback)));
}
void ReprocessManager::GetFpsRange(const std::string& device_id,
const uint32_t stream_width,
const uint32_t stream_height,
GetFpsRangeCallback callback) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&ReprocessManager::ReprocessManagerImpl::GetFpsRange,
base::Unretained(impl.get()), device_id, stream_width,
stream_height, std::move(callback)));
}
ReprocessManager::ReprocessManagerImpl::ReprocessManagerImpl(
CameraInfoGetter get_camera_info)
: get_camera_info_(std::move(get_camera_info)) {}
ReprocessManager::ReprocessManagerImpl::~ReprocessManagerImpl() = default;
void ReprocessManager::ReprocessManagerImpl::SetReprocessOption(
const std::string& device_id,
cros::mojom::Effect effect,
cros::mojom::CrosImageCapture::SetReprocessOptionCallback
reprocess_result_callback) {
ReprocessTask task;
task.effect = effect;
task.callback = std::move(reprocess_result_callback);
if (effect == cros::mojom::Effect::PORTRAIT_MODE) {
std::vector<uint8_t> portrait_mode_value(sizeof(int32_t));
*reinterpret_cast<int32_t*>(portrait_mode_value.data()) = 1;
cros::mojom::CameraMetadataEntryPtr e =
cros::mojom::CameraMetadataEntry::New();
e->tag =
static_cast<cros::mojom::CameraMetadataTag>(kPortraitModeVendorKey);
e->type = cros::mojom::EntryType::TYPE_INT32;
e->count = 1;
e->data = std::move(portrait_mode_value);
task.extra_metadata.push_back(std::move(e));
}
reprocess_task_queue_map_[device_id].push(std::move(task));
}
void ReprocessManager::ReprocessManagerImpl::ConsumeReprocessOptions(
const std::string& device_id,
media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback) {
ReprocessTaskQueue result_task_queue;
ReprocessTask still_capture_task;
still_capture_task.effect = cros::mojom::Effect::NO_EFFECT;
still_capture_task.callback =
base::BindOnce(&OnStillCaptureDone, std::move(take_photo_callback));
result_task_queue.push(std::move(still_capture_task));
auto& task_queue = reprocess_task_queue_map_[device_id];
while (!task_queue.empty()) {
result_task_queue.push(std::move(task_queue.front()));
task_queue.pop();
}
std::move(consumption_callback).Run(std::move(result_task_queue));
}
void ReprocessManager::ReprocessManagerImpl::Flush(
const std::string& device_id) {
auto empty_queue = ReprocessTaskQueue();
reprocess_task_queue_map_[device_id].swap(empty_queue);
auto empty_map = ResolutionFpsRangeMap();
resolution_fps_range_map_[device_id].swap(empty_map);
}
void ReprocessManager::ReprocessManagerImpl::GetCameraInfo(
const std::string& device_id,
GetCameraInfoCallback callback) {
std::move(callback).Run(get_camera_info_.Run(device_id));
}
void ReprocessManager::ReprocessManagerImpl::SetFpsRange(
const std::string& device_id,
const uint32_t stream_width,
const uint32_t stream_height,
const int32_t min_fps,
const int32_t max_fps,
cros::mojom::CrosImageCapture::SetFpsRangeCallback callback) {
const int entry_length = 2;
auto camera_info = get_camera_info_.Run(device_id);
auto& static_metadata = camera_info->static_camera_characteristics;
auto available_fps_range_entries = GetMetadataEntryAsSpan<int32_t>(
static_metadata, cros::mojom::CameraMetadataTag::
ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
CHECK(available_fps_range_entries.size() % entry_length == 0);
bool is_valid = false;
for (size_t i = 0; i < available_fps_range_entries.size();
i += entry_length) {
if (available_fps_range_entries[i] == min_fps &&
available_fps_range_entries[i + 1] == max_fps) {
is_valid = true;
break;
}
}
auto resolution = gfx::Size(stream_width, stream_height);
auto& fps_map = resolution_fps_range_map_[device_id];
if (!is_valid) {
// If the input range is invalid, we should still clear the cache range so
// that it will fallback to use default fps range rather than the cache one.
auto it = fps_map.find(resolution);
if (it != fps_map.end()) {
fps_map.erase(it);
}
std::move(callback).Run(false);
return;
}
auto fps_range = gfx::Range(min_fps, max_fps);
fps_map[resolution] = fps_range;
std::move(callback).Run(true);
}
void ReprocessManager::ReprocessManagerImpl::GetFpsRange(
const std::string& device_id,
const uint32_t stream_width,
const uint32_t stream_height,
GetFpsRangeCallback callback) {
if (resolution_fps_range_map_.find(device_id) ==
resolution_fps_range_map_.end()) {
std::move(callback).Run({});
return;
}
auto resolution = gfx::Size(stream_width, stream_height);
auto& fps_map = resolution_fps_range_map_[device_id];
if (fps_map.find(resolution) == fps_map.end()) {
std::move(callback).Run({});
return;
}
std::move(callback).Run(fps_map[resolution]);
}
bool ReprocessManager::ReprocessManagerImpl::SizeComparator::operator()(
const gfx::Size size_1,
const gfx::Size size_2) const {
return size_1.width() < size_2.width() || (size_1.width() == size_2.width() &&
size_1.height() < size_2.height());
}
} // namespace media