android: camera_device: Initialize stream configuration

Initialize the stream configuration map by applying the Android Camera3
requested resolutions and formats to the libcamera Camera device.

For each required format test a list of required and optional
resolutions, construct a map to translate from Android format to the
libcamera formats and store the available stream configuration to
be provided to the Android framework through static metadata.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
This commit is contained in:
Jacopo Mondi 2020-05-23 18:53:54 +02:00
parent cd1f258af9
commit 117588b371
2 changed files with 235 additions and 0 deletions

View file

@ -8,6 +8,8 @@
#include "camera_device.h"
#include "camera_ops.h"
#include <vector>
#include <libcamera/controls.h>
#include <libcamera/property_ids.h>
@ -15,9 +17,71 @@
#include "libcamera/internal/utils.h"
#include "camera_metadata.h"
#include "system/graphics.h"
using namespace libcamera;
namespace {
/*
* \var camera3Resolutions
* \brief The list of image resolutions defined as mandatory to be supported by
* the Android Camera3 specification
*/
const std::vector<Size> camera3Resolutions = {
{ 320, 240 },
{ 640, 480 },
{ 1280, 720 },
{ 1920, 1080 }
};
/*
* \struct Camera3Format
* \brief Data associated with an Android format identifier
* \var libcameraFormats List of libcamera pixel formats compatible with the
* Android format
* \var scalerFormat The format identifier to be reported to the android
* framework through the static format configuration map
* \var name The human-readable representation of the Android format code
*/
struct Camera3Format {
std::vector<PixelFormat> libcameraFormats;
camera_metadata_enum_android_scaler_available_formats_t scalerFormat;
const char *name;
};
/*
* \var camera3FormatsMap
* \brief Associate Android format code with ancillary data
*/
const std::map<int, const Camera3Format> camera3FormatsMap = {
{
HAL_PIXEL_FORMAT_BLOB, {
{ PixelFormat(DRM_FORMAT_MJPEG) },
ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
"BLOB"
}
}, {
HAL_PIXEL_FORMAT_YCbCr_420_888, {
{ PixelFormat(DRM_FORMAT_NV12), PixelFormat(DRM_FORMAT_NV21) },
ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
"YCbCr_420_888"
}
}, {
/*
* \todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc
* usage flag. For now, copy the YCbCr_420 configuration.
*/
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {
{ PixelFormat(DRM_FORMAT_NV12), PixelFormat(DRM_FORMAT_NV21) },
ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
"IMPLEMENTATION_DEFINED"
}
},
};
} /* namespace */
LOG_DECLARE_CATEGORY(HAL);
/*
@ -100,6 +164,165 @@ int CameraDevice::initialize()
if (properties.contains(properties::Rotation))
orientation_ = properties.get(properties::Rotation);
int ret = camera_->acquire();
if (ret) {
LOG(HAL, Error) << "Failed to temporarily acquire the camera";
return ret;
}
ret = initializeStreamConfigurations();
camera_->release();
return ret;
}
/*
* Initialize the format conversion map to translate from Android format
* identifier to libcamera pixel formats and fill in the list of supported
* stream configurations to be reported to the Android camera framework through
* the static stream configuration metadata.
*/
int CameraDevice::initializeStreamConfigurations()
{
/*
* Get the maximum output resolutions
* \todo Get this from the camera properties once defined
*/
std::unique_ptr<CameraConfiguration> cameraConfig =
camera_->generateConfiguration({ StillCapture });
if (!cameraConfig) {
LOG(HAL, Error) << "Failed to get maximum resolution";
return -EINVAL;
}
StreamConfiguration &cfg = cameraConfig->at(0);
/*
* \todo JPEG - Adjust the maximum available resolution by taking the
* JPEG encoder requirements into account (alignment and aspect ratio).
*/
const Size maxRes = cfg.size;
LOG(HAL, Debug) << "Maximum supported resolution: " << maxRes.toString();
/*
* Build the list of supported image resolutions.
*
* The resolutions listed in camera3Resolution are mandatory to be
* supported, up to the camera maximum resolution.
*
* Augment the list by adding resolutions calculated from the camera
* maximum one.
*/
std::vector<Size> cameraResolutions;
std::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),
std::back_inserter(cameraResolutions),
[&](const Size &res) { return res < maxRes; });
/*
* The Camera3 specification suggests adding 1/2 and 1/4 of the maximum
* resolution.
*/
for (unsigned int divider = 2;; divider <<= 1) {
Size derivedSize{
maxRes.width / divider,
maxRes.height / divider,
};
if (derivedSize.width < 320 ||
derivedSize.height < 240)
break;
cameraResolutions.push_back(derivedSize);
}
cameraResolutions.push_back(maxRes);
/* Remove duplicated entries from the list of supported resolutions. */
std::sort(cameraResolutions.begin(), cameraResolutions.end());
auto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());
cameraResolutions.erase(last, cameraResolutions.end());
/*
* Build the list of supported camera formats.
*
* To each Android format a list of compatible libcamera formats is
* associated. The first libcamera format that tests successful is added
* to the format translation map used when configuring the streams.
* It is then tested against the list of supported camera resolutions to
* build the stream configuration map reported through the camera static
* metadata.
*/
for (const auto &format : camera3FormatsMap) {
int androidFormat = format.first;
const Camera3Format &camera3Format = format.second;
const std::vector<PixelFormat> &libcameraFormats =
camera3Format.libcameraFormats;
/*
* Test the libcamera formats that can produce images
* compatible with the format defined by Android.
*/
PixelFormat mappedFormat;
for (const PixelFormat &pixelFormat : libcameraFormats) {
/* \todo Fixed mapping for JPEG. */
if (androidFormat == HAL_PIXEL_FORMAT_BLOB) {
mappedFormat = PixelFormat(DRM_FORMAT_MJPEG);
break;
}
/*
* The stream configuration size can be adjusted,
* not the pixel format.
*
* \todo This could be simplified once all pipeline
* handlers will report the StreamFormats list of
* supported formats.
*/
cfg.pixelFormat = pixelFormat;
CameraConfiguration::Status status = cameraConfig->validate();
if (status != CameraConfiguration::Invalid &&
cfg.pixelFormat == pixelFormat) {
mappedFormat = pixelFormat;
break;
}
}
if (!mappedFormat.isValid()) {
LOG(HAL, Error) << "Failed to map Android format "
<< camera3Format.name << " ("
<< utils::hex(androidFormat) << ")";
return -EINVAL;
}
/*
* Record the mapping and then proceed to generate the
* stream configurations map, by testing the image resolutions.
*/
formatsMap_[androidFormat] = mappedFormat;
for (const Size &res : cameraResolutions) {
cfg.pixelFormat = mappedFormat;
cfg.size = res;
CameraConfiguration::Status status = cameraConfig->validate();
/*
* Unconditionally report we can produce JPEG.
*
* \todo The JPEG stream will be implemented as an
* HAL-only stream, but some cameras can produce it
* directly. As of now, claim support for JPEG without
* inspecting where the JPEG stream is produced.
*/
if (androidFormat != HAL_PIXEL_FORMAT_BLOB &&
status != CameraConfiguration::Valid)
continue;
streamConfigurations_.push_back({ res, camera3Format.scalerFormat });
}
}
LOG(HAL, Debug) << "Collected stream configuration map: ";
for (const auto &entry : streamConfigurations_)
LOG(HAL, Debug) << "{ " << entry.resolution.toString() << " - "
<< utils::hex(entry.androidScalerCode) << " }";
return 0;
}