diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index 014dd95f36..6fb06f5ab3 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -46,6 +46,14 @@ SWITCH_BEGIN_EXTERN_C #define CHROMAKEY_MAX_MASK 25 +typedef enum { + SCV_FILTER_GRAY_FG = (1 << 0), + SCV_FILTER_GRAY_BG = (1 << 1), + SCV_FILTER_SEPIA_FG = (1 << 2), + SCV_FILTER_SEPIA_BG = (1 << 3) +} switch_core_video_filter_t; + + typedef enum { SWITCH_SHADE_NONE = 0, SWITCH_SHADE_RED, @@ -476,6 +484,8 @@ SWITCH_DECLARE(void) switch_chromakey_process(switch_chromakey_t *ck, switch_ima SWITCH_DECLARE(switch_image_t *) switch_chromakey_cache_image(switch_chromakey_t *ck); SWITCH_DECLARE(switch_shade_t) switch_chromakey_str2shade(switch_chromakey_t *ck, const char *shade_name); +SWITCH_DECLARE(void) switch_core_video_parse_filter_string(switch_core_video_filter_t *filters, const char *filter_str); + SWITCH_END_EXTERN_C #endif /* For Emacs: diff --git a/src/mod/applications/mod_conference/conference_api.c b/src/mod/applications/mod_conference/conference_api.c index cd283eb9d3..9b53a7f99d 100644 --- a/src/mod/applications/mod_conference/conference_api.c +++ b/src/mod/applications/mod_conference/conference_api.c @@ -551,7 +551,7 @@ switch_status_t conference_api_sub_video_filter(conference_member_t *member, swi { char *filter_str = (char *) data; - conference_video_parse_filter_string(&member->video_filters, filter_str); + switch_core_video_parse_filter_string(&member->video_filters, filter_str); stream->write_function(stream, "+OK\n"); diff --git a/src/mod/applications/mod_conference/conference_file.c b/src/mod/applications/mod_conference/conference_file.c index b9126d0f2c..5ed2851fd5 100644 --- a/src/mod/applications/mod_conference/conference_file.c +++ b/src/mod/applications/mod_conference/conference_file.c @@ -294,7 +294,7 @@ switch_status_t conference_file_play(conference_obj_t *conference, char *file, u if (!zstr(file_filters)) { - conference_video_parse_filter_string(&fnode->filters, file_filters); + switch_core_video_parse_filter_string(&fnode->filters, file_filters); } if (loopsstr) { diff --git a/src/mod/applications/mod_conference/conference_video.c b/src/mod/applications/mod_conference/conference_video.c index b8a8fdfb7a..9df71b3e6e 100644 --- a/src/mod/applications/mod_conference/conference_video.c +++ b/src/mod/applications/mod_conference/conference_video.c @@ -501,29 +501,6 @@ static void set_bounds(int *x, int *y, int img_w, int img_h, int crop_w, int cro } -void conference_video_parse_filter_string(conference_file_filter_t *filters, const char *filter_str) -{ - *filters = 0; - - if (!filter_str) return; - - if (switch_stristr("fg-gray", filter_str)) { - *filters |= FILTER_GRAY_FG; - } - - if (switch_stristr("bg-gray", filter_str)) { - *filters |= FILTER_GRAY_BG; - } - - if (switch_stristr("fg-sepia", filter_str)) { - *filters |= FILTER_SEPIA_FG; - } - - if (switch_stristr("bg-sepia", filter_str)) { - *filters |= FILTER_SEPIA_BG; - } -} - void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, switch_bool_t freeze) { switch_image_t *IMG, *img; @@ -893,19 +870,19 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, if (layer->overlay_img) { switch_img_fit(&layer->overlay_img, layer->img->d_w, layer->img->d_h, SWITCH_FIT_SCALE); - if (layer->overlay_filters & FILTER_GRAY_FG) { + if (layer->overlay_filters & SCV_FILTER_GRAY_FG) { switch_img_gray(layer->img, 0, 0, layer->img->d_w, layer->img->d_h); } - if (layer->overlay_filters & FILTER_SEPIA_FG) { + if (layer->overlay_filters & SCV_FILTER_SEPIA_FG) { switch_img_sepia(layer->img, 0, 0, layer->img->d_w, layer->img->d_h); } - if (layer->overlay_filters & FILTER_GRAY_BG) { + if (layer->overlay_filters & SCV_FILTER_GRAY_BG) { switch_img_gray(layer->overlay_img, 0, 0, layer->overlay_img->d_w, layer->overlay_img->d_h); } - if (layer->overlay_filters & FILTER_SEPIA_BG) { + if (layer->overlay_filters & SCV_FILTER_SEPIA_BG) { switch_img_sepia(layer->overlay_img, 0, 0, layer->overlay_img->d_w, layer->overlay_img->d_h); } @@ -2619,11 +2596,11 @@ void conference_video_pop_next_image(conference_member_t *member, switch_image_t } if (img) { - if (member->video_filters & FILTER_GRAY_FG) { + if (member->video_filters & SCV_FILTER_GRAY_FG) { switch_img_gray(img, 0, 0, img->d_w, img->d_h); } - if (member->video_filters & FILTER_SEPIA_FG) { + if (member->video_filters & SCV_FILTER_SEPIA_FG) { switch_img_sepia(img, 0, 0, img->d_w, img->d_h); } } @@ -3736,19 +3713,19 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr switch_image_t *overlay_img = NULL; switch_img_copy(canvas->img, &overlay_img); - if (conference->fnode->filters & FILTER_GRAY_BG) { + if (conference->fnode->filters & SCV_FILTER_GRAY_BG) { switch_img_gray(overlay_img, 0, 0, overlay_img->d_w, overlay_img->d_h); } - if (conference->fnode->filters & FILTER_SEPIA_BG) { + if (conference->fnode->filters & SCV_FILTER_SEPIA_BG) { switch_img_sepia(overlay_img, 0, 0, overlay_img->d_w, overlay_img->d_h); } - if (conference->fnode->filters & FILTER_GRAY_FG) { + if (conference->fnode->filters & SCV_FILTER_GRAY_FG) { switch_img_gray(file_img, 0, 0, file_img->d_w, file_img->d_h); } - if (conference->fnode->filters & FILTER_SEPIA_FG) { + if (conference->fnode->filters & SCV_FILTER_SEPIA_FG) { switch_img_sepia(file_img, 0, 0, file_img->d_w, file_img->d_h); } diff --git a/src/mod/applications/mod_conference/mod_conference.h b/src/mod/applications/mod_conference/mod_conference.h index b920e00bc4..8370232348 100644 --- a/src/mod/applications/mod_conference/mod_conference.h +++ b/src/mod/applications/mod_conference/mod_conference.h @@ -369,13 +369,6 @@ typedef struct al_handle_s { #endif struct conference_obj; -typedef enum { - FILTER_GRAY_FG = (1 << 0), - FILTER_GRAY_BG = (1 << 1), - FILTER_SEPIA_FG = (1 << 2), - FILTER_SEPIA_BG = (1 << 3) -} conference_file_filter_t; - typedef struct conference_file_node { switch_file_handle_t fh; switch_speech_handle_t *sh; @@ -397,7 +390,7 @@ typedef struct conference_file_node { int loops; int new_fnode; int layer_lock; - conference_file_filter_t filters; + switch_core_video_filter_t filters; } conference_file_node_t; typedef enum { @@ -504,7 +497,7 @@ typedef struct mcu_layer_s { switch_frame_geometry_t manual_geometry; mcu_layer_cam_opts_t cam_opts; switch_mutex_t *overlay_mutex; - conference_file_filter_t overlay_filters; + switch_core_video_filter_t overlay_filters; } mcu_layer_t; typedef struct video_layout_s { @@ -882,7 +875,7 @@ struct conference_member { uint32_t text_framesize; mcu_layer_cam_opts_t cam_opts; - conference_file_filter_t video_filters; + switch_core_video_filter_t video_filters; }; typedef enum { @@ -1052,7 +1045,6 @@ void conference_video_check_used_layers(mcu_canvas_t *canvas); void conference_video_check_flush(conference_member_t *member, switch_bool_t force); void conference_video_set_canvas_letterbox_bgcolor(mcu_canvas_t *canvas, char *color); void conference_video_set_canvas_bgcolor(mcu_canvas_t *canvas, char *color); -void conference_video_parse_filter_string(conference_file_filter_t *filters, const char *filter_str); void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, switch_bool_t freeze); void conference_video_reset_layer(mcu_layer_t *layer); void conference_video_reset_layer_cam(mcu_layer_t *layer); diff --git a/src/mod/applications/mod_video_filter/mod_video_filter.c b/src/mod/applications/mod_video_filter/mod_video_filter.c index 7b617e082f..de220d58cc 100644 --- a/src/mod/applications/mod_video_filter/mod_video_filter.c +++ b/src/mod/applications/mod_video_filter/mod_video_filter.c @@ -42,7 +42,9 @@ SWITCH_MODULE_DEFINITION(mod_video_filter, mod_video_filter_load, mod_video_filt typedef struct chromakey_context_s { int threshold; switch_image_t *bgimg; + switch_image_t *bgimg_orig; switch_image_t *bgimg_scaled; + switch_image_t *fgimg_scaled; switch_image_t *imgfg; switch_image_t *imgbg; void *data; @@ -50,12 +52,14 @@ typedef struct chromakey_context_s { switch_size_t datalen; switch_size_t patch_datalen; switch_file_handle_t vfh; + switch_file_handle_t fg_vfh; switch_rgb_color_t bgcolor; switch_core_session_t *session; switch_mutex_t *command_mutex; int patch; int mod; switch_chromakey_t *ck; + switch_core_video_filter_t video_filters; } chromakey_context_t; static void init_context(chromakey_context_t *context) @@ -69,14 +73,22 @@ static void init_context(chromakey_context_t *context) static void uninit_context(chromakey_context_t *context) { switch_img_free(&context->bgimg); + switch_img_free(&context->bgimg_orig); switch_img_free(&context->bgimg_scaled); + switch_img_free(&context->fgimg_scaled); switch_img_free(&context->imgbg); switch_img_free(&context->imgfg); + if (switch_test_flag(&context->vfh, SWITCH_FILE_OPEN)) { switch_core_file_close(&context->vfh); memset(&context->vfh, 0, sizeof(context->vfh)); } + if (switch_test_flag(&context->fg_vfh, SWITCH_FILE_OPEN)) { + switch_core_file_close(&context->fg_vfh); + memset(&context->vfh, 0, sizeof(context->fg_vfh)); + } + switch_safe_free(context->data); switch_safe_free(context->patch_data); switch_chromakey_destroy(&context->ck); @@ -139,6 +151,10 @@ static void parse_params(chromakey_context_t *context, int start, int argc, char memset(&context->vfh, 0, sizeof(context->vfh)); } + if (context->bgimg_orig) { + switch_img_free(&context->bgimg_orig); + } + if (context->bgimg) { switch_img_free(&context->bgimg); } @@ -147,11 +163,15 @@ static void parse_params(chromakey_context_t *context, int start, int argc, char switch_img_free(&context->bgimg_scaled); } + if (context->fgimg_scaled) { + switch_img_free(&context->fgimg_scaled); + } + if (argv[i][0] == '#') { // bgcolor switch_color_set_rgb(&context->bgcolor, argv[i]); } else if (switch_stristr(".png", argv[i])) { - if (!(context->bgimg = switch_img_read_png(argv[i], SWITCH_IMG_FMT_ARGB))) { + if (!(context->bgimg_orig = switch_img_read_png(argv[i], SWITCH_IMG_FMT_ARGB))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening png\n"); } } else { @@ -174,6 +194,50 @@ static void parse_params(chromakey_context_t *context, int start, int argc, char while (n > 3 && argv[i]) { + + if (!strncasecmp(argv[i], "filter:", 7)) { + char *filter = argv[i] + 7; + switch_core_video_parse_filter_string(&context->video_filters, filter); + + if (context->bgimg_orig && context->video_filters) { + switch_img_free(&context->bgimg); + switch_img_copy(context->bgimg_orig, &context->bgimg); + + if (context->video_filters & SCV_FILTER_SEPIA_BG) { + switch_img_sepia(context->bgimg, 0, 0, context->bgimg->d_w, context->bgimg->d_h); + } + + if (context->video_filters & SCV_FILTER_GRAY_BG) { + switch_img_sepia(context->bgimg, 0, 0, context->bgimg->d_w, context->bgimg->d_h); + } + } + } + + + if (!strncasecmp(argv[i], "fgvid:", 6)) { + char *file = argv[i] + 6; + + if (switch_test_flag(&context->fg_vfh, SWITCH_FILE_OPEN)) { + switch_core_file_close(&context->fg_vfh); + memset(&context->fg_vfh, 0, sizeof(context->fg_vfh)); + } + + if (!zstr(file)) { + if (switch_core_file_open(&context->fg_vfh, file, 1, 8000, + SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT | SWITCH_FILE_FLAG_VIDEO, + switch_core_session_get_pool(context->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening video file\n"); + } else { + switch_vid_params_t vp = { 0 }; + + switch_core_media_get_vid_params(context->session, &vp); + context->fg_vfh.mm.scale_w = vp.width; + context->fg_vfh.mm.scale_h = vp.height; + context->fg_vfh.mm.fps = vp.fps; + } + } + } + if (!strncasecmp(argv[i], "fg:", 3)) { switch_img_free(&context->imgfg); if (!zstr(argv[i]+3)) { @@ -197,6 +261,10 @@ static void parse_params(chromakey_context_t *context, int start, int argc, char i++; } + if (context->bgimg_orig && !context->bgimg) { + switch_img_copy(context->bgimg_orig, &context->bgimg); + } + switch_core_session_request_video_refresh(context->session); context->mod++; @@ -257,6 +325,14 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi switch_assert(img); switch_chromakey_process(context->ck, img); + if (context->video_filters & SCV_FILTER_GRAY_FG) { + switch_img_gray(img, 0, 0, img->d_w, img->d_h); + } + + if (context->video_filters & SCV_FILTER_SEPIA_FG) { + switch_img_sepia(img, 0, 0, img->d_w, img->d_h); + } + if (context->bgimg) { switch_image_t *tmp = NULL; @@ -304,6 +380,15 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi if (file_frame.img) { switch_img_free(&context->bgimg_scaled); use_img = context->bgimg_scaled = file_frame.img; + + if (context->video_filters & SCV_FILTER_SEPIA_BG) { + switch_img_sepia(use_img, 0, 0, use_img->d_w, use_img->d_h); + } + + if (context->video_filters & SCV_FILTER_GRAY_BG) { + switch_img_sepia(use_img, 0, 0, use_img->d_w, use_img->d_h); + } + } else { use_img = context->bgimg_scaled; } @@ -371,6 +456,49 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi switch_img_patch(img, context->imgfg, x, y); } + if (switch_test_flag(&context->fg_vfh, SWITCH_FILE_OPEN)) { + switch_frame_t file_frame = { 0 }; + switch_status_t status; + switch_image_t *use_img = NULL; + + context->fg_vfh.mm.scale_w = frame->img->d_w; + context->fg_vfh.mm.scale_h = frame->img->d_h; + + status = switch_core_file_read_video(&context->fg_vfh, &file_frame, SVR_FLUSH); + switch_core_file_command(&context->fg_vfh, SCFC_FLUSH_AUDIO); + + + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { + int close = 1; + + if (context->fg_vfh.params) { + const char *loopstr = switch_event_get_header(context->fg_vfh.params, "loop"); + if (switch_true(loopstr)) { + uint32_t pos = 0; + switch_core_file_seek(&context->fg_vfh, &pos, 0, SEEK_SET); + close = 0; + } + } + + if (close) { + switch_core_file_close(&context->fg_vfh); + } + } + + if (file_frame.img) { + switch_img_free(&context->fgimg_scaled); + use_img = context->fgimg_scaled = file_frame.img; + } else { + use_img = context->fgimg_scaled; + } + + if (use_img) { + switch_img_patch(img, use_img, 0, 0); + } + + } + + switch_img_from_raw(frame->img, patch_data, SWITCH_IMG_FMT_ARGB, frame->img->d_w, frame->img->d_h); switch_img_free(&img); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index f1fbfd957a..3d1e78da74 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -3301,6 +3301,32 @@ SWITCH_DECLARE(switch_status_t) switch_ARGBToARGB(const uint8_t* src_frame, int } +SWITCH_DECLARE(void) switch_core_video_parse_filter_string(switch_core_video_filter_t *filters, const char *filter_str) +{ + *filters = 0; + + if (!filter_str) return; + + if (switch_stristr("fg-gray", filter_str)) { + *filters |= SCV_FILTER_GRAY_FG; + } + + if (switch_stristr("bg-gray", filter_str)) { + *filters |= SCV_FILTER_GRAY_BG; + } + + if (switch_stristr("fg-sepia", filter_str)) { + *filters |= SCV_FILTER_SEPIA_FG; + } + + if (switch_stristr("bg-sepia", filter_str)) { + *filters |= SCV_FILTER_SEPIA_BG; + } +} + + + + /* For Emacs: * Local Variables: * mode:c