提交 c797e948 authored 作者: Bradley Jokinen's avatar Bradley Jokinen

FS-7824 Add functionality for capturing screenshots from both legs to uuid_write_png

With this patch, uuid_write_png is able to capture screenshots from both
legs of a bridged video call. It still expects a uuid and filename for
the first two arguments. If given a third argument, it must be concat
or split. If concat is specified, screenshots from both ends are taken
and written side by side to the given filename. If one image is shorter
than the other then it is padded with black and vertically centered. If
the third argument is split then the two screenshots are written to
separate files. In this case, a second filename is expected as a fourth
argument.
上级 a54e04df
...@@ -204,11 +204,19 @@ static switch_status_t png_file_read_video(switch_file_handle_t *handle, switch_ ...@@ -204,11 +204,19 @@ static switch_status_t png_file_read_video(switch_file_handle_t *handle, switch_
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
typedef struct {
switch_image_t *read_img;
switch_image_t *write_img;
char *path;
char *other_path;
switch_bool_t both_legs;
} png_write_data;
static switch_bool_t write_png_bug_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) static switch_bool_t write_png_bug_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{ {
switch_core_session_t *session = switch_core_media_bug_get_session(bug); switch_core_session_t *session = switch_core_media_bug_get_session(bug);
switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_t *channel = switch_core_session_get_channel(session);
char *path = (char *) user_data; png_write_data *data = (png_write_data *) user_data;
switch (type) { switch (type) {
case SWITCH_ABC_TYPE_INIT: case SWITCH_ABC_TYPE_INIT:
...@@ -225,25 +233,69 @@ static switch_bool_t write_png_bug_callback(switch_media_bug_t *bug, void *user_ ...@@ -225,25 +233,69 @@ static switch_bool_t write_png_bug_callback(switch_media_bug_t *bug, void *user_
case SWITCH_ABC_TYPE_READ_VIDEO_PING: case SWITCH_ABC_TYPE_READ_VIDEO_PING:
{ {
switch_frame_t *frame = switch_core_media_bug_get_video_ping_frame(bug); switch_frame_t *frame = switch_core_media_bug_get_video_ping_frame(bug);
if (!frame || !frame->img) break; if (!frame || !frame->img) break;
switch_img_write_png(frame->img, path);
if (data->both_legs == SWITCH_FALSE) {
switch_img_write_png(frame->img, data->path);
return SWITCH_FALSE; return SWITCH_FALSE;
} }
if (!data->read_img) {
switch_img_copy(frame->img, &data->read_img);
}
}
break;
case SWITCH_ABC_TYPE_WRITE_VIDEO_PING:
{
switch_frame_t *frame = switch_core_media_bug_get_video_ping_frame(bug);
if (!frame || !frame->img) break;
if (!data->write_img) {
switch_img_copy(frame->img, &data->write_img);
}
}
break; break;
default: default:
break; break;
} }
if (data->both_legs == SWITCH_TRUE && data->read_img && data->write_img) {
if (data->other_path) {
switch_img_write_png(data->read_img, data->path);
switch_img_write_png(data->write_img, data->other_path);
} else {
int width, height;
switch_image_t *img;
switch_rgb_color_t bgcolor;
switch_color_set_rgb(&bgcolor, "#000000");
width = data->read_img->d_w + data->write_img->d_w;
height = data->read_img->d_h > data->write_img->d_h ? data->read_img->d_h : data->write_img->d_h;
img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, width, height, 1);
switch_img_fill(img, 0, 0, width, height, &bgcolor);
switch_img_patch(img, data->read_img, 0, (height - data->read_img->d_h) / 2);
switch_img_patch(img, data->write_img, data->read_img->d_w, (height - data->write_img->d_h) / 2);
switch_img_write_png(img, data->path);
switch_img_free(&img);
}
switch_img_free(&data->read_img);
switch_img_free(&data->write_img);
return SWITCH_FALSE;
}
return SWITCH_TRUE; return SWITCH_TRUE;
} }
SWITCH_STANDARD_API(uuid_write_png_function) SWITCH_STANDARD_API(uuid_write_png_function)
{ {
int argc = 0; int argc = 0;
char *argv[2] = { 0 }; char *argv[4] = { 0 };
char *mydata = NULL; char *mydata = NULL;
char *uuid; char *uuid;
char *path; png_write_data *bug_data;
switch_media_bug_t *bug; switch_media_bug_t *bug;
switch_media_bug_flag_t flags = SMBF_READ_VIDEO_PING; switch_media_bug_flag_t flags = SMBF_READ_VIDEO_PING;
switch_core_session_t *session_; switch_core_session_t *session_;
...@@ -252,12 +304,13 @@ SWITCH_STANDARD_API(uuid_write_png_function) ...@@ -252,12 +304,13 @@ SWITCH_STANDARD_API(uuid_write_png_function)
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
} }
if (argc < 2) { if (argc < 2 || (argc > 2 && strcasecmp(argv[2], "concat") && strcasecmp(argv[2], "split"))) {
stream->write_function(stream, "-USAGE: <uuid> <path> \n"); stream->write_function(stream, "-USAGE: <uuid> <path> [concat | split <other_path>]\n");
goto end; goto end;
} }
uuid = argv[0]; uuid = argv[0];
if (!(session_ = switch_core_session_locate(uuid))) { if (!(session_ = switch_core_session_locate(uuid))) {
stream->write_function(stream, "-ERR Could not locate session.\n"); stream->write_function(stream, "-ERR Could not locate session.\n");
goto end; goto end;
...@@ -269,16 +322,46 @@ SWITCH_STANDARD_API(uuid_write_png_function) ...@@ -269,16 +322,46 @@ SWITCH_STANDARD_API(uuid_write_png_function)
goto end; goto end;
} }
bug_data = switch_core_session_alloc(session_, sizeof(*bug_data));
if (argc > 2) {
switch_channel_t *channel_ = switch_core_session_get_channel(session_);
if (!switch_channel_test_flag_partner(channel_, CF_VIDEO)) {
stream->write_function(stream, "-ERR Session must be bridged and other leg must have video.\n");
switch_core_session_rwunlock(session_);
goto end;
}
bug_data->both_legs = SWITCH_TRUE;
flags |= SMBF_WRITE_VIDEO_PING;
if (!strcasecmp(argv[2], "split")) {
if (argc == 3) {
stream->write_function(stream, "-ERR Second filename expected but not given.\n");
switch_core_session_rwunlock(session_);
goto end;
}
if (!switch_is_file_path(argv[3])) {
const char *prefix = SWITCH_GLOBAL_dirs.images_dir;
bug_data->other_path = switch_core_session_sprintf(session_, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, argv[3]);
} else {
bug_data->other_path = switch_core_session_strdup(session_, argv[3]);
}
}
}
if (!switch_is_file_path(argv[1])) { if (!switch_is_file_path(argv[1])) {
const char *prefix = SWITCH_GLOBAL_dirs.images_dir; const char *prefix = SWITCH_GLOBAL_dirs.images_dir;
path = switch_core_session_sprintf(session_, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, argv[1]); bug_data->path = switch_core_session_sprintf(session_, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, argv[1]);
} else { } else {
path = switch_core_session_strdup(session_, argv[1]); bug_data->path = switch_core_session_strdup(session_, argv[1]);
} }
switch_thread_rwlock_rdlock(MODULE_INTERFACE->rwlock); switch_thread_rwlock_rdlock(MODULE_INTERFACE->rwlock);
if (switch_core_media_bug_add(session_, NULL, NULL, write_png_bug_callback, path, 0, flags, &bug) != SWITCH_STATUS_SUCCESS) { if (switch_core_media_bug_add(session_, NULL, NULL, write_png_bug_callback, bug_data, 0, flags, &bug) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "-ERR Could not attach bug.\n"); stream->write_function(stream, "-ERR Could not attach bug.\n");
switch_thread_rwlock_unlock(MODULE_INTERFACE->rwlock); switch_thread_rwlock_unlock(MODULE_INTERFACE->rwlock);
} else { } else {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论