]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7513: add logo func and positioning param and vid snapshot
authorAnthony Minessale <anthm@freeswitch.org>
Sat, 14 Feb 2015 04:27:18 +0000 (22:27 -0600)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:47:02 +0000 (12:47 -0500)
src/include/switch_core_video.h
src/mod/applications/mod_conference/mod_conference.c
src/switch_core_video.c

index 00a7ee1620fa10daf0e912777c7ba1c6e69409df..6101fe2a3efba7a7d17daf326bdb8c769ad5f3b7 100644 (file)
 
 SWITCH_BEGIN_EXTERN_C
 
+typedef enum {
+       POS_LEFT_TOP = 0,
+       POS_LEFT_MID,
+       POS_LEFT_BOT,
+       POS_CENTER_TOP,
+       POS_CENTER_MID,
+       POS_CENTER_BOT,
+       POS_RIGHT_TOP,
+       POS_RIGHT_MID,
+       POS_RIGHT_BOT,
+       POS_NONE
+} switch_img_position_t;
+
+
 typedef struct switch_yuv_color_s {
        uint8_t y;
        uint8_t u;
@@ -195,7 +209,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_image_t *) switch_img_read_png(const char* file_name);
-SWITCH_DECLARE(void) switch_img_write_png(switch_image_t *img, char* file_name);
+SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char* file_name);
 
 SWITCH_DECLARE(void) switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_color_t *yuv, int x, int y);
 
@@ -203,6 +217,10 @@ SWITCH_DECLARE(void) switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_co
 
 SWITCH_DECLARE(void) switch_img_overlay(switch_image_t *IMG, switch_image_t *img, int x, int y, uint8_t alpha);
 
+SWITCH_DECLARE(switch_status_t) switch_img_scale(switch_image_t *src, switch_image_t **destP, int width, int height);
+SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, int height);
+SWITCH_DECLARE(switch_img_position_t) parse_img_position(const char *name);
+SWITCH_DECLARE(void) switch_img_find_position(switch_img_position_t pos, int sw, int sh, int iw, int ih, int *xP, int *yP);
 
 /** @} */
 
index e34d8e59cb0bbd2db38798ee4fb4185401272eef..e6bbe4b1e27988a6394728f16142996293976514 100644 (file)
@@ -39,7 +39,6 @@
  *
  */
 #include <switch.h>
-#include <libyuv.h>
 
 #ifdef OPENAL_POSITIONING
 #define AL_ALEXT_PROTOTYPES
@@ -361,6 +360,7 @@ struct vid_helper {
        int up;
 };
 
+
 typedef struct mcu_layer_geometry_s {
        int x;
        int y;
@@ -386,6 +386,7 @@ typedef struct mcu_layer_s {
        int y_pos;
        int banner_patched;
        int mute_patched;
+       switch_img_position_t logo_pos;
        switch_image_t *img;
        switch_image_t *cur_img;
        switch_image_t *banner_img;
@@ -624,6 +625,7 @@ struct conference_member {
        int video_codec_index;
        int video_codec_id;
        char *video_banner_text;
+       char *video_logo;
        char *video_mute_png;
 };
 
@@ -644,6 +646,7 @@ typedef struct api_command {
        char *psyntax;
 } api_command_t;
 
+
 /* Function Prototypes */
 static int setup_media(conference_member_t *member, conference_obj_t *conference);
 static uint32_t next_member_id(void);
@@ -756,7 +759,6 @@ typedef struct layout_group_s {
 } layout_group_t;
 
 
-
 static void conference_parse_layouts(conference_obj_t *conference)
 {
        switch_event_t *params;
@@ -940,7 +942,6 @@ static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer)
 
 static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, switch_image_t *ximg)
 {
-       int ret;
        switch_image_t *IMG, *img;
 
        switch_mutex_lock(conference->canvas->mutex);
@@ -968,17 +969,6 @@ static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, sw
                        y_pos += (layer->screen_h - img_h) / 2;
                }
 
-               /*int I420Scale(const uint8* src_y, int src_stride_y,
-                 const uint8* src_u, int src_stride_u,
-                 const uint8* src_v, int src_stride_v,
-                 int src_width, int src_height,
-                 uint8* dst_y, int dst_stride_y,
-                 uint8* dst_u, int dst_stride_u,
-                 uint8* dst_v, int dst_stride_v,
-                 int dst_width, int dst_height,
-                 enum FilterMode filtering)
-               */
-
                if (layer->img && (layer->img->d_w != img_w || layer->img->d_h != img_h)) {
                        switch_img_free(&layer->img);
                        layer->banner_patched = 0;
@@ -994,31 +984,20 @@ static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, sw
                        layer->banner_patched = 1;
                }
 
-               if (layer->logo_img) {
-                       switch_img_patch(img, layer->logo_img, img->d_w - layer->logo_img->d_w, 0);
-               }
-
-               
                switch_assert(layer->img);
 
-               //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "RESIZE %dx%d to %dx%d to fit in %dx%d and insert at %d,%d\n",
-               //                                img->d_w, img->d_h, img_w, img_h, screen_w, screen_h, x, y);
-
-               ret = I420Scale(img->planes[0], img->stride[0],
-                                               img->planes[1], img->stride[1],
-                                               img->planes[2], img->stride[2],
-                                               img->d_w, img->d_h,
-                                               layer->img->planes[0], layer->img->stride[0],
-                                               layer->img->planes[1], layer->img->stride[1],
-                                               layer->img->planes[2], layer->img->stride[2],
-                                               img_w, img_h,
-                                               kFilterBox);
-               
-               if (ret != 0) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scaling Error: ret: %d\n", ret);
-               } else {
+               if (switch_img_scale(img, &layer->img, img_w, img_h) == SWITCH_STATUS_SUCCESS) {
                        switch_img_patch(IMG, layer->img, x_pos, y_pos);
                }
+
+               if (layer->logo_img) {
+                       int ew = layer->screen_w, eh = layer->screen_h - (layer->banner_img ? layer->banner_img->d_h : 0);
+                       int ex = 0, ey = 0;
+
+                       switch_img_fit(&layer->logo_img, ew, eh);
+                       switch_img_find_position(layer->logo_pos, ew, eh, layer->logo_img->d_w, layer->logo_img->d_h, &ex, &ey);
+                       switch_img_patch(IMG, layer->logo_img, x_pos + ex, y_pos + ey);
+               }
        } else {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "insert at %d,%d\n", 0, 0);
                switch_img_patch(IMG, img, 0, 0);
@@ -1074,6 +1053,87 @@ static void detach_video_layer(conference_member_t *member)
        switch_mutex_unlock(member->conference->canvas->mutex);
 }
 
+
+static void layer_set_logo(conference_member_t *member, mcu_layer_t *layer, const char *path)
+{
+       const char *var = NULL;
+       char *dup = NULL;
+       switch_event_t *params = NULL;
+       char *parsed = NULL;
+       char *tmp;
+       switch_img_position_t pos = POS_LEFT_TOP;
+
+       switch_mutex_lock(member->conference->canvas->mutex);
+
+       if (!path) {
+               path = member->video_logo;
+       }
+       
+       if (!path) {
+               goto end;
+       }
+
+       if (*path == '{') {
+               dup = strdup(path);
+               path = dup;
+
+               if (switch_event_create_brackets((char *)path, '{', '}', ',', &params, &parsed, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS || !parsed) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
+               } else {
+                       path = parsed;
+               }
+       }
+
+
+       if (zstr(path) || !strcasecmp(path, "reset")) { 
+               path = switch_channel_get_variable_dup(member->channel, "video_logo_path", SWITCH_FALSE, -1);
+       }
+       
+       if (zstr(path) || !strcasecmp(path, "clear")) {
+               switch_rgb_color_t color;
+
+               switch_img_free(&layer->banner_img);
+               layer->banner_patched = 0;
+               
+               switch_color_set_rgb(&color, member->conference->video_layout_bgcolor);
+               switch_img_fill(member->conference->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &color);
+
+               goto end;
+       }
+
+       if ((tmp = strchr(path, '}'))) {
+               path = tmp + 1;
+       }
+
+
+       if (params) {
+               if ((var = switch_event_get_header(params, "position"))) {
+                       pos = parse_img_position(var);
+               }
+       }
+
+
+       if (path) {
+               switch_img_free(&layer->logo_img);
+       }
+
+
+       if (path && strcasecmp(path, "clear")) {
+               layer->logo_img = switch_img_read_png(path);
+       }
+
+       layer->logo_pos = pos;
+       
+       if (params) switch_event_destroy(&params);
+
+       switch_safe_free(dup);
+
+ end:
+
+       switch_mutex_unlock(member->conference->canvas->mutex);
+
+}
+
 static void layer_set_banner(conference_member_t *member, mcu_layer_t *layer, const char *text)
 {
        switch_rgb_color_t fgcolor, bgcolor;
@@ -1083,7 +1143,7 @@ static void layer_set_banner(conference_member_t *member, mcu_layer_t *layer, co
        const char *bg = "#142e55";
        char *parsed = NULL;
        switch_event_t *params = NULL;
-       const char *font_face = "/usr/share/fonts/truetype/freefont/FreeSansOblique.ttf", *logo_png = NULL;
+       const char *font_face = "/usr/share/fonts/truetype/freefont/FreeSansOblique.ttf";
        const char *var, *tmp = NULL;
        char *dup = NULL;
        
@@ -1117,8 +1177,6 @@ static void layer_set_banner(conference_member_t *member, mcu_layer_t *layer, co
                switch_rgb_color_t color;
 
                switch_img_free(&layer->banner_img);
-               switch_img_free(&layer->logo_img);
-               switch_img_free(&layer->mute_img);
                layer->banner_patched = 0;
                
                switch_color_set_rgb(&color, member->conference->video_layout_bgcolor);
@@ -1145,10 +1203,6 @@ static void layer_set_banner(conference_member_t *member, mcu_layer_t *layer, co
                        font_face = var;
                }
 
-               if ((var = switch_event_get_header(params, "logo_png"))) {
-                       logo_png = var;
-               }
-
                if ((var = switch_event_get_header(params, "font_scale"))) {
                        int tmp = atoi(var);
 
@@ -1168,10 +1222,6 @@ static void layer_set_banner(conference_member_t *member, mcu_layer_t *layer, co
        switch_img_free(&layer->logo_img);
        layer->banner_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, layer->screen_w, font_size * 2, 1);
 
-       if (logo_png) {
-               layer->logo_img = switch_img_read_png(logo_png);
-       }
-
        if (layer->txthandle) {
                switch_img_txt_handle_destroy(&layer->txthandle);
        }
@@ -1197,7 +1247,7 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx)
        switch_channel_t *channel = NULL;
        const char *res_id = NULL;
        switch_status_t status = SWITCH_STATUS_SUCCESS;
-       const char *banner = NULL;
+       const char *var = NULL;
        switch_rgb_color_t color;
        
        if (!member->session) abort();
@@ -1233,8 +1283,14 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx)
                }
        }
        
-       if (member->video_banner_text || (banner = switch_channel_get_variable_dup(channel, "video_banner_text", SWITCH_FALSE, -1))) {
-               layer_set_banner(member, layer, banner);
+       var = NULL;
+       if (member->video_banner_text || (var = switch_channel_get_variable_dup(channel, "video_banner_text", SWITCH_FALSE, -1))) {
+               layer_set_banner(member, layer, var);
+       }
+
+       var = NULL;
+       if (member->video_logo || (var = switch_channel_get_variable_dup(channel, "video_logo_path", SWITCH_FALSE, -1))) {
+               layer_set_logo(member, layer, var);
        }
 
        layer->member_id = member->id;
@@ -1444,7 +1500,7 @@ static void vmute_snap(conference_member_t *member, switch_bool_t clear)
                layer = &member->conference->canvas->layers[member->video_layer_id];
                switch_img_free(&layer->mute_img);
                
-               if (!clear) {
+               if (!clear && layer->cur_img) {
                        switch_img_copy(layer->cur_img, &layer->mute_img);
                }
 
@@ -1621,7 +1677,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                                                layer->mute_patched = 0;
                                        } else {
                                                switch_img_free(&img);
-                                               if (imember->video_mute_png && !layer->mute_patched) {
+                                               if (!layer->mute_patched) {
 
                                                        if (imember->video_mute_png || layer->mute_img) {
                                                                reset_layer(conference->canvas, layer);
@@ -8034,6 +8090,29 @@ static switch_status_t conf_api_sub_vid_fps(conference_obj_t *conference, switch
        
 }
 
+static switch_status_t conf_api_sub_write_png(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
+{
+       switch_status_t status = SWITCH_STATUS_FALSE;
+
+       if (!argv[2]) {
+               stream->write_function(stream, "Invalid input\n");
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if (!conference->canvas) {
+               stream->write_function(stream, "Conference is not in mixing mode\n");
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       switch_mutex_lock(conference->canvas->mutex);
+       status = switch_img_write_png(conference->canvas->img, argv[2]);
+       switch_mutex_unlock(conference->canvas->mutex);
+
+       stream->write_function(stream, "%s\n", status == SWITCH_STATUS_SUCCESS ? "+OK" : "-ERR");
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static switch_status_t conf_api_sub_vid_layout(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
 {
        video_layout_t *vlayout = NULL;
@@ -8293,13 +8372,14 @@ static switch_status_t conf_api_sub_vid_mute_img(conference_member_t *member, sw
                return SWITCH_STATUS_FALSE;
        }
 
-       switch_mutex_lock(member->conference->mutex);
+       switch_mutex_lock(member->conference->canvas->mutex);
 
        if (member->video_layer_id == -1 || !member->conference->canvas) {
                goto end;
        }
 
        member->video_mute_png = NULL;
+       layer = &member->conference->canvas->layers[member->video_layer_id];
 
        if (text) {
                switch_img_free(&layer->mute_img);
@@ -8307,14 +8387,49 @@ static switch_status_t conf_api_sub_vid_mute_img(conference_member_t *member, sw
 
        if (text && strcasecmp(text, "clear")) {
                member->video_mute_png = switch_core_strdup(member->pool, text);
-               layer = &member->conference->canvas->layers[member->video_layer_id];
        }
 
  end:
 
        stream->write_function(stream, "%s\n", member->video_mute_png ? member->video_mute_png : "_undef_");
 
-       switch_mutex_lock(member->conference->mutex);
+       switch_mutex_unlock(member->conference->canvas->mutex);
+
+       return SWITCH_STATUS_SUCCESS;
+
+}
+
+
+static switch_status_t conf_api_sub_vid_logo_img(conference_member_t *member, switch_stream_handle_t *stream, void *data)
+{
+       char *text = (char *) data;
+       mcu_layer_t *layer = NULL;
+
+       if (member == NULL)
+               return SWITCH_STATUS_GENERR;
+
+       if (!switch_channel_test_flag(member->channel, CF_VIDEO)) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       switch_mutex_lock(member->conference->canvas->mutex);
+
+       if (member->video_layer_id == -1 || !member->conference->canvas) {
+               goto end;
+       }
+
+       layer = &member->conference->canvas->layers[member->video_layer_id];
+
+       member->video_logo = switch_core_strdup(member->pool, text);
+
+       layer_set_logo(member, layer, text);
+
+ end:
+
+       stream->write_function(stream, "+OK\n");
+
+       switch_mutex_unlock(member->conference->canvas->mutex);
+
        return SWITCH_STATUS_SUCCESS;
 
 }
@@ -9788,8 +9903,10 @@ static api_command_t conf_api_sub_commands[] = {
        {"vid-floor", (void_fn_t) & conf_api_sub_vid_floor, CONF_API_SUB_MEMBER_TARGET, "vid-floor", "<member_id|last> [force]"},
        {"vid-banner", (void_fn_t) & conf_api_sub_vid_banner, CONF_API_SUB_MEMBER_TARGET, "vid-banner", "<member_id|last> <text>"},
        {"vid-mute-img", (void_fn_t) & conf_api_sub_vid_mute_img, CONF_API_SUB_MEMBER_TARGET, "vid-mute-img", "<member_id|last> [<path>|clear]"},
+       {"vid-logo-img", (void_fn_t) & conf_api_sub_vid_logo_img, CONF_API_SUB_MEMBER_TARGET, "vid-logo-img", "<member_id|last> [<path>|clear]"},
        {"clear-vid-floor", (void_fn_t) & conf_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""},
        {"vid-layout", (void_fn_t) & conf_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", "<layout name>"},
+       {"vid-write-png", (void_fn_t) & conf_api_sub_write_png, CONF_API_SUB_ARGS_SPLIT, "vid-write-png", "<path>"},
        {"vid-fps", (void_fn_t) & conf_api_sub_vid_fps, CONF_API_SUB_ARGS_SPLIT, "vid-fps", "<fps>"},
        {"vid-bandwidth", (void_fn_t) & conf_api_sub_vid_bandwidth, CONF_API_SUB_ARGS_SPLIT, "vid-bandwidth", "<BW>"}
 };
index 38dc897f6adf8491013cb8dd1fa3617aab68b135..068ef1ee2defb2a08bb9ae11bd6a9cfb23a7f7fc 100644 (file)
 #include <switch_utf8.h>
 #include <libyuv.h>
 
+struct pos_el {
+       switch_img_position_t pos;
+       const char *name;
+};
+
+
+static struct pos_el POS_TABLE[] = {
+       {POS_LEFT_TOP, "left-top"},
+       {POS_LEFT_MID, "left-mid"},
+       {POS_LEFT_BOT, "left-bot"},
+       {POS_CENTER_TOP, "center-top"},
+       {POS_CENTER_MID, "center-mid"},
+       {POS_CENTER_BOT, "center-bot"},
+       {POS_RIGHT_TOP, "right-top"},
+       {POS_RIGHT_MID, "right-mid"},
+       {POS_RIGHT_BOT, "right-bot"},
+       {POS_NONE, NULL}
+};
+
+
+SWITCH_DECLARE(switch_img_position_t) parse_img_position(const char *name)
+{
+       switch_img_position_t r = POS_LEFT_TOP;
+       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;
+}
+
+
+
+
 SWITCH_DECLARE(switch_image_t *)switch_img_alloc(switch_image_t  *img,
                                                 switch_img_fmt_t fmt,
                                                 unsigned int d_w,
@@ -582,7 +622,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_render(switch_img_txt_hand
 
        /* use 50pt at 100dpi */
        error = FT_Set_Char_Size(face, 64 * font_size, 0, 96, 96); /* set character size */
-       if (error) {printf("WTF %d\n", __LINE__); return SWITCH_STATUS_FALSE;}
+       if (error) return SWITCH_STATUS_FALSE;
 
        slot = face->glyph;
 
@@ -918,7 +958,7 @@ end:
        return img;
 }
 
-SWITCH_DECLARE(void) switch_img_write_png(switch_image_t *img, char* file_name)
+SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char* file_name)
 {
        int width, height;
        png_byte color_type;
@@ -930,6 +970,7 @@ SWITCH_DECLARE(void) switch_img_write_png(switch_image_t *img, char* file_name)
        int y;
        png_byte *buffer = NULL;
        FILE *fp = NULL;
+       switch_status_t status = SWITCH_STATUS_FALSE;
 
        width = img->d_w;
        height = img->d_h;
@@ -1010,12 +1051,135 @@ SWITCH_DECLARE(void) switch_img_write_png(switch_image_t *img, char* file_name)
 
        png_write_end(png_ptr, NULL);
 
+       status = SWITCH_STATUS_SUCCESS;
+
 end:
 
        switch_safe_free(buffer);
        switch_safe_free(row_pointers);
        fclose(fp);
        png_destroy_write_struct(&png_ptr, &info_ptr);
+
+       return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, int height)
+{
+       switch_image_t *src, *tmp = NULL;
+       int new_w = 0, new_h = 0;
+       double img_aspect;
+
+       switch_assert(srcP);
+       switch_assert(width && height);
+
+       img_aspect = (double) src->d_w / src->d_h;
+
+       src = *srcP;
+
+       if (!src || (src->d_w <= width && src->d_h <= height)) {
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       new_w = src->d_w;
+       new_h = src->d_h;
+       
+       while(new_w > width || new_h > height) { 
+               if (new_w >= new_h) {
+                       double m = (double) width / new_w;
+                       new_w = width;
+                       new_h = (int) (new_h * m * img_aspect);
+               } else {
+                       double m = (double) height / new_h;
+                       new_h = height;
+                       new_w = (int) (new_w * m * img_aspect);
+               }
+       }
+
+       if (new_w && new_h) {
+               if (switch_img_scale(src, &tmp, new_w, new_h) == SWITCH_STATUS_SUCCESS) {
+                       switch_img_free(&src);
+                       *srcP = tmp;
+                       return SWITCH_STATUS_SUCCESS;
+               }
+       }
+
+       return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_img_scale(switch_image_t *src, switch_image_t **destP, int width, int height)
+{
+       switch_image_t *dest = NULL;
+       int ret = 0;
+
+       if (destP) {
+               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 (ret != 0) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scaling Error: ret: %d\n", ret);
+               return SWITCH_STATUS_FALSE;
+       }
+
+       *destP = dest;
+       
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(void) switch_img_find_position(switch_img_position_t pos, int sw, int sh, int iw, int ih, int *xP, int *yP)
+{
+       switch(pos) {
+       case POS_NONE:
+       case POS_LEFT_TOP:
+               *xP = 0;
+               *yP = 0;
+               break;
+       case POS_LEFT_MID:
+               *xP = 0;
+               *yP = (sh - ih) / 2;
+               break;
+       case POS_LEFT_BOT:
+               *xP = 0;
+               *yP = (sh - ih);
+               break;
+       case POS_CENTER_TOP:
+               *xP = (sw - iw) / 2;
+               *yP = 0;
+               break;
+       case POS_CENTER_MID:
+               *xP = (sw - iw) / 2;
+               *yP = (sh - ih) / 2;
+               break;
+       case POS_CENTER_BOT:
+               *xP = (sw - iw) / 2;
+               *yP = (sh - ih);
+               break;
+       case POS_RIGHT_TOP:
+               *xP = (sw - iw);
+               *yP = 0;
+               break;
+       case POS_RIGHT_MID:
+               *xP = (sw - iw);
+               *yP = (sh - ih) / 2;
+               break;
+       case POS_RIGHT_BOT:     
+               *xP = (sw - iw);
+               *yP = (sh - ih);
+               break;
+       };
+
 }