v4l2: v4l2_camera: Don't use libcamera::Semaphore for available buffers
In V4L2, a blocked dqbuf should not not also block a streamoff. This means that on streamoff, the blocked dqbuf must return (with error). We cannot do this with the libcamera semaphore, so pull out the necessary components of a semaphore, and put them into V4L2Camera, so that dqbuf from V4L2CameraProxy can wait on a disjunct condition of the availability of the semaphore or the stopping of the stream. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
f155e63816
commit
566ccd75ca
3 changed files with 47 additions and 7 deletions
|
@ -18,7 +18,7 @@ LOG_DECLARE_CATEGORY(V4L2Compat);
|
||||||
|
|
||||||
V4L2Camera::V4L2Camera(std::shared_ptr<Camera> camera)
|
V4L2Camera::V4L2Camera(std::shared_ptr<Camera> camera)
|
||||||
: camera_(camera), isRunning_(false), bufferAllocator_(nullptr),
|
: camera_(camera), isRunning_(false), bufferAllocator_(nullptr),
|
||||||
efd_(-1)
|
efd_(-1), bufferAvailableCount_(0)
|
||||||
{
|
{
|
||||||
camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete);
|
camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete);
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,11 @@ void V4L2Camera::requestComplete(Request *request)
|
||||||
if (ret != sizeof(data))
|
if (ret != sizeof(data))
|
||||||
LOG(V4L2Compat, Error) << "Failed to signal eventfd POLLIN";
|
LOG(V4L2Compat, Error) << "Failed to signal eventfd POLLIN";
|
||||||
|
|
||||||
bufferSema_.release();
|
{
|
||||||
|
MutexLocker locker(bufferMutex_);
|
||||||
|
bufferAvailableCount_++;
|
||||||
|
}
|
||||||
|
bufferCV_.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
int V4L2Camera::configure(StreamConfiguration *streamConfigOut,
|
int V4L2Camera::configure(StreamConfiguration *streamConfigOut,
|
||||||
|
@ -192,7 +196,11 @@ int V4L2Camera::streamOff()
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret == -EACCES ? -EBUSY : ret;
|
return ret == -EACCES ? -EBUSY : ret;
|
||||||
|
|
||||||
isRunning_ = false;
|
{
|
||||||
|
MutexLocker locker(bufferMutex_);
|
||||||
|
isRunning_ = false;
|
||||||
|
}
|
||||||
|
bufferCV_.notify_all();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -228,6 +236,26 @@ int V4L2Camera::qbuf(unsigned int index)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void V4L2Camera::waitForBufferAvailable()
|
||||||
|
{
|
||||||
|
MutexLocker locker(bufferMutex_);
|
||||||
|
bufferCV_.wait(locker, [&] {
|
||||||
|
return bufferAvailableCount_ >= 1 || !isRunning_;
|
||||||
|
});
|
||||||
|
if (isRunning_)
|
||||||
|
bufferAvailableCount_--;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool V4L2Camera::isBufferAvailable()
|
||||||
|
{
|
||||||
|
MutexLocker locker(bufferMutex_);
|
||||||
|
if (bufferAvailableCount_ < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bufferAvailableCount_--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool V4L2Camera::isRunning()
|
bool V4L2Camera::isRunning()
|
||||||
{
|
{
|
||||||
return isRunning_;
|
return isRunning_;
|
||||||
|
|
|
@ -57,9 +57,10 @@ public:
|
||||||
|
|
||||||
int qbuf(unsigned int index);
|
int qbuf(unsigned int index);
|
||||||
|
|
||||||
bool isRunning();
|
void waitForBufferAvailable();
|
||||||
|
bool isBufferAvailable();
|
||||||
|
|
||||||
Semaphore bufferSema_;
|
bool isRunning();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void requestComplete(Request *request);
|
void requestComplete(Request *request);
|
||||||
|
@ -76,6 +77,10 @@ private:
|
||||||
std::deque<std::unique_ptr<Buffer>> completedBuffers_;
|
std::deque<std::unique_ptr<Buffer>> completedBuffers_;
|
||||||
|
|
||||||
int efd_;
|
int efd_;
|
||||||
|
|
||||||
|
Mutex bufferMutex_;
|
||||||
|
std::condition_variable bufferCV_;
|
||||||
|
unsigned int bufferAvailableCount_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __V4L2_CAMERA_H__ */
|
#endif /* __V4L2_CAMERA_H__ */
|
||||||
|
|
|
@ -588,10 +588,17 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!file->nonBlocking())
|
if (!file->nonBlocking())
|
||||||
vcam_->bufferSema_.acquire();
|
vcam_->waitForBufferAvailable();
|
||||||
else if (!vcam_->bufferSema_.tryAcquire())
|
else if (!vcam_->isBufferAvailable())
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to check here again in case stream was turned off while we
|
||||||
|
* were blocked on waitForBufferAvailable().
|
||||||
|
*/
|
||||||
|
if (!vcam_->isRunning())
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
updateBuffers();
|
updateBuffers();
|
||||||
|
|
||||||
struct v4l2_buffer &buf = buffers_[currentBuf_];
|
struct v4l2_buffer &buf = buffers_[currentBuf_];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue