| Message ID | 20261009193245.19325-1-robert.mader@collabora.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
There's a CI build failure on Debian 12, see below On 09.10.26 21:32, Robert Mader wrote: > Throttle requests to the minimal frame duration in order to honor the > configured framerates. Client-requested values are ignored for now. > > Signed-off-by: Robert Mader<robert.mader@collabora.com> > > --- > > Changes in v1 (from RFC version): > - Use std::this_thread::sleep_for() instead usleep() (Barnabás) > - Sleep only once per request, after generating all frames > - Remove control handling in start() (defer that for later) > - Reset state in stop() instead of start() > --- > src/libcamera/pipeline/virtual/virtual.cpp | 35 ++++++++++++++++++---- > src/libcamera/pipeline/virtual/virtual.h | 1 + > 2 files changed, 31 insertions(+), 5 deletions(-) > > diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp > index e25dd85a7391..8d63a39caca2 100644 > --- a/src/libcamera/pipeline/virtual/virtual.cpp > +++ b/src/libcamera/pipeline/virtual/virtual.cpp > @@ -130,6 +130,9 @@ VirtualCameraData::VirtualCameraData(PipelineHandler *pipe, > > void VirtualCameraData::processRequest(Request *request) > { > + int64_t sensorTimestamp = *request->metadata().get(controls::SensorTimestamp); > + std::vector<FrameBuffer *> buffers; > + > for (const auto &[stream, buffer] : request->buffers()) { > bool found = false; > /* map buffer and fill test patterns */ > @@ -139,7 +142,7 @@ void VirtualCameraData::processRequest(Request *request) > > fmd.status = FrameMetadata::Status::FrameSuccess; > fmd.sequence = streamConfig.seq++; > - fmd.timestamp = currentTimestamp(); > + fmd.timestamp = sensorTimestamp; > > std::span<const FrameBuffer::Plane> planes = buffer->planes(); > for (const auto [i, p] : utils::enumerate(planes)) > @@ -151,12 +154,22 @@ void VirtualCameraData::processRequest(Request *request) > stream->configuration().size, buffer)) > fmd.status = FrameMetadata::Status::FrameError; > > - bufferCompleted.emit(buffer); > + buffers.push_back(buffer); > break; > } > } > ASSERT(found); > } > + > + uint64_t now = currentTimestamp(); > + if (now < static_cast<uint64_t>(sensorTimestamp)) { > + std::chrono::nanoseconds sleep(sensorTimestamp - now); > + LOG(Virtual, Debug) << "Sleeping for ns: " << sleep; | ../src/libcamera/pipeline/virtual/virtual.cpp:167:46: error: invalid operands to binary expression ('basic_ostream<char, std::char_traits<char>>' and 'std::chrono::nanoseconds' (aka 'duration<long long, ratio<1LL, 1000000000LL>>')) LOG(Virtual, Debug) << "Sleeping for ns: " << sleep; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~ /usr/lib/llvm-14/bin/../include/c++/v1/cstddef:143:3: note: candidate function template not viable: no known conversion from 'basic_ostream<char, std::char_traits<char>>' to 'std::byte' for 1st argument operator<< (byte __lhs, _Integer __shift) noexcept | > + std::this_thread::sleep_for(sleep); > + } > + > + for (auto buffer : buffers) > + bufferCompleted.emit(buffer); > } > > VirtualCameraConfiguration::VirtualCameraConfiguration(VirtualCameraData *data) > @@ -349,18 +362,30 @@ void PipelineHandlerVirtual::stopDevice(Camera *camera) > /* Process pending `bufferCompleted` signals. */ > thread()->dispatchMessages(Message::Type::InvokeMessage, this); > data->bufferCompleted.disconnect(this); > + data->lastTimestamp = 0; > > while (!data->queuedRequests_.empty()) > cancelRequest(data->queuedRequests_.front()); > } > > -int PipelineHandlerVirtual::queueRequestDevice([[maybe_unused]] Camera *camera, > - Request *request) > +int PipelineHandlerVirtual::queueRequestDevice(Camera *camera, Request *request) > { > VirtualCameraData *data = cameraData(camera); > - const auto timestamp = currentTimestamp(); > + uint64_t timestamp = currentTimestamp(); > + uint64_t minFrameDurationNsec = > + camera->controls().find(&controls::FrameDurationLimits)->second.min().get<int64_t>() * 1000; > + > + if (data->lastTimestamp) { > + if (((timestamp - data->lastTimestamp) < minFrameDurationNsec) || > + (timestamp < data->lastTimestamp)) > + timestamp = data->lastTimestamp + minFrameDurationNsec; > + } else { > + timestamp += minFrameDurationNsec; > + } > > request->_d()->metadata().set(controls::SensorTimestamp, timestamp); > + data->lastTimestamp = timestamp; > + > data->invokeMethod(&VirtualCameraData::processRequest, > ConnectionTypeQueued, request); > > diff --git a/src/libcamera/pipeline/virtual/virtual.h b/src/libcamera/pipeline/virtual/virtual.h > index 215e56fa3b9d..84b53dfb66f3 100644 > --- a/src/libcamera/pipeline/virtual/virtual.h > +++ b/src/libcamera/pipeline/virtual/virtual.h > @@ -66,6 +66,7 @@ public: > > std::vector<StreamConfig> streamConfigs_; > Signal<FrameBuffer *> bufferCompleted; > + uint64_t lastTimestamp = 0; > }; > > } /* namespace libcamera */
diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp index e25dd85a7391..8d63a39caca2 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -130,6 +130,9 @@ VirtualCameraData::VirtualCameraData(PipelineHandler *pipe, void VirtualCameraData::processRequest(Request *request) { + int64_t sensorTimestamp = *request->metadata().get(controls::SensorTimestamp); + std::vector<FrameBuffer *> buffers; + for (const auto &[stream, buffer] : request->buffers()) { bool found = false; /* map buffer and fill test patterns */ @@ -139,7 +142,7 @@ void VirtualCameraData::processRequest(Request *request) fmd.status = FrameMetadata::Status::FrameSuccess; fmd.sequence = streamConfig.seq++; - fmd.timestamp = currentTimestamp(); + fmd.timestamp = sensorTimestamp; std::span<const FrameBuffer::Plane> planes = buffer->planes(); for (const auto [i, p] : utils::enumerate(planes)) @@ -151,12 +154,22 @@ void VirtualCameraData::processRequest(Request *request) stream->configuration().size, buffer)) fmd.status = FrameMetadata::Status::FrameError; - bufferCompleted.emit(buffer); + buffers.push_back(buffer); break; } } ASSERT(found); } + + uint64_t now = currentTimestamp(); + if (now < static_cast<uint64_t>(sensorTimestamp)) { + std::chrono::nanoseconds sleep(sensorTimestamp - now); + LOG(Virtual, Debug) << "Sleeping for ns: " << sleep; + std::this_thread::sleep_for(sleep); + } + + for (auto buffer : buffers) + bufferCompleted.emit(buffer); } VirtualCameraConfiguration::VirtualCameraConfiguration(VirtualCameraData *data) @@ -349,18 +362,30 @@ void PipelineHandlerVirtual::stopDevice(Camera *camera) /* Process pending `bufferCompleted` signals. */ thread()->dispatchMessages(Message::Type::InvokeMessage, this); data->bufferCompleted.disconnect(this); + data->lastTimestamp = 0; while (!data->queuedRequests_.empty()) cancelRequest(data->queuedRequests_.front()); } -int PipelineHandlerVirtual::queueRequestDevice([[maybe_unused]] Camera *camera, - Request *request) +int PipelineHandlerVirtual::queueRequestDevice(Camera *camera, Request *request) { VirtualCameraData *data = cameraData(camera); - const auto timestamp = currentTimestamp(); + uint64_t timestamp = currentTimestamp(); + uint64_t minFrameDurationNsec = + camera->controls().find(&controls::FrameDurationLimits)->second.min().get<int64_t>() * 1000; + + if (data->lastTimestamp) { + if (((timestamp - data->lastTimestamp) < minFrameDurationNsec) || + (timestamp < data->lastTimestamp)) + timestamp = data->lastTimestamp + minFrameDurationNsec; + } else { + timestamp += minFrameDurationNsec; + } request->_d()->metadata().set(controls::SensorTimestamp, timestamp); + data->lastTimestamp = timestamp; + data->invokeMethod(&VirtualCameraData::processRequest, ConnectionTypeQueued, request); diff --git a/src/libcamera/pipeline/virtual/virtual.h b/src/libcamera/pipeline/virtual/virtual.h index 215e56fa3b9d..84b53dfb66f3 100644 --- a/src/libcamera/pipeline/virtual/virtual.h +++ b/src/libcamera/pipeline/virtual/virtual.h @@ -66,6 +66,7 @@ public: std::vector<StreamConfig> streamConfigs_; Signal<FrameBuffer *> bufferCompleted; + uint64_t lastTimestamp = 0; }; } /* namespace libcamera */
Throttle requests to the minimal frame duration in order to honor the configured framerates. Client-requested values are ignored for now. Signed-off-by: Robert Mader <robert.mader@collabora.com> --- Changes in v1 (from RFC version): - Use std::this_thread::sleep_for() instead usleep() (Barnabás) - Sleep only once per request, after generating all frames - Remove control handling in start() (defer that for later) - Reset state in stop() instead of start() --- src/libcamera/pipeline/virtual/virtual.cpp | 35 ++++++++++++++++++---- src/libcamera/pipeline/virtual/virtual.h | 1 + 2 files changed, 31 insertions(+), 5 deletions(-)