linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] libv4lconvert: Add support for V4L2_PIX_FMT_NV12
@ 2019-04-16 12:02 Ricardo Ribalda Delgado
  2019-04-16 16:00 ` Hans de Goede
  2019-04-17 11:41 ` [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops Ricardo Ribalda Delgado
  0 siblings, 2 replies; 6+ messages in thread
From: Ricardo Ribalda Delgado @ 2019-04-16 12:02 UTC (permalink / raw)
  To: Hans de Goede, Hans Verkuil, Gregor Jasny, linux-media, daniel
  Cc: Ricardo Ribalda Delgado

NV12 is a two-plane version YUV 4:2:0, where the U and V components
are subsampled 2x2.

Signed-off-by: Ricardo Ribalda Delgado <ricardo@ribalda.com>
---
The code has ben tested with qv4l2 and vivid.
v4lconvert_nv12_to_yuv420 has not been tested!!, any suggestions for
how to do it?

Thanks!
 lib/libv4lconvert/libv4lconvert-priv.h |  6 +++
 lib/libv4lconvert/libv4lconvert.c      | 19 +++++++++
 lib/libv4lconvert/rgbyuv.c             | 56 ++++++++++++++++++++++++++
 3 files changed, 81 insertions(+)

diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h
index a8046ce2..c45b086e 100644
--- a/lib/libv4lconvert/libv4lconvert-priv.h
+++ b/lib/libv4lconvert/libv4lconvert-priv.h
@@ -285,6 +285,12 @@ void v4lconvert_hm12_to_yuv420(const unsigned char *src,
 void v4lconvert_hsv_to_rgb24(const unsigned char *src, unsigned char *dest,
 		int width, int height, int bgr, int Xin, unsigned char hsv_enc);
 
+void v4lconvert_nv12_to_rgb24(const unsigned char *src, unsigned char *dest,
+		int width, int height, int bgr);
+
+void v4lconvert_nv12_to_yuv420(const unsigned char *src, unsigned char *dest,
+		int width, int height, int yvu);
+
 void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
 		struct v4l2_format *fmt);
 
diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c
index 78fb3432..2111d19f 100644
--- a/lib/libv4lconvert/libv4lconvert.c
+++ b/lib/libv4lconvert/libv4lconvert.c
@@ -116,6 +116,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
 	{ V4L2_PIX_FMT_SN9C20X_I420,	12,	 6,	 3,	1 },
 	{ V4L2_PIX_FMT_M420,		12,	 6,	 3,	1 },
 	{ V4L2_PIX_FMT_HM12,		12,	 6,	 3,	1 },
+	{ V4L2_PIX_FMT_NV12,		12,	 6,	 3,	1 },
 	{ V4L2_PIX_FMT_CPIA1,		 0,	 6,	 3,	1 },
 	/* JPEG and variants */
 	{ V4L2_PIX_FMT_MJPEG,		 0,	 7,	 7,	0 },
@@ -902,6 +903,24 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
 		}
 		break;
 
+		/* NV12 formats */
+	case V4L2_PIX_FMT_NV12:
+		switch (dest_pix_fmt) {
+		case V4L2_PIX_FMT_RGB24:
+			v4lconvert_nv12_to_rgb24(src, dest, width, height, 0);
+			break;
+		case V4L2_PIX_FMT_BGR24:
+			v4lconvert_nv12_to_rgb24(src, dest, width, height, 1);
+			break;
+		case V4L2_PIX_FMT_YUV420:
+			v4lconvert_nv12_to_yuv420(src, dest, width, height, 0);
+			break;
+		case V4L2_PIX_FMT_YVU420:
+			v4lconvert_nv12_to_yuv420(src, dest, width, height, 1);
+			break;
+		}
+		break;
+
 		/* compressed bayer formats */
 	case V4L2_PIX_FMT_SPCA561:
 	case V4L2_PIX_FMT_SN9C10X:
diff --git a/lib/libv4lconvert/rgbyuv.c b/lib/libv4lconvert/rgbyuv.c
index 02c8cb5b..bfe3b15f 100644
--- a/lib/libv4lconvert/rgbyuv.c
+++ b/lib/libv4lconvert/rgbyuv.c
@@ -845,3 +845,59 @@ void v4lconvert_hsv_to_rgb24(const unsigned char *src, unsigned char *dest,
 			src += bppIN;
 		}
 }
+
+void v4lconvert_nv12_to_rgb24(const unsigned char *src, unsigned char *dest,
+		int width, int height, int bgr)
+{
+	int i, j;
+	const unsigned char *ysrc = src;
+	const unsigned char *uvsrc = src + width * height;
+
+	for (i = 0; i < height; i++) {
+		for (j = 0; j < width; j ++) {
+			if (bgr) {
+				*dest++ = YUV2B(*ysrc, *uvsrc, *(uvsrc + 1));
+				*dest++ = YUV2G(*ysrc, *uvsrc, *(uvsrc + 1));
+				*dest++ = YUV2R(*ysrc, *uvsrc, *(uvsrc + 1));
+			} else {
+				*dest++ = YUV2R(*ysrc, *uvsrc, *(uvsrc + 1));
+				*dest++ = YUV2G(*ysrc, *uvsrc, *(uvsrc + 1));
+				*dest++ = YUV2B(*ysrc, *uvsrc, *(uvsrc + 1));
+			}
+			ysrc++;
+			if (j&1)
+				uvsrc += 2;
+		}
+
+		/* Rewind u and v for next line */
+		if (!(i&1))
+			uvsrc -= width;
+	}
+}
+
+void v4lconvert_nv12_to_yuv420(const unsigned char *src, unsigned char *dest,
+		int width, int height, int yvu)
+{
+	int i, j;
+	const unsigned char *ysrc = src;
+	const unsigned char *uvsrc = src + width * height;
+	unsigned char *ydst = dest;
+	unsigned char *udst, *vdst;
+
+	if (yvu) {
+		vdst = ydst + width * height;
+		udst = vdst + ((width / 2) * (height / 2));
+	} else {
+		udst = ydst + width * height;
+		vdst = udst + ((width / 2) * (height / 2));
+	}
+
+	for (i = 0; i < height; i++)
+		for (j = 0; i < width; j++) {
+			*ydst++ = *ysrc++;
+			if (((i % 2) == 0) && ((j % 2) == 0)) {
+				*udst++ = *uvsrc++;
+				*vdst++ = *uvsrc++;
+			}
+		}
+}
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] libv4lconvert: Add support for V4L2_PIX_FMT_NV12
  2019-04-16 12:02 [PATCH] libv4lconvert: Add support for V4L2_PIX_FMT_NV12 Ricardo Ribalda Delgado
@ 2019-04-16 16:00 ` Hans de Goede
  2019-04-17 10:04   ` Ricardo Ribalda Delgado
  2019-04-17 11:41 ` [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops Ricardo Ribalda Delgado
  1 sibling, 1 reply; 6+ messages in thread
From: Hans de Goede @ 2019-04-16 16:00 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado, Hans Verkuil, Gregor Jasny, linux-media, daniel

Hi Ricardo,

On 16-04-19 14:02, Ricardo Ribalda Delgado wrote:
> NV12 is a two-plane version YUV 4:2:0, where the U and V components
> are subsampled 2x2.
> 
> Signed-off-by: Ricardo Ribalda Delgado <ricardo@ribalda.com>

Your patch looks good to me, but it pushed the array-size of
the supported_src_pixfmts array over 64 entries (right now it is
exactly 64 entries big).

Which breaks supported_src_formats as that is only 64 bits big:

struct v4lconvert_data {
         int fd;
	...
         int64_t supported_src_formats; /* bitfield */


See e.g. :

                 for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
                         if (fmt.pixelformat == supported_src_pixfmts[j].fmt)
                                 break;

                 if (j < ARRAY_SIZE(supported_src_pixfmts)) {
                         data->supported_src_formats |= 1ULL << j;

I believe this is best fixed by a preparation patch which introduces the
bit-ops from the kernel for this:

include/asm-generic/bitops/non-atomic.h:

static inline void __set_bit(int nr, volatile unsigned long *addr)
{
         unsigned long mask = BIT_MASK(nr);
         unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);

         *p  |= mask;
}

static inline void __clear_bit(int nr, volatile unsigned long *addr)
{
         unsigned long mask = BIT_MASK(nr);
         unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);

         *p &= ~mask;
}

static inline int test_bit(int nr, const volatile unsigned long *addr)
{
         return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}

So you will have to change your patch into a 2 patch patch-set with
the first patch introducing  set_bit / clear_bit / test_bit helpers
modelled after the kernel and changing the declaration of
supported_src_formats to:

	unsigned long supported_src_formats[128 / BITS_PER_LONG];

Thanks & Regards,

Hans









> ---
> The code has ben tested with qv4l2 and vivid.
> v4lconvert_nv12_to_yuv420 has not been tested!!, any suggestions for
> how to do it?
> 
> Thanks!
>   lib/libv4lconvert/libv4lconvert-priv.h |  6 +++
>   lib/libv4lconvert/libv4lconvert.c      | 19 +++++++++
>   lib/libv4lconvert/rgbyuv.c             | 56 ++++++++++++++++++++++++++
>   3 files changed, 81 insertions(+)
> 
> diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h
> index a8046ce2..c45b086e 100644
> --- a/lib/libv4lconvert/libv4lconvert-priv.h
> +++ b/lib/libv4lconvert/libv4lconvert-priv.h
> @@ -285,6 +285,12 @@ void v4lconvert_hm12_to_yuv420(const unsigned char *src,
>   void v4lconvert_hsv_to_rgb24(const unsigned char *src, unsigned char *dest,
>   		int width, int height, int bgr, int Xin, unsigned char hsv_enc);
>   
> +void v4lconvert_nv12_to_rgb24(const unsigned char *src, unsigned char *dest,
> +		int width, int height, int bgr);
> +
> +void v4lconvert_nv12_to_yuv420(const unsigned char *src, unsigned char *dest,
> +		int width, int height, int yvu);
> +
>   void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
>   		struct v4l2_format *fmt);
>   
> diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c
> index 78fb3432..2111d19f 100644
> --- a/lib/libv4lconvert/libv4lconvert.c
> +++ b/lib/libv4lconvert/libv4lconvert.c
> @@ -116,6 +116,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
>   	{ V4L2_PIX_FMT_SN9C20X_I420,	12,	 6,	 3,	1 },
>   	{ V4L2_PIX_FMT_M420,		12,	 6,	 3,	1 },
>   	{ V4L2_PIX_FMT_HM12,		12,	 6,	 3,	1 },
> +	{ V4L2_PIX_FMT_NV12,		12,	 6,	 3,	1 },
>   	{ V4L2_PIX_FMT_CPIA1,		 0,	 6,	 3,	1 },
>   	/* JPEG and variants */
>   	{ V4L2_PIX_FMT_MJPEG,		 0,	 7,	 7,	0 },
> @@ -902,6 +903,24 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
>   		}
>   		break;
>   
> +		/* NV12 formats */
> +	case V4L2_PIX_FMT_NV12:
> +		switch (dest_pix_fmt) {
> +		case V4L2_PIX_FMT_RGB24:
> +			v4lconvert_nv12_to_rgb24(src, dest, width, height, 0);
> +			break;
> +		case V4L2_PIX_FMT_BGR24:
> +			v4lconvert_nv12_to_rgb24(src, dest, width, height, 1);
> +			break;
> +		case V4L2_PIX_FMT_YUV420:
> +			v4lconvert_nv12_to_yuv420(src, dest, width, height, 0);
> +			break;
> +		case V4L2_PIX_FMT_YVU420:
> +			v4lconvert_nv12_to_yuv420(src, dest, width, height, 1);
> +			break;
> +		}
> +		break;
> +
>   		/* compressed bayer formats */
>   	case V4L2_PIX_FMT_SPCA561:
>   	case V4L2_PIX_FMT_SN9C10X:
> diff --git a/lib/libv4lconvert/rgbyuv.c b/lib/libv4lconvert/rgbyuv.c
> index 02c8cb5b..bfe3b15f 100644
> --- a/lib/libv4lconvert/rgbyuv.c
> +++ b/lib/libv4lconvert/rgbyuv.c
> @@ -845,3 +845,59 @@ void v4lconvert_hsv_to_rgb24(const unsigned char *src, unsigned char *dest,
>   			src += bppIN;
>   		}
>   }
> +
> +void v4lconvert_nv12_to_rgb24(const unsigned char *src, unsigned char *dest,
> +		int width, int height, int bgr)
> +{
> +	int i, j;
> +	const unsigned char *ysrc = src;
> +	const unsigned char *uvsrc = src + width * height;
> +
> +	for (i = 0; i < height; i++) {
> +		for (j = 0; j < width; j ++) {
> +			if (bgr) {
> +				*dest++ = YUV2B(*ysrc, *uvsrc, *(uvsrc + 1));
> +				*dest++ = YUV2G(*ysrc, *uvsrc, *(uvsrc + 1));
> +				*dest++ = YUV2R(*ysrc, *uvsrc, *(uvsrc + 1));
> +			} else {
> +				*dest++ = YUV2R(*ysrc, *uvsrc, *(uvsrc + 1));
> +				*dest++ = YUV2G(*ysrc, *uvsrc, *(uvsrc + 1));
> +				*dest++ = YUV2B(*ysrc, *uvsrc, *(uvsrc + 1));
> +			}
> +			ysrc++;
> +			if (j&1)
> +				uvsrc += 2;
> +		}
> +
> +		/* Rewind u and v for next line */
> +		if (!(i&1))
> +			uvsrc -= width;
> +	}
> +}
> +
> +void v4lconvert_nv12_to_yuv420(const unsigned char *src, unsigned char *dest,
> +		int width, int height, int yvu)
> +{
> +	int i, j;
> +	const unsigned char *ysrc = src;
> +	const unsigned char *uvsrc = src + width * height;
> +	unsigned char *ydst = dest;
> +	unsigned char *udst, *vdst;
> +
> +	if (yvu) {
> +		vdst = ydst + width * height;
> +		udst = vdst + ((width / 2) * (height / 2));
> +	} else {
> +		udst = ydst + width * height;
> +		vdst = udst + ((width / 2) * (height / 2));
> +	}
> +
> +	for (i = 0; i < height; i++)
> +		for (j = 0; i < width; j++) {
> +			*ydst++ = *ysrc++;
> +			if (((i % 2) == 0) && ((j % 2) == 0)) {
> +				*udst++ = *uvsrc++;
> +				*vdst++ = *uvsrc++;
> +			}
> +		}
> +}
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libv4lconvert: Add support for V4L2_PIX_FMT_NV12
  2019-04-16 16:00 ` Hans de Goede
@ 2019-04-17 10:04   ` Ricardo Ribalda Delgado
  0 siblings, 0 replies; 6+ messages in thread
From: Ricardo Ribalda Delgado @ 2019-04-17 10:04 UTC (permalink / raw)
  To: Hans de Goede; +Cc: Hans Verkuil, Gregor Jasny, linux-media, Daniel Gomez

Hi Hans

On Tue, Apr 16, 2019 at 6:00 PM Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi Ricardo,
>
> On 16-04-19 14:02, Ricardo Ribalda Delgado wrote:
> > NV12 is a two-plane version YUV 4:2:0, where the U and V components
> > are subsampled 2x2.
> >
> > Signed-off-by: Ricardo Ribalda Delgado <ricardo@ribalda.com>
>
> Your patch looks good to me, but it pushed the array-size of
> the supported_src_pixfmts array over 64 entries (right now it is
> exactly 64 entries big).
>
> Which breaks supported_src_formats as that is only 64 bits big:

Good catch. Thanks for detailed description. Will redo and send back


>
> struct v4lconvert_data {
>          int fd;
>         ...
>          int64_t supported_src_formats; /* bitfield */
>
>
> See e.g. :
>
>                  for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
>                          if (fmt.pixelformat == supported_src_pixfmts[j].fmt)
>                                  break;
>
>                  if (j < ARRAY_SIZE(supported_src_pixfmts)) {
>                          data->supported_src_formats |= 1ULL << j;
>
> I believe this is best fixed by a preparation patch which introduces the
> bit-ops from the kernel for this:
>
> include/asm-generic/bitops/non-atomic.h:
>
> static inline void __set_bit(int nr, volatile unsigned long *addr)
> {
>          unsigned long mask = BIT_MASK(nr);
>          unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
>
>          *p  |= mask;
> }
>
> static inline void __clear_bit(int nr, volatile unsigned long *addr)
> {
>          unsigned long mask = BIT_MASK(nr);
>          unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
>
>          *p &= ~mask;
> }
>
> static inline int test_bit(int nr, const volatile unsigned long *addr)
> {
>          return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
> }
>
> So you will have to change your patch into a 2 patch patch-set with
> the first patch introducing  set_bit / clear_bit / test_bit helpers
> modelled after the kernel and changing the declaration of
> supported_src_formats to:
>
>         unsigned long supported_src_formats[128 / BITS_PER_LONG];
>
> Thanks & Regards,
>
> Hans
>
>
>
>
>
>
>
>
>
> > ---
> > The code has ben tested with qv4l2 and vivid.
> > v4lconvert_nv12_to_yuv420 has not been tested!!, any suggestions for
> > how to do it?
> >
> > Thanks!
> >   lib/libv4lconvert/libv4lconvert-priv.h |  6 +++
> >   lib/libv4lconvert/libv4lconvert.c      | 19 +++++++++
> >   lib/libv4lconvert/rgbyuv.c             | 56 ++++++++++++++++++++++++++
> >   3 files changed, 81 insertions(+)
> >
> > diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h
> > index a8046ce2..c45b086e 100644
> > --- a/lib/libv4lconvert/libv4lconvert-priv.h
> > +++ b/lib/libv4lconvert/libv4lconvert-priv.h
> > @@ -285,6 +285,12 @@ void v4lconvert_hm12_to_yuv420(const unsigned char *src,
> >   void v4lconvert_hsv_to_rgb24(const unsigned char *src, unsigned char *dest,
> >               int width, int height, int bgr, int Xin, unsigned char hsv_enc);
> >
> > +void v4lconvert_nv12_to_rgb24(const unsigned char *src, unsigned char *dest,
> > +             int width, int height, int bgr);
> > +
> > +void v4lconvert_nv12_to_yuv420(const unsigned char *src, unsigned char *dest,
> > +             int width, int height, int yvu);
> > +
> >   void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
> >               struct v4l2_format *fmt);
> >
> > diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c
> > index 78fb3432..2111d19f 100644
> > --- a/lib/libv4lconvert/libv4lconvert.c
> > +++ b/lib/libv4lconvert/libv4lconvert.c
> > @@ -116,6 +116,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
> >       { V4L2_PIX_FMT_SN9C20X_I420,    12,      6,      3,     1 },
> >       { V4L2_PIX_FMT_M420,            12,      6,      3,     1 },
> >       { V4L2_PIX_FMT_HM12,            12,      6,      3,     1 },
> > +     { V4L2_PIX_FMT_NV12,            12,      6,      3,     1 },
> >       { V4L2_PIX_FMT_CPIA1,            0,      6,      3,     1 },
> >       /* JPEG and variants */
> >       { V4L2_PIX_FMT_MJPEG,            0,      7,      7,     0 },
> > @@ -902,6 +903,24 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
> >               }
> >               break;
> >
> > +             /* NV12 formats */
> > +     case V4L2_PIX_FMT_NV12:
> > +             switch (dest_pix_fmt) {
> > +             case V4L2_PIX_FMT_RGB24:
> > +                     v4lconvert_nv12_to_rgb24(src, dest, width, height, 0);
> > +                     break;
> > +             case V4L2_PIX_FMT_BGR24:
> > +                     v4lconvert_nv12_to_rgb24(src, dest, width, height, 1);
> > +                     break;
> > +             case V4L2_PIX_FMT_YUV420:
> > +                     v4lconvert_nv12_to_yuv420(src, dest, width, height, 0);
> > +                     break;
> > +             case V4L2_PIX_FMT_YVU420:
> > +                     v4lconvert_nv12_to_yuv420(src, dest, width, height, 1);
> > +                     break;
> > +             }
> > +             break;
> > +
> >               /* compressed bayer formats */
> >       case V4L2_PIX_FMT_SPCA561:
> >       case V4L2_PIX_FMT_SN9C10X:
> > diff --git a/lib/libv4lconvert/rgbyuv.c b/lib/libv4lconvert/rgbyuv.c
> > index 02c8cb5b..bfe3b15f 100644
> > --- a/lib/libv4lconvert/rgbyuv.c
> > +++ b/lib/libv4lconvert/rgbyuv.c
> > @@ -845,3 +845,59 @@ void v4lconvert_hsv_to_rgb24(const unsigned char *src, unsigned char *dest,
> >                       src += bppIN;
> >               }
> >   }
> > +
> > +void v4lconvert_nv12_to_rgb24(const unsigned char *src, unsigned char *dest,
> > +             int width, int height, int bgr)
> > +{
> > +     int i, j;
> > +     const unsigned char *ysrc = src;
> > +     const unsigned char *uvsrc = src + width * height;
> > +
> > +     for (i = 0; i < height; i++) {
> > +             for (j = 0; j < width; j ++) {
> > +                     if (bgr) {
> > +                             *dest++ = YUV2B(*ysrc, *uvsrc, *(uvsrc + 1));
> > +                             *dest++ = YUV2G(*ysrc, *uvsrc, *(uvsrc + 1));
> > +                             *dest++ = YUV2R(*ysrc, *uvsrc, *(uvsrc + 1));
> > +                     } else {
> > +                             *dest++ = YUV2R(*ysrc, *uvsrc, *(uvsrc + 1));
> > +                             *dest++ = YUV2G(*ysrc, *uvsrc, *(uvsrc + 1));
> > +                             *dest++ = YUV2B(*ysrc, *uvsrc, *(uvsrc + 1));
> > +                     }
> > +                     ysrc++;
> > +                     if (j&1)
> > +                             uvsrc += 2;
> > +             }
> > +
> > +             /* Rewind u and v for next line */
> > +             if (!(i&1))
> > +                     uvsrc -= width;
> > +     }
> > +}
> > +
> > +void v4lconvert_nv12_to_yuv420(const unsigned char *src, unsigned char *dest,
> > +             int width, int height, int yvu)
> > +{
> > +     int i, j;
> > +     const unsigned char *ysrc = src;
> > +     const unsigned char *uvsrc = src + width * height;
> > +     unsigned char *ydst = dest;
> > +     unsigned char *udst, *vdst;
> > +
> > +     if (yvu) {
> > +             vdst = ydst + width * height;
> > +             udst = vdst + ((width / 2) * (height / 2));
> > +     } else {
> > +             udst = ydst + width * height;
> > +             vdst = udst + ((width / 2) * (height / 2));
> > +     }
> > +
> > +     for (i = 0; i < height; i++)
> > +             for (j = 0; i < width; j++) {
> > +                     *ydst++ = *ysrc++;
> > +                     if (((i % 2) == 0) && ((j % 2) == 0)) {
> > +                             *udst++ = *uvsrc++;
> > +                             *vdst++ = *uvsrc++;
> > +                     }
> > +             }
> > +}
> >



--
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops
  2019-04-16 12:02 [PATCH] libv4lconvert: Add support for V4L2_PIX_FMT_NV12 Ricardo Ribalda Delgado
  2019-04-16 16:00 ` Hans de Goede
@ 2019-04-17 11:41 ` Ricardo Ribalda Delgado
  2019-04-17 11:41   ` [PATCH v2 2/2] libv4lconvert: Add support for V4L2_PIX_FMT_NV12 Ricardo Ribalda Delgado
  2019-04-18 11:21   ` [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops Hans de Goede
  1 sibling, 2 replies; 6+ messages in thread
From: Ricardo Ribalda Delgado @ 2019-04-17 11:41 UTC (permalink / raw)
  To: Hans de Goede, Hans Verkuil, Gregor Jasny, linux-media, daniel
  Cc: Ricardo Ribalda Delgado

We have passed the barrier of 64 supported formats, therefore a int64_t
is not enough for holding the bitfield.

Instead use bit-ops ala kernel.

Signed-off-by: Ricardo Ribalda Delgado <ricardo@ribalda.com>
Suggested-by: Hans de Goede <hdegoede@redhat.com>
---
 lib/libv4lconvert/libv4lconvert-priv.h |  3 +-
 lib/libv4lconvert/libv4lconvert.c      | 40 ++++++++++++++++++++++----
 2 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h
index a8046ce2..5286a9b1 100644
--- a/lib/libv4lconvert/libv4lconvert-priv.h
+++ b/lib/libv4lconvert/libv4lconvert-priv.h
@@ -38,6 +38,7 @@
 #include "tinyjpeg.h"
 
 #define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
+#define BITS_PER_LONG (8 * sizeof(long))
 
 #define V4LCONVERT_ERROR_MSG_SIZE 256
 #define V4LCONVERT_MAX_FRAMESIZES 256
@@ -55,7 +56,7 @@ struct v4lconvert_data {
 	int flags; /* bitfield */
 	int control_flags; /* bitfield */
 	unsigned int no_formats;
-	int64_t supported_src_formats; /* bitfield */
+	unsigned long supported_src_formats[128 / BITS_PER_LONG];
 	char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
 	struct jdec_private *tinyjpeg;
 #ifdef HAVE_JPEG
diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c
index 78fb3432..0607cc8b 100644
--- a/lib/libv4lconvert/libv4lconvert.c
+++ b/lib/libv4lconvert/libv4lconvert.c
@@ -32,6 +32,29 @@
 #include "libv4lsyscall-priv.h"
 
 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p  |= mask;
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p &= ~mask;
+}
+
+static inline int __test_bit(int nr, const volatile unsigned long *addr)
+{
+	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
 
 static void *dev_init(int fd)
 {
@@ -231,7 +254,7 @@ struct v4lconvert_data *v4lconvert_create_with_dev_ops(int fd, void *dev_ops_pri
 				break;
 
 		if (j < ARRAY_SIZE(supported_src_pixfmts)) {
-			data->supported_src_formats |= 1ULL << j;
+			__set_bit(j, data->supported_src_formats);
 			v4lconvert_get_framesizes(data, fmt.pixelformat, j);
 			if (!supported_src_pixfmts[j].needs_conversion)
 				always_needs_conversion = 0;
@@ -316,8 +339,15 @@ int v4lconvert_supported_dst_format(unsigned int pixelformat)
 
 int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data)
 {
-	return v4lcontrol_needs_conversion(data->control) &&
-		data->supported_src_formats;
+	int i;
+
+	for (i = 0 ; i < ARRAY_SIZE(data->supported_src_formats); i++)
+		if (data->supported_src_formats[i])
+			break;
+	if (i == ARRAY_SIZE(data->supported_src_formats))
+		return 0;
+
+	return v4lcontrol_needs_conversion(data->control);
 }
 
 /* See libv4lconvert.h for description of in / out parameters */
@@ -334,7 +364,7 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
 
 	for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
 		if (v4lconvert_supported_dst_fmt_only(data) ||
-				!(data->supported_src_formats & (1ULL << i))) {
+		    !__test_bit(i, data->supported_src_formats)) {
 			faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
 			no_faked_fmts++;
 		}
@@ -490,7 +520,7 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data,
 
 	for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
 		/* is this format supported? */
-		if (!(data->supported_src_formats & (1ULL << i)))
+		if (!__test_bit(i, data->supported_src_formats))
 			continue;
 
 		try_fmt = *dest_fmt;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/2] libv4lconvert: Add support for V4L2_PIX_FMT_NV12
  2019-04-17 11:41 ` [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops Ricardo Ribalda Delgado
@ 2019-04-17 11:41   ` Ricardo Ribalda Delgado
  2019-04-18 11:21   ` [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops Hans de Goede
  1 sibling, 0 replies; 6+ messages in thread
From: Ricardo Ribalda Delgado @ 2019-04-17 11:41 UTC (permalink / raw)
  To: Hans de Goede, Hans Verkuil, Gregor Jasny, linux-media, daniel
  Cc: Ricardo Ribalda Delgado

NV12 is a two-plane version YUV 4:2:0, where the U and V components
are subsampled 2x2.

Signed-off-by: Ricardo Ribalda Delgado <ricardo@ribalda.com>
---

Changelog v2:
- None

The code has ben tested with qv4l2 and vivid.
v4lconvert_nv12_to_yuv420 has not been tested!!, any suggestions for
how to do it?

 lib/libv4lconvert/libv4lconvert-priv.h |  6 +++
 lib/libv4lconvert/libv4lconvert.c      | 19 +++++++++
 lib/libv4lconvert/rgbyuv.c             | 56 ++++++++++++++++++++++++++
 3 files changed, 81 insertions(+)

diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h
index 5286a9b1..ce5970c9 100644
--- a/lib/libv4lconvert/libv4lconvert-priv.h
+++ b/lib/libv4lconvert/libv4lconvert-priv.h
@@ -286,6 +286,12 @@ void v4lconvert_hm12_to_yuv420(const unsigned char *src,
 void v4lconvert_hsv_to_rgb24(const unsigned char *src, unsigned char *dest,
 		int width, int height, int bgr, int Xin, unsigned char hsv_enc);
 
+void v4lconvert_nv12_to_rgb24(const unsigned char *src, unsigned char *dest,
+		int width, int height, int bgr);
+
+void v4lconvert_nv12_to_yuv420(const unsigned char *src, unsigned char *dest,
+		int width, int height, int yvu);
+
 void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
 		struct v4l2_format *fmt);
 
diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c
index 0607cc8b..665ee9ea 100644
--- a/lib/libv4lconvert/libv4lconvert.c
+++ b/lib/libv4lconvert/libv4lconvert.c
@@ -139,6 +139,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
 	{ V4L2_PIX_FMT_SN9C20X_I420,	12,	 6,	 3,	1 },
 	{ V4L2_PIX_FMT_M420,		12,	 6,	 3,	1 },
 	{ V4L2_PIX_FMT_HM12,		12,	 6,	 3,	1 },
+	{ V4L2_PIX_FMT_NV12,		12,	 6,	 3,	1 },
 	{ V4L2_PIX_FMT_CPIA1,		 0,	 6,	 3,	1 },
 	/* JPEG and variants */
 	{ V4L2_PIX_FMT_MJPEG,		 0,	 7,	 7,	0 },
@@ -932,6 +933,24 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
 		}
 		break;
 
+		/* NV12 formats */
+	case V4L2_PIX_FMT_NV12:
+		switch (dest_pix_fmt) {
+		case V4L2_PIX_FMT_RGB24:
+			v4lconvert_nv12_to_rgb24(src, dest, width, height, 0);
+			break;
+		case V4L2_PIX_FMT_BGR24:
+			v4lconvert_nv12_to_rgb24(src, dest, width, height, 1);
+			break;
+		case V4L2_PIX_FMT_YUV420:
+			v4lconvert_nv12_to_yuv420(src, dest, width, height, 0);
+			break;
+		case V4L2_PIX_FMT_YVU420:
+			v4lconvert_nv12_to_yuv420(src, dest, width, height, 1);
+			break;
+		}
+		break;
+
 		/* compressed bayer formats */
 	case V4L2_PIX_FMT_SPCA561:
 	case V4L2_PIX_FMT_SN9C10X:
diff --git a/lib/libv4lconvert/rgbyuv.c b/lib/libv4lconvert/rgbyuv.c
index 02c8cb5b..79bc0bdb 100644
--- a/lib/libv4lconvert/rgbyuv.c
+++ b/lib/libv4lconvert/rgbyuv.c
@@ -845,3 +845,59 @@ void v4lconvert_hsv_to_rgb24(const unsigned char *src, unsigned char *dest,
 			src += bppIN;
 		}
 }
+
+void v4lconvert_nv12_to_rgb24(const unsigned char *src, unsigned char *dest,
+		int width, int height, int bgr)
+{
+	int i, j;
+	const unsigned char *ysrc = src;
+	const unsigned char *uvsrc = src + width * height;
+
+	for (i = 0; i < height; i++) {
+		for (j = 0; j < width; j ++) {
+			if (bgr) {
+				*dest++ = YUV2B(*ysrc, *uvsrc, *(uvsrc + 1));
+				*dest++ = YUV2G(*ysrc, *uvsrc, *(uvsrc + 1));
+				*dest++ = YUV2R(*ysrc, *uvsrc, *(uvsrc + 1));
+			} else {
+				*dest++ = YUV2R(*ysrc, *uvsrc, *(uvsrc + 1));
+				*dest++ = YUV2G(*ysrc, *uvsrc, *(uvsrc + 1));
+				*dest++ = YUV2B(*ysrc, *uvsrc, *(uvsrc + 1));
+			}
+			ysrc++;
+			if (j&1)
+				uvsrc += 2;
+		}
+
+		/* Rewind u and v for next line */
+		if (!(i&1))
+			uvsrc -= width;
+	}
+}
+
+void v4lconvert_nv12_to_yuv420(const unsigned char *src, unsigned char *dest,
+		int width, int height, int yvu)
+{
+	int i, j;
+	const unsigned char *ysrc = src;
+	const unsigned char *uvsrc = src + width * height;
+	unsigned char *ydst = dest;
+	unsigned char *udst, *vdst;
+
+	if (yvu) {
+		vdst = ydst + width * height;
+		udst = vdst + ((width / 2) * (height / 2));
+	} else {
+		udst = ydst + width * height;
+		vdst = udst + ((width / 2) * (height / 2));
+	}
+
+	for (i = 0; i < height; i++)
+		for (j = 0; i < width; j++) {
+			*ydst++ = *ysrc++;
+			if (((i % 2) == 0) && ((j % 2) == 0)) {
+				*udst++ = *uvsrc++;
+				*vdst++ = *uvsrc++;
+			}
+		}
+}
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops
  2019-04-17 11:41 ` [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops Ricardo Ribalda Delgado
  2019-04-17 11:41   ` [PATCH v2 2/2] libv4lconvert: Add support for V4L2_PIX_FMT_NV12 Ricardo Ribalda Delgado
@ 2019-04-18 11:21   ` Hans de Goede
  1 sibling, 0 replies; 6+ messages in thread
From: Hans de Goede @ 2019-04-18 11:21 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado, Hans Verkuil, Gregor Jasny, linux-media, daniel

Hi,

On 17-04-19 13:41, Ricardo Ribalda Delgado wrote:
> We have passed the barrier of 64 supported formats, therefore a int64_t
> is not enough for holding the bitfield.
> 
> Instead use bit-ops ala kernel.
> 
> Signed-off-by: Ricardo Ribalda Delgado <ricardo@ribalda.com>
> Suggested-by: Hans de Goede <hdegoede@redhat.com>

Thank you.

I've dropped the unnecessary __prefix from the bitop functions and
I've pushed both patches to the upstream master branch now.

Regards,

Hans



> ---
>   lib/libv4lconvert/libv4lconvert-priv.h |  3 +-
>   lib/libv4lconvert/libv4lconvert.c      | 40 ++++++++++++++++++++++----
>   2 files changed, 37 insertions(+), 6 deletions(-)
> 
> diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h
> index a8046ce2..5286a9b1 100644
> --- a/lib/libv4lconvert/libv4lconvert-priv.h
> +++ b/lib/libv4lconvert/libv4lconvert-priv.h
> @@ -38,6 +38,7 @@
>   #include "tinyjpeg.h"
>   
>   #define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
> +#define BITS_PER_LONG (8 * sizeof(long))
>   
>   #define V4LCONVERT_ERROR_MSG_SIZE 256
>   #define V4LCONVERT_MAX_FRAMESIZES 256
> @@ -55,7 +56,7 @@ struct v4lconvert_data {
>   	int flags; /* bitfield */
>   	int control_flags; /* bitfield */
>   	unsigned int no_formats;
> -	int64_t supported_src_formats; /* bitfield */
> +	unsigned long supported_src_formats[128 / BITS_PER_LONG];
>   	char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
>   	struct jdec_private *tinyjpeg;
>   #ifdef HAVE_JPEG
> diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c
> index 78fb3432..0607cc8b 100644
> --- a/lib/libv4lconvert/libv4lconvert.c
> +++ b/lib/libv4lconvert/libv4lconvert.c
> @@ -32,6 +32,29 @@
>   #include "libv4lsyscall-priv.h"
>   
>   #define MIN(a, b) (((a) < (b)) ? (a) : (b))
> +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
> +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
> +
> +static inline void __set_bit(int nr, volatile unsigned long *addr)
> +{
> +	unsigned long mask = BIT_MASK(nr);
> +	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
> +
> +	*p  |= mask;
> +}
> +
> +static inline void __clear_bit(int nr, volatile unsigned long *addr)
> +{
> +	unsigned long mask = BIT_MASK(nr);
> +	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
> +
> +	*p &= ~mask;
> +}
> +
> +static inline int __test_bit(int nr, const volatile unsigned long *addr)
> +{
> +	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
> +}
>   
>   static void *dev_init(int fd)
>   {
> @@ -231,7 +254,7 @@ struct v4lconvert_data *v4lconvert_create_with_dev_ops(int fd, void *dev_ops_pri
>   				break;
>   
>   		if (j < ARRAY_SIZE(supported_src_pixfmts)) {
> -			data->supported_src_formats |= 1ULL << j;
> +			__set_bit(j, data->supported_src_formats);
>   			v4lconvert_get_framesizes(data, fmt.pixelformat, j);
>   			if (!supported_src_pixfmts[j].needs_conversion)
>   				always_needs_conversion = 0;
> @@ -316,8 +339,15 @@ int v4lconvert_supported_dst_format(unsigned int pixelformat)
>   
>   int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data)
>   {
> -	return v4lcontrol_needs_conversion(data->control) &&
> -		data->supported_src_formats;
> +	int i;
> +
> +	for (i = 0 ; i < ARRAY_SIZE(data->supported_src_formats); i++)
> +		if (data->supported_src_formats[i])
> +			break;
> +	if (i == ARRAY_SIZE(data->supported_src_formats))
> +		return 0;
> +
> +	return v4lcontrol_needs_conversion(data->control);
>   }
>   
>   /* See libv4lconvert.h for description of in / out parameters */
> @@ -334,7 +364,7 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
>   
>   	for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
>   		if (v4lconvert_supported_dst_fmt_only(data) ||
> -				!(data->supported_src_formats & (1ULL << i))) {
> +		    !__test_bit(i, data->supported_src_formats)) {
>   			faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
>   			no_faked_fmts++;
>   		}
> @@ -490,7 +520,7 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data,
>   
>   	for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
>   		/* is this format supported? */
> -		if (!(data->supported_src_formats & (1ULL << i)))
> +		if (!__test_bit(i, data->supported_src_formats))
>   			continue;
>   
>   		try_fmt = *dest_fmt;
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-04-18 11:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-16 12:02 [PATCH] libv4lconvert: Add support for V4L2_PIX_FMT_NV12 Ricardo Ribalda Delgado
2019-04-16 16:00 ` Hans de Goede
2019-04-17 10:04   ` Ricardo Ribalda Delgado
2019-04-17 11:41 ` [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops Ricardo Ribalda Delgado
2019-04-17 11:41   ` [PATCH v2 2/2] libv4lconvert: Add support for V4L2_PIX_FMT_NV12 Ricardo Ribalda Delgado
2019-04-18 11:21   ` [PATCH v2 1/2] libv4lconvert: Port supported_src_formats to bit-ops Hans de Goede

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).