*/
SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color);
-SWITCH_DECLARE(void) switch_img_grey(switch_image_t *img, int x, int y, int w, int h);
+SWITCH_DECLARE(void) switch_img_gray(switch_image_t *img, int x, int y, int w, int h);
+SWITCH_DECLARE(void) switch_img_sepia(switch_image_t *img, int x, int y, int w, int h);
SWITCH_DECLARE(void) switch_img_fill_noalpha(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color);
{"unvmute", (void_fn_t) & conference_api_sub_unvmute, CONF_API_SUB_MEMBER_TARGET, "unvmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
{"deaf", (void_fn_t) & conference_api_sub_deaf, CONF_API_SUB_MEMBER_TARGET, "deaf", "<[member_id|all]|last|non_moderator>"},
{"undeaf", (void_fn_t) & conference_api_sub_undeaf, CONF_API_SUB_MEMBER_TARGET, "undeaf", "<[member_id|all]|last|non_moderator>"},
+ {"vid-filter", (void_fn_t) & conference_api_sub_video_filter, CONF_API_SUB_MEMBER_TARGET, "vid-filter", "<[member_id|all]|last|non_moderator> <string>"},
{"relate", (void_fn_t) & conference_api_sub_relate, CONF_API_SUB_ARGS_SPLIT, "relate", "<member_id>[,<member_id>] <other_member_id>[,<other_member_id>] [nospeak|nohear|clear]"},
{"lock", (void_fn_t) & conference_api_sub_lock, CONF_API_SUB_ARGS_SPLIT, "lock", ""},
{"unlock", (void_fn_t) & conference_api_sub_unlock, CONF_API_SUB_ARGS_SPLIT, "unlock", ""},
return SWITCH_STATUS_SUCCESS;
}
+switch_status_t conference_api_sub_video_filter(conference_member_t *member, switch_stream_handle_t *stream, void *data)
+{
+ char *filter_str = (char *) data;
+
+ conference_video_parse_filter_string(&member->video_filters, filter_str);
+
+ stream->write_function(stream, "+OK\n");
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
switch_status_t conference_api_sub_undeaf(conference_member_t *member, switch_stream_handle_t *stream, void *data)
{
switch_event_t *event;
{
switch_event_t *event;
conference_member_t *member = NULL;
+ mcu_canvas_t *canvas = NULL;
if (test_eflag(conference, EFLAG_PLAY_FILE_DONE) &&
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_al_close(node->al);
}
#endif
- if (conference->playing_video_file) {
- conference->canvases[node->canvas_id]->send_keyframe = 1;
- conference->playing_video_file = 0;
+
+ canvas = conference->canvases[node->canvas_id];
+
+ if (canvas->playing_video_file) {
+ canvas->send_keyframe = 1;
+ canvas->playing_video_file = 0;
}
- if (conference->overlay_video_file) {
- conference->canvases[node->canvas_id]->send_keyframe = 1;
- conference->overlay_video_file = 0;
+ if (canvas->overlay_video_file) {
+ canvas->send_keyframe = 1;
+ canvas->overlay_video_file = 0;
}
return switch_core_file_close(&node->fh);
const char *overlay_layer = switch_event_get_header(fnode->fh.params, "overlay_layer");
const char *overlay_member = switch_event_get_header(fnode->fh.params, "overlay_member");
const char *overlay_role = switch_event_get_header(fnode->fh.params, "overlay_role");
+ const char *file_filters = switch_event_get_header(fnode->fh.params, "file_filters");
int canvas_id = -1;
int layer_id = -1;
+
+ if (!zstr(file_filters)) {
+ conference_video_parse_filter_string(&fnode->filters, file_filters);
+ }
+
if (loopsstr) {
fnode->loops = atoi(loopsstr);
}
-
+
+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_mutex_lock(layer->overlay_mutex);
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) {
+ switch_img_gray(layer->img, 0, 0, layer->img->d_w, layer->img->d_h);
+ }
+
+ if (layer->overlay_filters & 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) {
+ 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) {
+ switch_img_sepia(layer->overlay_img, 0, 0, layer->overlay_img->d_w, layer->overlay_img->d_h);
+ }
+
switch_img_patch(layer->img, layer->overlay_img, 0, 0);
}
switch_mutex_unlock(layer->overlay_mutex);
fnode->layer_id = -1;
fnode->canvas_id = -1;
xlayer->fnode = NULL;
+
+ switch_mutex_lock(xlayer->overlay_mutex);
+ switch_img_free(&xlayer->overlay_img);
if (fnode->layer_lock < 0) {
conference_video_reset_layer(xlayer);
}
+ switch_mutex_unlock(xlayer->overlay_mutex);
}
switch_mutex_unlock(canvas->mutex);
}
switch_mutex_lock(layer->overlay_mutex);
switch_img_free(&layer->overlay_img);
layer->overlay_img = file_frame.img;
+ layer->overlay_filters = fnode->filters;
switch_mutex_unlock(layer->overlay_mutex);
} else {
switch_img_free(&layer->cur_img);
if (full_screen) {
canvas->play_file = 1;
if (fnode->fh.mm.fmt == SWITCH_IMG_FMT_ARGB) {
- canvas->conference->overlay_video_file = 1;
+ canvas->overlay_video_file = 1;
} else {
- canvas->conference->playing_video_file = 1;
+ canvas->playing_video_file = 1;
}
} else {
conference_video_canvas_set_fnode_layer(canvas, fnode, -1);
conference_video_check_flush(member, SWITCH_FALSE);
}
+ if (img) {
+ if (member->video_filters & FILTER_GRAY_FG) {
+ switch_img_gray(img, 0, 0, img->d_w, img->d_h);
+ }
+
+ if (member->video_filters & FILTER_SEPIA_FG) {
+ switch_img_sepia(img, 0, 0, img->d_w, img->d_h);
+ }
+ }
+
*imgP = img;
}
conference_video_attach_video_layer(imember, canvas, canvas->layout_floor_id);
}
- if (conference->playing_video_file) {
+ if (canvas->playing_video_file) {
switch_img_free(&img);
switch_core_session_rwunlock(imember->session);
continue;
}
switch_mutex_unlock(conference->file_mutex);
- if (!conference->playing_video_file) {
+ if (!canvas->playing_video_file) {
for (i = 0; i < canvas->total_layers; i++) {
mcu_layer_t *layer = &canvas->layers[i];
switch_mutex_lock(conference->file_mutex);
if (conference->fnode && switch_test_flag(&conference->fnode->fh, SWITCH_FILE_OPEN)) {
- if (conference->overlay_video_file) {
+ if (canvas->overlay_video_file) {
if (switch_core_file_read_video(&conference->fnode->fh, &write_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
if (canvas->play_file) {
switch_image_t *overlay_img = NULL;
switch_img_copy(canvas->img, &overlay_img);
+ if (conference->fnode->filters & 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) {
+ switch_img_sepia(overlay_img, 0, 0, overlay_img->d_w, overlay_img->d_h);
+ }
+
+ if (conference->fnode->filters & 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) {
+ switch_img_sepia(file_img, 0, 0, file_img->d_w, file_img->d_h);
+ }
+
write_img = overlay_img;
switch_img_patch(write_img, file_img, 0, 0);
switch_img_free(&file_img);
} else if (file_img) {
write_img = file_img;
}
- } else if (conference->playing_video_file) {
+ } else if (canvas->playing_video_file) {
if (switch_core_file_read_video(&conference->fnode->fh, &write_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
if (canvas->play_file) {
if (conference_utils_test_flag(member->conference, CFLAG_VIDEO_MUXING)) {
switch_image_t *img_copy = NULL;
- if (frame->img && (member->video_layer_id > -1 || member->canvas) &&
+ int canvas_id = member->canvas_id;
+
+ if (frame->img && (member->video_layer_id > -1) && canvas_id > -1 &&
conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) &&
switch_queue_size(member->video_queue) < member->conference->video_fps.fps * 2 &&
- !member->conference->playing_video_file) {
+ !member->conference->canvases[canvas_id]->playing_video_file) {
if (conference_utils_member_test_flag(member, MFLAG_FLIP_VIDEO) || conference_utils_member_test_flag(member, MFLAG_ROTATE_VIDEO)) {
if (conference_utils_member_test_flag(member, MFLAG_ROTATE_VIDEO)) {
#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;
int loops;
int new_fnode;
int layer_lock;
+ conference_file_filter_t filters;
} conference_file_node_t;
typedef enum {
switch_frame_geometry_t manual_geometry;
mcu_layer_cam_opts_t cam_opts;
switch_mutex_t *overlay_mutex;
+ conference_file_filter_t overlay_filters;
} mcu_layer_t;
typedef struct video_layout_s {
switch_image_t *bgimg;
switch_image_t *fgimg;
switch_thread_rwlock_t *video_rwlock;
+ int playing_video_file;
+ int overlay_video_file;
} mcu_canvas_t;
/* Record Node */
switch_hash_t *layout_hash;
switch_hash_t *layout_group_hash;
struct conference_fps video_fps;
- int playing_video_file;
- int overlay_video_file;
int recording_members;
uint32_t video_floor_packets;
video_layout_t *new_personal_vlayout;
uint32_t text_framesize;
mcu_layer_cam_opts_t cam_opts;
-
+ conference_file_filter_t video_filters;
};
typedef enum {
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);
switch_status_t conference_api_sub_unvmute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
switch_status_t conference_api_sub_deaf(conference_member_t *member, switch_stream_handle_t *stream, void *data);
switch_status_t conference_api_sub_undeaf(conference_member_t *member, switch_stream_handle_t *stream, void *data);
+switch_status_t conference_api_sub_video_filter(conference_member_t *member, switch_stream_handle_t *stream, void *data);
switch_status_t conference_api_sub_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data);
switch_status_t conference_api_sub_vid_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data);
switch_status_t conference_api_sub_clear_vid_floor(conference_obj_t *conference, switch_stream_handle_t *stream, void *data);
#endif
}
-SWITCH_DECLARE(void) switch_img_grey(switch_image_t *img, int x, int y, int w, int h)
+SWITCH_DECLARE(void) switch_img_sepia(switch_image_t *img, int x, int y, int w, int h)
+{
+#ifdef SWITCH_HAVE_YUV
+ if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
+
+ if (img->fmt == SWITCH_IMG_FMT_ARGB) {
+ ARGBSepia(img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED], x, y, w, h);
+ } else if (img->fmt == SWITCH_IMG_FMT_I420) {
+ int len, i, max_h;
+
+ max_h = MIN(y + h, img->d_h);
+ len = MIN(w, img->d_w - x);
+
+ if (x & 1) { x++; len--; }
+ if (y & 1) y++;
+ if (len <= 0) return;
+
+ if ((len & 1) && (x + len) < img->d_w - 1) len++;
+
+ len /= 2;
+
+ for (i = y; i < max_h; i += 2) {
+ memset(img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * (i / 2) + x / 2, 108, len);
+ memset(img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * (i / 2) + x / 2, 137, len);
+ }
+ }
+#endif
+}
+
+SWITCH_DECLARE(void) switch_img_gray(switch_image_t *img, int x, int y, int w, int h)
{
#ifdef SWITCH_HAVE_YUV
- int len, i, max_h;
if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
- if (img->fmt == SWITCH_IMG_FMT_I420) {
+ if (img->fmt == SWITCH_IMG_FMT_ARGB) {
+ ARGBGray(img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED], x, y, w, h);
+ } else if (img->fmt == SWITCH_IMG_FMT_I420) {
+ int len, i, max_h;
+
max_h = MIN(y + h, img->d_h);
len = MIN(w, img->d_w - x);
len /= 2;
for (i = y; i < max_h; i += 2) {
- memset(img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * (i / 2) + x / 2, 0, len);
- memset(img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * (i / 2) + x / 2, 0, len);
+ memset(img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * (i / 2) + x / 2, 128, len);
+ memset(img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * (i / 2) + x / 2, 128, len);
}
}
#endif