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
3234namespace 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 ¶ms)
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 ¶ms)
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 ¶ms, 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+
13181380void 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
0 commit comments