]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-10088: [freeswitch-core] Backports backport video modification functions to fix...
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 15 Mar 2017 20:47:33 +0000 (15:47 -0500)
committerAnthony Minessale <anthm@freeswitch.org>
Wed, 15 Mar 2017 20:47:33 +0000 (15:47 -0500)
src/include/switch_core_video.h
src/switch_core_video.c

index babe865f4e6fcae813d3f56775b0e0937288f26e..c8b226509dbe4c4a33261d18e1162312142540c7 100644 (file)
 
 SWITCH_BEGIN_EXTERN_C
 
+typedef enum {
+       SWITCH_SHADE_NONE = 0,
+       SWITCH_SHADE_RED,
+       SWITCH_SHADE_GREEN,
+       SWITCH_SHADE_BLUE,
+       SWITCH_SHADE_AUTO
+} switch_shade_t;
+
 typedef enum {
        POS_LEFT_TOP = 0,
        POS_LEFT_MID,
@@ -70,12 +78,39 @@ typedef struct switch_yuv_color_s {
        uint8_t v;
 } switch_yuv_color_t;
 
+#if SWITCH_BYTE_ORDER == __BIG_ENDIAN
 typedef struct switch_rgb_color_s {
        uint8_t a;
        uint8_t r;
        uint8_t g;
        uint8_t b;
 } switch_rgb_color_t;
+#else
+typedef struct switch_rgb_color_s {
+       uint8_t b;
+       uint8_t g;
+       uint8_t r;
+       uint8_t a;
+} switch_rgb_color_t;
+#endif
+
+typedef struct switch_hsl_color_s {
+       double h;
+       double s;
+       double l;
+} switch_hsl_color_t;
+
+typedef struct {
+       double l;
+       double a;
+       double b;
+} switch_lab_color_t;
+
+typedef struct {
+       double x;
+       double y;
+       double z;
+} switch_xyz_color_t;
 
 /**\brief Representation of a rectangle on a surface */
 typedef struct switch_image_rect {
@@ -103,7 +138,7 @@ typedef enum {
        SRM_180 = 180,  // Rotate 180 degrees.
        SRM_270 = 270,  // Rotate 270 degrees clockwise.
 } switch_image_rotation_mode_t;
-       
+
 
 /*!\brief Open a descriptor, allocating storage for the underlying image
 *
@@ -186,6 +221,19 @@ SWITCH_DECLARE(int) switch_img_set_rect(switch_image_t  *img,
 */
 SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y);
 
+SWITCH_DECLARE(void) switch_img_attenuate(switch_image_t *img);
+
+/*!\brief patch a small img to a big IMG at position x,y
+*
+* Both IMG and img must be non-NULL
+*
+* \param[in]    IMG       The BIG Image descriptor
+* \param[in]    img       The small Image descriptor
+* \param[in]    x         Leftmost pos to patch to
+* \param[in]    y         Topmost pos to patch to
+* \param[in]    noalpha   skip writing to non-transparent pixels
+*/
+SWITCH_DECLARE(void) switch_img_patch_rgb(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_bool_t noalpha);
 
 /*!\brief patch part of a small img (x,y,w,h) to a big IMG at position X,Y
 *
@@ -264,6 +312,8 @@ SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, uint3
 */
 SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color);
 
+SWITCH_DECLARE(void) switch_img_fill_noalpha(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color);
+
 /*!\brief Set RGB color with a string
 *
 * Color string should be in #RRGGBB format
@@ -318,7 +368,7 @@ SWITCH_DECLARE(void) switch_img_txt_handle_destroy(switch_img_txt_handle_t **han
 SWITCH_DECLARE(uint32_t) switch_img_txt_handle_render(switch_img_txt_handle_t *handle, switch_image_t *img,
                                                                                                          int x, int y, const char *text,
                                                                                                          const char *font_family, const char *font_color, const char *bgcolor, uint16_t font_size, double angle);
-                                                
+
 
 SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_image_rect_t *rect);
 
@@ -387,7 +437,24 @@ SWITCH_DECLARE(switch_status_t) switch_I420_copy(const uint8_t* src_y, int src_s
 SWITCH_DECLARE(switch_status_t) switch_I420_copy2(uint8_t *src_planes[], int src_stride[],
                                                                                                  uint8_t *dst_planes[], int dst_stride[],
                                                                                                  int width, int height);
-/** @} */
+
+/*!\brief I420 to ARGB Convertion*/
+
+SWITCH_DECLARE(switch_status_t) switch_I420ToARGB(const uint8_t *src_y, int src_stride_y,
+                                                                                                       const uint8_t *src_u, int src_stride_u,
+                                                                                                       const uint8_t *src_v, int src_stride_v,
+                                                                                                       uint8_t *dst_argb, int dst_stride_argb,
+                                                                                                       int width, int height);
+
+SWITCH_DECLARE(switch_status_t) switch_RGBAToARGB(const uint8_t* src_frame, int src_stride_frame,
+                                                                                                       uint8_t* dst_argb, int dst_stride_argb,
+                                                                                                       int width, int height);
+SWITCH_DECLARE(switch_status_t) switch_ABGRToARGB(const uint8_t* src_frame, int src_stride_frame,
+                                                                                                       uint8_t* dst_argb, int dst_stride_argb,
+                                                                                                       int width, int height);
+SWITCH_DECLARE(switch_status_t) switch_ARGBToARGB(const uint8_t* src_frame, int src_stride_frame,
+                                                                                                       uint8_t* dst_argb, int dst_stride_argb,
+                                                                                                       int width, int height);
 
 SWITCH_END_EXTERN_C
 #endif
index a59f623a0231836b750c0f5a359051479de567ff..886eba812bf3b594f59cd0fbf6bea891510c0117 100644 (file)
@@ -110,14 +110,14 @@ SWITCH_DECLARE(switch_img_position_t) parse_img_position(const char *name)
        int i;
 
        switch_assert(name);
-       
+
        for(i = 0; POS_TABLE[i].name; i++) {
                if (!strcasecmp(POS_TABLE[i].name, name)) {
                        r = POS_TABLE[i].pos;
                        break;
                }
        }
-       
+
        return r;
 }
 
@@ -142,14 +142,14 @@ SWITCH_DECLARE(switch_img_fit_t) parse_img_fit(const char *name)
        int i;
 
        switch_assert(name);
-       
+
        for(i = 0; IMG_FIT_TABLE[i].name; i++) {
                if (!strcasecmp(IMG_FIT_TABLE[i].name, name)) {
                        r = IMG_FIT_TABLE[i].fit;
                        break;
                }
        }
-       
+
        return r;
 }
 
@@ -165,7 +165,7 @@ SWITCH_DECLARE(switch_bool_t) switch_core_has_video(void)
        return SWITCH_FALSE;
 #endif
 }
-                                                         
+
 SWITCH_DECLARE(switch_image_t *)switch_img_alloc(switch_image_t  *img,
                                                 switch_img_fmt_t fmt,
                                                 unsigned int d_w,
@@ -270,7 +270,9 @@ SWITCH_DECLARE(void) switch_img_free(switch_image_t **img)
                        gdImageDestroy((gdImagePtr)(*img)->user_priv);
 #endif
                } else {
-                       switch_safe_free((*img)->user_priv);
+                       if ((int)(intptr_t)(*img)->user_priv != 1) {
+                               switch_safe_free((*img)->user_priv);
+                       }
                }
                vpx_img_free((vpx_image_t *)*img);
                *img = NULL;
@@ -286,11 +288,115 @@ SWITCH_DECLARE(void) switch_img_free(switch_image_t **img)
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 #endif
 
+static void switch_img_patch_rgb_noalpha(switch_image_t *IMG, switch_image_t *img, int x, int y)
+{
+       int i;
+
+       if (img->fmt == SWITCH_IMG_FMT_ARGB && IMG->fmt == SWITCH_IMG_FMT_ARGB) {
+               int max_w = MIN(img->d_w, IMG->d_w - abs(x));
+               int max_h = MIN(img->d_h, IMG->d_h - abs(y));
+               int j;
+               uint8_t alpha, alphadiff;
+               switch_rgb_color_t *rgb, *RGB; 
+
+               for (i = 0; i < max_h; i++) {           
+                       for (j = 0; j < max_w; j++) {
+                               rgb = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->stride[SWITCH_PLANE_PACKED] + j * 4);
+                               RGB = (switch_rgb_color_t *)(IMG->planes[SWITCH_PLANE_PACKED] + (y + i) * IMG->stride[SWITCH_PLANE_PACKED] + (x + j) * 4);
+                               
+                               alpha = rgb->a;
+                               
+                               if (RGB->a != 0) {
+                                       continue;
+                               }
+
+                               if (alpha == 255) {
+                                       *RGB = *rgb;
+                               } else if (alpha != 0) {
+                                       alphadiff = 255 - alpha;
+                                       RGB->a = 255;
+                                       RGB->r = ((RGB->r * alphadiff) + (rgb->r * alpha)) >> 8;
+                                       RGB->g = ((RGB->g * alphadiff) + (rgb->g * alpha)) >> 8;
+                                       RGB->b = ((RGB->b * alphadiff) + (rgb->b * alpha)) >> 8;
+                               }
+                       }
+               }
+       }
+}
+
+SWITCH_DECLARE(void) switch_img_attenuate(switch_image_t *img)
+{
+       if (img->fmt != SWITCH_IMG_FMT_ARGB) {
+               return;
+       }
+
+       if (img->user_priv) return;
+
+       img->user_priv = (void *)(intptr_t)1;
+
+       ARGBAttenuate(img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED],
+                                 img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED], img->d_w, img->d_h);
+}
+
+SWITCH_DECLARE(void) switch_img_patch_rgb(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_bool_t noalpha)
+{
+       int i;
+
+       if (noalpha) {
+               switch_img_patch_rgb_noalpha(IMG, img, x, y);
+               return;
+       }
+
+       if (img->fmt == SWITCH_IMG_FMT_ARGB && IMG->fmt == SWITCH_IMG_FMT_ARGB) {
+               uint8* src_argb0 = img->planes[SWITCH_PLANE_PACKED];
+               int src_stride_argb0 = img->stride[SWITCH_PLANE_PACKED];
+               uint8* src_argb1 = IMG->planes[SWITCH_PLANE_PACKED];
+               int src_stride_argb1 = IMG->stride[SWITCH_PLANE_PACKED];
+               uint8* dst_argb = IMG->planes[SWITCH_PLANE_PACKED];
+               int dst_stride_argb = IMG->stride[SWITCH_PLANE_PACKED];
+               int width = MIN(img->d_w, IMG->d_w - abs(x));
+               int height = MIN(img->d_h, IMG->d_h - abs(y));
+               void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1, uint8* dst_argb, int width) = GetARGBBlend();
+
+               switch_img_attenuate(img);
+
+               // Coalesce rows. we have same size images, treat as a single row
+               if (src_stride_argb0 == width * 4 &&
+                       src_stride_argb1 == width * 4 &&
+                       x == 0 && y == 0) {
+                       width *= height;
+                       height = 1;
+                       src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
+               }
+
+               if (y) {
+                       src_argb1 += (y * IMG->d_w * 4);
+                       dst_argb  += (y * IMG->d_w * 4);
+               }
+               if (x) {
+                       src_argb1 += (x * 4);
+                       dst_argb  += (x * 4);
+               }
+
+               for (i = 0; i < height; ++i) {
+                       ARGBBlendRow(src_argb0, src_argb1, dst_argb, width);
+                       src_argb0 += src_stride_argb0;
+                       src_argb1 += src_stride_argb1;
+                       dst_argb += dst_stride_argb;
+               }
+       }
+}
+
 SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y)
 {
        int i, len, max_h;
        int xoff = 0, yoff = 0;
 
+       if (img->fmt == SWITCH_IMG_FMT_ARGB && IMG->fmt == SWITCH_IMG_FMT_ARGB) {
+               switch_img_patch_rgb(IMG, img, x, y, SWITCH_FALSE);
+               return;
+       }
+
        switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420);
 
        if (img->fmt == SWITCH_IMG_FMT_ARGB) {
@@ -302,24 +408,21 @@ SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img,
 
                for (i = 0; i < max_h; i++) {
                        for (j = 0; j < max_w; j++) {
-                               alpha = img->planes[SWITCH_PLANE_PACKED][i * img->stride[SWITCH_PLANE_PACKED] + j * 4];
+                               rgb = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->stride[SWITCH_PLANE_PACKED] + j * 4);
+                               alpha = rgb->a;
 
-                               if (alpha > 0) {
+                               if (alpha == 255) {
+                                       switch_img_draw_pixel(IMG, x + j, y + i, rgb);
+                               } else if (alpha != 0) {
                                        switch_rgb_color_t RGB = { 0 };
-
+                                       
                                        switch_img_get_rgb_pixel(IMG, &RGB, x + j, y + i);
-                                       rgb = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->stride[SWITCH_PLANE_PACKED] + j * 4);
-
-                                       if (alpha < 255) {
-                                               RGB.a = 255;
-                                               RGB.r = ((RGB.r * (255 - alpha)) >> 8) + ((rgb->r * alpha) >> 8);
-                                               RGB.g = ((RGB.g * (255 - alpha)) >> 8) + ((rgb->g * alpha) >> 8);
-                                               RGB.b = ((RGB.b * (255 - alpha)) >> 8) + ((rgb->b * alpha) >> 8);
-
-                                               switch_img_draw_pixel(IMG, x + j, y + i, &RGB);
-                                       } else {
-                                               switch_img_draw_pixel(IMG, x + j, y + i, rgb);
-                                       }
+                                       RGB.a = 255;
+                                       RGB.r = ((RGB.r * (255 - alpha)) >> 8) + ((rgb->r * alpha) >> 8);
+                                       RGB.g = ((RGB.g * (255 - alpha)) >> 8) + ((rgb->g * alpha) >> 8);
+                                       RGB.b = ((RGB.b * (255 - alpha)) >> 8) + ((rgb->b * alpha) >> 8);
+                                       
+                                       switch_img_draw_pixel(IMG, x + j, y + i, &RGB);
                                }
                        }
                }
@@ -419,36 +522,56 @@ SWITCH_DECLARE(void) switch_img_patch_rect(switch_image_t *IMG, int X, int Y, sw
 
 SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_img)
 {
+#ifdef SWITCH_HAVE_YUV
+       switch_img_fmt_t new_fmt = img->fmt;
+
        switch_assert(img);
        switch_assert(new_img);
 
-#ifdef SWITCH_HAVE_YUV
        if (img->fmt != SWITCH_IMG_FMT_I420 && img->fmt != SWITCH_IMG_FMT_ARGB) return;
 
-       if (*new_img != NULL) {
-               if (img->fmt != (*new_img)->fmt || img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_w) {
+       if (*new_img) {
+               if ((*new_img)->fmt != SWITCH_IMG_FMT_I420 && (*new_img)->fmt != SWITCH_IMG_FMT_ARGB) return;
+               if (img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_w ) {
+                       new_fmt = (*new_img)->fmt;
                        switch_img_free(new_img);
                }
        }
 
        if (*new_img == NULL) {
-               *new_img = switch_img_alloc(NULL, img->fmt, img->d_w, img->d_h, 1);
+               *new_img = switch_img_alloc(NULL, new_fmt, img->d_w, img->d_h, 1);
        }
 
        switch_assert(*new_img);
 
        if (img->fmt == SWITCH_IMG_FMT_I420) {
-               I420Copy(img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
-                                img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
-                                img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
-                                (*new_img)->planes[SWITCH_PLANE_Y], (*new_img)->stride[SWITCH_PLANE_Y],
-                                (*new_img)->planes[SWITCH_PLANE_U], (*new_img)->stride[SWITCH_PLANE_U],
-                                (*new_img)->planes[SWITCH_PLANE_V], (*new_img)->stride[SWITCH_PLANE_V],
-                                img->d_w, img->d_h);
+               if (new_fmt == SWITCH_IMG_FMT_I420) {
+                       I420Copy(img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
+                                        img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
+                                        img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
+                                        (*new_img)->planes[SWITCH_PLANE_Y], (*new_img)->stride[SWITCH_PLANE_Y],
+                                        (*new_img)->planes[SWITCH_PLANE_U], (*new_img)->stride[SWITCH_PLANE_U],
+                                        (*new_img)->planes[SWITCH_PLANE_V], (*new_img)->stride[SWITCH_PLANE_V],
+                                        img->d_w, img->d_h);
+               } else if (new_fmt == SWITCH_IMG_FMT_ARGB) {
+                       I420ToARGB(img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
+                               img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
+                               img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
+                               (*new_img)->planes[SWITCH_PLANE_PACKED], (*new_img)->stride[SWITCH_PLANE_PACKED],
+                               img->d_w, img->d_h);
+               }
        } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
-               ARGBCopy(img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED],
+               if (new_fmt == SWITCH_IMG_FMT_ARGB) {
+                       ARGBCopy(img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED],
                                 (*new_img)->planes[SWITCH_PLANE_PACKED], (*new_img)->stride[SWITCH_PLANE_PACKED],
                                 img->d_w, img->d_h);
+               } else if (new_fmt == SWITCH_IMG_FMT_I420) {
+                       ARGBToI420(img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED],
+                                         (*new_img)->planes[SWITCH_PLANE_Y], (*new_img)->stride[SWITCH_PLANE_Y],
+                                         (*new_img)->planes[SWITCH_PLANE_U], (*new_img)->stride[SWITCH_PLANE_U],
+                                         (*new_img)->planes[SWITCH_PLANE_V], (*new_img)->stride[SWITCH_PLANE_V],
+                                         img->d_w, img->d_h);
+               }
        }
 #else
        return;
@@ -527,10 +650,220 @@ SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, uint3
 #endif
 }
 
+#if 0
+static inline void switch_core_rgb2xyz(switch_rgb_color_t *rgb, switch_xyz_color_t *xyz)
+{
+       double r, g, b;
+
+       r = (double)rgb->r / 255;
+       g = (double)rgb->g / 255;
+       b = (double)rgb->b / 255;
+
+       if ( r > 0.04045 ) {
+               r = ( ( r + 0.055 ) / 1.055 );
+               r = pow(r, 2.4);
+       } else {
+               r = r / 12.92;
+       }
+
+       if ( g > 0.04045 ) {
+               g = ( ( g + 0.055 ) / 1.055 );
+               g = pow(g, 2.4);
+       } else {
+               g = g / 12.92;
+       }
+
+       if ( b > 0.04045 ) {
+               b = ( ( b + 0.055 ) / 1.055 );
+               b = pow(b, 2.4);
+       } else {
+               b = b / 12.92;
+       }
+
+       r = r * 100;
+       g = g * 100;
+       b = b * 100;
+               
+       //Observer. = 2degrees, Illuminant = D65
+       xyz->x = r * 0.4124 + g * 0.3576 + b * 0.1805;
+       xyz->y = r * 0.2126 + g * 0.7152 + b * 0.0722;
+       xyz->z = r * 0.0193 + g * 0.1192 + b * 0.9505;
+
+}
+
+#define SVMAX(a,b) ((a) > (b) ? (a) : (b))
+#define SVMAX3(a,b,c) (SVMAX((a), SVMAX((b),(c))))
+#define SVMIN(a,b) ((a) < (b) ? (a) : (b))
+#define SVMIN3(a,b,c) (SVMIN((a), SVMIN((b),(c))))
+
+
+static inline void switch_core_rgb2hsl(switch_rgb_color_t *rgb, switch_hsl_color_t *hsl)
+{
+       double r, g, b, max, min;
+
+       r = (double)rgb->r / 255;
+       g = (double)rgb->g / 255;
+       b = (double)rgb->b / 255;
+       
+       max = SVMAX3(r, g, b);
+       min = SVMIN3(r, g, b);
+
+       hsl->l = (max + min) / 2;
+
+       if (max != min) {
+               double d = max - min;
+
+               hsl->s = hsl->l > 0.5f ? d / (2 - max - min) : d / (max + min);
+
+               if (max == r) {
+                       hsl->h = (g - b) / (max - min);
+               } else if(max == g) {
+                       hsl->h = 2.0 + ((b - r) / (max - min));
+               } else {
+                       hsl->h = 4.0 + ((r - g) / (max - min));
+               }
+       } else {
+               hsl->h = hsl->s = 0;
+       }
+
+       hsl->h = round(hsl->h * 60);
+       if (hsl->h < 0) hsl->h += 360;
+
+       hsl->s *= 100;
+       hsl->l *= 100;
+
+}
+
+static inline void switch_core_rgb2lab(switch_rgb_color_t *rgb, switch_lab_color_t *lab)
+{
+       double x,y,z;
+       double r = rgb->r;
+       double g = rgb->g;
+       double b = rgb->b;
+
+       r=r>10.31475 ? 1.474000611989649e-6 * pow(r+14.025 , 2.4) : r * 0.0003035269835488375;
+       g=g>10.31475 ? 1.474000611989649e-6 * pow(g+14.025 , 2.4) : g * 0.0003035269835488375;
+       b=b>10.31475 ? 1.474000611989649e-6 * pow(b+14.025 , 2.4) : b * 0.0003035269835488375;
+       x=r * 0.43394994055572506 + g * 0.3762097699033109 + b * 0.18984028954096394;
+       y=r * 0.2126729 + g * 0.7151522 + b * 0.0721750;
+       z=r * 0.017756582753965265 + g * 0.10946796102238182 + b * 0.8727754562236529;
+
+
+       x = x > 0.008856452 ? pow(x , 0.3333333333333333) : 7.787037037037037 * x + 0.13793103448275862; 
+       y = y > 0.008856452 ?  pow(y , 0.3333333333333333) : 7.787037037037037 * y + 0.13793103448275862;
+       z = z > 0.008856452 ? pow(z , 0.3333333333333333) : 7.787037037037037 * z + 0.13793103448275862;
+
+       lab->l = 116 * y - 16;
+       lab->a = 500 * (x - y);
+       lab->b = 200 * (y - z);
+}
+
+
+
+/// Computes the CIEDE2000 color-difference between two Lab colors
+/// Based on the article:
+/// The CIEDE2000 Color-Difference Formula: Implementation Notes,
+/// Supplementary Test Data, and Mathematical Observations,", G. Sharma,
+/// W. Wu, E. N. Dalal, submitted to Color Research and Application,
+/// January 2004.
+/// Available at http://www.ece.rochester.edu/~/gsharma/ciede2000/
+/// Based on the C++ implementation by Ofir Pele, The Hebrew University of Jerusalem 2010.
+//
+static inline double switch_CIEDE2000(switch_lab_color_t *lab1, switch_lab_color_t *lab2)
+{
+       double Lstd = lab1->l;
+       double astd = lab1->a;
+       double bstd = lab1->b;
+       double pi = M_PI;
+
+       double Lsample = lab2->l;
+       double asample = lab2->a;
+       double bsample = lab2->b;
+
+       //double _kL = 1.0;
+       //double _kC = 1.0;
+       //double _kH = 1.0;
+
+       double Cabstd= sqrt(astd*astd+bstd*bstd);
+       double Cabsample= sqrt(asample*asample+bsample*bsample);
+
+       double Cabarithmean= (Cabstd + Cabsample)/2.0;
+
+       double G= 0.5*( 1.0 - sqrt( pow(Cabarithmean,7.0)/(pow(Cabarithmean,7.0) + pow(25.0,7.0))));
+
+       double apstd= (1.0+G)*astd; // aprime in paper
+       double apsample= (1.0+G)*asample; // aprime in paper
+       double Cpsample= sqrt(apsample*apsample+bsample*bsample);
+
+       double Cpstd= sqrt(apstd*apstd+bstd*bstd);
+       // Compute product of chromas
+       double Cpprod= (Cpsample*Cpstd);
+
+
+       double hpsample, dL, dC, dhp, dH, Lp, Cp;
+       double hp, Lpm502, Sl, Sc, T, Sh, delthetarad, Rc, RT;
+
+       // Ensure hue is between 0 and 2pi
+       double hpstd= atan2(bstd,apstd);
+       if (hpstd<0) hpstd+= 2.0*pi;  // rollover ones that come -ve
+
+       hpsample= atan2(bsample,apsample);
+       if (hpsample<0) hpsample+= 2.0*pi;
+       if ( (fabs(apsample)+fabs(bsample))==0.0)  hpsample= 0.0;
+
+       dL= (Lsample-Lstd);
+       dC= (Cpsample-Cpstd);
+
+       // Computation of hue difference
+       dhp= (hpsample-hpstd);
+       if (dhp>pi)  dhp-= 2.0*pi;
+       if (dhp<-pi) dhp+= 2.0*pi;
+       // set chroma difference to zero if the product of chromas is zero
+       if (Cpprod == 0.0) dhp= 0.0;
+
+       // Note that the defining equations actually need
+       // signed Hue and chroma differences which is different
+       // from prior color difference formulae
+
+       dH= 2.0*sqrt(Cpprod)*sin(dhp/2.0);
+       //%dH2 = 4*Cpprod.*(sin(dhp/2)).^2;
+
+       // weighting functions
+       Lp= (Lsample+Lstd)/2.0;
+       Cp= (Cpstd+Cpsample)/2.0;
+
+       // Average Hue Computation
+       // This is equivalent to that in the paper but simpler programmatically.
+       // Note average hue is computed in radians and converted to degrees only
+       // where needed
+       hp= (hpstd+hpsample)/2.0;
+       // Identify positions for which abs hue diff exceeds 180 degrees
+       if ( fabs(hpstd-hpsample)  > pi ) hp-= pi;
+       // rollover ones that come -ve
+       if (hp<0) hp+= 2.0*pi;
+
+       // Check if one of the chroma values is zero, in which case set
+       // mean hue to the sum which is equivalent to other value
+       if (Cpprod==0.0) hp= hpsample+hpstd;
+
+       Lpm502= (Lp-50.0)*(Lp-50.0);;
+       Sl= 1.0+0.015*Lpm502/sqrt(20.0+Lpm502);
+       Sc= 1.0+0.045*Cp;
+       T= 1.0 - 0.17*cos(hp - pi/6.0) + 0.24*cos(2.0*hp) + 0.32*cos(3.0*hp+pi/30.0) - 0.20*cos(4.0*hp-63.0*pi/180.0);
+       Sh= 1.0 + 0.015*Cp*T;
+       delthetarad= (30.0*pi/180.0)*exp(- pow(( (180.0/pi*hp-275.0)/25.0),2.0));
+       Rc=  2.0*sqrt(pow(Cp,7.0)/(pow(Cp,7.0) + pow(25.0,7.0)));
+       RT= -sin(2.0*delthetarad)*Rc;
+
+       // The CIE 00 color difference
+       return sqrt( pow((dL/Sl),2.0) + pow((dC/Sc),2.0) + pow((dH/Sh),2.0) + RT*(dC/Sc)*(dH/Sh) );
+}
+#endif
+
 static inline void switch_img_draw_pixel(switch_image_t *img, int x, int y, switch_rgb_color_t *color)
 {
-#ifdef SWITCH_HAVE_YUV 
-       switch_yuv_color_t yuv;
+#ifdef SWITCH_HAVE_YUV
+       switch_yuv_color_t yuv = {0};
 
        if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
 
@@ -544,18 +877,41 @@ static inline void switch_img_draw_pixel(switch_image_t *img, int x, int y, swit
                        img->planes[SWITCH_PLANE_V][y / 2 * img->stride[SWITCH_PLANE_V] + x / 2] = yuv.v;
                }
        } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
-               uint8_t *alpha = img->planes[SWITCH_PLANE_PACKED] + img->d_w * 4 * y + x * 4;
-               *(alpha    ) = color->a;
-               *(alpha + 1) = color->r;
-               *(alpha + 2) = color->g;
-               *(alpha + 3) = color->b;
+               *((switch_rgb_color_t *)img->planes[SWITCH_PLANE_PACKED] + img->d_w * y + x) = *color;
+       }
+#endif
+}
+
+SWITCH_DECLARE(void) switch_img_fill_noalpha(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color)
+{
+#ifdef SWITCH_HAVE_YUV
+       int i;
+
+       if (img->fmt == SWITCH_IMG_FMT_ARGB) {
+               int max_w = img->d_w;
+               int max_h = img->d_h;
+               int j;
+               switch_rgb_color_t *rgb; 
+
+               for (i = 0; i < max_h; i++) {           
+                       for (j = 0; j < max_w; j++) {
+                               rgb = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->stride[SWITCH_PLANE_PACKED] + j * 4);
+
+                               if (rgb->a != 0) {
+                                       continue;
+                               }
+                               
+                               *rgb = *color;
+                       }
+               }
        }
+
 #endif
 }
 
 SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color)
 {
-#ifdef SWITCH_HAVE_YUV 
+#ifdef SWITCH_HAVE_YUV
        int len, i, max_h;
        switch_yuv_color_t yuv_color;
 
@@ -585,10 +941,7 @@ SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, i
                }
        } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
                for (i = 0; i < img->d_w; i++) {
-                       *(img->planes[SWITCH_PLANE_PACKED] + i * 4    ) = color->a;
-                       *(img->planes[SWITCH_PLANE_PACKED] + i * 4 + 1) = color->r;
-                       *(img->planes[SWITCH_PLANE_PACKED] + i * 4 + 2) = color->g;
-                       *(img->planes[SWITCH_PLANE_PACKED] + i * 4 + 3) = color->b;
+                       *((switch_rgb_color_t *)img->planes[SWITCH_PLANE_PACKED] + i) = *color;
                }
 
                for (i = 1; i < img->d_h; i++) {
@@ -613,7 +966,7 @@ static inline void switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_colo
 
 static inline void switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_color_t *rgb, int x, int y)
 {
-#ifdef SWITCH_HAVE_YUV         
+#ifdef SWITCH_HAVE_YUV
        if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
 
        if (img->fmt == SWITCH_IMG_FMT_I420) {
@@ -622,13 +975,9 @@ static inline void switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_colo
                switch_img_get_yuv_pixel(img, &yuv, x, y);
                switch_color_yuv2rgb(&yuv, rgb);
        } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
-               uint8_t *a = img->planes[SWITCH_PLANE_PACKED] + img->d_w * 4 * y + 4 * x;
-               rgb->a = *a;
-               rgb->r = *(++a);
-               rgb->g = *(++a);
-               rgb->b = *(++a);
+               *rgb = *((switch_rgb_color_t *)img->planes[SWITCH_PLANE_PACKED] + img->d_w * y + x);
        }
-#endif 
+#endif
 }
 
 SWITCH_DECLARE(void) switch_img_overlay(switch_image_t *IMG, switch_image_t *img, int x, int y, uint8_t percent)
@@ -761,9 +1110,14 @@ SWITCH_DECLARE(void) switch_color_set_rgb(switch_rgb_color_t *color, const char
 #ifdef SWITCH_HAVE_YUV
 static inline void switch_color_rgb2yuv(switch_rgb_color_t *rgb, switch_yuv_color_t *yuv)
 {
-       yuv->y = (uint8_t)(((rgb->r * 4897) >> 14) + ((rgb->g * 9611) >> 14) + ((rgb->b * 1876) >> 14));
-       yuv->u = (uint8_t)(- ((rgb->r * 2766) >> 14)  - ((5426 * rgb->g) >> 14) + rgb->b / 2 + 128);
-       yuv->v = (uint8_t)(rgb->r / 2 -((6855 * rgb->g) >> 14) - ((rgb->b * 1337) >> 14) + 128);
+
+       yuv->y = ( (  66 * rgb->r + 129 * rgb->g +  25 * rgb->b + 128) >> 8) +  16;
+       yuv->u = ( ( -38 * rgb->r -  74 * rgb->g + 112 * rgb->b + 128) >> 8) + 128;
+       yuv->v = ( ( 112 * rgb->r -  94 * rgb->g -  18 * rgb->b + 128) >> 8) + 128;
+
+       //yuv->y = (uint8_t)(((rgb->r * 4897) >> 14) + ((rgb->g * 9611) >> 14) + ((rgb->b * 1876) >> 14));
+       //yuv->u = (uint8_t)(- ((rgb->r * 2766) >> 14)  - ((5426 * rgb->g) >> 14) + rgb->b / 2 + 128);
+       //yuv->v = (uint8_t)(rgb->r / 2 -((6855 * rgb->g) >> 14) - ((rgb->b * 1337) >> 14) + 128);
 }
 #endif
 
@@ -796,7 +1150,7 @@ SWITCH_DECLARE(void) switch_color_set_yuv(switch_yuv_color_t *color, const char
 
        switch_color_set_rgb(&rgb, str);
        switch_color_rgb2yuv(&rgb, color);
-#endif 
+#endif
 }
 
 #if SWITCH_HAVE_FREETYPE
@@ -903,11 +1257,11 @@ SWITCH_DECLARE(void) switch_img_txt_handle_destroy(switch_img_txt_handle_t **han
        switch_memory_pool_t *pool;
 
        switch_assert(handleP);
-       
+
        old_handle = *handleP;
        *handleP = NULL;
        if (!old_handle) return;
-       
+
 
 #if SWITCH_HAVE_FREETYPE
        if (old_handle->library) {
@@ -997,7 +1351,7 @@ static void draw_bitmap(switch_img_txt_handle_t *handle, switch_image_t *img, FT
 
 SWITCH_DECLARE(uint32_t) switch_img_txt_handle_render(switch_img_txt_handle_t *handle, switch_image_t *img,
                                                                                                                         int x, int y, const char *text,
-                                                                                                                        const char *font_family, const char *font_color, 
+                                                                                                                        const char *font_family, const char *font_color,
                                                                                                                         const char *bgcolor, uint16_t font_size, double angle)
 {
 #if SWITCH_HAVE_FREETYPE
@@ -1090,7 +1444,7 @@ SWITCH_DECLARE(uint32_t) switch_img_txt_handle_render(switch_img_txt_handle_t *h
                if (error) continue;
 
                this_x = pen.x + slot->bitmap_left;
-               
+
                if (img) {
                        /* now, draw to our target surface (convert position) */
                        draw_bitmap(handle, img, &slot->bitmap, this_x, pen.y - slot->bitmap_top + font_size);
@@ -1141,7 +1495,7 @@ SWITCH_DECLARE(switch_image_t *) switch_img_write_text_img(int w, int h, switch_
 
        if (strchr(text, ':')) {
                argc = switch_split(duptxt, ':', argv);
-               
+
                if (argc > 0 && !zstr(argv[0])) {
                        fg = argv[0];
                }
@@ -1152,11 +1506,11 @@ SWITCH_DECLARE(switch_image_t *) switch_img_write_text_img(int w, int h, switch_
                                bg = NULL;
                        }
                }
-               
+
                if (argc > 2 && !zstr(argv[2])) {
                        font_face = argv[2];
                }
-               
+
                if (argc > 3 && !zstr(argv[3])) {
                        fontsz = argv[3];
                }
@@ -1165,7 +1519,7 @@ SWITCH_DECLARE(switch_image_t *) switch_img_write_text_img(int w, int h, switch_
                        txt = argv[4];
                }
        } else txt = duptxt;
-       
+
        if (!txt) txt = duptxt;
 
        if (strrchr(fontsz, '%')) {
@@ -1176,7 +1530,7 @@ SWITCH_DECLARE(switch_image_t *) switch_img_write_text_img(int w, int h, switch_
 
        while (*txt == ' ') txt++;
        while (end_of(txt) == ' ') end_of(txt) = '\0';
-       
+
        len = strlen(txt);
 
        if (len < 5) len = 5;
@@ -1192,9 +1546,9 @@ SWITCH_DECLARE(switch_image_t *) switch_img_write_text_img(int w, int h, switch_
                                                                                         NULL,
                                                                                         font_size / 2, font_size / 2,
                                                                                         txt, NULL, fg, bg, 0, 0);
-       
+
        height = font_size * 2;
-       
+
        if (full && w > width) {
                width = w;
        } else {
@@ -1359,19 +1713,15 @@ SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, swit
 {
        switch_status_t status = SWITCH_STATUS_SUCCESS;
        switch_rgb_color_t *rgb_color;
-       uint8_t alpha;
        int i, j;
 
        switch_assert(use_png);
 
        for (i = 0; i < use_png->pvt->png.height; i++) {
                for (j = 0; j < use_png->pvt->png.width; j++) {
-                       //alpha = use_png->pvt->buffer[i * use_png->pvt->png.width * 4 + j * 4 + 3];
-                       alpha = use_png->pvt->buffer[i * use_png->pvt->png.width * 4 + j * 4];
-                       // printf("%d, %d alpha: %d\n", j, i, alpha);
+                       rgb_color = (switch_rgb_color_t *)use_png->pvt->buffer + i * use_png->pvt->png.width + j;
 
-                       if (alpha) { // todo, mux alpha with the underlying pixel
-                               rgb_color = (switch_rgb_color_t *)(use_png->pvt->buffer + i * use_png->pvt->png.width * 4 + j * 4);
+                       if (rgb_color->a) { // todo, mux alpha with the underlying pixel
                                switch_img_draw_pixel(img, x + j, y + i, rgb_color);
                        }
                }
@@ -1420,7 +1770,11 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, swit
        if (img_fmt == SWITCH_IMG_FMT_I420) {
                png.format = PNG_FORMAT_RGB;
        } else if (img_fmt == SWITCH_IMG_FMT_ARGB) {
+#if SWITCH_BYTE_ORDER == __BIG_ENDIAN
                png.format = PNG_FORMAT_ARGB;
+#else
+               png.format = PNG_FORMAT_BGRA;
+#endif
        } else {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unsupported image format: %x\n", img_fmt);
                goto err;
@@ -1449,7 +1803,7 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, swit
                        img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
                        png.width, png.height);
        } else if (img_fmt == SWITCH_IMG_FMT_ARGB){
-               ARGBToARGB(buffer, png.width * 4,
+               ARGBCopy(buffer, png.width * 4,
                        img->planes[SWITCH_PLANE_PACKED], png.width * 4,
                        png.width, png.height);
        }
@@ -1685,7 +2039,7 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, swit
                                        img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
                                        width, height);
                } else if (img_fmt == SWITCH_IMG_FMT_ARGB) {
-                       ARGBToRGBA(buffer, width * 4,
+                       BGRAToARGB(buffer, width * 4,
                                        img->planes[SWITCH_PLANE_PACKED], width * 4,
                                        width, height);
                }
@@ -1733,17 +2087,26 @@ SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char*
        png_bytep buffer = NULL;
        switch_status_t status = SWITCH_STATUS_SUCCESS;
 
-       buffer = malloc(img->d_w * img->d_h * 3);
-       switch_assert(buffer);
+       if (img->fmt == SWITCH_IMG_FMT_I420) {
+               png.format = PNG_FORMAT_RGB;
+               buffer = malloc(img->d_w * img->d_h * 3);
+               switch_assert(buffer);
 
-       I420ToRAW(  img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
+               I420ToRAW(img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
                                img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
                                img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
                                buffer, img->d_w * 3,
                                img->d_w, img->d_h);
+       } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
+#if SWITCH_BYTE_ORDER == __BIG_ENDIAN
+               png.format = PNG_FORMAT_ARGB;
+#else
+               png.format = PNG_FORMAT_BGRA;
+#endif
+               buffer = img->planes[SWITCH_PLANE_PACKED];
+       }
 
        png.version = PNG_IMAGE_VERSION;
-       png.format = PNG_FORMAT_RGB;
        png.width = img->d_w;
        png.height = img->d_h;
 
@@ -1752,7 +2115,10 @@ SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char*
                status = SWITCH_STATUS_FALSE;
        }
 
-       switch_safe_free(buffer);
+       if (img->fmt == SWITCH_IMG_FMT_I420) {
+               free(buffer);
+       }
+
        return status;
 }
 
@@ -1895,7 +2261,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_letterbox(switch_image_t *img, switch
        int y_pos = 0;
        switch_image_t *IMG = NULL, *scale_img = NULL;
        switch_rgb_color_t bgcolor = { 0 };
-       
+
        switch_assert(imgP);
        *imgP = NULL;
 
@@ -1913,7 +2279,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_letterbox(switch_image_t *img, switch
 
        screen_aspect = (double) IMG->d_w / IMG->d_h;
        img_aspect = (double) img->d_w / img->d_h;
-       
+
 
        if (screen_aspect > img_aspect) {
                img_w = img_aspect * IMG->d_h;
@@ -1922,7 +2288,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_letterbox(switch_image_t *img, switch
                img_h = IMG->d_w / img_aspect;
                y_pos = (IMG->d_h - img_h) / 2;
        }
-       
+
        switch_img_scale(img, &scale_img, img_w, img_h);
        switch_img_patch(IMG, scale_img, x_pos, y_pos);
        switch_img_free(&scale_img);
@@ -1955,7 +2321,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width,
 
        new_w = src->d_w;
        new_h = src->d_h;
-       
+
        if (src->d_w < width && src->d_h < height) {
                float rw = (float)new_w / width;
                float rh = (float)new_h / height;
@@ -1968,7 +2334,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width,
                        new_h = height;
                }
        } else {
-               while(new_w > width || new_h > height) { 
+               while(new_w > width || new_h > height) {
                        if (new_w > width) {
                                double m = (double) width / new_w;
                                new_w = width;
@@ -2016,7 +2382,7 @@ static inline uint32_t switch_img_fmt2fourcc(switch_img_fmt_t fmt)
                case SWITCH_IMG_FMT_YVYU:      fourcc = (uint32_t)FOURCC_ANY ; break;
                case SWITCH_IMG_FMT_BGR24:     fourcc = (uint32_t)FOURCC_RAW ; break;
                case SWITCH_IMG_FMT_RGB32_LE:  fourcc = (uint32_t)FOURCC_ANY ; break;
-               case SWITCH_IMG_FMT_ARGB:      fourcc = (uint32_t)FOURCC_ANY ; break;
+               case SWITCH_IMG_FMT_ARGB:      fourcc = (uint32_t)FOURCC_ARGB; break;
                case SWITCH_IMG_FMT_ARGB_LE:   fourcc = (uint32_t)FOURCC_ANY ; break;
                case SWITCH_IMG_FMT_RGB565_LE: fourcc = (uint32_t)FOURCC_ANY ; break;
                case SWITCH_IMG_FMT_RGB555_LE: fourcc = (uint32_t)FOURCC_ANY ; break;
@@ -2045,7 +2411,6 @@ SWITCH_DECLARE(switch_status_t) switch_img_to_raw(switch_image_t *src, void *des
        uint32_t fourcc;
        int ret;
 
-       switch_assert(src->fmt == SWITCH_IMG_FMT_I420); // todo: support other formats
        switch_assert(dest);
 
        fourcc = switch_img_fmt2fourcc(fmt);
@@ -2055,12 +2420,21 @@ SWITCH_DECLARE(switch_status_t) switch_img_to_raw(switch_image_t *src, void *des
                return SWITCH_STATUS_FALSE;
        }
 
-       ret = ConvertFromI420(src->planes[0], src->stride[0],
-                                       src->planes[1], src->stride[1],
-                                       src->planes[2], src->stride[2],
-                                       dest, stride,
-                                       src->d_w, src->d_h,
-                                       fourcc);
+       if (src->fmt == SWITCH_IMG_FMT_I420) {
+               ret = ConvertFromI420(src->planes[0], src->stride[0],
+                                               src->planes[1], src->stride[1],
+                                               src->planes[2], src->stride[2],
+                                               dest, stride,
+                                               src->d_w, src->d_h,
+                                               fourcc);
+       } else if (src->fmt == SWITCH_IMG_FMT_ARGB && fmt == src->fmt) {
+               ret = ARGBCopy(src->planes[SWITCH_PLANE_PACKED], src->stride[SWITCH_PLANE_PACKED],
+                                               dest, stride,
+                                               src->d_w, src->d_h);
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Convertion not supported %d -> %d\n", src->fmt, fmt);
+               return SWITCH_STATUS_FALSE;
+       }
 
        return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
 #else
@@ -2072,7 +2446,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_from_raw(switch_image_t *dest, void *
 {
 #ifdef SWITCH_HAVE_YUV
        uint32_t fourcc;
-       int ret;
+       int ret = -1;
 
        fourcc = switch_img_fmt2fourcc(fmt);
 
@@ -2103,7 +2477,8 @@ SWITCH_DECLARE(switch_status_t) switch_img_from_raw(switch_image_t *dest, void *
        src_size is only used when FOURCC_MJPG which we don't support so always 0
 */
 
-       ret = ConvertToI420(src, 0,
+       if (dest->fmt == SWITCH_IMG_FMT_I420) {
+               ret = ConvertToI420(src, 0,
                                        dest->planes[0], dest->stride[0],
                                        dest->planes[1], dest->stride[1],
                                        dest->planes[2], dest->stride[2],
@@ -2111,6 +2486,14 @@ SWITCH_DECLARE(switch_status_t) switch_img_from_raw(switch_image_t *dest, void *
                                        width, height,
                                        width, height,
                                        0, fourcc);
+       } else if (dest->fmt == SWITCH_IMG_FMT_ARGB) {
+               ConvertToARGB(src, 0,
+                                       dest->planes[0], width * 4,
+                                       0, 0,
+                                       width, height,
+                                       width, height,
+                                       0, fourcc);
+       }
 
        return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
 #else
@@ -2128,9 +2511,9 @@ SWITCH_DECLARE(switch_status_t) switch_img_scale(switch_image_t *src, switch_ima
                dest = *destP;
        }
 
-       if (!dest) dest = switch_img_alloc(NULL, src->fmt, width, height, 1);
+       if (dest && src->fmt != dest->fmt) switch_img_free(&dest);
 
-       switch_assert(src->fmt == dest->fmt);
+       if (!dest) dest = switch_img_alloc(NULL, src->fmt, width, height, 1);
 
        if (src->fmt == SWITCH_IMG_FMT_I420) {
                ret = I420Scale(src->planes[0], src->stride[0],
@@ -2158,7 +2541,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_scale(switch_image_t *src, switch_ima
        if (destP) {
                *destP = dest;
        }
-       
+
        return SWITCH_STATUS_SUCCESS;
 #else
        return SWITCH_STATUS_FALSE;
@@ -2201,7 +2584,7 @@ SWITCH_DECLARE(void) switch_img_find_position(switch_img_position_t pos, int sw,
                *xP = (sw - iw);
                *yP = (sh - ih) / 2;
                break;
-       case POS_RIGHT_BOT:     
+       case POS_RIGHT_BOT:
                *xP = (sw - iw);
                *yP = (sh - ih);
                break;
@@ -2292,6 +2675,66 @@ SWITCH_DECLARE(switch_status_t) switch_I420_copy2(uint8_t *src_planes[], int src
        return SWITCH_STATUS_FALSE;
 #endif
 }
+
+SWITCH_DECLARE(switch_status_t) switch_I420ToARGB(const uint8_t *src_y, int src_stride_y,
+                                                                                                       const uint8_t *src_u, int src_stride_u,
+                                                                                                       const uint8_t *src_v, int src_stride_v,
+                                                                                                       uint8_t *dst_argb, int dst_stride_argb,
+                                                                                                       int width, int height)
+{
+
+#ifdef SWITCH_HAVE_YUV
+       int ret = I420ToARGB(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+                                                dst_argb, dst_stride_argb, width, height);
+
+       return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
+#else
+       return SWITCH_STATUS_FALSE;
+#endif
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_RGBAToARGB(const uint8_t* src_frame, int src_stride_frame,
+                                                                                                       uint8_t* dst_argb, int dst_stride_argb,
+                                                                                                       int width, int height)
+{
+#ifdef SWITCH_HAVE_YUV
+       int ret = RGBAToARGB(src_frame, src_stride_frame, dst_argb, dst_stride_argb, width, height);
+
+       return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
+#else
+       return SWITCH_STATUS_FALSE;
+#endif
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_ABGRToARGB(const uint8_t* src_frame, int src_stride_frame,
+                                                                                                       uint8_t* dst_argb, int dst_stride_argb,
+                                                                                                       int width, int height)
+{
+#ifdef SWITCH_HAVE_YUV
+       int ret = ABGRToARGB(src_frame, src_stride_frame, dst_argb, dst_stride_argb, width, height);
+
+       return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
+#else
+       return SWITCH_STATUS_FALSE;
+#endif
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ARGBToARGB(const uint8_t* src_frame, int src_stride_frame,
+                                                                                                       uint8_t* dst_argb, int dst_stride_argb,
+                                                                                                       int width, int height)
+{
+#ifdef SWITCH_HAVE_YUV
+       int ret = ARGBToARGB(src_frame, src_stride_frame, dst_argb, dst_stride_argb, width, height);
+
+       return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
+#else
+       return SWITCH_STATUS_FALSE;
+#endif
+}
+
+
 /* For Emacs:
  * Local Variables:
  * mode:c