[libcamera-devel,06/15] v4l2: v4l2_camera_proxy: Implement VIDIOC_ENUM_FRAMESIZES

Message ID 20200616131244.70308-7-paul.elder@ideasonboard.com
State Superseded
Headers show
Series
  • Support v4l2-compliance
Related show

Commit Message

Paul Elder June 16, 2020, 1:12 p.m. UTC
Implement VIDIOC_ENUM_FRAMESIZES in the V4L2 compatibility layer.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
---
 src/v4l2/v4l2_camera_proxy.cpp | 24 ++++++++++++++++++++++++
 src/v4l2/v4l2_camera_proxy.h   |  1 +
 2 files changed, 25 insertions(+)

Comments

Jacopo Mondi June 17, 2020, 2:08 p.m. UTC | #1
Hi Paul,

On Tue, Jun 16, 2020 at 10:12:35PM +0900, Paul Elder wrote:
> Implement VIDIOC_ENUM_FRAMESIZES in the V4L2 compatibility layer.
>
> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> ---
>  src/v4l2/v4l2_camera_proxy.cpp | 24 ++++++++++++++++++++++++
>  src/v4l2/v4l2_camera_proxy.h   |  1 +
>  2 files changed, 25 insertions(+)
>
> diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> index 6c0dacc..a5fa478 100644
> --- a/src/v4l2/v4l2_camera_proxy.cpp
> +++ b/src/v4l2/v4l2_camera_proxy.cpp
> @@ -251,6 +251,27 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg)
>  	return 0;
>  }
>
> +int V4L2CameraProxy::vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg)
> +{
> +	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << fd;
> +
> +	if (arg == nullptr)
> +		return -EFAULT;
> +
> +	PixelFormat argFormat = v4l2ToDrm(arg->pixel_format);
 just format ?

> +	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(argFormat);

just sizes ?

Anyway, very few pipeline handlers report StreamFormats at the moment,
I would record this with a \todo entry.

Another point is that the streamConfig_ you here use to enumerate formats is
generated using the Viewfinder role only. In this case, I expect
pipeline handlers not to report any entry for, for example, raw
formats, while the Camera actually supports it.

There's no easy way around this I'm afraid, or at least I don't see an
easy one. I had to do a similar thing for Android, as you can see in
src/android/camera_device.cpp:243

There I decided to create a list of image resolutions, and test
them against the application provided pixel format, by using
CameraConfiguration::validate(). This probably won't scale here, as
the list of resolution would be quite arbitrary, while in Android I
have a specification to follow which dictates which resolution are
mandatory to be supported.

Generating multiple CameraConfiguration (one for each supported role)
and test all of them until we don't find on which reports the desired
image format is another option, but would require you to introduce an
API to do so in your V4L2Camera class. In both cases, a bit of rework
is required. What do you think ?

> +
> +	if (arg->index >= frameSizes.size())
> +		return -EINVAL;

That's fine, as if the format is not supported StreamFormats::sizes()
will return an empty vector, but the v4l2 specs do not say what is the
expected behaviour in that case. Does v4l2-compliance try this call
with an invalid format ?

> +
> +	arg->type = V4L2_FRMSIZE_TYPE_DISCRETE;
> +	arg->discrete.width = frameSizes[arg->index].width;
> +	arg->discrete.height = frameSizes[arg->index].height;
> +	memset(arg->reserved, 0, sizeof(arg->reserved));
> +
> +	return 0;
> +}
> +
>  int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg)
>  {
>  	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd;
> @@ -676,6 +697,9 @@ int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg)
>  	case VIDIOC_QUERYCAP:
>  		ret = vidioc_querycap(static_cast<struct v4l2_capability *>(arg));
>  		break;
> +	case VIDIOC_ENUM_FRAMESIZES:
> +		ret = vidioc_enum_framesizes(fd, static_cast<struct v4l2_frmsizeenum *>(arg));
> +		break;
>  	case VIDIOC_ENUM_FMT:
>  		ret = vidioc_enum_fmt(fd, static_cast<struct v4l2_fmtdesc *>(arg));
>  		break;
> diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
> index 2e90bfd..2ff9571 100644
> --- a/src/v4l2/v4l2_camera_proxy.h
> +++ b/src/v4l2/v4l2_camera_proxy.h
> @@ -45,6 +45,7 @@ private:
>  	int freeBuffers();
>
>  	int vidioc_querycap(struct v4l2_capability *arg);
> +	int vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg);
>  	int vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg);
>  	int vidioc_g_fmt(int fd, struct v4l2_format *arg);
>  	int vidioc_s_fmt(int fd, struct v4l2_format *arg);
> --
> 2.27.0
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
Laurent Pinchart June 17, 2020, 3:43 p.m. UTC | #2
Hi Jacopo,

On Wed, Jun 17, 2020 at 04:08:39PM +0200, Jacopo Mondi wrote:
> On Tue, Jun 16, 2020 at 10:12:35PM +0900, Paul Elder wrote:
> > Implement VIDIOC_ENUM_FRAMESIZES in the V4L2 compatibility layer.
> >
> > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > ---
> >  src/v4l2/v4l2_camera_proxy.cpp | 24 ++++++++++++++++++++++++
> >  src/v4l2/v4l2_camera_proxy.h   |  1 +
> >  2 files changed, 25 insertions(+)
> >
> > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> > index 6c0dacc..a5fa478 100644
> > --- a/src/v4l2/v4l2_camera_proxy.cpp
> > +++ b/src/v4l2/v4l2_camera_proxy.cpp
> > @@ -251,6 +251,27 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg)
> >  	return 0;
> >  }
> >
> > +int V4L2CameraProxy::vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg)
> > +{
> > +	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << fd;
> > +
> > +	if (arg == nullptr)
> > +		return -EFAULT;
> > +
> > +	PixelFormat argFormat = v4l2ToDrm(arg->pixel_format);
>  just format ?
> 
> > +	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(argFormat);
> 
> just sizes ?
> 
> Anyway, very few pipeline handlers report StreamFormats at the moment,
> I would record this with a \todo entry.
> 
> Another point is that the streamConfig_ you here use to enumerate formats is
> generated using the Viewfinder role only. In this case, I expect
> pipeline handlers not to report any entry for, for example, raw
> formats, while the Camera actually supports it.

Is that a problem though ? The V4L2 compat layer is meant to support
existing V4L2 applications that are not yet ported to libcamera (or that
can't easily be ported, for instance because they're not open-source),
on a best effort basis. I would not expect such applications to really
have a use for raw formats. I think the viewfinder role makes sense as a
best-effort implementation.

> There's no easy way around this I'm afraid, or at least I don't see an
> easy one. I had to do a similar thing for Android, as you can see in
> src/android/camera_device.cpp:243
> 
> There I decided to create a list of image resolutions, and test
> them against the application provided pixel format, by using
> CameraConfiguration::validate(). This probably won't scale here, as
> the list of resolution would be quite arbitrary, while in Android I
> have a specification to follow which dictates which resolution are
> mandatory to be supported.
> 
> Generating multiple CameraConfiguration (one for each supported role)
> and test all of them until we don't find on which reports the desired
> image format is another option, but would require you to introduce an
> API to do so in your V4L2Camera class. In both cases, a bit of rework
> is required. What do you think ?
> 
> > +
> > +	if (arg->index >= frameSizes.size())
> > +		return -EINVAL;
> 
> That's fine, as if the format is not supported StreamFormats::sizes()
> will return an empty vector, but the v4l2 specs do not say what is the
> expected behaviour in that case. Does v4l2-compliance try this call
> with an invalid format ?

	ret = testEnumFrameSizes(node, 0x20202020);
	if (ret != ENOTTY)
		return fail("Accepted framesize for invalid format\n");

and testEnumFrameSizes has a special case:

		if (f == 0 && ret == EINVAL)
			return ENOTTY;

(f being the loop index). So I think the code is fine.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> > +
> > +	arg->type = V4L2_FRMSIZE_TYPE_DISCRETE;
> > +	arg->discrete.width = frameSizes[arg->index].width;
> > +	arg->discrete.height = frameSizes[arg->index].height;
> > +	memset(arg->reserved, 0, sizeof(arg->reserved));
> > +
> > +	return 0;
> > +}
> > +
> >  int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg)
> >  {
> >  	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd;
> > @@ -676,6 +697,9 @@ int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg)
> >  	case VIDIOC_QUERYCAP:
> >  		ret = vidioc_querycap(static_cast<struct v4l2_capability *>(arg));
> >  		break;
> > +	case VIDIOC_ENUM_FRAMESIZES:
> > +		ret = vidioc_enum_framesizes(fd, static_cast<struct v4l2_frmsizeenum *>(arg));
> > +		break;
> >  	case VIDIOC_ENUM_FMT:
> >  		ret = vidioc_enum_fmt(fd, static_cast<struct v4l2_fmtdesc *>(arg));
> >  		break;
> > diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
> > index 2e90bfd..2ff9571 100644
> > --- a/src/v4l2/v4l2_camera_proxy.h
> > +++ b/src/v4l2/v4l2_camera_proxy.h
> > @@ -45,6 +45,7 @@ private:
> >  	int freeBuffers();
> >
> >  	int vidioc_querycap(struct v4l2_capability *arg);
> > +	int vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg);
> >  	int vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg);
> >  	int vidioc_g_fmt(int fd, struct v4l2_format *arg);
> >  	int vidioc_s_fmt(int fd, struct v4l2_format *arg);
Paul Elder June 18, 2020, 5:24 a.m. UTC | #3
Hi Jacopo,

Thanks for the review.

On Wed, Jun 17, 2020 at 04:08:39PM +0200, Jacopo Mondi wrote:
> Hi Paul,
> 
> On Tue, Jun 16, 2020 at 10:12:35PM +0900, Paul Elder wrote:
> > Implement VIDIOC_ENUM_FRAMESIZES in the V4L2 compatibility layer.
> >
> > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > ---
> >  src/v4l2/v4l2_camera_proxy.cpp | 24 ++++++++++++++++++++++++
> >  src/v4l2/v4l2_camera_proxy.h   |  1 +
> >  2 files changed, 25 insertions(+)
> >
> > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> > index 6c0dacc..a5fa478 100644
> > --- a/src/v4l2/v4l2_camera_proxy.cpp
> > +++ b/src/v4l2/v4l2_camera_proxy.cpp
> > @@ -251,6 +251,27 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg)
> >  	return 0;
> >  }
> >
> > +int V4L2CameraProxy::vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg)
> > +{
> > +	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << fd;
> > +
> > +	if (arg == nullptr)
> > +		return -EFAULT;
> > +
> > +	PixelFormat argFormat = v4l2ToDrm(arg->pixel_format);
>  just format ?
> 
> > +	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(argFormat);
> 
> just sizes ?

I don't understand; what's wrong with just format and just sizes? The
only two input parameters to enum_framesizes are index and pixel_format.

> Anyway, very few pipeline handlers report StreamFormats at the moment,
> I would record this with a \todo entry.

Oh, okay.

> Another point is that the streamConfig_ you here use to enumerate formats is
> generated using the Viewfinder role only. In this case, I expect
> pipeline handlers not to report any entry for, for example, raw
> formats, while the Camera actually supports it.
> There's no easy way around this I'm afraid, or at least I don't see an
> easy one. I had to do a similar thing for Android, as you can see in
> src/android/camera_device.cpp:243
> 
> There I decided to create a list of image resolutions, and test
> them against the application provided pixel format, by using
> CameraConfiguration::validate(). This probably won't scale here, as
> the list of resolution would be quite arbitrary, while in Android I

Yeah :/ I'd rather not.

> have a specification to follow which dictates which resolution are
> mandatory to be supported.
> 
> Generating multiple CameraConfiguration (one for each supported role)
> and test all of them until we don't find on which reports the desired
> image format is another option, but would require you to introduce an
> API to do so in your V4L2Camera class. In both cases, a bit of rework
> is required. What do you think ?

I can't keep what I already have here? tbh I just added this as a
convenience for applications where the user can explicitly choose the
format, like qv4l2, and not for applications that choose it
automatically, like firefox and skype. So in the absence of this ioctl,
applications would just go with the usual g/s_fmt negotiation.

> > +
> > +	if (arg->index >= frameSizes.size())
> > +		return -EINVAL;
> 
> That's fine, as if the format is not supported StreamFormats::sizes()
> will return an empty vector, but the v4l2 specs do not say what is the

Yeah, that was my intention.

> expected behaviour in that case. Does v4l2-compliance try this call
> with an invalid format ?


Thanks,

Paul

> > +
> > +	arg->type = V4L2_FRMSIZE_TYPE_DISCRETE;
> > +	arg->discrete.width = frameSizes[arg->index].width;
> > +	arg->discrete.height = frameSizes[arg->index].height;
> > +	memset(arg->reserved, 0, sizeof(arg->reserved));
> > +
> > +	return 0;
> > +}
> > +
> >  int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg)
> >  {
> >  	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd;
> > @@ -676,6 +697,9 @@ int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg)
> >  	case VIDIOC_QUERYCAP:
> >  		ret = vidioc_querycap(static_cast<struct v4l2_capability *>(arg));
> >  		break;
> > +	case VIDIOC_ENUM_FRAMESIZES:
> > +		ret = vidioc_enum_framesizes(fd, static_cast<struct v4l2_frmsizeenum *>(arg));
> > +		break;
> >  	case VIDIOC_ENUM_FMT:
> >  		ret = vidioc_enum_fmt(fd, static_cast<struct v4l2_fmtdesc *>(arg));
> >  		break;
> > diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
> > index 2e90bfd..2ff9571 100644
> > --- a/src/v4l2/v4l2_camera_proxy.h
> > +++ b/src/v4l2/v4l2_camera_proxy.h
> > @@ -45,6 +45,7 @@ private:
> >  	int freeBuffers();
> >
> >  	int vidioc_querycap(struct v4l2_capability *arg);
> > +	int vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg);
> >  	int vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg);
> >  	int vidioc_g_fmt(int fd, struct v4l2_format *arg);
> >  	int vidioc_s_fmt(int fd, struct v4l2_format *arg);
> > --
> > 2.27.0
> >
> > _______________________________________________
> > libcamera-devel mailing list
> > libcamera-devel@lists.libcamera.org
> > https://lists.libcamera.org/listinfo/libcamera-devel
Jacopo Mondi June 18, 2020, 7:58 a.m. UTC | #4
Hi Paul,

On Thu, Jun 18, 2020 at 02:24:25PM +0900, Paul Elder wrote:
> Hi Jacopo,
>
> Thanks for the review.
>
> On Wed, Jun 17, 2020 at 04:08:39PM +0200, Jacopo Mondi wrote:
> > Hi Paul,
> >
> > On Tue, Jun 16, 2020 at 10:12:35PM +0900, Paul Elder wrote:
> > > Implement VIDIOC_ENUM_FRAMESIZES in the V4L2 compatibility layer.
> > >
> > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > > ---
> > >  src/v4l2/v4l2_camera_proxy.cpp | 24 ++++++++++++++++++++++++
> > >  src/v4l2/v4l2_camera_proxy.h   |  1 +
> > >  2 files changed, 25 insertions(+)
> > >
> > > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> > > index 6c0dacc..a5fa478 100644
> > > --- a/src/v4l2/v4l2_camera_proxy.cpp
> > > +++ b/src/v4l2/v4l2_camera_proxy.cpp
> > > @@ -251,6 +251,27 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg)
> > >  	return 0;
> > >  }
> > >
> > > +int V4L2CameraProxy::vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg)
> > > +{
> > > +	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << fd;
> > > +
> > > +	if (arg == nullptr)
> > > +		return -EFAULT;
> > > +
> > > +	PixelFormat argFormat = v4l2ToDrm(arg->pixel_format);
> >  just format ?
> >
> > > +	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(argFormat);
> >
> > just sizes ?
>
> I don't understand; what's wrong with just format and just sizes? The
> only two input parameters to enum_framesizes are index and pixel_format.
>

ahah, I was suggesting to use "format" and "sizes" in place of
argFormat and frameSizes :)

> > Anyway, very few pipeline handlers report StreamFormats at the moment,
> > I would record this with a \todo entry.
>
> Oh, okay.
>
> > Another point is that the streamConfig_ you here use to enumerate formats is
> > generated using the Viewfinder role only. In this case, I expect
> > pipeline handlers not to report any entry for, for example, raw
> > formats, while the Camera actually supports it.
> > There's no easy way around this I'm afraid, or at least I don't see an
> > easy one. I had to do a similar thing for Android, as you can see in
> > src/android/camera_device.cpp:243
> >
> > There I decided to create a list of image resolutions, and test
> > them against the application provided pixel format, by using
> > CameraConfiguration::validate(). This probably won't scale here, as
> > the list of resolution would be quite arbitrary, while in Android I
>
> Yeah :/ I'd rather not.
>
> > have a specification to follow which dictates which resolution are
> > mandatory to be supported.
> >
> > Generating multiple CameraConfiguration (one for each supported role)
> > and test all of them until we don't find on which reports the desired
> > image format is another option, but would require you to introduce an
> > API to do so in your V4L2Camera class. In both cases, a bit of rework
> > is required. What do you think ?
>
> I can't keep what I already have here? tbh I just added this as a
> convenience for applications where the user can explicitly choose the
> format, like qv4l2, and not for applications that choose it
> automatically, like firefox and skype. So in the absence of this ioctl,
> applications would just go with the usual g/s_fmt negotiation.
>

As Laurent pointed out, this is a best effort support for existing
applications, and they likely are not interested in raw formats or
advanced capture modes, so I think it's fine!

> > > +
> > > +	if (arg->index >= frameSizes.size())
> > > +		return -EINVAL;
> >
> > That's fine, as if the format is not supported StreamFormats::sizes()
> > will return an empty vector, but the v4l2 specs do not say what is the
>
> Yeah, that was my intention.
>
> > expected behaviour in that case. Does v4l2-compliance try this call
> > with an invalid format ?

I guess the last question was the relevant one, but Laurent has
reported that an invalid format is tested with:
         ret = testEnumFrameSizes(node, 0x20202020);

So I think we're good with reporting EINVAL here

Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>

Thanks
   j

>
>
> Thanks,
>
> Paul
>
> > > +
> > > +	arg->type = V4L2_FRMSIZE_TYPE_DISCRETE;
> > > +	arg->discrete.width = frameSizes[arg->index].width;
> > > +	arg->discrete.height = frameSizes[arg->index].height;
> > > +	memset(arg->reserved, 0, sizeof(arg->reserved));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg)
> > >  {
> > >  	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd;
> > > @@ -676,6 +697,9 @@ int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg)
> > >  	case VIDIOC_QUERYCAP:
> > >  		ret = vidioc_querycap(static_cast<struct v4l2_capability *>(arg));
> > >  		break;
> > > +	case VIDIOC_ENUM_FRAMESIZES:
> > > +		ret = vidioc_enum_framesizes(fd, static_cast<struct v4l2_frmsizeenum *>(arg));
> > > +		break;
> > >  	case VIDIOC_ENUM_FMT:
> > >  		ret = vidioc_enum_fmt(fd, static_cast<struct v4l2_fmtdesc *>(arg));
> > >  		break;
> > > diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
> > > index 2e90bfd..2ff9571 100644
> > > --- a/src/v4l2/v4l2_camera_proxy.h
> > > +++ b/src/v4l2/v4l2_camera_proxy.h
> > > @@ -45,6 +45,7 @@ private:
> > >  	int freeBuffers();
> > >
> > >  	int vidioc_querycap(struct v4l2_capability *arg);
> > > +	int vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg);
> > >  	int vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg);
> > >  	int vidioc_g_fmt(int fd, struct v4l2_format *arg);
> > >  	int vidioc_s_fmt(int fd, struct v4l2_format *arg);
> > > --
> > > 2.27.0
> > >
> > > _______________________________________________
> > > libcamera-devel mailing list
> > > libcamera-devel@lists.libcamera.org
> > > https://lists.libcamera.org/listinfo/libcamera-devel

Patch

diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
index 6c0dacc..a5fa478 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -251,6 +251,27 @@  int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg)
 	return 0;
 }
 
+int V4L2CameraProxy::vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg)
+{
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << fd;
+
+	if (arg == nullptr)
+		return -EFAULT;
+
+	PixelFormat argFormat = v4l2ToDrm(arg->pixel_format);
+	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(argFormat);
+
+	if (arg->index >= frameSizes.size())
+		return -EINVAL;
+
+	arg->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	arg->discrete.width = frameSizes[arg->index].width;
+	arg->discrete.height = frameSizes[arg->index].height;
+	memset(arg->reserved, 0, sizeof(arg->reserved));
+
+	return 0;
+}
+
 int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg)
 {
 	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd;
@@ -676,6 +697,9 @@  int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg)
 	case VIDIOC_QUERYCAP:
 		ret = vidioc_querycap(static_cast<struct v4l2_capability *>(arg));
 		break;
+	case VIDIOC_ENUM_FRAMESIZES:
+		ret = vidioc_enum_framesizes(fd, static_cast<struct v4l2_frmsizeenum *>(arg));
+		break;
 	case VIDIOC_ENUM_FMT:
 		ret = vidioc_enum_fmt(fd, static_cast<struct v4l2_fmtdesc *>(arg));
 		break;
diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
index 2e90bfd..2ff9571 100644
--- a/src/v4l2/v4l2_camera_proxy.h
+++ b/src/v4l2/v4l2_camera_proxy.h
@@ -45,6 +45,7 @@  private:
 	int freeBuffers();
 
 	int vidioc_querycap(struct v4l2_capability *arg);
+	int vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg);
 	int vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg);
 	int vidioc_g_fmt(int fd, struct v4l2_format *arg);
 	int vidioc_s_fmt(int fd, struct v4l2_format *arg);