blob: 7f553adf4d7c73a2d08fc904fa0b079533c64d5f [file] [log] [blame] [edit]
/*
* Copyright 2021 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef CAMERA_COMMON_CAMERA_HAL3_HELPERS_H_
#define CAMERA_COMMON_CAMERA_HAL3_HELPERS_H_
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <cutils/native_handle.h>
#include <base/containers/span.h>
#include <base/synchronization/lock.h>
#include <camera/camera_metadata.h>
#include <hardware/camera3.h>
#include "cros-camera/camera_face_detection.h"
#include "cros-camera/common.h"
#include "cros-camera/common_types.h"
#include "cros-camera/export.h"
namespace perfetto {
// Forward declaring perfetto::EventContext instead of including the perfetto
// header file to avoid macro/variable definitions collisions between libchrome
// and perfetto.
class EventContext;
} // namespace perfetto
namespace cros {
// The still capture usage flag is used inside camera service to distinguish the
// YUV streams for still capture from theose for preview or video.
constexpr uint32_t kStillCaptureUsageFlag = GRALLOC_USAGE_PRIVATE_1;
// Types of effects that can be applied to the camera stream.
enum StreamEffectType {
kDefault = 0,
kPortraitMode = 1,
};
// Generic base struct for stream effect. Used by StreamEffectMap.
struct StreamEffect {
StreamEffectType type = StreamEffectType::kDefault;
};
struct PortraitModeStreamEffect : public StreamEffect {
bool enable_rectiface = false;
};
// A mapper from a camera3_stream_t pointer to a vector of StreamEffect objects.
// This is used to pass the effects information that is applied to each stream.
using StreamEffectMap =
std::map<const camera3_stream_t*,
std::vector<std::unique_ptr<const StreamEffect>>>;
// Utility function to produce a debug string for the given camera3_stream_t
// |stream|.
inline std::string GetDebugString(const camera3_stream_t* stream) {
return base::StringPrintf(
"stream=%p, type=%d, size=%ux%u, format=%d, usage=0x%x, max_buffers=%u, "
"rotation=%d, crop_rotate_scale_degrees=%d",
stream, stream->stream_type, stream->width, stream->height,
stream->format, stream->usage, stream->max_buffers, stream->rotation,
stream->crop_rotate_scale_degrees);
}
inline bool HaveSameAspectRatio(const camera3_stream_t* s1,
const camera3_stream_t* s2) {
return (s1->width * s2->height == s1->height * s2->width);
}
template <typename T>
inline Rect<float> NormalizeRect(const Rect<T>& rect, const Size& size) {
return Rect<float>(
static_cast<float>(rect.left) / static_cast<float>(size.width),
static_cast<float>(rect.top) / static_cast<float>(size.height),
static_cast<float>(rect.width) / static_cast<float>(size.width),
static_cast<float>(rect.height) / static_cast<float>(size.height));
}
template <typename T>
inline Rect<T> ClampRect(const Rect<T>& rect, const Rect<T>& bound) {
const T left = std::clamp(rect.left, bound.left, bound.right());
const T top = std::clamp(rect.top, bound.top, bound.bottom());
const T right = std::clamp(rect.right(), bound.left, bound.right());
const T bottom = std::clamp(rect.bottom(), bound.top, bound.bottom());
return Rect<T>(left, top, right - left + 1, bottom - top + 1);
}
// Returns the maximum centering crop window within |size| with the specified
// aspect ratio.
CROS_CAMERA_EXPORT Rect<uint32_t> GetCenteringFullCrop(Size size,
uint32_t aspect_ratio_x,
uint32_t aspect_ratio_y);
bool AddListItemToMetadataTag(android::CameraMetadata* metadata,
uint32_t tag,
int32_t item);
// Waits on |buffer.release_fence|, if valid, to be signalled with timeout
// |timeout_ms|. Returns true if the release fence is invalid (i.e. equals to
// -1), or if the fence is signalled within |timeout_ms|. Returns false
// otherwise.
//
// |buffer.release_fence| is closed and resets it to -1 on success. The function
// leaves |buffer.release_fence| untouched if the fence wait times out.
[[nodiscard]] bool CROS_CAMERA_EXPORT
WaitOnAndClearReleaseFence(camera3_stream_buffer_t& buffer, int timeout_ms);
// Extracts frame number from a notify message.
inline uint32_t GetFrameNumber(const camera3_notify_msg_t& msg) {
switch (msg.type) {
case CAMERA3_MSG_ERROR:
return msg.message.error.frame_number;
case CAMERA3_MSG_SHUTTER:
return msg.message.shutter.frame_number;
default:
NOTREACHED();
return 0u;
}
}
inline void SetStillCaptureUsage(camera3_stream* stream) {
stream->usage |= kStillCaptureUsageFlag;
}
// Returns ANDROID_REQUEST_PARTIAL_RESULT_COUNT value if exists.
// Returns 1 (default) otherwise.
CROS_CAMERA_EXPORT int32_t
GetPartialResultCount(const camera_metadata_t* metadata);
// A container for passing metadata across different StreamManipulator instances
// to allow different feature implementations to communicate with one another.
struct FeatureMetadata {
// |hdr_ratio| produced by GcamAeStreamManipulator and consumed by
// HdrNetStreamManipulator for HDRnet output frame rendering.
std::optional<float> hdr_ratio;
// The face rectangles detected by the FaceDetectionStreamManipulator when
// CrOS face detector is enabled. The coordinates of the rectangles are
// normalized with respect to the active sensor array size. The face ROIs are
// consumed by GcamAeStreamManipulator as input metadata.
std::optional<std::vector<human_sensing::CrosFace>> faces;
};
// A helper class that wraps a camera3_stream_buffer_t object to facilitate
// event tracing and simplify data access.
//
// The class does not take ownership of any of the resources in the input
// camera3_stream_buffer_t object. Specifically, the owner of the raw buffer
// object is responsible for managing the acquire and release fence FDs, either
// by passing on the ownership to the camera client or camera HAL, or closing
// the fence FD before setting a new one.
class CROS_CAMERA_EXPORT Camera3StreamBuffer {
public:
// The flow direction of the buffer. A buffer is either an input buffer from
// the upper layer, or an output buffer that needs to be filled by the lower
// layer.
enum class Direction {
kInvalidDirection = -1,
kInput = 0,
kOutput = 1,
};
// The type of the buffer. A buffer should either be associated with a capture
// request or a capture result.
enum class Type {
kInvalidType = -1,
kRequest = 0,
kResult = 1,
};
static constexpr camera3_stream_buffer_t kInvalidRawBuffer = {
.stream = nullptr,
.buffer = nullptr,
.status = CAMERA3_BUFFER_STATUS_ERROR,
.acquire_fence = -1,
.release_fence = -1,
};
static Camera3StreamBuffer MakeRequestInput(
const camera3_stream_buffer_t& stream_buffer);
static Camera3StreamBuffer MakeRequestOutput(
const camera3_stream_buffer_t& stream_buffer);
static Camera3StreamBuffer MakeResultInput(
const camera3_stream_buffer_t& stream_buffer);
static Camera3StreamBuffer MakeResultOutput(
const camera3_stream_buffer_t& stream_buffer);
// Default constructor creates an invalid buffer.
Camera3StreamBuffer() = default;
~Camera3StreamBuffer();
Camera3StreamBuffer(Camera3StreamBuffer&& other);
Camera3StreamBuffer& operator=(Camera3StreamBuffer&& other);
Camera3StreamBuffer(const Camera3StreamBuffer& other) = delete;
Camera3StreamBuffer& operator=(const Camera3StreamBuffer& other) = delete;
// Invalidates the wrapper and drops references to all buffer resources.
void Invalidate();
// See the docstring of WaitOnAndClearReleaseFence above.
[[nodiscard]] bool WaitOnAndClearReleaseFence(int timeout_ms) {
return cros::WaitOnAndClearReleaseFence(raw_buffer_, timeout_ms);
}
// Starts and ends a trace slice that associates the buffer with
// |frame_number|.
void StartTracing(int frame_number);
void EndTracing();
// Used for creating a Perfetto flow to visualize the buffer lifecycle.
uint64_t flow_id() const { return reinterpret_cast<uintptr_t>(*buffer()); }
bool is_valid() const {
return raw_buffer_.stream != nullptr && raw_buffer_.buffer != nullptr &&
*raw_buffer_.buffer != nullptr;
}
const camera3_stream_t* stream() const { return raw_buffer_.stream; }
const buffer_handle_t* buffer() const { return raw_buffer_.buffer; }
int status() const { return raw_buffer_.status; }
int acquire_fence() const { return raw_buffer_.acquire_fence; }
int release_fence() const { return raw_buffer_.release_fence; }
int take_acquire_fence() {
int fence = raw_buffer_.acquire_fence;
raw_buffer_.acquire_fence = -1;
return fence;
}
int take_release_fence() {
int fence = raw_buffer_.release_fence;
raw_buffer_.release_fence = -1;
return fence;
}
const camera3_stream_buffer_t& raw_buffer() const { return raw_buffer_; }
camera3_stream_buffer_t& mutable_raw_buffer() { return raw_buffer_; }
protected:
// LockAndFill is called only by the Camera3CaptureDescriptor to expose the
// input and output buffers in raw capture requests/results. Since the raw
// buffer states can be modified, we sync |container| back to |raw_buffer_| in
// Unlock.
friend class Camera3CaptureDescriptor;
void LockAndFill(camera3_stream_buffer_t* container);
void Unlock();
private:
Camera3StreamBuffer(const camera3_stream_buffer_t& stream_buffer,
Type type,
Direction dir);
camera3_stream_buffer_t raw_buffer_ = kInvalidRawBuffer;
Type type_ = Type::kInvalidType;
Direction dir_ = Direction::kInvalidDirection;
camera3_stream_buffer_t* lock_container_ = nullptr;
bool trace_started_ = false;
};
// A helper class to make it easy to modify camera3_stream_configuration_t.
//
// The class is not thread-safe. The user of this class needs to ensure that the
// method calls are serialized and also that the class instance remains valid
// when the data members are being referenced externally.
class CROS_CAMERA_EXPORT Camera3StreamConfiguration {
public:
// Default constructor creates an invalid instance.
Camera3StreamConfiguration() = default;
explicit Camera3StreamConfiguration(
const camera3_stream_configuration_t& stream_list,
const StreamEffectMap* stream_effects_map = nullptr);
~Camera3StreamConfiguration() = default;
Camera3StreamConfiguration(Camera3StreamConfiguration&& other) = default;
Camera3StreamConfiguration& operator=(Camera3StreamConfiguration&& other) =
default;
Camera3StreamConfiguration(const Camera3StreamConfiguration& other) = delete;
Camera3StreamConfiguration& operator=(
const Camera3StreamConfiguration& other) = delete;
// Gets the stream configuration in a span.
base::span<camera3_stream_t* const> GetStreams() const;
// Sets the stream configuration to |streams|.
bool SetStreams(base::span<camera3_stream_t* const> streams);
// Appends |stream| to the stream configuration.
bool AppendStream(camera3_stream_t* stream);
// Removes |stream| from the stream configuration.
bool RemoveStream(const camera3_stream_t* stream);
// Sets the updated session parameters.
bool SetSessionParameters(const camera_metadata_t* session_parameters);
// Locks the internal data and get the camera3_stream_configuration_t that can
// be consumed by the Android HAL3 API.
camera3_stream_configuration_t* Lock();
// Unlocks the instance for further modification.
void Unlock();
// Returns a JSON string describing the stream configurations.
std::string ToJsonString() const;
// Populates the given event context with the stream info debug annotation.
void PopulateEventAnnotation(perfetto::EventContext& ctx) const;
bool is_valid() const { return !streams_.empty(); }
uint32_t num_streams() const { return streams_.size(); }
uint32_t operation_mode() const { return operation_mode_; }
const camera_metadata_t* session_parameters() const {
return session_parameters_;
}
const StreamEffectMap* stream_effects_map() const {
return stream_effects_map_;
}
private:
bool IsLocked() const;
std::vector<camera3_stream_t*> streams_;
uint32_t operation_mode_ = 0;
const camera_metadata_t* session_parameters_ = nullptr;
std::optional<camera3_stream_configuration_t> raw_configuration_;
const StreamEffectMap* stream_effects_map_ = nullptr;
};
// A helper class to make it easy to modify camera3_capture_request_t and
// camera3_capture_result_t objects.
//
// The class is not thread-safe. The user of this class needs to ensure that the
// method calls are serialized and also that the class instance remains valid
// when the data members are being referenced externally.
class CROS_CAMERA_EXPORT Camera3CaptureDescriptor {
public:
enum class Type {
kInvalidType = -1,
kCaptureRequest,
kCaptureResult,
};
// Default constructor creates an invalid instance.
Camera3CaptureDescriptor() = default;
explicit Camera3CaptureDescriptor(const camera3_capture_request_t& request);
explicit Camera3CaptureDescriptor(const camera3_capture_result_t& result);
~Camera3CaptureDescriptor();
Camera3CaptureDescriptor(Camera3CaptureDescriptor&& other);
Camera3CaptureDescriptor& operator=(Camera3CaptureDescriptor&& other);
Camera3CaptureDescriptor(const Camera3CaptureDescriptor& other) = delete;
Camera3CaptureDescriptor& operator=(const Camera3CaptureDescriptor& other) =
delete;
// Metadata getter and setter. The templated methods only support the six data
// types defined for Android camera_metadata_entry_t: uint8_t, int32_t, float,
// double, int64_t, camera_metadata_rational_t.
// Check the metadata exists with |tag|.
bool HasMetadata(uint32_t tag) const;
// Gets the metadata associated with |tag| as span. Returns empty span if
// there's no metadata associated with |tag|.
template <typename T>
base::span<const T> GetMetadata(uint32_t tag) const;
// Updates, and creates if not exist, the metadata associated with |tag| with
// |values|. Returns true if the metadata is successfully updated; false
// otherwise.
template <typename T>
bool UpdateMetadata(uint32_t tag, base::span<const T> values) {
if (IsLocked()) {
LOGF(ERROR) << "Cannot update metadata when locked";
return false;
}
auto ret = metadata_.update(tag, values.data(), values.size());
return ret == 0;
}
// Appends |metadata| to |metadata_|. Returns true if |metadata| is
// successfully appended; false otherwise.
bool AppendMetadata(const camera_metadata_t* metadata);
// Deletes the metadata associated with |tag|. Returns true if the metadata is
// successfully deleted; false otherwise.
bool DeleteMetadata(uint32_t tag);
// Sets the existing metadata by copying the contents from |metadata|.
// Returns true if the metadata are set successfully; false otherwise.
bool SetMetadata(const camera_metadata_t* metadata);
// Releases the metadata to the caller.
android::CameraMetadata ReleaseMetadata();
// Sets the partial result number.
void SetPartialResult(uint32_t partial_result);
// Getter and setter for the input buffer.
const Camera3StreamBuffer* GetInputBuffer() const;
std::optional<Camera3StreamBuffer> AcquireInputBuffer();
void SetInputBuffer(Camera3StreamBuffer input_buffer);
// Getter and setter for the output buffers.
base::span<const Camera3StreamBuffer> GetOutputBuffers() const;
base::span<Camera3StreamBuffer> GetMutableOutputBuffers();
std::vector<Camera3StreamBuffer> AcquireOutputBuffers();
void SetOutputBuffers(std::vector<Camera3StreamBuffer> output_buffers);
void AppendOutputBuffer(Camera3StreamBuffer buffer);
// Locks the internal data and get the raw camera3_capture_request_t /
// camera3_capture_result_t that can be consumed by the Android HAL3 API.
const camera3_capture_request_t* LockForRequest();
const camera3_capture_result_t* LockForResult();
const camera3_capture_request_t* GetLockedRequest();
const camera3_capture_result_t* GetLockedResult();
// Unlocks the descriptor for further modification.
void Unlock();
// Returns a JSON string describing the capture request / result.
std::string ToJsonString() const;
// Populates the given event context with the capture info debug annotation.
void PopulateEventAnnotation(perfetto::EventContext& ctx) const;
bool is_empty() const {
return !has_metadata() && !has_input_buffer() && partial_result() == 0 &&
num_output_buffers() == 0;
}
bool is_valid() const { return type_ != Type::kInvalidType; }
uint32_t frame_number() const { return frame_number_; }
bool has_metadata() const { return !metadata_.isEmpty(); }
const android::CameraMetadata& metadata() const { return metadata_; }
android::CameraMetadata& mutable_metadata() { return metadata_; }
bool has_input_buffer() const { return input_buffer_.has_value(); }
uint32_t num_output_buffers() const { return output_buffers_.size(); }
uint32_t partial_result() const { return partial_result_; }
uint32_t num_physcam_metadata() const { return num_physcam_metadata_; }
const char** physcam_ids() const { return physcam_ids_; }
const camera_metadata_t** physcam_metadata() const {
return physcam_metadata_;
}
FeatureMetadata& feature_metadata() { return feature_metadata_; }
const FeatureMetadata& feature_metadata() const { return feature_metadata_; }
protected:
void Invalidate();
bool IsLocked() const;
Type type_ = Type::kInvalidType;
// Flattened data for both kCaptureRequest and kCaptureResult.
uint32_t frame_number_ = 0;
android::CameraMetadata metadata_;
std::optional<Camera3StreamBuffer> input_buffer_;
std::vector<Camera3StreamBuffer> output_buffers_;
// For kCaptureResult only.
uint32_t partial_result_ = 0;
// The physical camera info are not being active used at the moment, so we
// just use these fields to keep track of the original values.
uint32_t num_physcam_metadata_ = 0;
const char** physcam_ids_ = nullptr;
const camera_metadata_t** physcam_metadata_ = nullptr;
FeatureMetadata feature_metadata_;
union RawDescriptor {
camera3_capture_request_t raw_request;
camera3_capture_result_t raw_result;
};
std::vector<camera3_stream_buffer_t> raw_output_buffers_;
std::optional<RawDescriptor> raw_descriptor_;
};
template <>
CROS_CAMERA_EXPORT base::span<const uint8_t>
Camera3CaptureDescriptor::GetMetadata(uint32_t tag) const;
template <>
CROS_CAMERA_EXPORT base::span<const int32_t>
Camera3CaptureDescriptor::GetMetadata(uint32_t tag) const;
template <>
CROS_CAMERA_EXPORT base::span<const float>
Camera3CaptureDescriptor::GetMetadata(uint32_t tag) const;
template <>
CROS_CAMERA_EXPORT base::span<const double>
Camera3CaptureDescriptor::GetMetadata(uint32_t tag) const;
template <>
CROS_CAMERA_EXPORT base::span<const int64_t>
Camera3CaptureDescriptor::GetMetadata(uint32_t tag) const;
template <>
CROS_CAMERA_EXPORT base::span<const camera_metadata_rational_t>
Camera3CaptureDescriptor::GetMetadata(uint32_t tag) const;
} // namespace cros
#endif // CAMERA_COMMON_CAMERA_HAL3_HELPERS_H_