From 34fd0e9ad8a39e78f4b20cf78f35bb367b87af5e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 28 Jul 2015 19:40:14 -0500 Subject: [PATCH] FS-7769 More features add var=val member lookup usable wherver member_id is valid in api commands add bgimg to layouts with api command or config for global setting fix bug with overlap layouts combined with odd sized layers improve switch_img_fit to take a modifier for fit, streach or both at once --- .../conference_layouts.conf.xml | 37 +++++++ libs/esl/perl/single_command.pl | 2 +- src/include/switch_core_video.h | 9 +- .../mod_conference/conference_api.c | 74 +++++++++++++- .../mod_conference/conference_file.c | 1 + .../mod_conference/conference_member.c | 46 +++++++++ .../mod_conference/conference_video.c | 97 ++++++++++++++++--- .../mod_conference/mod_conference.h | 9 ++ .../mod_local_stream/mod_local_stream.c | 2 +- src/switch_core_media_bug.c | 4 +- src/switch_core_video.c | 49 +++++++++- src/switch_ivr_async.c | 2 +- 12 files changed, 307 insertions(+), 25 deletions(-) diff --git a/conf/vanilla/autoload_configs/conference_layouts.conf.xml b/conf/vanilla/autoload_configs/conference_layouts.conf.xml index 444b63471b..0e082a2c22 100644 --- a/conf/vanilla/autoload_configs/conference_layouts.conf.xml +++ b/conf/vanilla/autoload_configs/conference_layouts.conf.xml @@ -12,6 +12,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/esl/perl/single_command.pl b/libs/esl/perl/single_command.pl index 40216723f5..aa0d67b57a 100644 --- a/libs/esl/perl/single_command.pl +++ b/libs/esl/perl/single_command.pl @@ -4,6 +4,6 @@ require ESL; my $command = shift; my $args = join(" ", @ARGV); -my $con = new ESL::ESLconnection("localhost", "8021", "ClueCon"); +my $con = new ESL::ESLconnection("127.0.0.1", "8021", "ClueCon"); my $e = $con->api($command, $args); print $e->getBody(); diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index a18a39da41..43a96e87ac 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -57,6 +57,12 @@ typedef enum { POS_NONE } switch_img_position_t; +typedef enum { + SWITCH_FIT_SIZE, + SWITCH_FIT_SCALE, + SWITCH_FIT_SIZE_AND_SCALE, + SWITCH_FIT_NONE +} switch_img_fit_t; typedef struct switch_yuv_color_s { uint8_t y; @@ -356,8 +362,9 @@ 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_status_t) switch_img_fit(switch_image_t **srcP, int width, int height, switch_img_fit_t fit); SWITCH_DECLARE(switch_img_position_t) parse_img_position(const char *name); +SWITCH_DECLARE(switch_img_fit_t) parse_img_fit(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); SWITCH_DECLARE(switch_status_t) switch_img_convert(switch_image_t *src, switch_convert_fmt_t fmt, void *dest, switch_size_t *size); SWITCH_DECLARE(switch_image_t *) switch_img_write_text_img(int w, int h, switch_bool_t full, const char *text); diff --git a/src/mod/applications/mod_conference/conference_api.c b/src/mod/applications/mod_conference/conference_api.c index d15e7a1b10..242b7b2844 100644 --- a/src/mod/applications/mod_conference/conference_api.c +++ b/src/mod/applications/mod_conference/conference_api.c @@ -101,6 +101,7 @@ api_command_t conference_api_sub_commands[] = { {"vid-layout", (void_fn_t) & conference_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", "|group []"}, {"vid-write-png", (void_fn_t) & conference_api_sub_write_png, CONF_API_SUB_ARGS_SPLIT, "vid-write-png", ""}, {"vid-fps", (void_fn_t) & conference_api_sub_vid_fps, CONF_API_SUB_ARGS_SPLIT, "vid-fps", ""}, + {"vid-bgimg", (void_fn_t) & conference_api_sub_canvas_bgimg, CONF_API_SUB_ARGS_SPLIT, "vid-bgimg", " | clear []"}, {"vid-bandwidth", (void_fn_t) & conference_api_sub_vid_bandwidth, CONF_API_SUB_ARGS_SPLIT, "vid-bandwidth", ""} }; @@ -1001,6 +1002,7 @@ switch_status_t conference_api_sub_volume_out(conference_member_t *member, switc switch_status_t conference_api_sub_vid_bandwidth(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) { int32_t i, video_write_bandwidth; + int x = 0; if (!conference_utils_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { stream->write_function(stream, "Bandwidth control not available.\n"); @@ -1013,13 +1015,60 @@ switch_status_t conference_api_sub_vid_bandwidth(conference_obj_t *conference, s } video_write_bandwidth = switch_parse_bandwidth_string(argv[2]); - for (i = 0; i >= conference->canvas_count; i++) { + for (i = 0; i <= conference->canvas_count; i++) { if (conference->canvases[i]) { + stream->write_function(stream, "Set Bandwidth for canvas %d to %d\n", i + 1, video_write_bandwidth); + x++; conference->canvases[i]->video_write_bandwidth = video_write_bandwidth; } } - stream->write_function(stream, "Set Bandwidth %d\n", video_write_bandwidth); + if (!x) { + stream->write_function(stream, "Bandwidth not set\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + + +switch_status_t conference_api_sub_canvas_bgimg(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) +{ + mcu_canvas_t *canvas = NULL; + int idx = 0; + char *file = NULL; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!argv[2]) { + stream->write_function(stream, "Invalid input\n"); + return SWITCH_STATUS_SUCCESS; + } + + file = argv[2]; + + if (argv[3]) { + idx = atoi(argv[3]) - 1; + } + + if (idx < 0 || idx > SUPER_CANVAS_ID || !conference->canvases[idx]) { + stream->write_function(stream, "Invalid canvas\n"); + return SWITCH_STATUS_SUCCESS; + } + + if ((canvas = conference->canvases[idx])) { + switch_mutex_lock(canvas->mutex); + if (!strcasecmp(file, "clear")) { + conference_video_reset_image(canvas->img, &canvas->bgcolor); + } else { + status = conference_video_set_canvas_bgimg(canvas, file); + } + switch_mutex_unlock(canvas->mutex); + } + + if (status == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "Set Bgimg %s\n", file); + } else { + stream->write_function(stream, "Error Setting Bgimg %s\n", file); + } return SWITCH_STATUS_SUCCESS; } @@ -2712,6 +2761,27 @@ switch_status_t conference_api_dispatch(conference_obj_t *conference, switch_str } else { stream->write_function(stream, "Non-Existant ID %u\n", id); } + } else if (strchr(argv[argn + 1], '=')) { + conference_api_member_cmd_t pfn = (conference_api_member_cmd_t) conference_api_sub_commands[i].pfnapicmd; + conference_member_t *member; + char *var, *val; + + var = strdup(argv[argn + 1]); + + if ((val = strchr(var, '='))) { + *val++ = '\0'; + } + + member = conference_member_get_by_var(conference, var, val); + + if (member != NULL) { + pfn(member, stream, argv[argn + 2]); + switch_thread_rwlock_unlock(member->rwlock); + } else { + stream->write_function(stream, "Non-Existant member\n"); + } + + switch_safe_free(var); } else { stream->write_function(stream, "%s %s", conference_api_sub_commands[i].pcommand, conference_api_sub_commands[i].psyntax); } diff --git a/src/mod/applications/mod_conference/conference_file.c b/src/mod/applications/mod_conference/conference_file.c index f9b9995197..e720d46d8e 100644 --- a/src/mod/applications/mod_conference/conference_file.c +++ b/src/mod/applications/mod_conference/conference_file.c @@ -112,6 +112,7 @@ uint32_t conference_file_stop(conference_obj_t *conference, file_stop_t stop) nptr->done++; count++; } + if (conference->async_fnode) { conference->async_fnode->done++; count++; diff --git a/src/mod/applications/mod_conference/conference_member.c b/src/mod/applications/mod_conference/conference_member.c index 5ccc1bf4ee..7862156ae6 100644 --- a/src/mod/applications/mod_conference/conference_member.c +++ b/src/mod/applications/mod_conference/conference_member.c @@ -392,6 +392,52 @@ conference_member_t *conference_member_get(conference_obj_t *conference, uint32_ return member; } + +/* traverse the conference member list for the specified member with var/val and return it's pointer */ +conference_member_t *conference_member_get_by_var(conference_obj_t *conference, const char *var, const char *val) +{ + conference_member_t *member = NULL; + + switch_assert(conference != NULL); + if (!(var && val)) { + return NULL; + } + + switch_mutex_lock(conference->member_mutex); + for (member = conference->members; member; member = member->next) { + const char *check_var; + + if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) { + continue; + } + + if ((check_var = switch_channel_get_variable_dup(member->channel, var , SWITCH_FALSE, -1)) && !strcmp(check_var, val)) { + break; + } + } + + if (member) { + if (!conference_utils_member_test_flag(member, MFLAG_INTREE) || + conference_utils_member_test_flag(member, MFLAG_KICKED) || + (member->session && !switch_channel_up(switch_core_session_get_channel(member->session)))) { + + /* member is kicked or hanging up so forget it */ + member = NULL; + } + } + + if (member) { + if (switch_thread_rwlock_tryrdlock(member->rwlock) != SWITCH_STATUS_SUCCESS) { + /* if you cant readlock it's way to late to do anything */ + member = NULL; + } + } + + switch_mutex_unlock(conference->member_mutex); + + return member; +} + void conference_member_check_agc_levels(conference_member_t *member) { int x = 0; diff --git a/src/mod/applications/mod_conference/conference_video.c b/src/mod/applications/mod_conference/conference_video.c index 11d0f0e335..a0e6edee84 100644 --- a/src/mod/applications/mod_conference/conference_video.c +++ b/src/mod/applications/mod_conference/conference_video.c @@ -110,7 +110,7 @@ void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int if ((x_layouts = switch_xml_child(x_layout_settings, "layouts"))) { for (x_layout = switch_xml_child(x_layouts, "layout"); x_layout; x_layout = x_layout->next) { video_layout_t *vlayout; - const char *val = NULL, *name = NULL; + const char *val = NULL, *name = NULL, *bgimg = NULL; switch_bool_t auto_3d = SWITCH_FALSE; int border = 0; @@ -125,6 +125,8 @@ void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int auto_3d = switch_true(switch_xml_attr(x_layout, "auto-3d-position")); + bgimg = switch_xml_attr(x_layout, "bgimg"); + if ((val = switch_xml_attr(x_layout, "border"))) { border = atoi(val); if (border < 0) border = 0; @@ -134,6 +136,10 @@ void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int vlayout = switch_core_alloc(conference->pool, sizeof(*vlayout)); vlayout->name = switch_core_strdup(conference->pool, name); + if (bgimg) { + vlayout->bgimg = switch_core_strdup(conference->pool, bgimg); + } + for (x_image = switch_xml_child(x_layout, "image"); x_image; x_image = x_image->next) { const char *res_id = NULL, *audio_position = NULL; int x = -1, y = -1, scale = -1, hscale = -1, floor = 0, flooronly = 0, fileonly = 0, overlap = 0, zoom = 0; @@ -379,34 +385,43 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, double screen_aspect = 0, img_aspect = 0; int x_pos = layer->x_pos; int y_pos = layer->y_pos; + int64_t img_addr = 0; img_w = layer->screen_w = IMG->d_w * layer->geometry.scale / VIDEO_LAYOUT_SCALE; img_h = layer->screen_h = IMG->d_h * layer->geometry.hscale / VIDEO_LAYOUT_SCALE; + screen_aspect = (double) layer->screen_w / layer->screen_h; img_aspect = (double) img->d_w / img->d_h; - if (layer->geometry.zoom) { + img_addr = (int64_t)img; + + if (layer->last_img_addr != img_addr && layer->geometry.zoom) { if (screen_aspect < img_aspect) { int cropsize = 0; double scale = 1; if (img->d_h != layer->screen_h) { scale = (double)layer->screen_h / img->d_h; } + cropsize = ((img->d_w )-((double)layer->screen_w/scale)) / 2; - switch_img_set_rect(img, cropsize, 0, layer->screen_w/scale, layer->screen_h/scale); - img_aspect = (double) img->d_w / img->d_h; + if (cropsize) { + switch_img_set_rect(img, cropsize, 0, layer->screen_w/scale, layer->screen_h/scale); + img_aspect = (double) img->d_w / img->d_h; + } + } else if (screen_aspect > img_aspect) { int cropsize = 0; double scale = 1; if (img->d_w != layer->screen_w) { scale = (double)layer->screen_w / img->d_w; } - cropsize = ((img->d_h )-((double)layer->screen_h/scale)) / 2; - - switch_img_set_rect(img, 0, cropsize, layer->screen_w/scale, layer->screen_h/scale); - img_aspect = (double) img->d_w / img->d_h; + cropsize = ceil(((img->d_h )-((double)layer->screen_h/scale)) / 2); + if (cropsize) { + switch_img_set_rect(img, 0, cropsize, layer->screen_w/scale, layer->screen_h/scale); + img_aspect = (double) img->d_w / img->d_h; + } } } @@ -415,10 +430,10 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, } if (screen_aspect > img_aspect) { - img_w = img_aspect * layer->screen_h; + img_w = ceil((double)img_aspect * layer->screen_h); x_pos += (layer->screen_w - img_w) / 2; } else if (screen_aspect < img_aspect) { - img_h = layer->screen_w / img_aspect; + img_h = ceil((double)layer->screen_w / img_aspect); y_pos += (layer->screen_h - img_h) / 2; } @@ -452,7 +467,9 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, img_w -= (layer->geometry.border * 2); img_h -= (layer->geometry.border * 2); - if (switch_img_scale(img, &layer->img, img_w, img_h) == SWITCH_STATUS_SUCCESS) { + switch_img_scale(img, &layer->img, img_w, img_h); + + if (layer->img) { if (layer->bugged && layer->member_id > -1) { conference_member_t *member; if ((member = conference_member_get(layer->canvas->conference, layer->member_id))) { @@ -470,19 +487,23 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, int ew = layer->screen_w - (layer->geometry.border * 2), eh = layer->screen_h - (layer->banner_img ? layer->banner_img->d_h : 0) - (layer->geometry.border * 2); int ex = 0, ey = 0; - switch_img_fit(&layer->logo_img, ew, eh); + switch_img_fit(&layer->logo_img, ew, eh, layer->logo_fit); + 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, layer->x_pos + ex + layer->geometry.border, layer->y_pos + ey + layer->geometry.border); if (layer->logo_text_img) { int tx = 0, ty = 0; - switch_img_fit(&layer->logo_text_img, (ew / 2) + 1, (eh / 2) + 1); + switch_img_fit(&layer->logo_text_img, (ew / 2) + 1, (eh / 2) + 1, SWITCH_FIT_SIZE); switch_img_find_position(POS_LEFT_BOT, layer->logo_img->d_w, layer->logo_img->d_h, layer->logo_text_img->d_w, layer->logo_text_img->d_h, &tx, &ty); switch_img_patch(IMG, layer->logo_text_img, layer->x_pos + ex + tx + layer->geometry.border, layer->y_pos + ey + ty + layer->geometry.border); } } + + layer->last_img_addr = img_addr; + } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "insert at %d,%d\n", 0, 0); switch_img_patch(IMG, img, 0, 0); @@ -631,6 +652,7 @@ void conference_video_layer_set_logo(conference_member_t *member, mcu_layer_t *l char *parsed = NULL; char *tmp; switch_img_position_t pos = POS_LEFT_TOP; + switch_img_fit_t fit = SWITCH_FIT_SIZE; switch_mutex_lock(layer->canvas->mutex); @@ -677,11 +699,14 @@ void conference_video_layer_set_logo(conference_member_t *member, mcu_layer_t *l path = tmp + 1; } - if (params) { if ((var = switch_event_get_header(params, "position"))) { pos = parse_img_position(var); } + + if ((var = switch_event_get_header(params, "fit"))) { + fit = parse_img_fit(var); + } } if (path && strcasecmp(path, "clear")) { @@ -690,6 +715,7 @@ void conference_video_layer_set_logo(conference_member_t *member, mcu_layer_t *l if (layer->logo_img) { layer->logo_pos = pos; + layer->logo_fit = fit; if (params) { if ((var = switch_event_get_header(params, "text"))) { @@ -1012,11 +1038,42 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva canvas->total_layers = vlayout->layers; canvas->send_keyframe = 1; + if (vlayout->bgimg) { + conference_video_set_canvas_bgimg(canvas, vlayout->bgimg); + } else if (canvas->bgimg) { + switch_img_free(&canvas->bgimg); + } + + if (conference->video_canvas_bgimg && !vlayout->bgimg) { + conference_video_set_canvas_bgimg(canvas, conference->video_canvas_bgimg); + } + + switch_mutex_unlock(canvas->mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Canvas position %d applied layout %s\n", canvas->canvas_id, vlayout->name); } +switch_status_t conference_video_set_canvas_bgimg(mcu_canvas_t *canvas, const char *img_path) +{ + + int x = 0, y = 0; + switch_img_free(&canvas->bgimg); + canvas->bgimg = switch_img_read_png(img_path, SWITCH_IMG_FMT_I420); + + if (!canvas->bgimg) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot open image for bgimg\n"); + return SWITCH_STATUS_FALSE; + } + + switch_img_fit(&canvas->bgimg, canvas->img->d_w, canvas->img->d_h, SWITCH_FIT_SIZE); + switch_img_find_position(POS_CENTER_MID, canvas->img->d_w, canvas->img->d_h, canvas->bgimg->d_w, canvas->bgimg->d_h, &x, &y); + switch_img_patch(canvas->img, canvas->bgimg, x, y); + + return SWITCH_STATUS_SUCCESS; +} + + switch_status_t conference_video_attach_canvas(conference_obj_t *conference, mcu_canvas_t *canvas, int super) { if (conference->canvas_count >= MAX_CANVASES + 1) { @@ -1098,6 +1155,7 @@ void conference_video_destroy_canvas(mcu_canvas_t **canvasP) { mcu_canvas_t *canvas = *canvasP; switch_img_free(&canvas->img); + switch_img_free(&canvas->bgimg); conference_video_flush_queue(canvas->video_queue); for (i = 0; i < MCU_MAX_LAYERS; i++) { @@ -1296,7 +1354,7 @@ void conference_video_canvas_set_fnode_layer(mcu_canvas_t *canvas, conference_fi for (i = 0; i < canvas->total_layers; i++) { xlayer = &canvas->layers[i]; - if (xlayer->fnode || xlayer->geometry.res_id || xlayer->member_id) { + if (xlayer->fnode || (xlayer->geometry.res_id && (!fnode->res_id || strcmp(xlayer->geometry.res_id, fnode->res_id))) || xlayer->member_id) { continue; } @@ -1529,11 +1587,18 @@ void conference_video_fnode_check(conference_file_node_t *fnode) { if (switch_core_file_has_video(&fnode->fh) && switch_core_file_read_video(&fnode->fh, NULL, SVR_CHECK) == SWITCH_STATUS_BREAK) { int full_screen = 0; + char *res_id = NULL; if (fnode->fh.params && fnode->conference->canvas_count == 1) { full_screen = switch_true(switch_event_get_header(fnode->fh.params, "full-screen")); } + if (fnode->fh.params) { + if ((res_id = switch_event_get_header(fnode->fh.params, "reservation_id"))) { + fnode->res_id = switch_core_strdup(fnode->pool, res_id); + } + } + if (full_screen) { canvas->play_file = 1; canvas->conference->playing_video_file = 1; @@ -2971,7 +3036,7 @@ void conference_video_write_frame(conference_obj_t *conference, conference_membe int x,y; switch_img_copy(vid_frame->img, &tmp_img); - switch_img_fit(&tmp_img, conference->canvases[0]->width, conference->canvases[0]->height); + switch_img_fit(&tmp_img, conference->canvases[0]->width, conference->canvases[0]->height, SWITCH_FIT_SIZE); frame_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->canvases[0]->width, conference->canvases[0]->height, 1); conference_video_reset_image(frame_img, &conference->canvases[0]->bgcolor); switch_img_find_position(POS_CENTER_MID, frame_img->d_w, frame_img->d_h, tmp_img->d_w, tmp_img->d_h, &x, &y); diff --git a/src/mod/applications/mod_conference/mod_conference.h b/src/mod/applications/mod_conference/mod_conference.h index d0e9356909..62c88dede3 100644 --- a/src/mod/applications/mod_conference/mod_conference.h +++ b/src/mod/applications/mod_conference/mod_conference.h @@ -379,6 +379,7 @@ typedef struct conference_file_node { int layer_id; int canvas_id; struct conference_obj *conference; + char *res_id; } conference_file_node_t; typedef enum { @@ -437,6 +438,7 @@ typedef struct mcu_layer_s { int avatar_patched; int refresh; int is_avatar; + int64_t last_img_addr; switch_img_position_t logo_pos; switch_image_t *img; switch_image_t *cur_img; @@ -446,12 +448,14 @@ typedef struct mcu_layer_s { switch_image_t *mute_img; switch_img_txt_handle_t *txthandle; conference_file_node_t *fnode; + switch_img_fit_t logo_fit; struct mcu_canvas_s *canvas; } mcu_layer_t; typedef struct video_layout_s { char *name; char *audio_position; + char *bgimg; mcu_layer_geometry_t images[MCU_MAX_LAYERS]; int layers; } video_layout_t; @@ -491,6 +495,7 @@ typedef struct mcu_canvas_s { switch_queue_t *video_queue; int32_t video_write_bandwidth; int recording; + switch_image_t *bgimg; } mcu_canvas_t; /* Record Node */ @@ -545,6 +550,7 @@ typedef struct conference_obj { char *video_layout_name; char *video_layout_group; char *video_canvas_bgcolor; + char *video_canvas_bgimg; char *video_border_color; char *video_super_canvas_bgcolor; char *video_letterbox_bgcolor; @@ -919,6 +925,7 @@ void conference_video_check_avatar(conference_member_t *member, switch_bool_t fo void conference_video_find_floor(conference_member_t *member, switch_bool_t entering); void conference_video_destroy_canvas(mcu_canvas_t **canvasP); void conference_video_fnode_check(conference_file_node_t *fnode); +switch_status_t conference_video_set_canvas_bgimg(mcu_canvas_t *canvas, const char *img_path); switch_status_t conference_al_parse_position(al_handle_t *al, const char *data); switch_status_t conference_video_thread_callback(switch_core_session_t *session, switch_frame_t *frame, void *user_data); void *SWITCH_THREAD_FUNC conference_video_muxing_write_thread_run(switch_thread_t *thread, void *obj); @@ -934,6 +941,7 @@ void conference_fnode_toggle_pause(conference_file_node_t *fnode, switch_stream_ conference_relationship_t *conference_member_add_relationship(conference_member_t *member, uint32_t id); conference_member_t *conference_member_get(conference_obj_t *conference, uint32_t id); +conference_member_t *conference_member_get_by_var(conference_obj_t *conference, const char *var, const char *val); switch_status_t conference_member_del_relationship(conference_member_t *member, uint32_t id); switch_status_t conference_member_add(conference_obj_t *conference, conference_member_t *member); @@ -1050,6 +1058,7 @@ switch_status_t conference_api_sub_get(conference_obj_t *conference, switch_stre switch_status_t conference_api_sub_vid_mute_img(conference_member_t *member, switch_stream_handle_t *stream, void *data); switch_status_t conference_api_sub_vid_logo_img(conference_member_t *member, switch_stream_handle_t *stream, void *data); switch_status_t conference_api_sub_vid_fps(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv); +switch_status_t conference_api_sub_canvas_bgimg(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv); switch_status_t conference_api_sub_write_png(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv); switch_status_t conference_api_sub_file_vol(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv); switch_status_t conference_api_sub_recording(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv); diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c index 9cbdbe2b9c..3b6bed2fdd 100644 --- a/src/mod/formats/mod_local_stream/mod_local_stream.c +++ b/src/mod/formats/mod_local_stream/mod_local_stream.c @@ -782,7 +782,7 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle switch_img_copy(src_img, &img); if (context->last_w && context->last_h) { - switch_img_fit(&img, context->last_w, context->last_h); + switch_img_fit(&img, context->last_w, context->last_h, SWITCH_FIT_SIZE); } frame->img = img; diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index 823bfeb8cb..28f461c3f1 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -471,8 +471,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_patch_spy_frame(switch_med switch_img_copy(img, &img_dup); img_tmp = switch_img_copy_rect(img_dup, w / 4, 0, w / 2, h); - switch_img_fit(&spy_tmp, w / 2, h); - switch_img_fit(&img_tmp, w / 2, h); + switch_img_fit(&spy_tmp, w / 2, h, SWITCH_FIT_SIZE); + switch_img_fit(&img_tmp, w / 2, h, SWITCH_FIT_SIZE); switch_color_set_rgb(&bgcolor, "#000000"); switch_img_fill(img, 0, 0, img->d_w, img->d_h, &bgcolor); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index e33291fde2..52fb1c8b99 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -86,6 +86,38 @@ SWITCH_DECLARE(switch_img_position_t) parse_img_position(const char *name) return r; } + +struct fit_el { + switch_img_fit_t fit; + const char *name; +}; + + +static struct fit_el IMG_FIT_TABLE[] = { + {SWITCH_FIT_SIZE, "fit-size"}, + {SWITCH_FIT_SCALE, "fit-scale"}, + {SWITCH_FIT_SIZE_AND_SCALE, "fit-size-and-scale"}, + {SWITCH_FIT_NONE, NULL} +}; + + +SWITCH_DECLARE(switch_img_fit_t) parse_img_fit(const char *name) +{ + switch_img_fit_t r = SWITCH_FIT_SIZE; + 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; +} + SWITCH_DECLARE(switch_bool_t) switch_core_has_video(void) { #ifdef SWITCH_HAVE_VPX @@ -1797,7 +1829,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_letterbox(switch_image_t *img, switch return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, int height) +SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, int height, switch_img_fit_t fit) { switch_image_t *src, *tmp = NULL; int new_w = 0, new_h = 0; @@ -1811,6 +1843,13 @@ SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, return SWITCH_STATUS_SUCCESS; } + if (fit == SWITCH_FIT_SCALE) { + switch_img_scale(src, &tmp, width, height); + switch_img_free(&src); + *srcP = tmp; + return SWITCH_STATUS_SUCCESS; + } + new_w = src->d_w; new_h = src->d_h; @@ -1843,6 +1882,14 @@ SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, if (switch_img_scale(src, &tmp, new_w, new_h) == SWITCH_STATUS_SUCCESS) { switch_img_free(&src); *srcP = tmp; + + if (fit == SWITCH_FIT_SIZE_AND_SCALE) { + src = *srcP; + switch_img_scale(src, &tmp, width, height); + switch_img_free(&src); + *srcP = tmp; + } + return SWITCH_STATUS_SUCCESS; } } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index c0e8510d1d..2be166bf4b 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -5086,7 +5086,7 @@ static switch_bool_t video_write_overlay_callback(switch_media_bug_t *bug, void if (frame->img && oht->img) { switch_img_copy(oht->img, &oimg); - switch_img_fit(&oimg, frame->img->d_w, frame->img->d_h); + switch_img_fit(&oimg, frame->img->d_w, frame->img->d_h, SWITCH_FIT_SIZE); switch_img_find_position(oht->pos, frame->img->d_w, frame->img->d_h, oimg->d_w, oimg->d_h, &x, &y); switch_img_overlay(frame->img, oimg, x, y, oht->alpha); //switch_img_patch(frame->img, oimg, x, y);