--- /dev/null
+#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;
+}