FS-9742: [mod_conference,mod_cv] Refactor canvas zoom code #resolve

This commit is contained in:
Anthony Minessale 2016-11-30 18:17:47 -06:00
parent a4eddcafda
commit da6b9e001c
11 changed files with 868 additions and 109 deletions

View File

@ -22,6 +22,8 @@ install-maxdemo: all verto-max.js
install-video_demo: all
cp verto-min.js ../video_demo/js
cp verto-min.js ../video_demo-live_canvas/js
install-video_maxdemo: all verto-max.js
cp verto-max.js ../video_demo/js/verto-min.js
cp verto-max.js ../video_demo-live_canvas/js/verto-min.js

View File

@ -1247,6 +1247,14 @@
}
});
verto.subscribe(conf.params.laData.infoChannel, {
handler: function(v, e) {
if (typeof(conf.params.infoCallback) === "function") {
conf.params.infoCallback(v,e);
}
}
});
verto.subscribe(conf.params.laData.chatChannel, {
handler: function(v, e) {
if (typeof(conf.params.chatCallback) === "function") {
@ -1283,6 +1291,10 @@
if (conf.params.laData.chatChannel) {
conf.verto.unsubscribe(conf.params.laData.chatChannel);
}
if (conf.params.laData.infoChannel) {
conf.verto.unsubscribe(conf.params.laData.infoChannel);
}
};
function createMainModeratorMethods() {
@ -1684,6 +1696,14 @@
//$(".jsDataTable").width(confMan.params.hasVid ? "900px" : "800px");
verto.subscribe(confMan.params.laData.infoChannel, {
handler: function(v, e) {
if (typeof(confMan.params.infoCallback) === "function") {
confMan.params.infoCallback(v,e);
}
}
});
verto.subscribe(confMan.params.laData.chatChannel, {
handler: function(v, e) {
if (typeof(confMan.params.chatCallback) === "function") {

View File

@ -213,8 +213,9 @@ dt.fnClearTable();dt.fnAddData(genArray(obj));dt.fnAdjustColumnSizing();break;ca
if(args.redraw>-1){dt.fnClearTable();dt.fnAddData(genArray(obj));}else{dt.fnAddData(genRow(args.data));}
dt.fnAdjustColumnSizing();break;case"modify":if(!args.data){return;}
dt.fnUpdate(genRow(args.data),index);dt.fnAdjustColumnSizing();break;case"del":dt.fnDeleteRow(index);dt.fnAdjustColumnSizing();break;case"clear":dt.fnClearTable();break;case"reorder":dt.fnClearTable();dt.fnAddData(genArray(obj));break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;}
if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}};la.onChange(la,{action:"init"});};var CONFMAN_SERNO=1;$.verto.conf=function(verto,params){var conf=this;conf.params=$.extend({dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);conf.verto=verto;conf.serno=CONFMAN_SERNO++;createMainModeratorMethods();verto.subscribe(conf.params.laData.modChannel,{handler:function(v,e){if(conf.params.onBroadcast){conf.params.onBroadcast(verto,conf,e.data);}}});verto.subscribe(conf.params.laData.chatChannel,{handler:function(v,e){if(typeof(conf.params.chatCallback)==="function"){conf.params.chatCallback(v,e);}}});};$.verto.conf.prototype.modCommand=function(cmd,id,value){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.conf.prototype.destroy=function(){var conf=this;conf.destroyed=true;conf.params.onBroadcast(conf.verto,conf,'destroy');if(conf.params.laData.modChannel){conf.verto.unsubscribe(conf.params.laData.modChannel);}
if(conf.params.laData.chatChannel){conf.verto.unsubscribe(conf.params.laData.chatChannel);}};function createMainModeratorMethods(){$.verto.conf.prototype.listVideoLayouts=function(){this.modCommand("list-videoLayouts",null,null);};$.verto.conf.prototype.play=function(file){this.modCommand("play",null,file);};$.verto.conf.prototype.stop=function(){this.modCommand("stop",null,"all");};$.verto.conf.prototype.deaf=function(memberID){this.modCommand("deaf",parseInt(memberID));};$.verto.conf.prototype.undeaf=function(memberID){this.modCommand("undeaf",parseInt(memberID));};$.verto.conf.prototype.record=function(file){this.modCommand("recording",null,["start",file]);};$.verto.conf.prototype.stopRecord=function(){this.modCommand("recording",null,["stop","all"]);};$.verto.conf.prototype.snapshot=function(file){if(!this.params.hasVid){throw'Conference has no video';}
if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}};la.onChange(la,{action:"init"});};var CONFMAN_SERNO=1;$.verto.conf=function(verto,params){var conf=this;conf.params=$.extend({dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);conf.verto=verto;conf.serno=CONFMAN_SERNO++;createMainModeratorMethods();verto.subscribe(conf.params.laData.modChannel,{handler:function(v,e){if(conf.params.onBroadcast){conf.params.onBroadcast(verto,conf,e.data);}}});verto.subscribe(conf.params.laData.infoChannel,{handler:function(v,e){if(typeof(conf.params.infoCallback)==="function"){conf.params.infoCallback(v,e);}}});verto.subscribe(conf.params.laData.chatChannel,{handler:function(v,e){if(typeof(conf.params.chatCallback)==="function"){conf.params.chatCallback(v,e);}}});};$.verto.conf.prototype.modCommand=function(cmd,id,value){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.conf.prototype.destroy=function(){var conf=this;conf.destroyed=true;conf.params.onBroadcast(conf.verto,conf,'destroy');if(conf.params.laData.modChannel){conf.verto.unsubscribe(conf.params.laData.modChannel);}
if(conf.params.laData.chatChannel){conf.verto.unsubscribe(conf.params.laData.chatChannel);}
if(conf.params.laData.infoChannel){conf.verto.unsubscribe(conf.params.laData.infoChannel);}};function createMainModeratorMethods(){$.verto.conf.prototype.listVideoLayouts=function(){this.modCommand("list-videoLayouts",null,null);};$.verto.conf.prototype.play=function(file){this.modCommand("play",null,file);};$.verto.conf.prototype.stop=function(){this.modCommand("stop",null,"all");};$.verto.conf.prototype.deaf=function(memberID){this.modCommand("deaf",parseInt(memberID));};$.verto.conf.prototype.undeaf=function(memberID){this.modCommand("undeaf",parseInt(memberID));};$.verto.conf.prototype.record=function(file){this.modCommand("recording",null,["start",file]);};$.verto.conf.prototype.stopRecord=function(){this.modCommand("recording",null,["stop","all"]);};$.verto.conf.prototype.snapshot=function(file){if(!this.params.hasVid){throw'Conference has no video';}
this.modCommand("vid-write-png",null,file);};$.verto.conf.prototype.setVideoLayout=function(layout,canvasID){if(!this.params.hasVid){throw'Conference has no video';}
if(canvasID){this.modCommand("vid-layout",null,[layout,canvasID]);}else{this.modCommand("vid-layout",null,layout);}};$.verto.conf.prototype.kick=function(memberID){this.modCommand("kick",parseInt(memberID));};$.verto.conf.prototype.muteMic=function(memberID){this.modCommand("tmute",parseInt(memberID));};$.verto.conf.prototype.muteVideo=function(memberID){if(!this.params.hasVid){throw'Conference has no video';}
this.modCommand("tvmute",parseInt(memberID));};$.verto.conf.prototype.presenter=function(memberID){if(!this.params.hasVid){throw'Conference has no video';}
@ -230,7 +231,7 @@ html+="<br>"+"<button class='ctlbtn' id='"+layer_set_id+"'>Set Layer</button>"+"
jq.html(html);if(!jq.data("mouse")){$("#"+box_id).hide();}
jq.mouseover(function(e){jq.data({"mouse":true});$("#"+box_id).show();});jq.mouseout(function(e){jq.data({"mouse":false});$("#"+box_id).hide();});$("#"+transfer_id).click(function(){var xten=prompt("Enter Extension");if(xten){confMan.modCommand("transfer",x,xten);}});$("#"+kick_id).click(function(){confMan.modCommand("kick",x);});$("#"+layer_set_id).click(function(){var cid=prompt("Please enter layer ID","");if(cid){confMan.modCommand("vid-layer",x,cid);}});$("#"+layer_next_id).click(function(){confMan.modCommand("vid-layer",x,"next");});$("#"+layer_prev_id).click(function(){confMan.modCommand("vid-layer",x,"prev");});$("#"+canvas_in_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-canvas",x,cid);}});$("#"+canvas_out_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-watching-canvas",x,cid);}});$("#"+canvas_in_next_id).click(function(){confMan.modCommand("vid-canvas",x,"next");});$("#"+canvas_in_prev_id).click(function(){confMan.modCommand("vid-canvas",x,"prev");});$("#"+canvas_out_next_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"next");});$("#"+canvas_out_prev_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"prev");});$("#"+tmute_id).click(function(){confMan.modCommand("tmute",x);});if(confMan.params.hasVid){$("#"+tvmute_id).click(function(){confMan.modCommand("tvmute",x);});$("#"+tvpresenter_id).click(function(){confMan.modCommand("vid-res-id",x,"presenter");});$("#"+tvfloor_id).click(function(){confMan.modCommand("vid-floor",x,"force");});$("#"+vbanner_id).click(function(){var text=prompt("Please enter text","");if(text){confMan.modCommand("vid-banner",x,escape(text));}});}
$("#"+gainup_id).click(function(){confMan.modCommand("volume_in",x,"up");});$("#"+gaindn_id).click(function(){confMan.modCommand("volume_in",x,"down");});$("#"+volup_id).click(function(){confMan.modCommand("volume_out",x,"up");});$("#"+voldn_id).click(function(){confMan.modCommand("volume_out",x,"down");});return html;}
var atitle="";var awidth=0;verto.subscribe(confMan.params.laData.chatChannel,{handler:function(v,e){if(typeof(confMan.params.chatCallback)==="function"){confMan.params.chatCallback(v,e);}}});if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=600;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready<br><br>");}else{$(confMan.params.mainModID).html("");}
var atitle="";var awidth=0;verto.subscribe(confMan.params.laData.infoChannel,{handler:function(v,e){if(typeof(confMan.params.infoCallback)==="function"){confMan.params.infoCallback(v,e);}}});verto.subscribe(confMan.params.laData.chatChannel,{handler:function(v,e){if(typeof(confMan.params.chatCallback)==="function"){confMan.params.chatCallback(v,e);}}});if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=600;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready<br><br>");}else{$(confMan.params.mainModID).html("");}
verto.subscribe(confMan.params.laData.modChannel,{handler:function(v,e){if(confMan.params.onBroadcast){confMan.params.onBroadcast(verto,confMan,e.data);}
if(e.data["conf-command"]==="list-videoLayouts"){for(var j=0;j<confMan.canvasCount;j++){var vlselect_id="#confman_vl_select_"+j+"_"+confMan.serno;var vlayout_id="#confman_vid_layout_"+j+"_"+confMan.serno;var x=0;var options;$(vlselect_id).selectmenu({});$(vlselect_id).selectmenu("enable");$(vlselect_id).empty();$(vlselect_id).append(new Option("Choose a Layout","none"));if(e.data.responseData){var rdata=[];for(var i in e.data.responseData){rdata.push(e.data.responseData[i].name);}
options=rdata.sort(function(a,b){var ga=a.substring(0,6)=="group:"?true:false;var gb=b.substring(0,6)=="group:"?true:false;if((ga||gb)&&ga!=gb){return ga?-1:1;}

View File

@ -40,14 +40,15 @@
SWITCH_BEGIN_EXTERN_C
struct switch_frame_geometry {
typedef struct switch_frame_geometry {
uint32_t w;
uint32_t h;
uint32_t x;
uint32_t y;
uint32_t z;
uint32_t m;
};
uint32_t M;
uint32_t X;
} switch_frame_geometry_t;
/*! \brief An abstraction of a data frame */
struct switch_frame {

View File

@ -60,6 +60,7 @@ api_command_t conference_api_sub_commands[] = {
{"file_seek", (void_fn_t) & conference_api_sub_file_seek, CONF_API_SUB_ARGS_SPLIT, "file_seek", "[+-]<val> [<member_id>]"},
{"say", (void_fn_t) & conference_api_sub_say, CONF_API_SUB_ARGS_AS_ONE, "say", "<text>"},
{"saymember", (void_fn_t) & conference_api_sub_saymember, CONF_API_SUB_ARGS_AS_ONE, "saymember", "<member_id> <text>"},
{"cam", (void_fn_t) & conference_api_sub_cam, CONF_API_SUB_ARGS_SPLIT, "cam", ""},
{"stop", (void_fn_t) & conference_api_sub_stop, CONF_API_SUB_ARGS_SPLIT, "stop", "<[current|all|async|last]> [<member_id>]"},
{"dtmf", (void_fn_t) & conference_api_sub_dtmf, CONF_API_SUB_MEMBER_TARGET, "dtmf", "<[member_id|all|last|non_moderator]> <digits>"},
{"kick", (void_fn_t) & conference_api_sub_kick, CONF_API_SUB_MEMBER_TARGET, "kick", "<[member_id|all|last|non_moderator]> [<optional sound file>]"},
@ -2009,6 +2010,262 @@ switch_status_t conference_api_sub_saymember(conference_obj_t *conference, switc
return ret_status;
}
switch_status_t conference_api_sub_cam(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
int x;
int canvas_id = -1;
int layer_id = -1;
int ok = 0;
mcu_canvas_t *canvas = NULL;
mcu_layer_t *layer = NULL;
if (!conference->canvases[0]) {
stream->write_function(stream, "Conference is not in mixing mode\n");
return SWITCH_STATUS_SUCCESS;
}
if (argc > 4) {
canvas_id = atoi(argv[2]);
layer_id = atoi(argv[3]);
if (canvas_id > -1 && layer_id > -1 && canvas_id < conference->canvas_count) {
switch_mutex_lock(conference->canvas_mutex);
canvas = conference->canvases[canvas_id];
switch_mutex_lock(canvas->mutex);
if (layer_id < canvas->total_layers) {
layer = &canvas->layers[layer_id];
ok = 1;
for (x = 4; x < argc; x++) {
char *p = strchr(argv[x], '=');
int val = -1, isfalse = 0;
char *str_arg = NULL;
if (p) {
*p++ = '\0';
if (!p) p = "";
if (!strcasecmp(argv[x], "zoom") || !strcasecmp(argv[x], "pan")) {
str_arg = p;
if (switch_false(p)) {
isfalse = 1;
}
} else {
if (switch_is_number(p)) {
val = atoi(p);
} else if (switch_true(p)) {
val = 1;
} else {
val = 0;
isfalse = 1;
}
}
} else if (!strcasecmp(argv[x], "reset")) {
str_arg = "true";
}
if (val < 0 && !str_arg) {
stream->write_function(stream, "-ERR invalid val for option [%s]\n", argv[x]);
continue;
}
if (!strcasecmp(argv[x], "autozoom")) {
if ((layer->cam_opts.autozoom = val)) {
layer->cam_opts.manual_zoom = 0;
}
} else if (!strcasecmp(argv[x], "autopan")) {
if ((layer->cam_opts.autopan = val)) {
layer->cam_opts.manual_pan = 0;
}
} else if (!strcasecmp(argv[x], "zoom_factor")) {
if (val > 0 && val < 5) {
layer->cam_opts.zoom_factor = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-4\n", argv[x]);
}
} else if (!strcasecmp(argv[x], "snap_factor")) {
if (val > 0 && val < layer->screen_w / 2) {
layer->cam_opts.snap_factor = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-%d\n", argv[x], layer->screen_w / 2);
}
} else if (!strcasecmp(argv[x], "zoom_move_factor")) {
if (val > 0 && val < layer->screen_w / 2) {
layer->cam_opts.zoom_move_factor = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-4\n", argv[x], layer->screen_w / 2);
}
} else if (!strcasecmp(argv[x], "pan_speed")) {
if (val > 0 && val < 100) {
layer->cam_opts.pan_speed = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
}
} else if (!strcasecmp(argv[x], "pan_accel_speed")) {
if (val > 0 && val < 100) {
layer->cam_opts.pan_accel_speed = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
}
} else if (!strcasecmp(argv[x], "pan_accel_min")) {
if (val > 0 && val < 100) {
layer->cam_opts.pan_accel_min = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
}
} else if (!strcasecmp(argv[x], "zoom_speed")) {
if (val > 0 && val < 100) {
layer->cam_opts.zoom_speed = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
}
} else if (!strcasecmp(argv[x], "zoom_accel_speed")) {
if (val > 0 && val < 100) {
layer->cam_opts.zoom_accel_speed = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
}
} else if (!strcasecmp(argv[x], "zoom_accel_min")) {
if (val > 0 && val < 100) {
layer->cam_opts.zoom_accel_min = val;
} else {
stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
}
} else if (!strcasecmp(argv[x], "reset")) {
conference_video_reset_layer_cam(layer);
} else if (!strcasecmp(argv[x], "pan")) {
char *x_val = NULL, *y_val = NULL;
int x = -1, y = -1;
int on = 0;
if (isfalse) {
layer->pan_geometry.x = 0;
layer->pan_geometry.y = 0;
layer->cam_opts.manual_pan = 0;
} else {
if (str_arg) {
char *p = strchr(str_arg, ':');
if (p) {
*p++ = '\0';
if (*str_arg == 'x') {
x_val = p;
} else if (*str_arg == 'y') {
y_val = p;
}
}
}
if (!x_val && !y_val) {
stream->write_function(stream, "-ERR invalid val for pan\n");
}
if (x_val) x = atoi(x_val);
if (y_val) y = atoi(y_val);
if (x_val && strrchr(x_val, 'i')) {
int nx = (int)layer->pan_geometry.x + x;
if (nx < 0) nx = 0;
if (nx + layer->pan_geometry.w > layer->img->d_w) nx = layer->img->d_w - layer->pan_geometry.w;
layer->pan_geometry.x = nx;
on++;
} else if (x > -1) {
layer->pan_geometry.x = x;
on++;
}
if (y_val && strrchr(y_val, 'i')) {
int ny = (int)layer->pan_geometry.y + y;
if (ny < 0) ny = 0;
if (ny + layer->pan_geometry.h > layer->img->d_h) ny = layer->img->d_h - layer->pan_geometry.h;
layer->pan_geometry.y = ny;
on++;
} else if (y > -1) {
layer->pan_geometry.y = y;
on++;
}
if (on) {
layer->cam_opts.manual_pan = 1;
layer->cam_opts.autopan = 0;
stream->write_function(stream, "+OK PAN %d,%d\n", layer->pan_geometry.x, layer->pan_geometry.y);
}
}
} else if (!strcasecmp(argv[x], "zoom")) {
if (str_arg && !isfalse) {
char *array[4] = {0};
int iray[4] = {0};
int ac;
if ((ac = switch_split(str_arg, ':', array)) >= 3) {
int i;
for (i = 0; i < ac; i++) {
int tmp = atoi(array[i]);
if (tmp < 0) break;
iray[i] = tmp;
}
if (i == ac) {
layer->cam_opts.manual_zoom = 1;
layer->cam_opts.autozoom = 0;
layer->zoom_geometry.x = iray[0];
layer->zoom_geometry.y = iray[1];
layer->zoom_geometry.w = iray[2];
if (iray[3]) {
layer->zoom_geometry.h = iray[3];
} else {
layer->zoom_geometry.h = iray[2];
}
layer->crop_x = iray[0];
layer->crop_y = iray[1];
layer->crop_w = iray[2];
layer->crop_h = iray[2];
layer->pan_geometry = layer->zoom_geometry;
} else {
ok = 0;
}
}
} else {
layer->zoom_geometry.x = 0;
layer->zoom_geometry.y = 0;
layer->zoom_geometry.w = 0;
layer->zoom_geometry.h = 0;
layer->cam_opts.manual_zoom = 0;
}
} else {
stream->write_function(stream, "-ERR invalid option [%s]\n", argv[x]);
}
}
}
switch_mutex_unlock(canvas->mutex);
switch_mutex_unlock(conference->canvas_mutex);
}
}
if (ok) {
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR invalid args\n");
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t conference_api_sub_stop(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
uint8_t current = 0, all = 0, async = 0;

View File

@ -237,14 +237,22 @@ void conference_event_mod_channel_handler(const char *event_channel, cJSON *json
const void *vvar;
cJSON *array = cJSON_CreateArray();
conference_obj_t *conference = NULL;
int i;
if ((conference = conference_find(conference_name, NULL))) {
switch_mutex_lock(conference_globals.setup_mutex);
for (i = 0; i <= conference->canvas_count; i++) {
if (conference->canvases[i]) {
conference_event_adv_layout(conference, conference->canvases[i], conference->canvases[i]->vlayout);
}
}
if (conference->layout_hash) {
for (hi = switch_core_hash_first(conference->layout_hash); hi; hi = switch_core_hash_next(&hi)) {
video_layout_t *vlayout;
cJSON *obj = cJSON_CreateObject();
cJSON *resarray = cJSON_CreateArray();
int i;
switch_core_hash_this(hi, &vvar, NULL, &val);
vlayout = (video_layout_t *)val;
@ -292,6 +300,83 @@ void conference_event_mod_channel_handler(const char *event_channel, cJSON *json
switch_thread_rwlock_unlock(conference->rwlock);
}
addobj = array;
} else if (!strcasecmp(action, "click-layer")) {
} else if (!strcasecmp(action, "shift-click-layer")) {
} else if (!strcasecmp(action, "reset-layer") || !strcasecmp(action, "layer-pan-x") || !strcasecmp(action, "layer-pan-y")) {
cJSON *v;
int layer_id = 0, canvas_id = 0, metric = 0, absolute = 0;
const char *i = "i", *xy = "";
if ((v = cJSON_GetObjectItem(data, "layerID"))) {
layer_id = v->valueint;
}
if ((v = cJSON_GetObjectItem(data, "canvasID"))) {
canvas_id = v->valueint;
}
if ((v = cJSON_GetObjectItem(data, "metric"))) {
metric = v->valueint;
}
if ((v = cJSON_GetObjectItem(data, "absolute"))) {
if ((absolute = v->valueint)) {
i = "";
}
}
if (canvas_id > -1 && layer_id > -1) {
if (!strcasecmp(action, "layer-pan-x")) {
xy = "x";
} else if (!strcasecmp(action, "layer-pan-y")) {
xy = "y";
}
if (!strcasecmp(action, "reset-layer")) {
exec = switch_mprintf("%s cam %d %d reset", conference_name, canvas_id, layer_id);
} else {
exec = switch_mprintf("%s cam %d %d pan=%s:%d%s", conference_name, canvas_id, layer_id, xy, metric, i);
}
}
} else if (!strcasecmp(action, "zoom-layer")) {
cJSON *v;
int layer_id = -1, canvas_id = -1, x = -1, y = -1, w = -1, h = -1;
if ((v = cJSON_GetObjectItem(data, "layerID"))) {
layer_id = v->valueint;
}
if ((v = cJSON_GetObjectItem(data, "canvasID"))) {
canvas_id = v->valueint;
}
if ((v = cJSON_GetObjectItem(data, "dimensions"))) {
cJSON *d;
if ((d = cJSON_GetObjectItem(v, "w"))) {
w = d->valueint;
}
if ((d = cJSON_GetObjectItem(v, "h"))) {
h = d->valueint;
}
if ((d = cJSON_GetObjectItem(v, "x"))) {
x = d->valueint;
}
if ((d = cJSON_GetObjectItem(v, "y"))) {
y = d->valueint;
}
}
if (canvas_id > -1 && layer_id > -1 && x > -1 && y > -1 && w > -1 && h > -1) {
exec = switch_mprintf("%s cam %d %d zoom=%d:%d:%d:%d snap_factor=1 zoom_factor=1", conference_name, canvas_id, layer_id, x, y, w, h);
}
}
if (exec) {
@ -486,6 +571,59 @@ void conference_event_la_command_handler(switch_live_array_t *la, const char *cm
{
}
void conference_event_adv_layout(conference_obj_t *conference, mcu_canvas_t *canvas, video_layout_t *vlayout)
{
cJSON *msg, *data, *obj;
int i = 0;
msg = cJSON_CreateObject();
data = json_add_child_obj(msg, "eventData", NULL);
cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(conference->info_event_channel));
cJSON_AddItemToObject(data, "contentType", cJSON_CreateString("layout-info"));
switch_thread_rwlock_rdlock(canvas->video_rwlock);
switch_mutex_lock(canvas->mutex);
if ((obj = get_canvas_info(canvas))) {
cJSON *array = cJSON_CreateArray();
for (i = 0; i < vlayout->layers; i++) {
cJSON *layout = cJSON_CreateObject();
int scale = vlayout->images[i].scale;
int hscale = vlayout->images[i].hscale ? vlayout->images[i].hscale : scale;
cJSON_AddItemToObject(layout, "x", cJSON_CreateNumber(vlayout->images[i].x));
cJSON_AddItemToObject(layout, "y", cJSON_CreateNumber(vlayout->images[i].y));
cJSON_AddItemToObject(layout, "scale", cJSON_CreateNumber(vlayout->images[i].scale));
cJSON_AddItemToObject(layout, "hscale", cJSON_CreateNumber(hscale));
cJSON_AddItemToObject(layout, "scale", cJSON_CreateNumber(scale));
cJSON_AddItemToObject(layout, "zoom", cJSON_CreateNumber(vlayout->images[i].zoom));
cJSON_AddItemToObject(layout, "border", cJSON_CreateNumber(vlayout->images[i].border));
cJSON_AddItemToObject(layout, "floor", cJSON_CreateNumber(vlayout->images[i].floor));
cJSON_AddItemToObject(layout, "overlap", cJSON_CreateNumber(vlayout->images[i].overlap));
cJSON_AddItemToObject(layout, "screenWidth", cJSON_CreateNumber((uint32_t)(canvas->img->d_w * scale / VIDEO_LAYOUT_SCALE)));
cJSON_AddItemToObject(layout, "screenHeight", cJSON_CreateNumber((uint32_t)(canvas->img->d_h * hscale / VIDEO_LAYOUT_SCALE)));
cJSON_AddItemToObject(layout, "xPOS", cJSON_CreateNumber((int)(canvas->img->d_w * vlayout->images[i].x / VIDEO_LAYOUT_SCALE)));
cJSON_AddItemToObject(layout, "yPOS", cJSON_CreateNumber((int)(canvas->img->d_h * vlayout->images[i].y / VIDEO_LAYOUT_SCALE)));
cJSON_AddItemToObject(layout, "resID", cJSON_CreateString(vlayout->images[i].res_id));
cJSON_AddItemToObject(layout, "audioPOS", cJSON_CreateString(vlayout->images[i].audio_position));
cJSON_AddItemToArray(array, layout);
}
cJSON_AddItemToObject(obj, "canvasLayouts", array);
cJSON_AddItemToObject(obj, "scale", cJSON_CreateNumber(VIDEO_LAYOUT_SCALE));
cJSON_AddItemToObject(data, "canvasInfo", obj);
}
switch_mutex_unlock(canvas->mutex);
switch_thread_rwlock_unlock(canvas->video_rwlock);
switch_event_channel_broadcast(conference->info_event_channel, &msg, "mod_conference", conference_globals.event_channel_id);
}
void conference_event_adv_la(conference_obj_t *conference, conference_member_t *member, switch_bool_t join)
{
@ -501,6 +639,7 @@ void conference_event_adv_la(conference_obj_t *conference, conference_member_t *
switch_event_t *variables;
switch_event_header_t *hp;
char idstr[128] = "";
int i;
snprintf(idstr, sizeof(idstr), "%d", member->id);
msg = cJSON_CreateObject();
@ -526,6 +665,7 @@ void conference_event_adv_la(conference_obj_t *conference, conference_member_t *
}
cJSON_AddItemToObject(data, "chatChannel", cJSON_CreateString(conference->chat_event_channel));
cJSON_AddItemToObject(data, "infoChannel", cJSON_CreateString(conference->info_event_channel));
switch_core_get_variables(&variables);
for (hp = variables->headers; hp; hp = hp->next) {
@ -538,12 +678,19 @@ void conference_event_adv_la(conference_obj_t *conference, conference_member_t *
}
switch_event_destroy(&variables);
switch_event_channel_broadcast(event_channel, &msg, "mod_conference", conference_globals.event_channel_id);
if (cookie) {
switch_event_channel_permission_modify(cookie, conference->la_event_channel, join);
switch_event_channel_permission_modify(cookie, conference->mod_event_channel, join);
switch_event_channel_permission_modify(cookie, conference->chat_event_channel, join);
switch_event_channel_permission_modify(cookie, conference->info_event_channel, join);
}
switch_event_channel_broadcast(event_channel, &msg, "mod_conference", conference_globals.event_channel_id);
for (i = 0; i <= conference->canvas_count; i++) {
if (conference->canvases[i]) {
conference_event_adv_layout(conference, conference->canvases[i], conference->canvases[i]->vlayout);
}
}
}
}

View File

@ -349,6 +349,45 @@ void conference_video_clear_layer(mcu_layer_t *layer)
}
static void set_default_cam_opts(mcu_layer_t *layer)
{
//layer->cam_opts.autozoom = 1;
//layer->cam_opts.autopan = 1;
layer->cam_opts.manual_pan = 0;
layer->cam_opts.manual_zoom = 0;
layer->cam_opts.zoom_factor = 3;
layer->cam_opts.snap_factor = 25;
layer->cam_opts.zoom_move_factor = 125;
layer->cam_opts.pan_speed = 3;
layer->cam_opts.pan_accel_speed = 10;
layer->cam_opts.pan_accel_min = 50;
layer->cam_opts.zoom_speed = 3;
layer->cam_opts.zoom_accel_speed = 10;
layer->cam_opts.zoom_accel_min = 50;
}
void conference_video_reset_layer_cam(mcu_layer_t *layer)
{
layer->crop_x = 0;
layer->crop_y = 0;
layer->crop_w = 0;
layer->crop_h = 0;
layer->last_w = 0;
layer->last_h = 0;
layer->img_count = 0;
memset(&layer->bug_frame, 0, sizeof(layer->bug_frame));
memset(&layer->auto_geometry, 0, sizeof(layer->auto_geometry));
memset(&layer->pan_geometry, 0, sizeof(layer->pan_geometry));
memset(&layer->zoom_geometry, 0, sizeof(layer->zoom_geometry));
memset(&layer->last_geometry, 0, sizeof(layer->last_geometry));
set_default_cam_opts(layer);
}
void conference_video_reset_layer(mcu_layer_t *layer)
{
switch_img_free(&layer->banner_img);
@ -361,7 +400,7 @@ void conference_video_reset_layer(mcu_layer_t *layer)
layer->is_avatar = 0;
layer->need_patch = 0;
memset(&layer->bug_frame, 0, sizeof(layer->bug_frame));
conference_video_reset_layer_cam(layer);
if (layer->geometry.overlap) {
layer->canvas->refresh = 1;
@ -375,36 +414,73 @@ void conference_video_reset_layer(mcu_layer_t *layer)
switch_img_free(&layer->cur_img);
}
static void set_pan(mcu_layer_t *layer, int crop_point, int max_width)
static void set_pan(int crop_point, int *target_point, int accel_speed, int accel_min, int speed)
{
if (layer->crop_point <= 0 || layer->crop_point > max_width) {
layer->crop_point = crop_point;
} else if (crop_point > layer->crop_point) {
if (crop_point - layer->crop_point > 25) {
layer->crop_point += 5;
if (crop_point > *target_point) {
if ((crop_point - *target_point) > accel_min) {
*target_point += accel_speed;
} else {
layer->crop_point++;
*target_point += speed;
}
if (crop_point < layer->crop_point) {
layer->crop_point = crop_point;
if (*target_point > crop_point) {
*target_point = crop_point;
}
} else if (crop_point < layer->crop_point) {
if (layer->crop_point - crop_point > 25) {
layer->crop_point -= 5;
} else if (crop_point < *target_point) {
if ((*target_point - crop_point) > accel_min) {
*target_point -= accel_speed;
} else {
layer->crop_point--;
*target_point -= speed;
}
if (crop_point > layer->crop_point) {
layer->crop_point = crop_point;
if (*target_point < crop_point) {
*target_point = crop_point;
}
}
}
static void set_bounds(int *x, int *y, int img_w, int img_h, int crop_w, int crop_h)
{
int crop_x = *x;
int crop_y = *y;
if (crop_x < 0) {
crop_x = 0;
}
if (crop_y < 0) {
crop_y = 0;
}
if (crop_x + crop_w > img_w) {
crop_x = img_w - crop_w;
}
if (crop_y + crop_h > img_h) {
crop_y = img_h - crop_h;
}
if (crop_x < 0) {
crop_x = 0;
}
if (crop_y < 0) {
crop_y = 0;
}
*x = crop_x;
*y = crop_y;
}
void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, switch_bool_t freeze)
{
switch_image_t *IMG, *img;
int img_changed = 0;
switch_mutex_lock(layer->canvas->mutex);
@ -417,6 +493,47 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
switch_mutex_unlock(layer->canvas->mutex);
return;
}
//printf("RAW %dx%d\n", img->d_w, img->d_h);
if (layer->img_count++ == 0 || layer->last_w != img->d_w || layer->last_h != img->d_h) {
double change_scale;
if (img->d_w && layer->last_w) {
if (img->d_w < layer->last_w) {
change_scale = layer->last_w / img->d_w;
} else {
change_scale = img->d_w / layer->last_w;
}
layer->crop_x = (int)(layer->crop_x * change_scale);
layer->crop_y = (int)(layer->crop_y * change_scale);
layer->crop_w = (int)(layer->crop_w * change_scale);
layer->crop_h = (int)(layer->crop_h * change_scale);
layer->zoom_geometry.x = (int)(layer->zoom_geometry.x * change_scale);
layer->zoom_geometry.y = (int)(layer->zoom_geometry.y * change_scale);
layer->zoom_geometry.w = (int)(layer->zoom_geometry.w * change_scale);
layer->zoom_geometry.h = (int)(layer->zoom_geometry.h * change_scale);
layer->pan_geometry.x = (int)(layer->pan_geometry.x * change_scale);
layer->pan_geometry.y = (int)(layer->pan_geometry.y * change_scale);
layer->pan_geometry.w = (int)(layer->pan_geometry.w * change_scale);
layer->pan_geometry.h = (int)(layer->pan_geometry.h * change_scale);
}
memset(&layer->auto_geometry, 0, sizeof(layer->auto_geometry));
//memset(&layer->zoom_geometry, 0, sizeof(layer->zoom_geometry));
//memset(&layer->pan_geometry, 0, sizeof(layer->pan_geometry));
memset(&layer->last_geometry, 0, sizeof(layer->last_geometry));
img_changed = 1;
}
layer->last_w = img->d_w;
layer->last_h = img->d_h;
if (layer->bugged) {
if (layer->member_id > -1 && layer->member && switch_thread_rwlock_tryrdlock(layer->member->rwlock) == SWITCH_STATUS_SUCCESS) {
@ -427,7 +544,39 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
switch_thread_rwlock_unlock(layer->member->rwlock);
}
if ((!layer->manual_geometry.w ||
(layer->last_geometry.x && abs(layer->manual_geometry.x - layer->last_geometry.x) > layer->cam_opts.zoom_move_factor) ||
(layer->last_geometry.y && abs(layer->manual_geometry.y - layer->last_geometry.y) > layer->cam_opts.zoom_move_factor) ||
(layer->last_geometry.w && abs(layer->manual_geometry.w - layer->last_geometry.w) > layer->cam_opts.zoom_move_factor / 2))) {
switch_event_t *event;
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "action", "movement-detection");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "member_id", "%d", layer->member_id);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "last_x", "%d", layer->manual_geometry.x);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "last_y", "%d", layer->manual_geometry.y);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "last_w", "%d", layer->manual_geometry.w);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "last_h", "%d", layer->manual_geometry.h);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "new_x", "%d", layer->bug_frame.geometry.x);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "new_y", "%d", layer->bug_frame.geometry.y);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "new_w", "%d", layer->bug_frame.geometry.w);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "new_h", "%d", layer->bug_frame.geometry.h);
switch_event_fire(&event);
}
layer->manual_geometry = layer->bug_frame.geometry;
}
layer->bugged = 0;
} else {
if (layer->bug_frame.geometry.w) {
memset(&layer->bug_frame, 0, sizeof(layer->bug_frame));
}
layer->cam_opts.autozoom = 0;
layer->cam_opts.autopan = 0;
}
if (layer->clear) {
@ -446,7 +595,7 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
int x_pos = layer->x_pos;
int y_pos = layer->y_pos;
switch_size_t img_addr = 0;
switch_frame_geometry_t *use_geometry = &layer->auto_geometry;
img_w = layer->screen_w = (uint32_t)(IMG->d_w * layer->geometry.scale / VIDEO_LAYOUT_SCALE);
img_h = layer->screen_h = (uint32_t)(IMG->d_h * layer->geometry.hscale / VIDEO_LAYOUT_SCALE);
@ -456,76 +605,184 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
img_addr = (switch_size_t)img;
if (layer->last_img_addr != img_addr && layer->geometry.zoom) {
uint32_t new_w = 0, new_h = 0;
int crop_point = 0;
if (layer->last_img_addr != img_addr && (layer->geometry.zoom || layer->cam_opts.autozoom ||
layer->cam_opts.autopan || layer->cam_opts.manual_pan || layer->cam_opts.manual_zoom)) {
double scale = 1;
int crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0, zoom_w = 0, zoom_h = 0;
int can_pan = 0;
int can_zoom = 0;
int did_zoom = 0;
if (screen_aspect < img_aspect) {
if (img->d_h != layer->screen_h) {
scale = (double)layer->screen_h / img->d_h;
}
new_w = (uint32_t)((double)layer->screen_w / scale);
new_h = (uint32_t)((double)layer->screen_h / scale);
if (layer->bug_frame.geometry.w) {
//new_w = layer->bug_frame.geometry.w * 2;
//new_h = new_w / screen_aspect;
crop_point = switch_round_to_step(layer->bug_frame.geometry.x - (new_w / 2), 25);
} else {
crop_point = (img->d_w - new_w) / 2;
}
if (crop_point < 1) {
crop_point = 1;
} else if (crop_point > img->d_w - new_w) {
crop_point = img->d_w - new_w;
}
set_pan(layer, crop_point, img->d_w - new_w);
if (layer->crop_point > 0) {
switch_img_set_rect(img, layer->crop_point, 0, new_w, new_h);
img_aspect = (double) img->d_w / img->d_h;
}
} else if (screen_aspect > img_aspect) {
if (img->d_w != layer->screen_w) {
scale = (double)layer->screen_w / img->d_w;
}
}
if (scale == 1) {
crop_w = img->d_w;
crop_h = img->d_h;
} else {
crop_w = (uint32_t)((double)layer->screen_w / scale);
crop_h = (uint32_t)((double)layer->screen_h / scale);
}
new_w = (uint32_t)((double)layer->screen_w / scale);
new_h = (uint32_t)((double)layer->screen_h / scale);
//if (layer->bug_frame.geometry.X > 90) {
// memset(&layer->auto_geometry, 0, sizeof(layer->auto_geometry));
//}
if (layer->cam_opts.autopan) {
can_pan = layer->bug_frame.geometry.w && (layer->geometry.zoom || layer->cam_opts.manual_zoom);
} else {
can_pan = layer->cam_opts.manual_pan && (layer->geometry.zoom || layer->cam_opts.manual_zoom);
}
if (layer->bug_frame.geometry.w) {
crop_point = layer->bug_frame.geometry.y - (new_h / 2);
if (layer->cam_opts.autozoom) {
can_zoom = layer->bug_frame.geometry.w;
} else {
can_zoom = layer->cam_opts.manual_zoom && layer->zoom_geometry.w;
}
//printf("CHECK %d %d,%d %d,%d %d/%d\n", layer->auto_geometry.w,
// layer->last_geometry.x, layer->last_geometry.y,
// layer->auto_geometry.x, layer->auto_geometry.y,
// abs(layer->auto_geometry.x - layer->last_geometry.x),
// abs(layer->auto_geometry.y - layer->last_geometry.y));
if ((layer->cam_opts.autozoom || layer->cam_opts.autopan) &&
(!layer->auto_geometry.w ||
(layer->last_geometry.x && abs(layer->auto_geometry.x - layer->last_geometry.x) > layer->cam_opts.zoom_move_factor) ||
(layer->last_geometry.y && abs(layer->auto_geometry.y - layer->last_geometry.y) > layer->cam_opts.zoom_move_factor) ||
(layer->last_geometry.w && abs(layer->auto_geometry.w - layer->last_geometry.w) > layer->cam_opts.zoom_move_factor / 2))) {
layer->auto_geometry = layer->bug_frame.geometry;
}
if (can_zoom) {
if (layer->cam_opts.autozoom) {
use_geometry = &layer->auto_geometry;
} else {
crop_point = (img->d_h - new_h) / 2;
use_geometry = &layer->zoom_geometry;
}
if (crop_point < 1) {
crop_point = 1;
} else if (crop_point > img->d_h - new_h) {
crop_point = img->d_h - new_h;
}
zoom_w = use_geometry->w * layer->cam_opts.zoom_factor;
zoom_h = zoom_w / screen_aspect;
if (zoom_w < crop_w && zoom_h < crop_h) {
int c_x = use_geometry->x;
int c_y = use_geometry->y;
crop_w = zoom_w;
crop_h = zoom_h;
//crop_w = switch_round_to_step(crop_w, layer->cam_opts.snap_factor);
//crop_h = switch_round_to_step(crop_h, layer->cam_opts.snap_factor);
set_pan(layer, crop_point, img->d_h - new_h);
if (layer->cam_opts.autozoom) {
did_zoom = 1;
}
if (crop_point > 0) {
switch_img_set_rect(img, 0, crop_point, (unsigned int)(layer->screen_w/scale), (unsigned int)(layer->screen_h/scale));
img_aspect = (double) img->d_w / img->d_h;
if (layer->cam_opts.autozoom) {
c_x = switch_round_to_step(c_x, layer->cam_opts.snap_factor);
c_y = switch_round_to_step(c_y, layer->cam_opts.snap_factor);
crop_x = c_x - (crop_w / 2);
crop_y = c_y - (crop_h / 2);
} else {
crop_x = c_x;
crop_y = c_y;
}
set_bounds(&crop_x, &crop_y, img->d_w, img->d_h, crop_w, crop_h);
//printf("ZOOM %d,%d %d,%d %dx%d\n", crop_x, crop_y, c_x, c_y, zoom_w, zoom_h);
}
}
if (!did_zoom) {
if (layer->cam_opts.autopan) {
use_geometry = &layer->auto_geometry;
} else {
use_geometry = &layer->pan_geometry;
}
if (can_pan) {
if (layer->cam_opts.autopan) {
crop_x = use_geometry->x - (crop_w / 2);
} else {
crop_x = use_geometry->x;
}
} else if (screen_aspect > img_aspect) {
crop_x = img->d_w / 4;
}
if (can_pan) {
if (layer->cam_opts.autopan) {
crop_y = use_geometry->y - (crop_h / 2);
} else {
crop_y = use_geometry->y;
}
} else if (screen_aspect < img_aspect) {
crop_y = img->d_h / 4;
}
crop_x = switch_round_to_step(crop_x, layer->cam_opts.snap_factor);
crop_y = switch_round_to_step(crop_y, layer->cam_opts.snap_factor);
}
//printf("BOUNDS B4 %d,%d %dx%d %dx%d\n", crop_x, crop_y, img->d_w, img->d_h, crop_w, crop_h);
set_bounds(&crop_x, &crop_y, img->d_w, img->d_h, crop_w, crop_h);
//printf("BOUNDS AF %d,%d %dx%d %dx%d\n", crop_x, crop_y, img->d_w, img->d_h, crop_w, crop_h);
if (img_changed) {
layer->crop_x = crop_x;
layer->crop_y = crop_y;
layer->crop_w = crop_w;
layer->crop_h = crop_h;
}
//printf("B4 %d,%d %d,%d\n", crop_x, crop_y, layer->crop_x, layer->crop_y);
set_pan(crop_x, &layer->crop_x, layer->cam_opts.pan_accel_speed, layer->cam_opts.pan_accel_min, layer->cam_opts.pan_speed);
set_pan(crop_y, &layer->crop_y, layer->cam_opts.pan_accel_speed, layer->cam_opts.pan_accel_min, layer->cam_opts.pan_speed);
//printf("AF %d,%d\n", layer->crop_x, layer->crop_y);
//printf("B4 %dx%d %dx%d\n", crop_w, crop_h, layer->crop_w, layer->crop_h);
set_pan(crop_w, &layer->crop_w, layer->cam_opts.zoom_accel_speed, layer->cam_opts.zoom_accel_min, layer->cam_opts.zoom_speed);
layer->crop_h = layer->crop_w / screen_aspect;
set_bounds(&layer->crop_x, &layer->crop_y, img->d_w, img->d_h, layer->crop_w, layer->crop_h);
assert(layer->crop_w > 0);
//printf("RECT %d,%d %dx%d (%dx%d) [%dx%d] [%dx%d]\n", layer->crop_x, layer->crop_y, layer->crop_w, layer->crop_h, layer->crop_w + layer->crop_x, layer->crop_h + layer->crop_y, img->d_w, img->d_h, layer->screen_w, layer->screen_h);
switch_img_set_rect(img, layer->crop_x, layer->crop_y, layer->crop_w, layer->crop_h);
switch_assert(img->d_w == layer->crop_w);
img_aspect = (double) img->d_w / img->d_h;
}
layer->last_geometry = layer->bug_frame.geometry;
if (freeze) {
switch_img_free(&layer->img);
}
if (screen_aspect > img_aspect) {
img_w = (uint32_t)ceil((double)img_aspect * layer->screen_h);
x_pos += (layer->screen_w - img_w) / 2;
@ -565,9 +822,12 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
img_w -= (layer->geometry.border * 2);
img_h -= (layer->geometry.border * 2);
//printf("SCALE %d,%d %dx%d\n", x_pos, y_pos, img_w, img_h);
switch_img_scale(img, &layer->img, img_w, img_h);
if (layer->img) {
//switch_img_copy(img, &layer->img);
switch_img_patch(IMG, layer->img, x_pos + layer->geometry.border, y_pos + layer->geometry.border);
}
@ -734,6 +994,8 @@ void conference_video_detach_video_layer(conference_member_t *member)
switch_img_txt_handle_destroy(&layer->txthandle);
}
member->cam_opts = layer->cam_opts;
conference_video_reset_layer(layer);
layer->member_id = 0;
layer->member = NULL;
@ -1121,6 +1383,9 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
for (i = 0; i < vlayout->layers; i++) {
mcu_layer_t *layer = &canvas->layers[i];
conference_video_reset_layer(layer);
layer->geometry.x = vlayout->images[i].x;
layer->geometry.y = vlayout->images[i].y;
layer->geometry.hscale = vlayout->images[i].scale;
@ -1137,7 +1402,6 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
layer->idx = i;
layer->refresh = 1;
layer->screen_w = (uint32_t)(canvas->img->d_w * layer->geometry.scale / VIDEO_LAYOUT_SCALE);
layer->screen_h = (uint32_t)(canvas->img->d_h * layer->geometry.hscale / VIDEO_LAYOUT_SCALE);
@ -1147,6 +1411,8 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
layer->x_pos = (int)(canvas->img->d_w * layer->geometry.x / VIDEO_LAYOUT_SCALE);
layer->y_pos = (int)(canvas->img->d_h * layer->geometry.y / VIDEO_LAYOUT_SCALE);
set_default_cam_opts(layer);
if (layer->geometry.floor) {
canvas->layout_floor_id = i;
@ -1199,6 +1465,8 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
switch_mutex_unlock(canvas->mutex);
switch_thread_rwlock_unlock(canvas->video_rwlock);
conference_event_adv_layout(conference, canvas, vlayout);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Canvas position %d applied layout %s\n", canvas->canvas_id + 1, vlayout->name);
}

View File

@ -3447,6 +3447,34 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
conference->super_canvas_label_layers = video_super_canvas_label_layers;
conference->super_canvas_show_all_layers = video_super_canvas_show_all_layers;
if (conference_utils_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) {
char *p;
if (strchr(conference->name, '@')) {
conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s", conference->name);
conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s", conference->name);
conference->info_event_channel = switch_core_sprintf(conference->pool, "conference-info.%s", conference->name);
conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s", conference->name);
} else {
conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s@%s", conference->name, conference->domain);
conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s@%s", conference->name, conference->domain);
conference->info_event_channel = switch_core_sprintf(conference->pool, "conference-info.%s@%s", conference->name, conference->domain);
conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s@%s", conference->name, conference->domain);
}
conference->la_name = switch_core_strdup(conference->pool, conference->name);
if ((p = strchr(conference->la_name, '@'))) {
*p = '\0';
}
switch_live_array_create(conference->la_event_channel, conference->la_name, conference_globals.event_channel_id, &conference->la);
switch_live_array_set_user_data(conference->la, conference);
switch_live_array_set_command_handler(conference->la, conference_event_la_command_handler);
}
if (video_canvas_count < 1) video_canvas_count = 1;
if (conference_utils_test_flag(conference, CFLAG_PERSONAL_CANVAS) && video_canvas_count > 1) {
@ -3499,30 +3527,6 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "conference-create");
switch_event_fire(&event);
if (conference_utils_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) {
char *p;
if (strchr(conference->name, '@')) {
conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s", conference->name);
conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s", conference->name);
conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s", conference->name);
} else {
conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s@%s", conference->name, conference->domain);
conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s@%s", conference->name, conference->domain);
conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s@%s", conference->name, conference->domain);
}
conference->la_name = switch_core_strdup(conference->pool, conference->name);
if ((p = strchr(conference->la_name, '@'))) {
*p = '\0';
}
switch_live_array_create(conference->la_event_channel, conference->la_name, conference_globals.event_channel_id, &conference->la);
switch_live_array_set_user_data(conference->la, conference);
switch_live_array_set_command_handler(conference->la, conference_event_la_command_handler);
}
end:
switch_mutex_unlock(conference_globals.hash_mutex);

View File

@ -429,6 +429,23 @@ typedef struct mcu_layer_def_s {
mcu_layer_geometry_t layers[MCU_MAX_LAYERS];
} mcu_layer_def_t;
typedef struct mcu_layer_cam_opts_s {
int manual_pan;
int manual_zoom;
int autozoom;
int autopan;
int zoom_factor;
int snap_factor;
int zoom_move_factor;
int pan_speed;
int pan_accel_speed;
int pan_accel_min;
int zoom_speed;
int zoom_accel_speed;
int zoom_accel_min;
} mcu_layer_cam_opts_t;
struct mcu_canvas_s;
typedef struct mcu_layer_s {
@ -447,7 +464,13 @@ typedef struct mcu_layer_s {
int refresh;
int clear;
int is_avatar;
int crop_point;
int crop_x;
int crop_y;
int crop_w;
int crop_h;
int last_w;
int last_h;
uint32_t img_count;
switch_size_t last_img_addr;
switch_image_t *img;
switch_image_t *cur_img;
@ -463,6 +486,12 @@ typedef struct mcu_layer_s {
int need_patch;
conference_member_t *member;
switch_frame_t bug_frame;
switch_frame_geometry_t last_geometry;
switch_frame_geometry_t auto_geometry;
switch_frame_geometry_t zoom_geometry;
switch_frame_geometry_t pan_geometry;
switch_frame_geometry_t manual_geometry;
mcu_layer_cam_opts_t cam_opts;
} mcu_layer_t;
typedef struct video_layout_s {
@ -540,6 +569,7 @@ typedef struct conference_obj {
char *la_event_channel;
char *chat_event_channel;
char *mod_event_channel;
char *info_event_channel;
char *desc;
char *timer_name;
char *tts_engine;
@ -809,6 +839,7 @@ struct conference_member {
char *text_framedata;
uint32_t text_framesize;
mcu_layer_cam_opts_t cam_opts;
};
@ -967,6 +998,7 @@ void conference_event_send_rfc(conference_obj_t *conference);
void conference_member_update_status_field(conference_member_t *member);
void conference_event_la_command_handler(switch_live_array_t *la, const char *cmd, const char *sessid, cJSON *jla, void *user_data);
void conference_event_adv_la(conference_obj_t *conference, conference_member_t *member, switch_bool_t join);
void conference_event_adv_layout(conference_obj_t *conference, mcu_canvas_t *canvas, video_layout_t *vlayout);
switch_status_t conference_video_init_canvas(conference_obj_t *conference, video_layout_t *vlayout, mcu_canvas_t **canvasP);
switch_status_t conference_video_attach_canvas(conference_obj_t *conference, mcu_canvas_t *canvas, int super);
void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canvas_t *canvas, video_layout_t *vlayout);
@ -980,6 +1012,7 @@ void conference_video_set_canvas_letterbox_bgcolor(mcu_canvas_t *canvas, char *c
void conference_video_set_canvas_bgcolor(mcu_canvas_t *canvas, char *color);
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);
void conference_video_clear_layer(mcu_layer_t *layer);
void conference_video_reset_image(switch_image_t *img, switch_rgb_color_t *color);
void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int HEIGHT);
@ -1111,6 +1144,7 @@ switch_status_t conference_api_sub_check_record(conference_obj_t *conference, sw
switch_status_t conference_api_sub_check_record(conference_obj_t *conference, switch_stream_handle_t *stream, int arc, char **argv);
switch_status_t conference_api_sub_volume_in(conference_member_t *member, switch_stream_handle_t *stream, void *data);
switch_status_t conference_api_sub_file_seek(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
switch_status_t conference_api_sub_cam(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
switch_status_t conference_api_sub_stop(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
switch_status_t conference_api_sub_hup(conference_member_t *member, switch_stream_handle_t *stream, void *data);
switch_status_t conference_api_sub_pauserec(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);

View File

@ -134,6 +134,10 @@ typedef struct cv_context_s {
char *png_prefix;
int tick_speed;
int confidence_level;
int max_search_w;
int max_search_h;
int neighbors;
double search_scale;
} cv_context_t;
@ -484,6 +488,12 @@ static void init_context(cv_context_t *context)
context->cascade_path = switch_core_get_variable_pdup("cv_default_cascade", context->pool);
context->nested_cascade_path = switch_core_get_variable_pdup("cv_default_nested_cascade", context->pool);
context->confidence_level = 20;
context->max_search_w = 20;
context->max_search_h = 20;
context->neighbors = 2;
context->search_scale = 1.1;
for (int i = 0; i < MAX_OVERLAY; i++) {
context->overlay[i] = (struct overlay *) switch_core_alloc(context->pool, sizeof(struct overlay));
@ -588,12 +598,12 @@ void detectAndDraw(cv_context_t *context)
equalizeHist( smallImg, smallImg );
context->cascade->detectMultiScale( smallImg, detectedObjs,
1.1, 2, 0
context->search_scale, context->neighbors, 0
|CV_HAAR_FIND_BIGGEST_OBJECT
|CV_HAAR_DO_ROUGH_SEARCH
|CV_HAAR_SCALE_IMAGE
,
Size(20, 20) );
Size(context->max_search_w, context->max_search_h) );
parse_stats(&context->detected, detectedObjs.size(), context->skip);
@ -616,7 +626,7 @@ void detectAndDraw(cv_context_t *context)
double aspect_ratio = (double)r->width/r->height;
if (context->shape_idx >= MAX_SHAPES) {
if (context->shape_idx >= 1) {//MAX_SHAPES) {
break;
}
@ -625,6 +635,7 @@ void detectAndDraw(cv_context_t *context)
center.x = switch_round_to_step(cvRound((r->x + r->width*0.5)*scale), 20);
center.y = switch_round_to_step(cvRound((r->y + r->height*0.5)*scale), 20);
radius = switch_round_to_step(cvRound((r->width + r->height)*0.25*scale), 20);
if (context->debug) {
circle( img, center, radius, color, 3, 8, 0 );
@ -679,6 +690,7 @@ void detectAndDraw(cv_context_t *context)
// Draw rectangle reflecting confidence
const int object_neighbors = nestedObjects.size();
//printf("WTF %d\n", object_neighbors);
//cout << "Detected " << object_neighbors << " object neighbors" << endl;
const int rect_height = cvRound((float)img.rows * object_neighbors / max_neighbors);
CvScalar col = CV_RGB((float)255 * object_neighbors / max_neighbors, 0, 0);
@ -861,9 +873,11 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
frame->geometry.y = context->shape[0].cy;
frame->geometry.w = context->shape[0].w;
frame->geometry.h = context->shape[0].h;
frame->geometry.m = 1;
frame->geometry.M++;
frame->geometry.X = 0;
} else {
frame->geometry.m = 0;
frame->geometry.M = 0;
frame->geometry.X++;
}
if (context->overlay_count && (abs || (context->detect_event && context->shape[0].cx))) {
@ -991,7 +1005,7 @@ static void parse_params(cv_context_t *context, int start, int argc, char **argv
*val++ = '\0';
}
if (name && val) {
if (name && !zstr(val)) {
if (!strcasecmp(name, "xo")) {
context->overlay[png_idx]->xo = atof(val);
} else if (!strcasecmp(name, "nick")) {
@ -1029,6 +1043,17 @@ static void parse_params(cv_context_t *context, int start, int argc, char **argv
context->skip = atoi(val);
} else if (!strcasecmp(name, "debug")) {
context->debug = atoi(val);
} else if (!strcasecmp(name, "neighbors")) {
context->neighbors = atoi(val);
} else if (!strcasecmp(name, "max_search_w")) {
context->max_search_w = atoi(val);
} else if (!strcasecmp(name, "max_search_h")) {
context->max_search_h = atoi(val);
} else if (!strcasecmp(name, "search_scale")) {
double tmp = atof(val);
if (tmp > 1) {
context->search_scale = tmp;
}
} else if (!strcasecmp(name, "confidence")) {
context->confidence_level = atoi(val);
} else if (!strcasecmp(name, "cascade")) {

View File

@ -3898,7 +3898,6 @@ static switch_bool_t verto__unsubscribe_func(const char *method, cJSON *params,
static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
{
char *json_text = NULL;
switch_bool_t r = SWITCH_FALSE;
const char *event_channel = cJSON_GetObjectCstr(params, "eventChannel");
cJSON *jevent, *broadcast;
const char *display = NULL;
@ -3941,11 +3940,12 @@ static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, js
if (mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1) <= 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "multicast socket send error! %s\n", strerror(errno));
r = SWITCH_FALSE;
cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Send failure!"));
//r = SWITCH_FALSE;
//cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Send failure!"));
} else {
r = SWITCH_TRUE;
cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Sent"));
//r = SWITCH_TRUE;
//cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Sent"));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MCAST Data Sent\n");
}
free(json_text);
json_text = NULL;
@ -3956,7 +3956,7 @@ static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, js
end:
return r;
return SWITCH_TRUE;
}
static switch_bool_t login_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)