Files
motion/src/libcam.cpp
2023-10-20 17:12:24 -06:00

858 lines
29 KiB
C++

/*
* This file is part of MotionPlus.
*
* MotionPlus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MotionPlus is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MotionPlus. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright 2020-2023 MotionMrDave@gmail.com
*
*/
/* TODO:
* Determine if we need to have multiple requests or buffers.
* (The current logic is just a single request and buffer but
* this may need to change to allow for multiple requests or buffers
* so as to reduce latency. As of now, it is kept simple with
* a single request and buffer.)
* Need to determine flags for designating start up, shutdown
* etc. and possibly add mutex locking. Startup currently has
* a SLEEP to allow for initialization but this should change
*/
#include "motionplus.hpp"
#include "conf.hpp"
#include "logger.hpp"
#include "util.hpp"
#include "rotate.hpp"
#include "video_common.hpp"
#include "libcam.hpp"
#ifdef HAVE_LIBCAM
using namespace libcamera;
bool cls_libcam::cam_parm_bool(char *parm)
{
if (mystrceq(parm,"1") || mystrceq(parm,"yes") || mystrceq(parm,"on") || mystrceq(parm,"true") ) {
return true;
} else {
return false;
}
}
float cls_libcam::cam_parm_single(char *parm)
{
return (float)atof(parm);
}
void cls_libcam:: cam_log_transform()
{
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, "Libcamera Transform Options:");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Identity");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Rot0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " HFlip");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " VFlip");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " HVFlip");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Rot180");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Transpose");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Rot270");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Rot90");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Rot180Transpose");
}
void cls_libcam:: cam_log_controls()
{
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, "Libcamera Controls:");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeEnable(bool)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeLocked(bool)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeMeteringMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " MeteringCentreWeighted = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " MeteringSpot = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " MeteringMatrix = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " MeteringCustom = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeConstraintMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ConstraintNormal = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ConstraintHighlight = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ConstraintShadows = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ConstraintCustom = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeExposureMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ExposureNormal = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ExposureShort = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ExposureLong = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ExposureCustom = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ExposureValue(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ExposureTime(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AnalogueGain(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Brightness(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Contrast(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Lux(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbEnable(bool)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbAuto = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbIncandescent = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbTungsten = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbFluorescent = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbIndoor = 4");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbDaylight = 5");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbCloudy = 6");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbCustom = 7");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbLocked(bool)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ColourTemperature(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Saturation(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " Sharpness(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " FocusFoM(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ScalerCrop(Rect x-y-h-w)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " DigitalGain(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " FrameDuration(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " SensorTemperature(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " SensorTimestamp(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfModeManual = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfModeAuto = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfModeContinuous = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfRange(0-2)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfRangeNormal = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfRangeMacro = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfRangeFull = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfSpeed(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfSpeedNormal = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfSpeedFast = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfMetering(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfMeteringAuto = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfMeteringWindows = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfWindows(rect x-y-h-w)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfTrigger(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfTriggerStart = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfTriggerCancel = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfPause(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfPauseImmediate = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfPauseDeferred = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfPauseResume = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " LensPosition(float)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfState(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfStateIdle = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfStateScanning = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfStateFocused = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfStateFailed = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfPauseState(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfPauseStateRunning = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfPauseStatePausing = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AfPauseStatePaused = 2");
}
void cls_libcam:: cam_log_draft()
{
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, "Libcamera Controls Draft:");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AePrecaptureTrigger(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AePrecaptureTriggerIdle = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AePrecaptureTriggerStart = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AePrecaptureTriggerCancel = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " NoiseReductionMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " NoiseReductionModeOff = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " NoiseReductionModeFast = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " NoiseReductionModeHighQuality = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " NoiseReductionModeMinimal = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " NoiseReductionModeZSL = 4");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ColorCorrectionAberrationMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ColorCorrectionAberrationOff = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ColorCorrectionAberrationFast = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " ColorCorrectionAberrationHighQuality = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeState(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeStateSearching = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeStateConverged = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeStateLocked = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeStateFlashRequired = 4");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AeStatePrecapture = 5");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbState(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbStateInactive = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbStateSearching = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbConverged = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " AwbLocked = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " SensorRollingShutterSkew(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " LensShadingMapMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " LensShadingMapModeOff = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " LensShadingMapModeOn = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " SceneFlicker(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " SceneFickerOff = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " SceneFicker50Hz = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " SceneFicker60Hz = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " PipelineDepth(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " MaxLatency(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " TestPatternMode(int)");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " TestPatternModeOff = 0");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " TestPatternModeSolidColor = 1");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " TestPatternModeColorBars = 2");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " TestPatternModeColorBarsFadeToGray = 3");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " TestPatternModePn9 = 4");
motpls_log(DBG, TYPE_VIDEO, NO_ERRNO,0, " TestPatternModeCustom1 = 256");
}
void cls_libcam::cam_start_params(ctx_dev *ptr)
{
int indx;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Starting.");
camctx = ptr;
camctx->libcam->params = (ctx_params*)mymalloc(sizeof(ctx_params));
camctx->libcam->params->update_params = true;
util_parms_parse(camctx->libcam->params, camctx->conf->libcam_params);
for (indx = 0; indx < camctx->libcam->params->params_count; indx++) {
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s : %s"
,camctx->libcam->params->params_array[indx].param_name
,camctx->libcam->params->params_array[indx].param_value
);
}
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Finished.");
}
int cls_libcam::cam_start_mgr()
{
int retcd;
std::string camid;
libcamera::Size picsz;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Starting.");
cam_mgr = std::make_unique<CameraManager>();
retcd = cam_mgr->start();
if (retcd != 0) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Error starting camera manager. Return code: %d",retcd);
return retcd;
}
started_mgr = true;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "cam_mgr started.");
if (camctx->conf->libcam_device == "camera0"){
camid = cam_mgr->cameras()[0]->id();
} else {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Invalid libcam_device '%s'. The only name supported is 'camera0' "
,camctx->conf->libcam_device.c_str());
return -1;
}
camera = cam_mgr->get(camid);
camera->acquire();
started_aqr = true;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Finished.");
return 0;
}
void cls_libcam::cam_config_control_item(char *pname, char *pvalue)
{
char *x, *y, *w, *h;
if (mystrceq(pname, "AeEnable")) {
controls.set(controls::AeEnable, cam_parm_bool(pvalue));
}
if (mystrceq(pname, "AeLocked")) {
controls.set(controls::AeLocked, cam_parm_bool(pvalue));
}
if (mystrceq(pname,"AeMeteringMode")) {
controls.set(controls::AeMeteringMode, atoi(pvalue));
}
if (mystrceq(pname,"AeConstraintMode")) {
controls.set(controls::AeConstraintMode, atoi(pvalue));
}
if (mystrceq(pname,"AeExposureMode")) {
controls.set(controls::AeExposureMode, atoi(pvalue));
}
if (mystrceq(pname,"ExposureValue")) {
controls.set(controls::ExposureValue, cam_parm_single(pvalue));
}
if (mystrceq(pname,"ExposureTime")) {
controls.set(controls::ExposureTime, atoi(pvalue));
}
if (mystrceq(pname,"AnalogueGain")) {
controls.set(controls::AnalogueGain, cam_parm_single(pvalue));
}
if (mystrceq(pname,"Brightness")) {
controls.set(controls::Brightness, cam_parm_single(pvalue));
}
if (mystrceq(pname,"Contrast")) {
controls.set(controls::Contrast, cam_parm_single(pvalue));
}
if (mystrceq(pname,"Lux")) {
controls.set(controls::Lux, cam_parm_single(pvalue));
}
if (mystrceq(pname, "AwbEnable")) {
controls.set(controls::AwbEnable, cam_parm_bool(pvalue));
}
if (mystrceq(pname,"AwbMode")) {
controls.set(controls::AwbMode, atoi(pvalue));
}
if (mystrceq(pname, "AwbLocked")) {
controls.set(controls::AwbLocked, cam_parm_bool(pvalue));
}
if (mystrceq(pname,"ColourTemperature")) {
controls.set(controls::ColourTemperature, atoi(pvalue));
}
if (mystrceq(pname,"Saturation")) {
controls.set(controls::Saturation, cam_parm_single(pvalue));
}
if (mystrceq(pname,"Sharpness")) {
controls.set(controls::Sharpness, cam_parm_single(pvalue));
}
if (mystrceq(pname,"FocusFoM")) {
controls.set(controls::FocusFoM, atoi(pvalue));
}
if (mystrceq(pname,"ScalerCrop")) {
x = strtok(pvalue, "-");
y = strtok(0, "-");
w = strtok(0, "-");
h = strtok(0, "-");
if (h != NULL) {
controls.set(controls::ScalerCrop, Rectangle(atoi(x),atoi(y),atoi(w),atoi(h)));
}
}
if (mystrceq(pname,"DigitalGain")) {
controls.set(controls::DigitalGain, cam_parm_single(pvalue));
}
if (mystrceq(pname,"FrameDuration")) {
controls.set(controls::FrameDuration, atoi(pvalue));
}
if (mystrceq(pname,"SensorTemperature")) {
controls.set(controls::SensorTemperature, cam_parm_single(pvalue));
}
if (mystrceq(pname,"SensorTimestamp")) {
controls.set(controls::SensorTimestamp, atoi(pvalue));
}
if (mystrceq(pname,"AfMode")) {
controls.set(controls::AfMode, atoi(pvalue));
}
if (mystrceq(pname,"AfRange")) {
controls.set(controls::AfRange, atoi(pvalue));
}
if (mystrceq(pname,"AfSpeed")) {
controls.set(controls::AfSpeed, atoi(pvalue));
}
if (mystrceq(pname,"AfMetering")) {
controls.set(controls::AfMetering, atoi(pvalue));
}
if (mystrceq(pname,"AfWindows")) {
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO
, "AfWindows Not Implemented.");
}
if (mystrceq(pname,"AfTrigger")) {
controls.set(controls::AfTrigger, atoi(pvalue));
}
if (mystrceq(pname,"AfPause")) {
controls.set(controls::AfPause, atoi(pvalue));
}
if (mystrceq(pname,"LensPosition")) {
controls.set(controls::LensPosition, cam_parm_single(pvalue));
}
if (mystrceq(pname,"AfState")) {
controls.set(controls::AfState, atoi(pvalue));
}
if (mystrceq(pname,"AfPauseState")) {
controls.set(controls::AfPauseState, atoi(pvalue));
}
/* DRAFT*/
if (mystrceq(pname,"AePrecaptureTrigger")) {
controls.set(controls::draft::AePrecaptureTrigger, atoi(pvalue));
}
if (mystrceq(pname,"NoiseReductionMode")) {
controls.set(controls::draft::NoiseReductionMode, atoi(pvalue));
}
if (mystrceq(pname,"ColorCorrectionAberrationMode")) {
controls.set(controls::draft::ColorCorrectionAberrationMode, atoi(pvalue));
}
if (mystrceq(pname,"AeState")) {
controls.set(controls::draft::AeState, atoi(pvalue));
}
if (mystrceq(pname,"AwbState")) {
controls.set(controls::draft::AwbState, atoi(pvalue));
}
if (mystrceq(pname,"SensorRollingShutterSkew")) {
controls.set(controls::draft::SensorRollingShutterSkew, atoi(pvalue));
}
if (mystrceq(pname,"LensShadingMapMode")) {
controls.set(controls::draft::LensShadingMapMode, atoi(pvalue));
}
if (mystrceq(pname,"PipelineDepth")) {
controls.set(controls::draft::PipelineDepth, atoi(pvalue));
}
if (mystrceq(pname,"MaxLatency")) {
controls.set(controls::draft::MaxLatency, atoi(pvalue));
}
if (mystrceq(pname,"TestPatternMode")) {
controls.set(controls::draft::TestPatternMode, atoi(pvalue));
}
}
void cls_libcam:: cam_config_controls()
{
int indx, retcd;
for (indx = 0; indx < camctx->libcam->params->params_count; indx++) {
cam_config_control_item(
camctx->libcam->params->params_array[indx].param_name
,camctx->libcam->params->params_array[indx].param_value);
}
retcd = config->validate();
if (retcd == CameraConfiguration::Adjusted) {
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO
, "Configuration adjusted.");
} else if (retcd == CameraConfiguration::Valid) {
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
, "Configuration valid");
} else if (retcd == CameraConfiguration::Invalid) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Configuration error");
}
}
void cls_libcam:: cam_config_transform()
{
int indx, retcd;
ctx_params_item itm;
config->transform = Transform::Identity;
for (indx = 0; indx < camctx->libcam->params->params_count; indx++) {
itm = camctx->libcam->params->params_array[indx];
if (mystreq(itm.param_name,"transform")) {
if (mystrceq(itm.param_value,"identity")) {
config->transform = Transform::Identity;
} else if (mystrceq(itm.param_value,"rot0")) {
config->transform = Transform::Rot0;
} else if (mystrceq(itm.param_value,"hflip")) {
config->transform = Transform::HFlip;
} else if (mystrceq(itm.param_value,"vflip")) {
config->transform = Transform::VFlip;
} else if (mystrceq(itm.param_value,"hvflip")) {
config->transform = Transform::HVFlip;
} else if (mystrceq(itm.param_value,"rot180")) {
config->transform = Transform::Rot180;
} else if (mystrceq(itm.param_value,"transpose")) {
config->transform = Transform::Transpose;
} else if (mystrceq(itm.param_value,"rot270")) {
config->transform = Transform::Rot270;
} else if (mystrceq(itm.param_value,"rot90")) {
config->transform = Transform::Rot90;
} else if (mystrceq(itm.param_value,"rot180transpose")) {
config->transform = Transform::Rot180Transpose;
} else {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Invalid transform option: %s."
, itm.param_value);
}
}
}
retcd = config->validate();
if (retcd == CameraConfiguration::Adjusted) {
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO
, "Configuration adjusted.");
} else if (retcd == CameraConfiguration::Valid) {
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
, "Configuration valid");
} else if (retcd == CameraConfiguration::Invalid) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Configuration error");
}
}
int cls_libcam::cam_start_config()
{
int retcd;
libcamera::Size picsz;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Starting.");
config = camera->generateConfiguration({ StreamRole::Viewfinder });
config->at(0).pixelFormat = PixelFormat::fromString("YUV420");
config->at(0).size.width = camctx->conf->width;
config->at(0).size.height = camctx->conf->height;
config->at(0).bufferCount = 1;
retcd = config->validate();
if (retcd == CameraConfiguration::Adjusted) {
if (config->at(0).pixelFormat != PixelFormat::fromString("YUV420")) {
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
, "Pixel format was adjusted to %s."
, config->at(0).pixelFormat.toString().c_str());
return -1;
} else {
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
, "Configuration adjusted.");
}
} else if (retcd == CameraConfiguration::Valid) {
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
, "Configuration is valid");
} else if (retcd == CameraConfiguration::Invalid) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Error setting configuration");
return -1;
}
if ((config->at(0).size.width != (unsigned int)camctx->conf->width) ||
(config->at(0).size.height != (unsigned int)camctx->conf->height)) {
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
, "Image size adjusted from %d x %d to %d x %d"
, camctx->conf->width
, camctx->conf->height
, config->at(0).size.width
, config->at(0).size.height);
}
camctx->imgs.width = config->at(0).size.width;
camctx->imgs.height = config->at(0).size.height;
camctx->imgs.size_norm = (camctx->imgs.width * camctx->imgs.height * 3) / 2;
camctx->imgs.motionsize = camctx->imgs.width * camctx->imgs.height;
cam_log_transform();
cam_log_controls();
cam_log_draft();
cam_config_transform();
cam_config_controls();
camera->configure(config.get());
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Finished.");
return 0;
}
int cls_libcam::req_add(Request *request)
{
int retcd;
retcd = camera->queueRequest(request);
return retcd;
}
int cls_libcam::cam_start_req()
{
int retcd, bytes, indx, width;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Starting.");
camera->requestCompleted.connect(this, &cls_libcam::req_complete);
frmbuf = std::make_unique<FrameBufferAllocator>(camera);
retcd = frmbuf->allocate(config->at(0).stream());
if (retcd < 0) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Buffer allocation error.");
return -1;
}
std::unique_ptr<Request> request = camera->createRequest();
if (!request) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Create request error.");
return -1;
}
Stream *stream = config->at(0).stream();
const std::vector<std::unique_ptr<FrameBuffer>> &buffers =
frmbuf->buffers(stream);
const std::unique_ptr<FrameBuffer> &buffer = buffers[0];
retcd = request->addBuffer(stream, buffer.get());
if (retcd < 0) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Add buffer for request error.");
return -1;
}
started_req = true;
const FrameBuffer::Plane &plane0 = buffer->planes()[0];
bytes = 0;
for (indx=0; indx<(int)buffer->planes().size(); indx++){
bytes += buffer->planes()[indx].length;
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "Plane %d of %d length %d"
, indx, buffer->planes().size()
, buffer->planes()[indx].length);
}
if (bytes > camctx->imgs.size_norm) {
width = (buffer->planes()[0].length / camctx->imgs.height);
if (((int)buffer->planes()[0].length != (width * camctx->imgs.height)) ||
(bytes > ((width * camctx->imgs.height * 3)/2))) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Error setting image size. Plane 0 length %d, total bytes %d"
, buffer->planes()[0].length, bytes);
}
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
, "Image size adjusted from %d x %d to %d x %d"
, camctx->imgs.width,camctx->imgs.height
, width,camctx->imgs.height);
camctx->imgs.width = width;
camctx->imgs.size_norm = (camctx->imgs.width * camctx->imgs.height * 3) / 2;
camctx->imgs.motionsize = camctx->imgs.width * camctx->imgs.height;
}
membuf.buf = (uint8_t *)mmap(NULL, bytes, PROT_READ
, MAP_SHARED, plane0.fd.get(), 0);
membuf.bufsz = bytes;
requests.push_back(std::move(request));
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Finished.");
return 0;
}
int cls_libcam::cam_start_capture()
{
int retcd;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Starting.");
retcd = camera->start(&this->controls);
if (retcd) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Failed to start capture.");
return -1;
}
controls.clear();
for (std::unique_ptr<Request> &request : requests) {
retcd = req_add(request.get());
if (retcd < 0) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
, "Failed to queue request.");
if (started_cam) {
camera->stop();
}
return -1;
}
}
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Finished.");
return 0;
}
void cls_libcam::req_complete(Request *request)
{
if (request->status() == Request::RequestCancelled) {
return;
}
req_queue.push(request);
}
int cls_libcam::cam_start(ctx_dev *cam)
{
int retcd;
started_cam = false;
started_mgr = false;
started_aqr = false;
started_req = false;
cam_start_params(cam);
retcd = cam_start_mgr();
if (retcd != 0) {
return -1;
}
retcd = cam_start_config();
if (retcd != 0) {
return -1;
}
retcd = cam_start_req();
if (retcd != 0) {
return -1;
}
retcd = cam_start_capture();
if (retcd != 0) {
return -1;
}
SLEEP(2,0);
started_cam = true;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Started all.");
return 0;
}
void cls_libcam::cam_stop()
{
util_parms_free(camctx->libcam->params);
myfree(&camctx->libcam->params);
camctx->libcam->params = NULL;
if (started_aqr) {
camera->stop();
}
if (started_req) {
camera->requestCompleted.disconnect(this, &cls_libcam::req_complete);
while (req_queue.empty() == false) {
req_queue.pop();
}
requests.clear();
frmbuf->free(config->at(0).stream());
frmbuf.reset();
}
controls.clear();
if (started_aqr){
camera->release();
camera.reset();
}
if (started_mgr) {
cam_mgr->stop();
cam_mgr.reset();
}
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Stopped.");
}
/* get the image from libcam */
int cls_libcam::cam_next(ctx_image_data *img_data)
{
int indx;
if (started_cam == false) {
return CAPTURE_FAILURE;
}
/* Allow time for request to finish.*/
indx=0;
while ((req_queue.empty() == true) && (indx < 50)) {
SLEEP(0,2000)
indx++;
}
if (req_queue.empty() == false) {
Request *request = this->req_queue.front();
memcpy(img_data->image_norm, membuf.buf, membuf.bufsz);
this->req_queue.pop();
request->reuse(Request::ReuseBuffers);
req_add(request);
return CAPTURE_SUCCESS;
} else {
return CAPTURE_FAILURE;
}
}
#endif
/** close and stop libcam */
void libcam_cleanup(ctx_dev *cam)
{
#ifdef HAVE_LIBCAM
cam->libcam->cam_stop();
delete cam->libcam;
cam->libcam = nullptr;
#endif
cam->device_status = STATUS_CLOSED;
}
/** initialize and start libcam */
void libcam_start(ctx_dev *cam)
{
#ifdef HAVE_LIBCAM
int retcd;
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening libcam"));
cam->libcam = new cls_libcam;
retcd = cam->libcam->cam_start(cam);
if (retcd < 0) {
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("libcam failed to open"));
libcam_cleanup(cam);
} else {
cam->device_status = STATUS_OPENED;
}
#else
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("libcam not available"));
cam->device_status = STATUS_CLOSED;
#endif
}
/** get next image from libcam */
int libcam_next(ctx_dev *cam, ctx_image_data *img_data)
{
#ifdef HAVE_LIBCAM
int retcd;
if (cam->libcam == nullptr){
return CAPTURE_FAILURE;
}
retcd = cam->libcam->cam_next(img_data);
if (retcd == CAPTURE_SUCCESS) {
rotate_map(cam, img_data);
}
return retcd;
#else
(void)cam;
(void)img_data;
return CAPTURE_FAILURE;
#endif
}