Hi Hans
On Tue, Apr 16, 2019 at 6:00 PM Hans de Goede <[email protected]> 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 <[email protected]>
>
> 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