libcamera: v4l2_videodevice: Add helper to queue all buffers
When starting the stream on a capture video device it is often needed to queue all the allocated buffers. Add a helper method to do so, and refactor the existing queueBuffer() method to make it clearer. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
parent
33d3c4e204
commit
9bb36ec274
5 changed files with 70 additions and 24 deletions
|
@ -139,6 +139,7 @@ public:
|
||||||
int releaseBuffers();
|
int releaseBuffers();
|
||||||
|
|
||||||
int queueBuffer(Buffer *buffer);
|
int queueBuffer(Buffer *buffer);
|
||||||
|
std::vector<std::unique_ptr<Buffer>> queueAllBuffers();
|
||||||
Signal<Buffer *> bufferReady;
|
Signal<Buffer *> bufferReady;
|
||||||
|
|
||||||
int streamOn();
|
int streamOn();
|
||||||
|
|
|
@ -131,6 +131,7 @@ public:
|
||||||
CameraSensor *sensor_;
|
CameraSensor *sensor_;
|
||||||
|
|
||||||
BufferPool pool_;
|
BufferPool pool_;
|
||||||
|
std::vector<std::unique_ptr<Buffer>> buffers_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IPU3Stream : public Stream
|
class IPU3Stream : public Stream
|
||||||
|
@ -1430,11 +1431,9 @@ int CIO2Device::start()
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
for (Buffer &buffer : pool_.buffers()) {
|
buffers_ = output_->queueAllBuffers();
|
||||||
ret = output_->queueBuffer(&buffer);
|
if (buffers_.empty())
|
||||||
if (ret)
|
return -EINVAL;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = output_->streamOn();
|
ret = output_->streamOn();
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -1445,7 +1444,9 @@ int CIO2Device::start()
|
||||||
|
|
||||||
int CIO2Device::stop()
|
int CIO2Device::stop()
|
||||||
{
|
{
|
||||||
return output_->streamOff();
|
int ret = output_->streamOff();
|
||||||
|
buffers_.clear();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CIO2Device::mediaBusToFormat(unsigned int code)
|
int CIO2Device::mediaBusToFormat(unsigned int code)
|
||||||
|
|
|
@ -894,8 +894,8 @@ int V4L2VideoDevice::releaseBuffers()
|
||||||
*/
|
*/
|
||||||
int V4L2VideoDevice::queueBuffer(Buffer *buffer)
|
int V4L2VideoDevice::queueBuffer(Buffer *buffer)
|
||||||
{
|
{
|
||||||
|
struct v4l2_plane v4l2Planes[VIDEO_MAX_PLANES] = {};
|
||||||
struct v4l2_buffer buf = {};
|
struct v4l2_buffer buf = {};
|
||||||
struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
buf.index = buffer->index();
|
buf.index = buffer->index();
|
||||||
|
@ -904,21 +904,20 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)
|
||||||
buf.field = V4L2_FIELD_NONE;
|
buf.field = V4L2_FIELD_NONE;
|
||||||
|
|
||||||
bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);
|
bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);
|
||||||
|
const std::vector<Plane> &planes = buffer->planes();
|
||||||
|
|
||||||
if (buf.memory == V4L2_MEMORY_DMABUF) {
|
if (buf.memory == V4L2_MEMORY_DMABUF) {
|
||||||
if (multiPlanar) {
|
if (multiPlanar) {
|
||||||
for (unsigned int p = 0;
|
for (unsigned int p = 0; p < planes.size(); ++p)
|
||||||
p < buffer->planes().size();
|
v4l2Planes[p].m.fd = planes[p].dmabuf();
|
||||||
p++)
|
|
||||||
planes[p].m.fd = buffer->planes()[p].dmabuf();
|
|
||||||
} else {
|
} else {
|
||||||
buf.m.fd = buffer->planes()[0].dmabuf();
|
buf.m.fd = planes[0].dmabuf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multiPlanar) {
|
if (multiPlanar) {
|
||||||
buf.length = buffer->planes().size();
|
buf.length = planes.size();
|
||||||
buf.m.planes = planes;
|
buf.m.planes = v4l2Planes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (V4L2_TYPE_IS_OUTPUT(bufferType_)) {
|
if (V4L2_TYPE_IS_OUTPUT(bufferType_)) {
|
||||||
|
@ -944,6 +943,53 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Queue all buffers into the video device
|
||||||
|
*
|
||||||
|
* When starting video capture users of the video device often need to queue
|
||||||
|
* all allocated buffers to the device. This helper method simplifies the
|
||||||
|
* implementation of the user by queuing all buffers and returning a vector of
|
||||||
|
* Buffer instances for each queued buffer.
|
||||||
|
*
|
||||||
|
* This method is meant to be used with video capture devices internal to a
|
||||||
|
* pipeline handler, such as ISP statistics capture devices, or raw CSI-2
|
||||||
|
* receivers. For video capture devices facing applications, buffers shall
|
||||||
|
* instead be queued when requests are received, and for video output devices,
|
||||||
|
* buffers shall be queued when frames are ready to be output.
|
||||||
|
*
|
||||||
|
* The caller shall ensure that the returned buffers vector remains valid until
|
||||||
|
* all the queued buffers are dequeued, either during capture, or by stopping
|
||||||
|
* the video device.
|
||||||
|
*
|
||||||
|
* Calling this method on an output device or on a device that has buffers
|
||||||
|
* already queued is an error and will return an empty vector.
|
||||||
|
*
|
||||||
|
* \return A vector of queued buffers, which will be empty if an error occurs
|
||||||
|
*/
|
||||||
|
std::vector<std::unique_ptr<Buffer>> V4L2VideoDevice::queueAllBuffers()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (queuedBuffersCount_)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (V4L2_TYPE_IS_OUTPUT(bufferType_))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Buffer>> buffers;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < bufferPool_->count(); ++i) {
|
||||||
|
Buffer *buffer = new Buffer();
|
||||||
|
buffer->index_ = i;
|
||||||
|
buffers.emplace_back(buffer);
|
||||||
|
ret = queueBuffer(buffer);
|
||||||
|
if (ret)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Dequeue the next available buffer from the video device
|
* \brief Dequeue the next available buffer from the video device
|
||||||
*
|
*
|
||||||
|
|
|
@ -117,11 +117,10 @@ protected:
|
||||||
capture_->bufferReady.connect(this, &BufferSharingTest::captureBufferReady);
|
capture_->bufferReady.connect(this, &BufferSharingTest::captureBufferReady);
|
||||||
output_->bufferReady.connect(this, &BufferSharingTest::outputBufferReady);
|
output_->bufferReady.connect(this, &BufferSharingTest::outputBufferReady);
|
||||||
|
|
||||||
/* Queue all the buffers to the capture device. */
|
std::vector<std::unique_ptr<Buffer>> buffers;
|
||||||
for (Buffer &buffer : pool_.buffers()) {
|
buffers = capture_->queueAllBuffers();
|
||||||
if (capture_->queueBuffer(&buffer))
|
if (buffers.empty())
|
||||||
return TestFail;
|
return TestFail;
|
||||||
}
|
|
||||||
|
|
||||||
ret = capture_->streamOn();
|
ret = capture_->streamOn();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -46,11 +46,10 @@ protected:
|
||||||
|
|
||||||
capture_->bufferReady.connect(this, &CaptureAsyncTest::receiveBuffer);
|
capture_->bufferReady.connect(this, &CaptureAsyncTest::receiveBuffer);
|
||||||
|
|
||||||
/* Queue all the buffers to the device. */
|
std::vector<std::unique_ptr<Buffer>> buffers;
|
||||||
for (Buffer &b : pool_.buffers()) {
|
buffers = capture_->queueAllBuffers();
|
||||||
if (capture_->queueBuffer(&b))
|
if (buffers.empty())
|
||||||
return TestFail;
|
return TestFail;
|
||||||
}
|
|
||||||
|
|
||||||
ret = capture_->streamOn();
|
ret = capture_->streamOn();
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue