From 81ef7703bd7fd6641d272b72349756a2266474d2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 15 May 2015 15:28:45 -0500 Subject: [PATCH] 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: [] [] POSITIONS: left-top left-mid left-bot center-top center-mid center-bot right-top right-mid right-bot --- src/include/switch_ivr.h | 7 ++ src/include/switch_types.h | 8 +- .../applications/mod_dptools/mod_dptools.c | 39 +++++++ src/switch_core_media.c | 26 ++++- src/switch_ivr_async.c | 102 ++++++++++++++++++ 5 files changed, 177 insertions(+), 5 deletions(-) diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 155ba583fb..7bb00cb06b 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -41,6 +41,7 @@ #define SWITCH_IVR_H #include +#include #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 diff --git a/src/include/switch_types.h b/src/include/switch_types.h index df4e5a4198..2a597465a0 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -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; diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index a72a6b96af..18d8910c33 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -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 [] [' [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, "", SAF_NONE); + SWITCH_ADD_APP(app_interface, "video_write_overlay", "Video write overlay", "Video write overlay", video_write_overlay_session_function, " [] []", SAF_MEDIA_TAP); + SWITCH_ADD_APP(app_interface, "stop_record_session", "Stop Record Session", STOP_SESS_REC_DESC, stop_record_session_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "record_session", "Record Session", SESS_REC_DESC, record_session_function, " [+]", SAF_MEDIA_TAP); SWITCH_ADD_APP(app_interface, "record_session_mask", "Mask audio in recording", SESS_REC_MASK_DESC, record_session_mask_function, "", SAF_MEDIA_TAP); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 03c6278de7..4100f2837e 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -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); diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 2204d8a33b..da4c65314d 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -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