mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-03-13 20:50:41 +00:00
FS-7500: add video_write_overlay and stop_video_write_overlay
Use it to add an image to the write stream to see a recording banner on video echoed back to you during recording. ARGS: <file> [<position>] [<opacity 0-255>] POSITIONS: left-top left-mid left-bot center-top center-mid center-bot right-top right-mid right-bot <extension name="example"> <condition field="destination_number" expression="^overlay$"> <action application="answer"/> <action application="video_write_overlay" data="/path/to/img.png"/> <action application="record" data="/data/file.mp4"/> <action application="stop_video_write_overlay"/> </condition> </extension>
This commit is contained in:
parent
e8f2366bdf
commit
81ef7703bd
@ -41,6 +41,7 @@
|
||||
#define SWITCH_IVR_H
|
||||
|
||||
#include <switch.h>
|
||||
#include <switch_core_video.h>
|
||||
#include "switch_json.h"
|
||||
|
||||
SWITCH_BEGIN_EXTERN_C struct switch_unicast_conninfo {
|
||||
@ -1003,6 +1004,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_kill_uuid(const char *uuid, switch_ca
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_blind_transfer_ack(switch_core_session_t *session, switch_bool_t success);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_mask(switch_core_session_t *session, const char *file, switch_bool_t on);
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_stop_video_write_overlay_session(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_video_write_overlay_session(switch_core_session_t *session, const char *img_path,
|
||||
switch_img_position_t pos, uint8_t alpha);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
@ -489,6 +489,7 @@ typedef enum {
|
||||
SWITCH_ABC_TYPE_TAP_NATIVE_WRITE,
|
||||
SWITCH_ABC_TYPE_CLOSE,
|
||||
SWITCH_ABC_TYPE_READ_VIDEO_PING,
|
||||
SWITCH_ABC_TYPE_WRITE_VIDEO_PING,
|
||||
SWITCH_ABC_TYPE_STREAM_VIDEO_PING,
|
||||
SWITCH_ABC_TYPE_VIDEO_PATCH
|
||||
} switch_abc_type_t;
|
||||
@ -1736,9 +1737,10 @@ typedef enum {
|
||||
SMBF_ONE_ONLY = (1 << 15),
|
||||
SMBF_MASK = (1 << 16),
|
||||
SMBF_READ_VIDEO_PING = (1 << 17),
|
||||
SMBF_READ_VIDEO_STREAM = (1 << 18),
|
||||
SMBF_WRITE_VIDEO_STREAM = (1 << 19),
|
||||
SMBF_VIDEO_PATCH = (1 << 20)
|
||||
SMBF_WRITE_VIDEO_PING = (1 << 18),
|
||||
SMBF_READ_VIDEO_STREAM = (1 << 19),
|
||||
SMBF_WRITE_VIDEO_STREAM = (1 << 20),
|
||||
SMBF_VIDEO_PATCH = (1 << 21)
|
||||
} switch_media_bug_flag_enum_t;
|
||||
typedef uint32_t switch_media_bug_flag_t;
|
||||
|
||||
|
@ -3024,6 +3024,41 @@ SWITCH_STANDARD_APP(stop_record_session_function)
|
||||
switch_ivr_stop_record_session(session, data);
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_APP(video_write_overlay_session_function)
|
||||
{
|
||||
char *mydata;
|
||||
char *argv[3] = { 0 };
|
||||
int argc = 0;
|
||||
switch_img_position_t pos = POS_LEFT_BOT;
|
||||
uint8_t alpha = 255;
|
||||
|
||||
if (zstr(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mydata = switch_core_session_strdup(session, data);
|
||||
argc = switch_split(mydata, ' ', argv);
|
||||
|
||||
if (argc > 1) {
|
||||
pos = parse_img_position(argv[1]);
|
||||
}
|
||||
|
||||
if (argc > 2) {
|
||||
int x = atoi(argv[2]);
|
||||
if (x > 0 && x < 256) {
|
||||
alpha = (uint8_t) x;
|
||||
}
|
||||
}
|
||||
|
||||
switch_ivr_video_write_overlay_session(session, argv[0], pos, alpha);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(stop_video_write_overlay_session_function)
|
||||
{
|
||||
switch_ivr_stop_video_write_overlay_session(session);
|
||||
}
|
||||
|
||||
/********************************************************************************/
|
||||
/* Bridge Functions */
|
||||
/********************************************************************************/
|
||||
@ -6065,6 +6100,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SWITCH_ADD_APP(app_interface, "play_and_get_digits", "Play and get Digits", "Play and get Digits",
|
||||
play_and_get_digits_function,
|
||||
"\n\t<min> <max> <tries> <timeout> <terminators> <file> <invalid_file> <var_name> <regexp> [<digit_timeout>] ['<failure_ext> [failure_dp [failure_context]]']", SAF_NONE);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "stop_video_write_overlay", "Stop video write overlay", "Stop video write overlay", stop_video_write_overlay_session_function, "<path>", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "video_write_overlay", "Video write overlay", "Video write overlay", video_write_overlay_session_function, "<path> [<pos>] [<alpha>]", SAF_MEDIA_TAP);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "stop_record_session", "Stop Record Session", STOP_SESS_REC_DESC, stop_record_session_function, "<path>", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "record_session", "Record Session", SESS_REC_DESC, record_session_function, "<path> [+<timeout>]", SAF_MEDIA_TAP);
|
||||
SWITCH_ADD_APP(app_interface, "record_session_mask", "Mask audio in recording", SESS_REC_MASK_DESC, record_session_mask_function, "<path>", SAF_MEDIA_TAP);
|
||||
|
@ -10307,11 +10307,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
|
||||
img = dup_img;
|
||||
}
|
||||
|
||||
|
||||
if (session->bugs) {
|
||||
switch_media_bug_t *bp;
|
||||
//switch_bool_t ok = SWITCH_TRUE;
|
||||
switch_bool_t ok = SWITCH_TRUE;
|
||||
int prune = 0;
|
||||
|
||||
switch_thread_rwlock_rdlock(session->bug_rwlock);
|
||||
for (bp = session->bugs; bp; bp = bp->next) {
|
||||
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
|
||||
@ -10333,6 +10333,28 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
|
||||
switch_queue_push(bp->write_video_queue, dimg);
|
||||
|
||||
}
|
||||
|
||||
if (bp->ready && img && switch_test_flag(bp, SMBF_WRITE_VIDEO_PING)) {
|
||||
switch_frame_t bug_frame = { 0 };
|
||||
|
||||
bug_frame.img = img;
|
||||
bp->ping_frame = &bug_frame;
|
||||
|
||||
if (bp->callback) {
|
||||
if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE_VIDEO_PING) == SWITCH_FALSE
|
||||
|| (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) {
|
||||
ok = SWITCH_FALSE;
|
||||
}
|
||||
}
|
||||
bp->ping_frame = NULL;
|
||||
}
|
||||
|
||||
if (ok == SWITCH_FALSE) {
|
||||
switch_set_flag(bp, SMBF_PRUNE);
|
||||
prune++;
|
||||
}
|
||||
|
||||
|
||||
switch_thread_rwlock_unlock(session->bug_rwlock);
|
||||
if (prune) {
|
||||
switch_core_media_bug_prune(session);
|
||||
|
@ -3612,6 +3612,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_tone_detect_session(switch_core_sessi
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char *app;
|
||||
uint32_t flags;
|
||||
@ -4813,6 +4814,107 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_broadcast(const char *uuid, const cha
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
typedef struct oht_s {
|
||||
switch_image_t *img;
|
||||
switch_img_position_t pos;
|
||||
uint8_t alpha;
|
||||
} overly_helper_t;
|
||||
|
||||
static switch_bool_t video_write_overlay_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
||||
{
|
||||
overly_helper_t *oht = (overly_helper_t *) user_data;
|
||||
switch_core_session_t *session = switch_core_media_bug_get_session(bug);
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
switch (type) {
|
||||
case SWITCH_ABC_TYPE_INIT:
|
||||
{
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_CLOSE:
|
||||
{
|
||||
switch_img_free(&oht->img);
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_WRITE_VIDEO_PING:
|
||||
if (switch_channel_test_flag(channel, CF_VIDEO_DECODED_READ)) {
|
||||
switch_frame_t *frame = switch_core_media_bug_get_video_ping_frame(bug);
|
||||
int x = 0, y = 0;
|
||||
switch_image_t *oimg = NULL;
|
||||
|
||||
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_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);
|
||||
switch_img_free(&oimg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_stop_video_write_overlay_session(switch_core_session_t *session)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_media_bug_t *bug = switch_channel_get_private(channel, "_video_write_overlay_bug_");
|
||||
|
||||
if (bug) {
|
||||
switch_channel_set_private(channel, "_video_write_overlay_bug_", NULL);
|
||||
switch_core_media_bug_remove(session, &bug);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_video_write_overlay_session(switch_core_session_t *session, const char *img_path,
|
||||
switch_img_position_t pos, uint8_t alpha)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_status_t status;
|
||||
switch_media_bug_flag_t bflags = SMBF_WRITE_VIDEO_PING;
|
||||
switch_media_bug_t *bug;
|
||||
overly_helper_t *oht;
|
||||
switch_image_t *img;
|
||||
|
||||
bflags |= SMBF_NO_PAUSE;
|
||||
|
||||
if (switch_channel_get_private(channel, "_video_write_overlay_bug_")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Only one of this type of bug per channel\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!(img = switch_img_read_png(img_path, SWITCH_IMG_FMT_ARGB))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening file: %s\n", img_path);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
oht = switch_core_session_alloc(session, sizeof(*oht));
|
||||
oht->img = img;
|
||||
oht->pos = pos;
|
||||
oht->alpha = alpha;
|
||||
|
||||
if ((status = switch_core_media_bug_add(session, "video_write_overlay", NULL,
|
||||
video_write_overlay_callback, oht, 0, bflags, &bug)) != SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating bug, file: %s\n", img_path);
|
||||
switch_img_free(&oht->img);
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_channel_set_private(channel, "_video_write_overlay_bug_", bug);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
Loading…
x
Reference in New Issue
Block a user