Skip to content

Commit b26502f

Browse files
naushirdavidplowman
authored andcommitted
ipa: rpi: Add base classes and plumbing for sync algorithm
We add a base class for a "sync algorithm", and define its inputs and outputs in the SyncStatus class. We add the necessary plumbing to the base IPA code so as to arrange for the necessary parameters to be made available to such an algorithm, and also to handle the return values, passing them back as necessary to the pipeline handler. Signed-off-by: Naushir Patuck <[email protected]> Signed-off-by: David Plowman <[email protected]>
1 parent 17f3d0f commit b26502f

File tree

4 files changed

+136
-5
lines changed

4 files changed

+136
-5
lines changed

src/ipa/rpi/common/ipa_base.cpp

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "controller/lux_status.h"
2929
#include "controller/sharpen_algorithm.h"
3030
#include "controller/statistics.h"
31+
#include "controller/sync_algorithm.h"
32+
#include "controller/sync_status.h"
3133

3234
namespace libcamera {
3335

@@ -72,6 +74,8 @@ const ControlInfoMap::Map ipaControls{
7274
{ &controls::Sharpness, ControlInfo(0.0f, 16.0f, 1.0f) },
7375
{ &controls::ScalerCrop, ControlInfo(Rectangle{}, Rectangle(65535, 65535, 65535, 65535), Rectangle{}) },
7476
{ &controls::FrameDurationLimits, ControlInfo(INT64_C(33333), INT64_C(120000)) },
77+
{ &controls::rpi::SyncMode, ControlInfo(controls::rpi::SyncModeValues) },
78+
{ &controls::rpi::SyncFrames, ControlInfo(1, 1000000, 100) },
7579
{ &controls::draft::NoiseReductionMode, ControlInfo(controls::draft::NoiseReductionModeValues) },
7680
{ &controls::rpi::StatsOutputEnable, ControlInfo(false, true, false) },
7781
{ &controls::rpi::CnnEnableInputTensor, ControlInfo(false, true, false) },
@@ -391,6 +395,7 @@ void IpaBase::prepareIsp(const PrepareParams &params)
391395

392396
rpiMetadata.clear();
393397
fillDeviceStatus(params.sensorControls, ipaContext);
398+
fillSyncParams(params, ipaContext);
394399

395400
if (params.buffers.embedded) {
396401
/*
@@ -489,10 +494,24 @@ void IpaBase::processStats(const ProcessParams &params)
489494
helper_->process(statistics, rpiMetadata);
490495
controller_.process(statistics, &rpiMetadata);
491496

497+
/* Send any sync algorithm outputs back to the pipeline handler */
498+
Duration offset(0s);
499+
struct SyncStatus syncStatus;
500+
if (rpiMetadata.get("sync.status", syncStatus) == 0) {
501+
if (minFrameDuration_ != maxFrameDuration_)
502+
LOG(IPARPI, Error) << "Sync algorithm enabled with variable framerate. "
503+
<< minFrameDuration_ << " " << maxFrameDuration_;
504+
offset = syncStatus.frameDurationOffset;
505+
506+
libcameraMetadata_.set(controls::rpi::SyncReady, syncStatus.ready);
507+
if (syncStatus.timerKnown)
508+
libcameraMetadata_.set(controls::rpi::SyncTimer, syncStatus.timerValue);
509+
}
510+
492511
struct AgcStatus agcStatus;
493512
if (rpiMetadata.get("agc.status", agcStatus) == 0) {
494513
ControlList ctrls(sensorCtrls_);
495-
applyAGC(&agcStatus, ctrls);
514+
applyAGC(&agcStatus, ctrls, offset);
496515
setDelayedControls.emit(ctrls, ipaContext);
497516
setCameraTimeoutValue();
498517
}
@@ -729,6 +748,7 @@ void IpaBase::applyControls(const ControlList &controls)
729748
using RPiController::ContrastAlgorithm;
730749
using RPiController::DenoiseAlgorithm;
731750
using RPiController::HdrAlgorithm;
751+
using RPiController::SyncAlgorithm;
732752

733753
/* Clear the return metadata buffer. */
734754
libcameraMetadata_.clear();
@@ -1279,6 +1299,35 @@ void IpaBase::applyControls(const ControlList &controls)
12791299
cnnEnableInputTensor_ = ctrl.second.get<bool>();
12801300
break;
12811301

1302+
case controls::rpi::SYNC_MODE: {
1303+
SyncAlgorithm *sync = dynamic_cast<SyncAlgorithm *>(controller_.getAlgorithm("sync"));
1304+
1305+
if (sync) {
1306+
int mode = ctrl.second.get<int32_t>();
1307+
SyncAlgorithm::Mode m = SyncAlgorithm::Mode::Off;
1308+
if (mode == controls::rpi::SyncModeServer) {
1309+
m = SyncAlgorithm::Mode::Server;
1310+
LOG(IPARPI, Info) << "Sync mode set to server";
1311+
} else if (mode == controls::rpi::SyncModeClient) {
1312+
m = SyncAlgorithm::Mode::Client;
1313+
LOG(IPARPI, Info) << "Sync mode set to client";
1314+
}
1315+
sync->setMode(m);
1316+
}
1317+
break;
1318+
}
1319+
1320+
case controls::rpi::SYNC_FRAMES: {
1321+
SyncAlgorithm *sync = dynamic_cast<SyncAlgorithm *>(controller_.getAlgorithm("sync"));
1322+
1323+
if (sync) {
1324+
int frames = ctrl.second.get<int32_t>();
1325+
if (frames > 0)
1326+
sync->setReadyFrame(frames);
1327+
}
1328+
break;
1329+
}
1330+
12821331
default:
12831332
LOG(IPARPI, Warning)
12841333
<< "Ctrl " << controls::controls.at(ctrl.first)->name()
@@ -1315,6 +1364,19 @@ void IpaBase::fillDeviceStatus(const ControlList &sensorControls, unsigned int i
13151364
rpiMetadata_[ipaContext].set("device.status", deviceStatus);
13161365
}
13171366

1367+
void IpaBase::fillSyncParams(const PrepareParams &params, unsigned int ipaContext)
1368+
{
1369+
RPiController::SyncAlgorithm *sync = dynamic_cast<RPiController::SyncAlgorithm *>(
1370+
controller_.getAlgorithm("sync"));
1371+
if (!sync)
1372+
return;
1373+
1374+
SyncParams syncParams;
1375+
syncParams.wallClock = *params.sensorControls.get(controls::FrameWallClock);
1376+
syncParams.sensorTimestamp = *params.sensorControls.get(controls::SensorTimestamp);
1377+
rpiMetadata_[ipaContext].set("sync.params", syncParams);
1378+
}
1379+
13181380
void IpaBase::reportMetadata(unsigned int ipaContext)
13191381
{
13201382
RPiController::Metadata &rpiMetadata = rpiMetadata_[ipaContext];
@@ -1528,14 +1590,22 @@ void IpaBase::applyFrameDurations(Duration minFrameDuration, Duration maxFrameDu
15281590
* value possible.
15291591
*/
15301592
Duration maxExposureTime = Duration::max();
1531-
helper_->getBlanking(maxExposureTime, minFrameDuration_, maxFrameDuration_);
1593+
auto [vblank, hblank] = helper_->getBlanking(maxExposureTime, minFrameDuration_, maxFrameDuration_);
15321594

15331595
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
15341596
controller_.getAlgorithm("agc"));
15351597
agc->setMaxExposureTime(maxExposureTime);
1598+
1599+
RPiController::SyncAlgorithm *sync = dynamic_cast<RPiController::SyncAlgorithm *>(
1600+
controller_.getAlgorithm("sync"));
1601+
if (sync) {
1602+
Duration duration = (mode_.height + vblank) * ((mode_.width + hblank) * 1.0s / mode_.pixelRate);
1603+
LOG(IPARPI, Debug) << "setting sync frame duration to " << duration;
1604+
sync->setFrameDuration(duration);
1605+
}
15361606
}
15371607

1538-
void IpaBase::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)
1608+
void IpaBase::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls, Duration frameDurationOffset)
15391609
{
15401610
const int32_t minGainCode = helper_->gainCode(mode_.minAnalogueGain);
15411611
const int32_t maxGainCode = helper_->gainCode(mode_.maxAnalogueGain);
@@ -1550,7 +1620,8 @@ void IpaBase::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)
15501620

15511621
/* getBlanking might clip exposure time to the fps limits. */
15521622
Duration exposure = agcStatus->exposureTime;
1553-
auto [vblank, hblank] = helper_->getBlanking(exposure, minFrameDuration_, maxFrameDuration_);
1623+
auto [vblank, hblank] = helper_->getBlanking(exposure, minFrameDuration_ - frameDurationOffset,
1624+
maxFrameDuration_ - frameDurationOffset);
15541625
int32_t exposureLines = helper_->exposureLines(exposure,
15551626
helper_->hblankToLineLength(hblank));
15561627

src/ipa/rpi/common/ipa_base.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,11 @@ class IpaBase : public IPARPiInterface
9595
void applyControls(const ControlList &controls);
9696
virtual void handleControls(const ControlList &controls) = 0;
9797
void fillDeviceStatus(const ControlList &sensorControls, unsigned int ipaContext);
98+
void fillSyncParams(const PrepareParams &params, unsigned int ipaContext);
9899
void reportMetadata(unsigned int ipaContext);
99100
void applyFrameDurations(utils::Duration minFrameDuration, utils::Duration maxFrameDuration);
100-
void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);
101+
void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls,
102+
utils::Duration frameDurationOffset = utils::Duration(0));
101103

102104
std::map<unsigned int, MappedFrameBuffer> buffers_;
103105

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* SPDX-License-Identifier: BSD-2-Clause */
2+
/*
3+
* Copyright (C) 2024, Raspberry Pi Ltd
4+
*
5+
* sync_algorithm.h - Camera sync algorithm interface
6+
*/
7+
#pragma once
8+
9+
#include <libcamera/base/utils.h>
10+
11+
#include "algorithm.h"
12+
13+
namespace RPiController {
14+
15+
class SyncAlgorithm : public Algorithm
16+
{
17+
public:
18+
enum class Mode {
19+
Off,
20+
Server,
21+
Client,
22+
};
23+
24+
SyncAlgorithm(Controller *controller)
25+
: Algorithm(controller) {}
26+
virtual void setFrameDuration(libcamera::utils::Duration frameDuration) = 0;
27+
virtual void setReadyFrame(unsigned int frame) = 0;
28+
virtual void setMode(Mode mode) = 0;
29+
};
30+
31+
} /* namespace RPiController */

src/ipa/rpi/controller/sync_status.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* SPDX-License-Identifier: BSD-2-Clause */
2+
/*
3+
* Copyright (C) 2024, Raspberry Pi Ltd
4+
*
5+
* sync_status.h - Sync algorithm params and status structures
6+
*/
7+
#pragma once
8+
9+
#include <libcamera/base/utils.h>
10+
11+
struct SyncParams {
12+
/* Wall clock time for this frame */
13+
uint64_t wallClock;
14+
/* Kernel timestamp for this frame */
15+
uint64_t sensorTimestamp;
16+
};
17+
18+
struct SyncStatus {
19+
/* Frame length correction to apply */
20+
libcamera::utils::Duration frameDurationOffset;
21+
/* Whether the "ready time" has been reached */
22+
bool ready;
23+
/* Time until the "ready time" */
24+
int64_t timerValue;
25+
/* Whether timerValue is known (client has to wait for a server message) */
26+
bool timerKnown;
27+
};

0 commit comments

Comments
 (0)