]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7500: refactor to support Alpha channel on core image, only ARGB & I420 are supported
authorSeven Du <dujinfang@gmail.com>
Sun, 12 Apr 2015 06:20:52 +0000 (14:20 +0800)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:47:20 +0000 (12:47 -0500)
src/include/switch_core_video.h
src/include/switch_vpx.h
src/mod/applications/mod_conference/mod_conference.c
src/mod/formats/mod_png/mod_png.c
src/switch_core_media.c
src/switch_core_video.c

index 3a42f3fe629e96e4dd8492abdb55741c6d4071aa..cb6ce5c58283efbd354af92c8bfd70e709447702 100644 (file)
@@ -223,7 +223,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_render(switch_img_txt_hand
 SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_image_rect_t *rect);
 
 SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, switch_image_t *img, int x, int y);
-SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char *file_name);
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char *file_name, switch_img_fmt_t img_fmt);
 SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char *file_name);
 SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char *file_name);
 SWITCH_DECLARE(void) switch_png_free(switch_png_t **pngP);
index 6a0f6de71b251c4d6ad08d89e87a75f974ccef57..ee57f387549d41d0082edcc75473a1c98865e209 100644 (file)
@@ -63,6 +63,7 @@ SWITCH_BEGIN_EXTERN_C
 
 #define SWITCH_IMG_FMT_HIGH      VPX_IMG_FMT_HIGH
 #define SWITCH_IMG_FMT_I420         VPX_IMG_FMT_I420
+#define SWITCH_IMG_FMT_ARGB         VPX_IMG_FMT_ARGB
 
 typedef vpx_img_fmt_t switch_img_fmt_t;
 
index 59e5a0a034ba741caa9f646c5f15d3a026ca35b9..ad35052ed0ad07662bbf5d94b0367b338ac35db7 100644 (file)
@@ -1227,7 +1227,7 @@ static void layer_set_logo(conference_member_t *member, mcu_layer_t *layer, cons
        }
 
        if (path && strcasecmp(path, "clear")) {
-               layer->logo_img = switch_img_read_png(path);
+               layer->logo_img = switch_img_read_png(path, SWITCH_IMG_FMT_ARGB);
        }
 
        layer->logo_pos = pos;
@@ -1967,7 +1967,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                                                                clear_layer(conference->canvas, layer);
 
                                                                if (!layer->mute_img && imember->video_mute_png) {
-                                                                       layer->mute_img = switch_img_read_png(imember->video_mute_png);
+                                                                       layer->mute_img = switch_img_read_png(imember->video_mute_png, SWITCH_IMG_FMT_I420);
                                                                }
 
                                                                if (layer->mute_img) {
@@ -3944,7 +3944,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
                }
                
                if (avatar) {
-                       member->avatar_png_img = switch_img_read_png(avatar);
+                       member->avatar_png_img = switch_img_read_png(avatar, SWITCH_IMG_FMT_I420);
                }
 
                if ((var = switch_channel_get_variable_dup(member->channel, "video_mute_png", SWITCH_FALSE, -1))) {
index a64c2db4d0a4675e15b72b8c5204ed4f707d99f2..7007e04dcf31ed8204366865c0a1c8f3ef69674c 100644 (file)
@@ -74,7 +74,7 @@ static switch_status_t png_file_open(switch_file_handle_t *handle, const char *p
 
        memset(context, 0, sizeof(png_file_context_t));
 
-       if (!(context->img = switch_img_read_png(path))) {
+       if (!(context->img = switch_img_read_png(path, SWITCH_IMG_FMT_I420))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening %s\n", path);
                return SWITCH_STATUS_GENERR;
        }
index 79132a8c9941a7da97a7aed8dbff0dac4ded1f16..42b349fa4fb20186b744721272b5ac1e960a7bdc 100644 (file)
@@ -4782,7 +4782,7 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
        }
 
        if ((var = switch_channel_get_variable(session->channel, "core_video_blank_image"))) {
-               blank_img = switch_img_read_png(var);
+               blank_img = switch_img_read_png(var, SWITCH_IMG_FMT_I420);
        }
 
        if (!blank_img) {
index 5a86c37d34ee205d6e5a1a25fa34fde9919884e1..63b5abb9667541363d13718a17b35657afa95f0e 100644 (file)
@@ -70,9 +70,6 @@ SWITCH_DECLARE(switch_img_position_t) parse_img_position(const char *name)
        return r;
 }
 
-
-
-
 SWITCH_DECLARE(switch_image_t *)switch_img_alloc(switch_image_t  *img,
                                                 switch_img_fmt_t fmt,
                                                 unsigned int d_w,
@@ -128,12 +125,32 @@ SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img,
 {
        int i, len, max_h;
 
-       switch_assert(x > -1);
-       switch_assert(y > -1);
-
-       switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
        switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420);
 
+       if (img->fmt == SWITCH_IMG_FMT_ARGB) {
+               int max_w = MIN(img->d_w, IMG->d_w - x);
+               int max_h = MIN(img->d_h, IMG->d_h - y);
+               int j;
+               uint8_t alpha;
+               switch_rgb_color_t *rgb_color;
+               switch_yuv_color_t yuv_color;
+
+               for (i = 0; i < max_h; i++) {
+                       for (j = 0; j < max_w; j++) {
+                               alpha = img->planes[SWITCH_PLANE_PACKED][i * img->d_w * 4 + j * 4];
+                               // printf("%d, %d alpha: %d\n", j, i, alpha);
+
+                               if (alpha > 127) { // todo: mux alpha with the underlying pixel ?
+                                       rgb_color = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->d_w * 4 + j * 4 + 1);
+                                       switch_color_rgb2yuv(rgb_color, &yuv_color);
+                                       switch_img_draw_pixel(IMG, x + j, y + i, &yuv_color);
+                               }
+                       }
+               }
+
+               return;
+       }
+
        max_h = MIN(y + img->d_h, IMG->d_h);
        len = MIN(img->d_w, IMG->d_w - x);
 
@@ -162,27 +179,31 @@ SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_i
        switch_assert(img);
        switch_assert(new_img);
 
-       if (!(img->fmt == SWITCH_IMG_FMT_I420)) return;
+       if (img->fmt != SWITCH_IMG_FMT_I420 && img->fmt != SWITCH_IMG_FMT_ARGB) return;
 
        if (*new_img != NULL) {
-               if (img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_w) {
+               if (img->fmt != (*new_img)->fmt || img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_w) {
                        switch_img_free(new_img);
                }
        }
 
        if (*new_img == NULL) {
-               *new_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, img->d_w, img->d_h, 1);
+               *new_img = switch_img_alloc(NULL, img->fmt, img->d_w, img->d_h, 1);
        }
 
        switch_assert(*new_img);
 
-       for (i = 0; i < (*new_img)->h; i++) {
-               memcpy((*new_img)->planes[SWITCH_PLANE_Y] + (*new_img)->stride[SWITCH_PLANE_Y] * i, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * i, img->d_w);
-       }
+       if (img->fmt == SWITCH_IMG_FMT_I420) {
+               for (i = 0; i < (*new_img)->h; i++) {
+                       memcpy((*new_img)->planes[SWITCH_PLANE_Y] + (*new_img)->stride[SWITCH_PLANE_Y] * i, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * i, img->d_w);
+               }
 
-       for (i = 0; i < (*new_img)->h / 2; i++) {
-               memcpy((*new_img)->planes[SWITCH_PLANE_U] + (*new_img)->stride[SWITCH_PLANE_U] * i, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * i, img->d_w / 2);
-               memcpy((*new_img)->planes[SWITCH_PLANE_V] + (*new_img)->stride[SWITCH_PLANE_V] * i, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * i, img->d_w /2);
+               for (i = 0; i < (*new_img)->h / 2; i++) {
+                       memcpy((*new_img)->planes[SWITCH_PLANE_U] + (*new_img)->stride[SWITCH_PLANE_U] * i, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * i, img->d_w / 2);
+                       memcpy((*new_img)->planes[SWITCH_PLANE_V] + (*new_img)->stride[SWITCH_PLANE_V] * i, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * i, img->d_w / 2);
+               }
+       } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
+               memcpy((*new_img)->planes[SWITCH_PLANE_PACKED], img->planes[SWITCH_PLANE_PACKED], img->d_w * img->d_h * 4);
        }
 
 }
@@ -219,7 +240,7 @@ SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, int x
 
 SWITCH_DECLARE(void) switch_img_draw_pixel(switch_image_t *img, int x, int y, switch_yuv_color_t *color)
 {
-       if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
+       if (img->fmt != SWITCH_IMG_FMT_I420 || x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
 
        img->planes[SWITCH_PLANE_Y][y * img->stride[SWITCH_PLANE_Y] + x] = color->y;
 
@@ -234,7 +255,7 @@ SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, i
        int len, i, max_h;
        switch_yuv_color_t yuv_color;
 
-       if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
+       if (img->fmt != SWITCH_IMG_FMT_I420 || x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
 
        switch_color_rgb2yuv(color, &yuv_color);
 
@@ -261,6 +282,7 @@ SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, i
 
 SWITCH_DECLARE(void) switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_color_t *yuv, int x, int y)
 {
+       // switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
        yuv->y = *(img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * y + x);
        yuv->u = *(img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * y / 2 + x / 2);
        yuv->v = *(img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * y / 2 + x / 2);
@@ -597,6 +619,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_render(switch_img_txt_hand
        FT_Face face;
 
        if (zstr(text)) return SWITCH_STATUS_FALSE;
+       switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
 
        if (font_family) {
                handle->font_family = switch_core_strdup(handle->pool, font_family);
@@ -744,7 +767,7 @@ SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t *
 
 struct switch_png_opaque_s {
        png_image png;
-       png_bytep buffer;       
+       png_bytep buffer;
 };
 
 
@@ -757,13 +780,13 @@ SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char
        switch_zmalloc(use_png, sizeof(*use_png));
        switch_zmalloc(use_png->pvt, sizeof(struct switch_png_opaque_s));
        use_png->pvt->png.version = PNG_IMAGE_VERSION;
-               
+
        if (!png_image_begin_read_from_file(&use_png->pvt->png, file_name)) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read PNG %s\n", file_name);
                switch_goto_status(SWITCH_STATUS_FALSE, end);
        }
-               
-       use_png->pvt->png.format = PNG_FORMAT_RGBA;
+
+       use_png->pvt->png.format = PNG_FORMAT_ARGB;
 
        use_png->pvt->buffer = malloc(PNG_IMAGE_SIZE(use_png->pvt->png));
        switch_assert(use_png->pvt->buffer);
@@ -811,16 +834,18 @@ SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, swit
        switch_yuv_color_t yuv_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);
 
                        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);
+                               rgb_color = (switch_rgb_color_t *)(use_png->pvt->buffer + i * use_png->pvt->png.width * 4 + j * 4 + 1);
                                switch_color_rgb2yuv(rgb_color, &yuv_color);
                                switch_img_draw_pixel(img, x + j, y + i, &yuv_color);
                        }
@@ -838,12 +863,12 @@ SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char
        return SWITCH_STATUS_FALSE;
 }
 
-SWITCH_DECLARE(void) switch_png_free(switch_png_t **pngP) 
+SWITCH_DECLARE(void) switch_png_free(switch_png_t **pngP)
 {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT IMPLEMENTED\n");
 }
 
-SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, switch_image_t *img, int x, int y) 
+SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, switch_image_t *img, int x, int y)
 {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT IMPLEMENTED\n");
        return SWITCH_STATUS_FALSE;
@@ -854,7 +879,7 @@ SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, swit
 
 #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* available from libpng 1.6.0 */
 
-SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, switch_img_fmt_t img_fmt)
 {
        png_image png = { 0 };
        png_bytep buffer = NULL;
@@ -867,7 +892,15 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
                goto err;
        }
 
-       png.format = PNG_FORMAT_RGB;
+       if (img_fmt == SWITCH_IMG_FMT_I420) {
+               png.format = PNG_FORMAT_RGB;
+       } else if (img_fmt == SWITCH_IMG_FMT_ARGB) {
+               png.format = PNG_FORMAT_ARGB;
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unsupported image format: %x\n", img_fmt);
+               goto err;
+       }
+
        buffer = malloc(PNG_IMAGE_SIZE(png));
        switch_assert(buffer);
 
@@ -881,14 +914,20 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
                goto err;
        }
 
-       img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, png.width, png.height, 1);
+       img = switch_img_alloc(NULL, img_fmt, png.width, png.height, 1);
        switch_assert(img);
 
-       RAWToI420(buffer, png.width * 3,
-               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],
-               png.width, png.height);
+       if (img_fmt == SWITCH_IMG_FMT_I420) {
+               RAWToI420(buffer, png.width * 3,
+                       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],
+                       png.width, png.height);
+       } else if (img_fmt == SWITCH_IMG_FMT_ARGB){
+               ARGBToARGB(buffer, png.width * 4,
+                       img->planes[SWITCH_PLANE_PACKED], png.width * 4,
+                       png.width, png.height);
+       }
 
 err:
        png_image_free(&png);
@@ -905,7 +944,7 @@ err:
 // http://www.libpng.org/pub/png/libpng-1.2.5-manual.html
 // ftp://ftp.oreilly.com/examples/9781565920583/CDROM/SOFTWARE/SOURCE/LIBPNG/EXAMPLE.C
 
-SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, switch_img_fmt_t img_fmt)
 {
        png_byte header[8];    // 8 is the maximum size that can be checked
        png_bytep *row_pointers = NULL;
@@ -920,14 +959,19 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
        //int number_of_passes;
        int row_bytes;
        png_color_8p sig_bit;
-    // png_color_16 my_background = { 0 }; //{index,r, g, b, grey}
-    png_color_16 my_background = {0, 99, 99, 99, 0};
 
        png_byte *buffer = NULL;
        switch_image_t *img = NULL;
 
+       FILE *fp;
+
+       if (img_fmt != SWITCH_IMG_FMT_I420 && img_fmt != SWITCH_IMG_FMT_ARGB) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Only ARGB and I420 are supported, you want 0x%x\n", img_fmt);
+               return NULL;
+       }
+
        /* open file and test for it being a png */
-       FILE *fp = fopen(file_name, "rb");
+       fp = fopen(file_name, "rb");
        if (!fp) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File %s could not be opened for reading\n", file_name);
                goto end;
@@ -957,7 +1001,6 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
        }
 
        png_init_io(png_ptr, fp);
-
        png_set_sig_bytes(png_ptr, 8);
        png_read_info(png_ptr, info_ptr);
 
@@ -985,13 +1028,14 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
                png_set_expand(png_ptr);
        }
 
-       /* Set the background color to draw transparent and alpha
-       images over */
+       /* Set the background color to draw transparent and alpha images over */
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
                // png_get_bKGD(png_ptr, info_ptr, &my_background);
                // png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
        } else {
-               png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+               // png_color_16 my_background = { 0 }; //{index,r, g, b, grey}
+               // png_color_16 my_background = {0, 99, 99, 99, 0};
+               // png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
        }
 
        /* tell libpng to handle the gamma conversion for you */
@@ -1051,7 +1095,7 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
                png_set_swap(png_ptr);
        }
 
-       if (color_type & PNG_COLOR_MASK_ALPHA) {
+       if (0 && color_type & PNG_COLOR_MASK_ALPHA) {
                if (setjmp(png_jmpbuf(png_ptr))) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error!!!!\n");
                        goto end;
@@ -1060,8 +1104,20 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
                png_set_strip_alpha(png_ptr);
        }
 
+       if (setjmp(png_jmpbuf(png_ptr))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Error during read_updated_info\n");
+               goto end;
+       }
+
+       if (color_type == PNG_COLOR_TYPE_PALETTE) {
+               png_set_palette_to_rgb(png_ptr);
+       }
+
        png_read_update_info(png_ptr, info_ptr);
 
+       color_type = png_get_color_type(png_ptr, info_ptr);
+       // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "color_type: 0x%x\n", color_type);
+
        if (width > SWITCH_IMG_MAX_WIDTH || height > SWITCH_IMG_MAX_HEIGHT) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PNG is too large! %dx%d\n", width, height);
        }
@@ -1075,17 +1131,10 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
        buffer = (png_byte *)malloc(row_bytes * height);
        switch_assert(buffer);
 
-       for (y = 0; y< height; y++) {
+       for (y = 0; y < height; y++) {
                row_pointers[y] = buffer + row_bytes * y;
        }
 
-       if (color_type == PNG_COLOR_TYPE_PALETTE) {
-               png_set_palette_to_rgb(png_ptr);
-       }
-
-       img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, width, height, 1);
-       switch_assert(img);
-
        /* read file */
        if (setjmp(png_jmpbuf(png_ptr))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error during read_image");
@@ -1094,28 +1143,42 @@ SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
 
        png_read_image(png_ptr, row_pointers);
 
-       if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGBA) {
-               // should never get here since we already use png_set_strip_alpha() ?
-               switch_assert(1 == 2);
+       if (color_type == PNG_COLOR_TYPE_RGBA) {
+               if (row_bytes > width * 4) {
+                       for(y = 1; y < height; y++) {
+                               memcpy(buffer + y * width * 4, row_pointers[y], width * 4);
+                       }
+               }
 
-               switch_assert(row_bytes >= width * 4);
+               img = switch_img_alloc(NULL, img_fmt, width, height, 1);
+               switch_assert(img);
+
+               if (img_fmt == SWITCH_IMG_FMT_I420) {
+                       ABGRToI420(buffer, width * 4,
+                                       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],
+                                       width, height);
+               } else if (img_fmt == SWITCH_IMG_FMT_ARGB) {
+                       ARGBToRGBA(buffer, width * 4,
+                                       img->planes[SWITCH_PLANE_PACKED], width * 4,
+                                       width, height);
+               }
+       } else if (color_type == PNG_COLOR_TYPE_RGB) {
+               if (row_bytes > width * 3) {
+                       for(y = 1; y < height; y++) {
+                               memcpy(buffer + y * width * 3, row_pointers[y], width * 3);
+                       }
+               }
 
-               for(y = 1; y < height; y++) {
-                       memcpy(buffer + y * width * 4, row_pointers[y], width * 4);
+               if (img_fmt == SWITCH_IMG_FMT_ARGB) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No alpha channel in image [%s], fallback to I420\n", file_name);
+                       img_fmt = SWITCH_IMG_FMT_I420;
                }
 
-               // ABGRToI420(buffer, width * 4,
-               RGBAToI420(buffer, width * 4,
-                               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],
-                               width, height);
-       } else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) {
-               switch_assert(row_bytes >= width * 3);
+               img = switch_img_alloc(NULL, img_fmt, width, height, 1);
+               switch_assert(img);
 
-               for(y = 1; y < height; y++) {
-                       memcpy(buffer + y * width * 3, row_pointers[y], width * 3);
-               }
                RAWToI420(buffer, width * 3,
                                img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
                                img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
@@ -1285,7 +1348,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_patch_png(switch_image_t *img, int x,
        return SWITCH_STATUS_FALSE;
 }
 
-SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, switch_img_fmt_t img_fmt)
 {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This function is not available, libpng not installed\n");
        return NULL;
@@ -1341,6 +1404,8 @@ SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width,
 
 SWITCH_DECLARE(switch_status_t) switch_img_convert(switch_image_t *src, switch_convert_fmt_t fmt, void *dest, switch_size_t *size)
 {
+       switch_assert(src->fmt = SWITCH_IMG_FMT_I420);
+
        switch (fmt) {
        case SWITCH_CONVERT_FMT_YUYV:
                {
@@ -1372,18 +1437,27 @@ SWITCH_DECLARE(switch_status_t) switch_img_scale(switch_image_t *src, switch_ima
                dest = *destP;
        }
 
-       if (!dest) dest = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, width, height, 1);
-       
-       ret = I420Scale(src->planes[0], src->stride[0],
-                                       src->planes[1], src->stride[1],
-                                       src->planes[2], src->stride[2],
-                                       src->d_w, src->d_h,
-                                       dest->planes[0], dest->stride[0],
-                                       dest->planes[1], dest->stride[1],
-                                       dest->planes[2], dest->stride[2],
-                                       width, height,
-                                       kFilterBox);
-               
+       if (!dest) dest = switch_img_alloc(NULL, src->fmt, width, height, 1);
+
+       switch_assert(src->fmt == dest->fmt);
+
+       if (src->fmt == SWITCH_IMG_FMT_I420) {
+               ret = I420Scale(src->planes[0], src->stride[0],
+                                               src->planes[1], src->stride[1],
+                                               src->planes[2], src->stride[2],
+                                               src->d_w, src->d_h,
+                                               dest->planes[0], dest->stride[0],
+                                               dest->planes[1], dest->stride[1],
+                                               dest->planes[2], dest->stride[2],
+                                               width, height,
+                                               kFilterBox);
+       } else if (src->fmt == SWITCH_IMG_FMT_ARGB) {
+               ret = ARGBScale(src->planes[SWITCH_PLANE_PACKED], src->d_w * 4,
+              src->d_w, src->d_h,
+              dest->planes[SWITCH_PLANE_PACKED], width * 4,
+              width, height,
+              kFilterBox);
+       }
 
        if (ret != 0) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scaling Error: ret: %d\n", ret);