* [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).