video: Added a util API for converting pixel format of tbm_surface_h from NV12 to... 81/217381/6
authorSeunghun Lee <shiin.lee@samsung.com>
Tue, 5 Nov 2019 06:28:27 +0000 (15:28 +0900)
committerSeunghun Lee <shiin.lee@samsung.com>
Tue, 12 Nov 2019 05:52:09 +0000 (14:52 +0900)
Change-Id: Ie98092de369b14f34c4b1d3b754f6555fe28955f

src/bin/Makefile.mk
src/bin/video/e_util_video.c [new file with mode: 0644]
src/bin/video/e_util_video.h [new file with mode: 0644]

index cff8d69..c093051 100644 (file)
@@ -228,6 +228,7 @@ src/bin/video/e_comp_wl_video_buffer.c \
 src/bin/video/e_client_video.c \
 src/bin/video/e_zone_video.c \
 src/bin/video/e_video_debug.c \
+src/bin/video/e_util_video.c \
 src/bin/video/iface/e_video_hwc.c \
 src/bin/video/iface/e_video_hwc_planes.c \
 src/bin/video/iface/e_video_hwc_windows.c \
diff --git a/src/bin/video/e_util_video.c b/src/bin/video/e_util_video.c
new file mode 100644 (file)
index 0000000..3371ef0
--- /dev/null
@@ -0,0 +1,225 @@
+#include "e.h"
+#include <tbm_surface.h>
+
+/* This algorithm for converting pixels from nv12 to rgb is copied from evas_object_image */
+static unsigned char _clip_lut[1024];
+
+#define LUT_CLIP(i) ((_clip_lut+384)[(i)])
+
+#define RGB_JOIN(r,g,b) \
+    (((r) << 16) + ((g) << 8) + (b))
+
+#ifndef DATA32
+#define DATA32  unsigned int
+#endif
+
+#define CRV    104595
+#define CBU    132251
+#define CGU    25624
+#define CGV    53280
+
+#define YMUL   76283
+#define OFF    32768
+#define BITRES 16
+
+#define CRV709 117504
+#define CBU709 138607
+#define CGU709  13959
+#define CGV709  34996
+
+static void
+_yuv_init(void)
+{
+   int i;
+
+   for (i = -384; i < 640; i++)
+     _clip_lut[i+384] = i < 0 ? 0 : (i > 255) ? 255 : i;
+}
+
+static inline void
+_yuv2rgb_420_raster(unsigned char *yp1, unsigned char *yp2, unsigned char *up, unsigned char *vp,
+                    unsigned char *dp1, unsigned char *dp2)
+{
+   int y, u, v;
+   int vmu;
+   int rgb;
+
+   /* collect u & v for 4 pixels block */
+   u = *up;
+   v = *vp;
+
+   /* save lookups */
+   u -= 128;
+   v -= 128;
+   vmu = v * CGV + u * CGU;
+   u = u * CBU;
+   v = v * CRV;
+
+   /* do the top 2 pixels of the 2x2 block which shared u & v */
+   /* yuv to rgb */
+   y = (*yp1 - 16 ) * YMUL;
+   rgb = RGB_JOIN(LUT_CLIP(((y + v) >> 16)),
+                  LUT_CLIP(((y - vmu + OFF) >> 16)),
+                  LUT_CLIP(((y + u + OFF) >> 16)));
+   *((DATA32 *) dp1) = 0xff000000 + rgb;
+
+   dp1 += 4; yp1++;
+
+   /* yuv to rgb */
+   y = (*yp1 - 16 ) * YMUL;
+   rgb = RGB_JOIN(LUT_CLIP(((y + v) >> 16)),
+                  LUT_CLIP(((y - vmu + OFF) >> 16)),
+                  LUT_CLIP(((y + u + OFF) >> 16)));
+   *((DATA32 *) dp1) = 0xff000000 + rgb;
+
+   /* do the bottom 2 pixels of the 2x2 block which shared u & v */
+   /* yuv to rgb */
+   y = (*yp2 - 16 ) * YMUL;
+   rgb = RGB_JOIN(LUT_CLIP(((y + v) >> 16)),
+                  LUT_CLIP(((y - vmu + OFF) >> 16)),
+                  LUT_CLIP(((y + u + OFF) >> 16)));
+   *((DATA32 *) dp2) = 0xff000000 + rgb;
+
+   dp2 += 4; yp2++;
+
+   /* yuv to rgb */
+   y = (*yp2 - 16 ) * YMUL;
+   rgb = RGB_JOIN(LUT_CLIP(((y + v) >> 16)),
+                  LUT_CLIP(((y - vmu + OFF) >> 16)),
+                  LUT_CLIP(((y + u + OFF) >> 16)));
+   *((DATA32 *) dp2) = 0xff000000 + rgb;
+}
+
+static void
+_nv12torgb_raster(unsigned char *y_ptr, unsigned char *uv_ptr, int yuv_stride, int w, int h, unsigned char *dst_ptr, int dst_stride)
+{
+   static int initted = 0;
+   int xx, yy;
+   unsigned char *yp1, *yp2, *up, *vp;
+   unsigned char *dp1;
+   unsigned char *dp2;
+
+   if (!initted) _yuv_init();
+
+   dp1 = dst_ptr;
+   dp2 = dp1 + dst_stride;
+
+   for (yy = 0; yy < h; yy++)
+     {
+        yp1 = y_ptr + (yy++ * yuv_stride);
+        yp2 = y_ptr + (yy * yuv_stride);
+
+        up = uv_ptr + ((yy >> 1) * yuv_stride);
+        vp = up + 1;
+
+        for (xx = 0; xx < w; xx += 2)
+          {
+             _yuv2rgb_420_raster(yp1, yp2, up, vp, dp1, dp2);
+
+             /* the previous call just rendered 2 pixels per lines */
+             dp1 += 8; dp2 += 8;
+
+             /* and took for that 2 lines with 2 Y, 1 U and 1 V. Don't forget U & V are in the same plane */
+             yp1 += 2; yp2 += 2; up += 2; vp += 2;
+          }
+
+        /* jump one line */
+        dp1 += dst_stride;
+        dp2 += dst_stride;
+     }
+}
+/* The end of copied code lines from evas_object_image. */
+
+static tbm_surface_h
+_tbm_surface_nv12_to_rgb_convert(tbm_surface_h src)
+{
+   tbm_surface_h dst;
+   tbm_surface_info_s info;
+   unsigned char *rgb_ptr, *y_ptr, *uv_ptr;
+   int rgb_stride, yuv_stride;
+   int w, h;
+   int ret;
+
+   w = tbm_surface_get_width(src);
+   h = tbm_surface_get_height(src);
+   if ((w <= 0) || (h <= 0))
+     {
+        ERR("Abnormal size buffer is passed (%dx%d)", w, h);
+        return NULL;
+     }
+
+   ret = tbm_surface_map(src, TBM_SURF_OPTION_READ, &info);
+   if (ret != TBM_SURFACE_ERROR_NONE)
+     {
+        ERR("Failed to map tbm_surface_h");
+        return NULL;
+     }
+
+   if (info.num_planes != 2)
+     {
+        ERR("NV12 format must have 2 planes");
+        tbm_surface_unmap(src);
+        return NULL;
+     }
+
+   y_ptr = (unsigned char *)info.planes[0].ptr;
+   uv_ptr = (unsigned char *)info.planes[1].ptr;
+   yuv_stride = info.planes[0].stride;
+
+   dst = tbm_surface_create(w, h, TBM_FORMAT_ARGB8888);
+   if (!dst)
+     {
+        ERR("Failed to create output tbm_surface_h");
+        tbm_surface_unmap(src);
+        return NULL;
+     }
+
+   ret = tbm_surface_map(dst, TBM_SURF_OPTION_WRITE, &info);
+   if (ret != TBM_SURFACE_ERROR_NONE)
+     {
+        ERR("Failed to map tbm_surface_h");
+        tbm_surface_destroy(dst);
+        tbm_surface_unmap(src);
+        return NULL;
+     }
+
+   rgb_ptr = (unsigned char *)info.planes[0].ptr;
+   rgb_stride = info.planes[0].stride;
+
+   _nv12torgb_raster(y_ptr, uv_ptr, yuv_stride, w, h, rgb_ptr, rgb_stride);
+
+   tbm_surface_unmap(dst);
+   tbm_surface_unmap(src);
+
+   return dst;
+}
+
+EINTERN tbm_surface_h
+e_util_video_tbm_surface_convert_to_rgb(tbm_surface_h src)
+{
+   tbm_surface_h dst = NULL;
+   tbm_format format;
+
+   format = tbm_surface_get_format(src);
+   if ((format == TBM_FORMAT_ARGB8888) ||
+       (format == TBM_FORMAT_XRGB8888))
+     {
+        WRN("The format of given tbm_surface_h is already RGB colorspace");
+        return NULL;
+     }
+
+   switch (format)
+     {
+      case TBM_FORMAT_NV12:
+         dst = _tbm_surface_nv12_to_rgb_convert(src);
+         if (!dst)
+           ERR("Failed to convert pixel format to RGB colorspace (%c%c%c%c)",
+               FOURCC_STR(format));
+         break;
+      default:
+         ERR("Unsupported format (%c%c%c%c)", FOURCC_STR(format));
+         break;
+     }
+
+   return dst;
+}
diff --git a/src/bin/video/e_util_video.h b/src/bin/video/e_util_video.h
new file mode 100644 (file)
index 0000000..b304ed3
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef E_UTIL_VIDEO_H
+#define E_UTIL_VIDEO_H
+
+#include <tbm_surface.h>
+
+/* Convert colorspace for given tbm_surface_h to RGB.
+ * Note that returned tbm_surface_h has to be freed after use. */
+EINTERN tbm_surface_h e_util_video_tbm_surface_convert_to_rgb(tbm_surface_h surface);
+
+#endif