From: Seunghun Lee Date: Tue, 5 Nov 2019 06:28:27 +0000 (+0900) Subject: video: Added a util API for converting pixel format of tbm_surface_h from NV12 to... X-Git-Tag: submit/tizen/20191112.105927~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a7271df9d082ff6301c08d311671dbcdd0e7a583;p=platform%2Fupstream%2Fenlightenment.git video: Added a util API for converting pixel format of tbm_surface_h from NV12 to RGB. Change-Id: Ie98092de369b14f34c4b1d3b754f6555fe28955f --- diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index cff8d69607..c09305156a 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -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 index 0000000000..3371ef044a --- /dev/null +++ b/src/bin/video/e_util_video.c @@ -0,0 +1,225 @@ +#include "e.h" +#include + +/* 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 index 0000000000..b304ed39a0 --- /dev/null +++ b/src/bin/video/e_util_video.h @@ -0,0 +1,10 @@ +#ifndef E_UTIL_VIDEO_H +#define E_UTIL_VIDEO_H + +#include + +/* 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