v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support

v4l2-compliance reports an error due to VIDIOC_S_PARM being supported
without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy
all compliance tests, VIDIOC_S_PARM also needs to be updated to properly
zero reserved fields.

Fixes: 5456e02d3f ("v4l2: Support setting frame rate in the V4L2 Adaptation layer")
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2024-10-31 01:00:01 +02:00
parent f326eb4bf2
commit 77438775b3
3 changed files with 64 additions and 2 deletions

View file

@ -195,6 +195,29 @@ void V4L2CameraProxy::setFmtFromConfig(const StreamConfiguration &streamConfig)
v4l2PixFormat_.xfer_func = V4L2_XFER_FUNC_DEFAULT;
sizeimage_ = streamConfig.frameSize;
const ControlInfoMap &controls = vcam_->controlInfo();
const auto &it = controls.find(&controls::FrameDurationLimits);
if (it != controls.end()) {
const int64_t duration = it->second.def().get<int64_t>();
v4l2TimePerFrame_.numerator = duration;
v4l2TimePerFrame_.denominator = 1000000;
} else {
/*
* Default to 30fps if the camera doesn't expose the
* FrameDurationLimits control.
*
* \todo Remove this once all pipeline handlers implement the
* control
*/
LOG(V4L2Compat, Warning)
<< "Camera does not support FrameDurationLimits";
v4l2TimePerFrame_.numerator = 333333;
v4l2TimePerFrame_.denominator = 1000000;
}
}
void V4L2CameraProxy::querycap(std::shared_ptr<Camera> camera)
@ -758,6 +781,22 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg)
return ret;
}
int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)
{
LOG(V4L2Compat, Debug)
<< "[" << file->description() << "] " << __func__ << "()";
if (!validateBufferType(arg->type))
return -EINVAL;
memset(&arg->parm, 0, sizeof(arg->parm));
arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
arg->parm.capture.timeperframe = v4l2TimePerFrame_;
return 0;
}
int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)
{
LOG(V4L2Compat, Debug)
@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm
if (!validateBufferType(arg->type))
return -EINVAL;
struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;
utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;
/*
* Store the frame duration if it is valid, otherwise keep the current
* value.
*
* \todo The provided value should be adjusted based on the camera
* capabilities.
*/
if (arg->parm.capture.timeperframe.numerator &&
arg->parm.capture.timeperframe.denominator)
v4l2TimePerFrame_ = arg->parm.capture.timeperframe;
memset(&arg->parm, 0, sizeof(arg->parm));
arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
arg->parm.capture.timeperframe = v4l2TimePerFrame_;
/* Apply the frame duration. */
utils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator
/ v4l2TimePerFrame_.denominator;
int64_t uDuration = frameDuration.get<std::micro>();
vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });
@ -795,6 +850,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {
VIDIOC_EXPBUF,
VIDIOC_STREAMON,
VIDIOC_STREAMOFF,
VIDIOC_G_PARM,
VIDIOC_S_PARM,
};
@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void
case VIDIOC_STREAMOFF:
ret = vidioc_streamoff(file, static_cast<int *>(arg));
break;
case VIDIOC_G_PARM:
ret = vidioc_g_parm(file, static_cast<struct v4l2_streamparm *>(arg));
break;
case VIDIOC_S_PARM:
ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));
break;