@@ -655,7 +655,7 @@ void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])
lineBufferIndex_ = (lineBufferIndex_ + 1) % (patternHeight + 1);
}
-void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
+void DebayerCpu::process2(uint32_t frame, const uint8_t *src, uint8_t *dst)
{
unsigned int yEnd = window_.y + window_.height;
/* Holds [0] previous- [1] current- [2] next-line */
@@ -681,7 +681,7 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
for (unsigned int y = window_.y; y < yEnd; y += 2) {
shiftLinePointers(linePointers, src);
memcpyNextLine(linePointers);
- stats_->processLine0(y, linePointers);
+ stats_->processLine0(frame, y, linePointers);
(this->*debayer0_)(dst, linePointers);
src += inputConfig_.stride;
dst += outputConfig_.stride;
@@ -696,7 +696,7 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
if (window_.y == 0) {
shiftLinePointers(linePointers, src);
memcpyNextLine(linePointers);
- stats_->processLine0(yEnd, linePointers);
+ stats_->processLine0(frame, yEnd, linePointers);
(this->*debayer0_)(dst, linePointers);
src += inputConfig_.stride;
dst += outputConfig_.stride;
@@ -710,7 +710,7 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
}
}
-void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
+void DebayerCpu::process4(uint32_t frame, const uint8_t *src, uint8_t *dst)
{
const unsigned int yEnd = window_.y + window_.height;
/*
@@ -733,7 +733,7 @@ void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
for (unsigned int y = window_.y; y < yEnd; y += 4) {
shiftLinePointers(linePointers, src);
memcpyNextLine(linePointers);
- stats_->processLine0(y, linePointers);
+ stats_->processLine0(frame, y, linePointers);
(this->*debayer0_)(dst, linePointers);
src += inputConfig_.stride;
dst += outputConfig_.stride;
@@ -746,7 +746,7 @@ void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
shiftLinePointers(linePointers, src);
memcpyNextLine(linePointers);
- stats_->processLine2(y, linePointers);
+ stats_->processLine2(frame, y, linePointers);
(this->*debayer2_)(dst, linePointers);
src += inputConfig_.stride;
dst += outputConfig_.stride;
@@ -821,12 +821,12 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
return;
}
- stats_->startFrame();
+ stats_->startFrame(frame);
if (inputConfig_.patternSize.height == 2)
- process2(in.planes()[0].data(), out.planes()[0].data());
+ process2(frame, in.planes()[0].data(), out.planes()[0].data());
else
- process4(in.planes()[0].data(), out.planes()[0].data());
+ process4(frame, in.planes()[0].data(), out.planes()[0].data());
metadata.planes()[0].bytesused = out.planes()[0].size();
@@ -133,8 +133,8 @@ private:
void setupInputMemcpy(const uint8_t *linePointers[]);
void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src);
void memcpyNextLine(const uint8_t *linePointers[]);
- void process2(const uint8_t *src, uint8_t *dst);
- void process4(const uint8_t *src, uint8_t *dst);
+ void process2(uint32_t frame, const uint8_t *src, uint8_t *dst);
+ void process4(uint32_t frame, const uint8_t *src, uint8_t *dst);
/* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */
static constexpr unsigned int kMaxLineBuffers = 5;
@@ -62,8 +62,9 @@ namespace libcamera {
*/
/**
- * \fn void SwStatsCpu::processLine0(unsigned int y, const uint8_t *src[])
+ * \fn void SwStatsCpu::processLine0(uint32_t frame, unsigned int y, const uint8_t *src[])
* \brief Process line 0
+ * \param[in] frame The frame number
* \param[in] y The y coordinate.
* \param[in] src The input data.
*
@@ -74,8 +75,9 @@ namespace libcamera {
*/
/**
- * \fn void SwStatsCpu::processLine2(unsigned int y, const uint8_t *src[])
+ * \fn void SwStatsCpu::processLine2(uint32_t frame, unsigned int y, const uint8_t *src[])
* \brief Process line 2 and 3
+ * \param[in] frame The frame number
* \param[in] y The y coordinate.
* \param[in] src The input data.
*
@@ -89,6 +91,11 @@ namespace libcamera {
* \brief Signals that the statistics are ready
*/
+/**
+ * \var SwStatsCpu::kStatPerNumFrames
+ * \brief Run stats once every kStatPerNumFrames frames
+ */
+
/**
* \typedef SwStatsCpu::statsProcessFn
* \brief Called when there is data to get statistics from
@@ -295,11 +302,15 @@ void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src[])
/**
* \brief Reset state to start statistics gathering for a new frame
+ * \param[in] frame The frame number
*
* This may only be called after a successful setWindow() call.
*/
-void SwStatsCpu::startFrame(void)
+void SwStatsCpu::startFrame(uint32_t frame)
{
+ if (frame % kStatPerNumFrames)
+ return;
+
if (window_.width == 0)
LOG(SwStatsCpu, Error) << "Calling startFrame() without setWindow()";
@@ -318,7 +329,7 @@ void SwStatsCpu::startFrame(void)
*/
void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId)
{
- stats_.valid = true;
+ stats_.valid = frame % kStatPerNumFrames == 0;
*sharedStats_ = stats_;
statsReady.emit(frame, bufferId);
}
@@ -32,6 +32,14 @@ public:
SwStatsCpu();
~SwStatsCpu() = default;
+ /*
+ * The combination of pipeline + sensor delays means that
+ * exposure changes can take up to 3 frames to get applied,
+ * Run stats once every 4 frames to ensure any previous
+ * exposure changes have been applied.
+ */
+ static constexpr uint32_t kStatPerNumFrames = 4;
+
bool isValid() const { return sharedStats_.fd().isValid(); }
const SharedFD &getStatsFD() { return sharedStats_.fd(); }
@@ -40,11 +48,14 @@ public:
int configure(const StreamConfiguration &inputCfg);
void setWindow(const Rectangle &window);
- void startFrame();
+ void startFrame(uint32_t frame);
void finishFrame(uint32_t frame, uint32_t bufferId);
- void processLine0(unsigned int y, const uint8_t *src[])
+ void processLine0(uint32_t frame, unsigned int y, const uint8_t *src[])
{
+ if (frame % kStatPerNumFrames)
+ return;
+
if ((y & ySkipMask_) || y < static_cast<unsigned int>(window_.y) ||
y >= (window_.y + window_.height))
return;
@@ -52,8 +63,11 @@ public:
(this->*stats0_)(src);
}
- void processLine2(unsigned int y, const uint8_t *src[])
+ void processLine2(uint32_t frame, unsigned int y, const uint8_t *src[])
{
+ if (frame % kStatPerNumFrames)
+ return;
+
if ((y & ySkipMask_) || y < static_cast<unsigned int>(window_.y) ||
y >= (window_.y + window_.height))
return;