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 <rica...@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

Reply via email to