blob: 9a78e6edb126a188530d7caa0a7c36edc8f241e1 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "GCH_HdrplusCaptureSession"
#define ATRACE_TAG ATRACE_TAG_CAMERA
#include "hdrplus_capture_session.h"
#include <cutils/properties.h>
#include <inttypes.h>
#include <log/log.h>
#include <utils/Trace.h>
#include <set>
#include "hal_utils.h"
#include "hdrplus_process_block.h"
#include "hdrplus_request_processor.h"
#include "hdrplus_result_processor.h"
#include "realtime_process_block.h"
#include "realtime_zsl_request_processor.h"
#include "realtime_zsl_result_processor.h"
#include "vendor_tag_defs.h"
namespace android {
namespace google_camera_hal {
bool HdrplusCaptureSession::IsStreamConfigurationSupported(
CameraDeviceSessionHwl* device_session_hwl,
const StreamConfiguration& stream_config) {
ATRACE_CALL();
if (device_session_hwl == nullptr) {
ALOGE("%s: device_session_hwl is nullptr", __FUNCTION__);
return false;
}
uint32_t num_physical_cameras =
device_session_hwl->GetPhysicalCameraIds().size();
if (num_physical_cameras > 1) {
ALOGD("%s: HdrplusCaptureSession doesn't support %u physical cameras",
__FUNCTION__, num_physical_cameras);
return false;
}
std::unique_ptr<HalCameraMetadata> characteristics;
status_t res = device_session_hwl->GetCameraCharacteristics(&characteristics);
if (res != OK) {
ALOGE("%s: GetCameraCharacteristics failed.", __FUNCTION__);
return BAD_VALUE;
}
if (hal_utils::IsStreamHdrplusCompatible(stream_config,
characteristics.get()) == false) {
return false;
}
if (!hal_utils::IsBayerCamera(characteristics.get())) {
ALOGD("%s: camera %d is not a bayer camera", __FUNCTION__,
device_session_hwl->GetCameraId());
return false;
}
ALOGI("%s: HDR+ is enabled", __FUNCTION__);
ALOGD("%s: HdrplusCaptureSession supports the stream config", __FUNCTION__);
return true;
}
std::unique_ptr<HdrplusCaptureSession> HdrplusCaptureSession::Create(
CameraDeviceSessionHwl* device_session_hwl,
const StreamConfiguration& stream_config,
ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
HwlSessionCallback /*session_callback*/,
std::vector<HalStream>* hal_configured_streams,
CameraBufferAllocatorHwl* /*camera_allocator_hwl*/) {
ATRACE_CALL();
auto session =
std::unique_ptr<HdrplusCaptureSession>(new HdrplusCaptureSession());
if (session == nullptr) {
ALOGE("%s: Creating HdrplusCaptureSession failed.", __FUNCTION__);
return nullptr;
}
status_t res = session->Initialize(device_session_hwl, stream_config,
process_capture_result, notify,
hal_configured_streams);
if (res != OK) {
ALOGE("%s: Initializing HdrplusCaptureSession failed: %s (%d).",
__FUNCTION__, strerror(-res), res);
return nullptr;
}
return session;
}
HdrplusCaptureSession::~HdrplusCaptureSession() {
ATRACE_CALL();
if (device_session_hwl_ != nullptr) {
device_session_hwl_->DestroyPipelines();
}
}
status_t HdrplusCaptureSession::ConfigureStreams(
const StreamConfiguration& stream_config,
RequestProcessor* request_processor, ProcessBlock* process_block,
int32_t* raw_stream_id) {
ATRACE_CALL();
if (request_processor == nullptr || process_block == nullptr ||
raw_stream_id == nullptr) {
ALOGE(
"%s: request_processor (%p) or process_block (%p) is nullptr or "
"raw_stream_id (%p) is nullptr",
__FUNCTION__, request_processor, process_block, raw_stream_id);
return BAD_VALUE;
}
StreamConfiguration process_block_stream_config;
// Configure streams for request processor
status_t res = request_processor->ConfigureStreams(
internal_stream_manager_.get(), stream_config,
&process_block_stream_config);
if (res != OK) {
ALOGE("%s: Configuring stream for request processor failed.", __FUNCTION__);
return res;
}
// Check all streams are configured.
if (stream_config.streams.size() > process_block_stream_config.streams.size()) {
ALOGE("%s: stream_config has %zu streams but only configured %zu streams",
__FUNCTION__, stream_config.streams.size(),
process_block_stream_config.streams.size());
return UNKNOWN_ERROR;
}
for (auto& stream : stream_config.streams) {
bool found = false;
for (auto& configured_stream : process_block_stream_config.streams) {
if (stream.id == configured_stream.id) {
found = true;
break;
}
}
if (!found) {
ALOGE("%s: Cannot find stream %u in configured streams.", __FUNCTION__,
stream.id);
return UNKNOWN_ERROR;
}
}
for (auto& configured_stream : process_block_stream_config.streams) {
if (configured_stream.format == kHdrplusRawFormat) {
*raw_stream_id = configured_stream.id;
break;
}
}
if (*raw_stream_id == -1) {
ALOGE("%s: Configuring stream fail due to wrong raw_stream_id",
__FUNCTION__);
return UNKNOWN_ERROR;
}
// Configure streams for process block.
res = process_block->ConfigureStreams(process_block_stream_config,
stream_config);
if (res != OK) {
ALOGE("%s: Configuring stream for process block failed.", __FUNCTION__);
return res;
}
return OK;
}
status_t HdrplusCaptureSession::ConfigureHdrplusStreams(
const StreamConfiguration& stream_config,
RequestProcessor* hdrplus_request_processor,
ProcessBlock* hdrplus_process_block) {
ATRACE_CALL();
if (hdrplus_process_block == nullptr || hdrplus_request_processor == nullptr) {
ALOGE("%s: hdrplus_process_block or hdrplus_request_processor is nullptr",
__FUNCTION__);
return BAD_VALUE;
}
StreamConfiguration process_block_stream_config;
// Configure streams for request processor
status_t res = hdrplus_request_processor->ConfigureStreams(
internal_stream_manager_.get(), stream_config,
&process_block_stream_config);
if (res != OK) {
ALOGE("%s: Configuring stream for request processor failed.", __FUNCTION__);
return res;
}
// Check all streams are configured.
if (stream_config.streams.size() > process_block_stream_config.streams.size()) {
ALOGE("%s: stream_config has %zu streams but only configured %zu streams",
__FUNCTION__, stream_config.streams.size(),
process_block_stream_config.streams.size());
return UNKNOWN_ERROR;
}
for (auto& stream : stream_config.streams) {
bool found = false;
for (auto& configured_stream : process_block_stream_config.streams) {
if (stream.id == configured_stream.id) {
found = true;
break;
}
}
if (!found) {
ALOGE("%s: Cannot find stream %u in configured streams.", __FUNCTION__,
stream.id);
return UNKNOWN_ERROR;
}
}
// Configure streams for HDR+ process block.
res = hdrplus_process_block->ConfigureStreams(process_block_stream_config,
stream_config);
if (res != OK) {
ALOGE("%s: Configuring hdrplus stream for process block failed.",
__FUNCTION__);
return res;
}
return OK;
}
status_t HdrplusCaptureSession::BuildPipelines(
ProcessBlock* process_block, ProcessBlock* hdrplus_process_block,
std::vector<HalStream>* hal_configured_streams) {
ATRACE_CALL();
if (process_block == nullptr || hal_configured_streams == nullptr) {
ALOGE("%s: process_block (%p) or hal_configured_streams (%p) is nullptr",
__FUNCTION__, process_block, hal_configured_streams);
return BAD_VALUE;
}
status_t res = device_session_hwl_->BuildPipelines();
if (res != OK) {
ALOGE("%s: Building pipelines failed: %s(%d)", __FUNCTION__, strerror(-res),
res);
return res;
}
res = process_block->GetConfiguredHalStreams(hal_configured_streams);
if (res != OK) {
ALOGE("%s: Getting HAL streams failed: %s(%d)", __FUNCTION__,
strerror(-res), res);
return res;
}
std::vector<HalStream> hdrplus_hal_configured_streams;
res = hdrplus_process_block->GetConfiguredHalStreams(
&hdrplus_hal_configured_streams);
if (res != OK) {
ALOGE("%s: Getting HDR+ HAL streams failed: %s(%d)", __FUNCTION__,
strerror(-res), res);
return res;
}
// Combine realtime and HDR+ hal stream.
// Only usage of internal raw stream is different, so combine usage directly
uint64_t consumer_usage = 0;
for (uint32_t i = 0; i < hdrplus_hal_configured_streams.size(); i++) {
if (hdrplus_hal_configured_streams[i].override_format == kHdrplusRawFormat) {
consumer_usage = hdrplus_hal_configured_streams[i].consumer_usage;
break;
}
}
for (uint32_t i = 0; i < hal_configured_streams->size(); i++) {
if (hal_configured_streams->at(i).override_format == kHdrplusRawFormat) {
hal_configured_streams->at(i).consumer_usage = consumer_usage;
if (hal_configured_streams->at(i).max_buffers < kRawMinBufferCount) {
hal_configured_streams->at(i).max_buffers = kRawMinBufferCount;
}
// Allocate internal raw stream buffers
uint32_t additional_num_buffers =
(hal_configured_streams->at(i).max_buffers >= kRawBufferCount)
? 0
: (kRawBufferCount - hal_configured_streams->at(i).max_buffers);
res = internal_stream_manager_->AllocateBuffers(
hal_configured_streams->at(i), additional_num_buffers);
if (res != OK) {
ALOGE("%s: AllocateBuffers failed.", __FUNCTION__);
return UNKNOWN_ERROR;
}
break;
}
}
return OK;
}
status_t HdrplusCaptureSession::ConnectProcessChain(
RequestProcessor* request_processor,
std::unique_ptr<ProcessBlock> process_block,
std::unique_ptr<ResultProcessor> result_processor) {
ATRACE_CALL();
if (request_processor == nullptr) {
ALOGE("%s: request_processor is nullptr", __FUNCTION__);
return BAD_VALUE;
}
status_t res = process_block->SetResultProcessor(std::move(result_processor));
if (res != OK) {
ALOGE("%s: Setting result process in process block failed.", __FUNCTION__);
return res;
}
res = request_processor->SetProcessBlock(std::move(process_block));
if (res != OK) {
ALOGE(
"%s: Setting process block for HdrplusRequestProcessor failed: %s(%d)",
__FUNCTION__, strerror(-res), res);
return res;
}
return OK;
}
status_t HdrplusCaptureSession::SetupRealtimeProcessChain(
const StreamConfiguration& stream_config,
ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
std::unique_ptr<ProcessBlock>* realtime_process_block,
std::unique_ptr<ResultProcessor>* realtime_result_processor,
int32_t* raw_stream_id) {
ATRACE_CALL();
if (realtime_process_block == nullptr ||
realtime_result_processor == nullptr || raw_stream_id == nullptr) {
ALOGE(
"%s: realtime_process_block(%p) or realtime_result_processor(%p) or "
"raw_stream_id(%p) is nullptr",
__FUNCTION__, realtime_process_block, realtime_result_processor,
raw_stream_id);
return BAD_VALUE;
}
// Create realtime process block.
auto process_block = RealtimeProcessBlock::Create(device_session_hwl_);
if (process_block == nullptr) {
ALOGE("%s: Creating RealtimeProcessBlock failed.", __FUNCTION__);
return UNKNOWN_ERROR;
}
// Create realtime request processor.
request_processor_ = RealtimeZslRequestProcessor::Create(
device_session_hwl_, HAL_PIXEL_FORMAT_RAW10);
if (request_processor_ == nullptr) {
ALOGE("%s: Creating RealtimeZslsRequestProcessor failed.", __FUNCTION__);
return UNKNOWN_ERROR;
}
status_t res = ConfigureStreams(stream_config, request_processor_.get(),
process_block.get(), raw_stream_id);
if (res != OK) {
ALOGE("%s: Configuring stream failed: %s(%d)", __FUNCTION__, strerror(-res),
res);
return res;
}
// Create realtime result processor.
auto result_processor = RealtimeZslResultProcessor::Create(
internal_stream_manager_.get(), *raw_stream_id, HAL_PIXEL_FORMAT_RAW10);
if (result_processor == nullptr) {
ALOGE("%s: Creating RealtimeZslResultProcessor failed.", __FUNCTION__);
return UNKNOWN_ERROR;
}
result_processor->SetResultCallback(process_capture_result, notify);
*realtime_process_block = std::move(process_block);
*realtime_result_processor = std::move(result_processor);
return OK;
}
status_t HdrplusCaptureSession::SetupHdrplusProcessChain(
const StreamConfiguration& stream_config,
ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
std::unique_ptr<ProcessBlock>* hdrplus_process_block,
std::unique_ptr<ResultProcessor>* hdrplus_result_processor,
int32_t raw_stream_id) {
ATRACE_CALL();
if (hdrplus_process_block == nullptr || hdrplus_result_processor == nullptr) {
ALOGE(
"%s: hdrplus_process_block(%p) or hdrplus_result_processor(%p) is "
"nullptr",
__FUNCTION__, hdrplus_process_block, hdrplus_result_processor);
return BAD_VALUE;
}
// Create hdrplus process block.
auto process_block = HdrplusProcessBlock::Create(
device_session_hwl_, device_session_hwl_->GetCameraId());
if (process_block == nullptr) {
ALOGE("%s: Creating HdrplusProcessBlock failed.", __FUNCTION__);
return UNKNOWN_ERROR;
}
// Create hdrplus request processor.
hdrplus_request_processor_ = HdrplusRequestProcessor::Create(
device_session_hwl_, raw_stream_id, device_session_hwl_->GetCameraId());
if (hdrplus_request_processor_ == nullptr) {
ALOGE("%s: Creating HdrplusRequestProcessor failed.", __FUNCTION__);
return UNKNOWN_ERROR;
}
// Create hdrplus result processor.
auto result_processor = HdrplusResultProcessor::Create(
internal_stream_manager_.get(), raw_stream_id);
if (result_processor == nullptr) {
ALOGE("%s: Creating HdrplusResultProcessor failed.", __FUNCTION__);
return UNKNOWN_ERROR;
}
result_processor->SetResultCallback(process_capture_result, notify);
status_t res = ConfigureHdrplusStreams(
stream_config, hdrplus_request_processor_.get(), process_block.get());
if (res != OK) {
ALOGE("%s: Configuring hdrplus stream failed: %s(%d)", __FUNCTION__,
strerror(-res), res);
return res;
}
*hdrplus_process_block = std::move(process_block);
*hdrplus_result_processor = std::move(result_processor);
return OK;
}
status_t HdrplusCaptureSession::Initialize(
CameraDeviceSessionHwl* device_session_hwl,
const StreamConfiguration& stream_config,
ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
std::vector<HalStream>* hal_configured_streams) {
ATRACE_CALL();
if (!IsStreamConfigurationSupported(device_session_hwl, stream_config)) {
ALOGE("%s: stream configuration is not supported.", __FUNCTION__);
return BAD_VALUE;
}
std::unique_ptr<HalCameraMetadata> characteristics;
status_t res = device_session_hwl->GetCameraCharacteristics(&characteristics);
if (res != OK) {
ALOGE("%s: GetCameraCharacteristics failed.", __FUNCTION__);
return BAD_VALUE;
}
camera_metadata_ro_entry entry;
res = characteristics->Get(VendorTagIds::kHdrUsageMode, &entry);
if (res == OK) {
hdr_mode_ = static_cast<HdrMode>(entry.data.u8[0]);
}
for (auto stream : stream_config.streams) {
if (utils::IsPreviewStream(stream)) {
hal_preview_stream_id_ = stream.id;
break;
}
}
device_session_hwl_ = device_session_hwl;
internal_stream_manager_ = InternalStreamManager::Create();
if (internal_stream_manager_ == nullptr) {
ALOGE("%s: Cannot create internal stream manager.", __FUNCTION__);
return UNKNOWN_ERROR;
}
// Create result dispatcher
result_dispatcher_ = ResultDispatcher::Create(
kPartialResult, process_capture_result, notify, "HdrplusDispatcher");
if (result_dispatcher_ == nullptr) {
ALOGE("%s: Cannot create result dispatcher.", __FUNCTION__);
return UNKNOWN_ERROR;
}
device_session_notify_ = notify;
process_capture_result_ =
ProcessCaptureResultFunc([this](std::unique_ptr<CaptureResult> result) {
ProcessCaptureResult(std::move(result));
});
notify_ = NotifyFunc(
[this](const NotifyMessage& message) { NotifyHalMessage(message); });
// Setup realtime process chain
int32_t raw_stream_id = -1;
std::unique_ptr<ProcessBlock> realtime_process_block;
std::unique_ptr<ResultProcessor> realtime_result_processor;
res = SetupRealtimeProcessChain(stream_config, process_capture_result_,
notify_, &realtime_process_block,
&realtime_result_processor, &raw_stream_id);
if (res != OK) {
ALOGE("%s: SetupRealtimeProcessChain fail: %s(%d)", __FUNCTION__,
strerror(-res), res);
return res;
}
// Setup hdrplus process chain
std::unique_ptr<ProcessBlock> hdrplus_process_block;
std::unique_ptr<ResultProcessor> hdrplus_result_processor;
res = SetupHdrplusProcessChain(stream_config, process_capture_result_,
notify_, &hdrplus_process_block,
&hdrplus_result_processor, raw_stream_id);
if (res != OK) {
ALOGE("%s: SetupHdrplusProcessChain fail: %s(%d)", __FUNCTION__,
strerror(-res), res);
return res;
}
// Realtime and HDR+ streams are configured
// Start to build pipleline
res = BuildPipelines(realtime_process_block.get(),
hdrplus_process_block.get(), hal_configured_streams);
if (res != OK) {
ALOGE("%s: Building pipelines failed: %s(%d)", __FUNCTION__, strerror(-res),
res);
return res;
}
res = PurgeHalConfiguredStream(stream_config, hal_configured_streams);
if (res != OK) {
ALOGE("%s: Removing internal streams from configured stream failed: %s(%d)",
__FUNCTION__, strerror(-res), res);
return res;
}
// Connect realtime process chain
res = ConnectProcessChain(request_processor_.get(),
std::move(realtime_process_block),
std::move(realtime_result_processor));
if (res != OK) {
ALOGE("%s: Connecting process chain failed: %s(%d)", __FUNCTION__,
strerror(-res), res);
return res;
}
// Connect HDR+ process chain
res = ConnectProcessChain(hdrplus_request_processor_.get(),
std::move(hdrplus_process_block),
std::move(hdrplus_result_processor));
if (res != OK) {
ALOGE("%s: Connecting HDR+ process chain failed: %s(%d)", __FUNCTION__,
strerror(-res), res);
return res;
}
return OK;
}
status_t HdrplusCaptureSession::ProcessRequest(const CaptureRequest& request) {
ATRACE_CALL();
bool is_hdrplus_request =
hal_utils::IsRequestHdrplusCompatible(request, hal_preview_stream_id_);
status_t res = result_dispatcher_->AddPendingRequest(request);
if (res != OK) {
ALOGE("%s: frame(%d) fail to AddPendingRequest", __FUNCTION__,
request.frame_number);
return BAD_VALUE;
}
if (is_hdrplus_request) {
ALOGI("%s: hdrplus snapshot (%d), output stream size:%zu", __FUNCTION__,
request.frame_number, request.output_buffers.size());
res = hdrplus_request_processor_->ProcessRequest(request);
if (res != OK) {
ALOGI("%s: hdrplus snapshot frame(%d) request to realtime process",
__FUNCTION__, request.frame_number);
res = request_processor_->ProcessRequest(request);
}
} else {
res = request_processor_->ProcessRequest(request);
}
if (res != OK) {
ALOGE("%s: ProcessRequest (%d) fail and remove pending request",
__FUNCTION__, request.frame_number);
result_dispatcher_->RemovePendingRequest(request.frame_number);
}
return res;
}
status_t HdrplusCaptureSession::Flush() {
ATRACE_CALL();
return request_processor_->Flush();
}
void HdrplusCaptureSession::ProcessCaptureResult(
std::unique_ptr<CaptureResult> result) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(callback_lock_);
if (result == nullptr) {
return;
}
if (result->result_metadata && hdr_mode_ != HdrMode::kHdrplusMode) {
device_session_hwl_->FilterResultMetadata(result->result_metadata.get());
}
status_t res = result_dispatcher_->AddResult(std::move(result));
if (res != OK) {
ALOGE("%s: fail to AddResult", __FUNCTION__);
return;
}
}
status_t HdrplusCaptureSession::PurgeHalConfiguredStream(
const StreamConfiguration& stream_config,
std::vector<HalStream>* hal_configured_streams) {
if (hal_configured_streams == nullptr) {
ALOGE("%s: HAL configured stream list is null.", __FUNCTION__);
return BAD_VALUE;
}
std::set<int32_t> framework_stream_id_set;
for (auto& stream : stream_config.streams) {
framework_stream_id_set.insert(stream.id);
}
std::vector<HalStream> configured_streams;
for (auto& hal_stream : *hal_configured_streams) {
if (framework_stream_id_set.find(hal_stream.id) !=
framework_stream_id_set.end()) {
configured_streams.push_back(hal_stream);
}
}
*hal_configured_streams = configured_streams;
return OK;
}
void HdrplusCaptureSession::NotifyHalMessage(const NotifyMessage& message) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(callback_lock_);
if (device_session_notify_ == nullptr) {
ALOGE("%s: device_session_notify_ is nullptr. Dropping a message.",
__FUNCTION__);
return;
}
if (message.type == MessageType::kShutter) {
status_t res = result_dispatcher_->AddShutter(
message.message.shutter.frame_number,
message.message.shutter.timestamp_ns,
message.message.shutter.readout_timestamp_ns);
if (res != OK) {
ALOGE("%s: AddShutter for frame %u failed: %s (%d).", __FUNCTION__,
message.message.shutter.frame_number, strerror(-res), res);
return;
}
} else if (message.type == MessageType::kError) {
status_t res = result_dispatcher_->AddError(message.message.error);
if (res != OK) {
ALOGE("%s: AddError for frame %u failed: %s (%d).", __FUNCTION__,
message.message.error.frame_number, strerror(-res), res);
return;
}
} else {
ALOGW("%s: Unsupported message type: %u", __FUNCTION__, message.type);
device_session_notify_(message);
}
}
} // namespace google_camera_hal
} // namespace android