mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-03-06 02:22:56 +00:00
FS-7515: add more features to mod_cv
This commit is contained in:
parent
40d0e1fdd7
commit
93c841d9e8
@ -88,13 +88,14 @@ struct overlay {
|
|||||||
float xo;
|
float xo;
|
||||||
float yo;
|
float yo;
|
||||||
float shape_scale;
|
float shape_scale;
|
||||||
|
int scale_w;
|
||||||
|
int scale_h;
|
||||||
int zidx;
|
int zidx;
|
||||||
switch_img_position_t abs;
|
switch_img_position_t abs;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct cv_context_s {
|
typedef struct cv_context_s {
|
||||||
IplImage *rawImage;
|
IplImage *rawImage;
|
||||||
IplImage *yuvImage;
|
|
||||||
CascadeClassifier *cascade;
|
CascadeClassifier *cascade;
|
||||||
CascadeClassifier *nestedCascade;
|
CascadeClassifier *nestedCascade;
|
||||||
int w;
|
int w;
|
||||||
@ -130,20 +131,93 @@ static int clear_overlay(cv_context_t *context, int idx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
context->overlay[idx]->png_path = NULL;
|
context->overlay[idx]->png_path = NULL;
|
||||||
context->overlay[idx]->nick = NULL;
|
context->overlay[idx]->nick = NULL;
|
||||||
switch_img_free(&context->overlay[idx]->png);
|
switch_img_free(&context->overlay[idx]->png);
|
||||||
memset(context->overlay[idx], 0, sizeof(struct overlay));
|
memset(context->overlay[idx], 0, sizeof(struct overlay));
|
||||||
|
context->overlay[idx]->shape_scale = 1;
|
||||||
context->overlay_count--;
|
context->overlay_count--;
|
||||||
|
|
||||||
|
|
||||||
for (x = idx + 1; x < i; x++) {
|
for (x = idx + 1; x < i; x++) {
|
||||||
context->overlay[x-1] = context->overlay[x];
|
context->overlay[x-1] = context->overlay[x];
|
||||||
memset(context->overlay[x], 0, sizeof(struct overlay));
|
memset(context->overlay[x], 0, sizeof(struct overlay));
|
||||||
|
context->overlay[x]->shape_scale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return idx - 1 > 0 ? idx -1 : 0;
|
return idx - 1 > 0 ? idx -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_text(cv_context_t *context, const char *nick, const char *fg, const char *bg, const char *font_face, int font_size, const char *text)
|
||||||
|
{
|
||||||
|
uint32_t i = context->overlay_count;
|
||||||
|
switch_rgb_color_t fgcolor, bgcolor;
|
||||||
|
int x = 0, width = 0, is_new = 1;
|
||||||
|
switch_img_txt_handle_t *txthandle = NULL;
|
||||||
|
|
||||||
|
for (x = 0; x < i; x++) {
|
||||||
|
if (context->overlay[x] && context->overlay[x]->png) {
|
||||||
|
if (!zstr(nick)) {
|
||||||
|
if (!zstr(context->overlay[x]->nick) && !strcmp(context->overlay[x]->nick, nick)) {
|
||||||
|
i = x;
|
||||||
|
is_new = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (strstr(context->overlay[x]->png_path, text)) {
|
||||||
|
if (!zstr(nick) && (zstr(context->overlay[x]->nick) || strcmp(nick, context->overlay[x]->nick))) {
|
||||||
|
context->overlay[x]->nick = switch_core_strdup(context->pool, nick);
|
||||||
|
}
|
||||||
|
i = x;
|
||||||
|
is_new = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_new) {
|
||||||
|
context->overlay_count++;
|
||||||
|
if (!zstr(nick)) {
|
||||||
|
context->overlay[i]->nick = switch_core_strdup(context->pool, nick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!font_size) {
|
||||||
|
font_size = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!font_face) {
|
||||||
|
font_face = "FreeMono.ttf";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fg) {
|
||||||
|
fg = "#cccccc";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bg) {
|
||||||
|
bg = "#142e55";
|
||||||
|
}
|
||||||
|
|
||||||
|
width = (int) (float)(font_size * 0.75f * strlen(text));
|
||||||
|
|
||||||
|
switch_color_set_rgb(&fgcolor, fg);
|
||||||
|
switch_color_set_rgb(&bgcolor, bg);
|
||||||
|
|
||||||
|
switch_img_free(&context->overlay[i]->png);
|
||||||
|
context->overlay[i]->png = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, width, font_size * 2, 1);
|
||||||
|
switch_img_fill(context->overlay[i]->png, 0, 0, context->overlay[i]->png->d_w, context->overlay[i]->png->d_h, &bgcolor);
|
||||||
|
switch_img_txt_handle_create(&txthandle, font_face, fg, bg, font_size, 0, NULL);
|
||||||
|
switch_img_txt_handle_render(txthandle, context->overlay[i]->png, font_size / 2, font_size / 2, text, NULL, fg, bg, 0, 0);
|
||||||
|
switch_img_txt_handle_destroy(&txthandle);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int add_overlay(cv_context_t *context, const char *png_path, const char *nick)
|
static int add_overlay(cv_context_t *context, const char *png_path, const char *nick)
|
||||||
{
|
{
|
||||||
uint32_t i = context->overlay_count;
|
uint32_t i = context->overlay_count;
|
||||||
@ -159,6 +233,9 @@ static int add_overlay(cv_context_t *context, const char *png_path, const char *
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (strstr(context->overlay[x]->png_path, png_path)) {
|
if (strstr(context->overlay[x]->png_path, png_path)) {
|
||||||
|
if (!zstr(nick) && (zstr(context->overlay[x]->nick) || strcmp(nick, context->overlay[x]->nick))) {
|
||||||
|
context->overlay[x]->nick = switch_core_strdup(context->pool, nick);
|
||||||
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,8 +259,6 @@ static int add_overlay(cv_context_t *context, const char *png_path, const char *
|
|||||||
if (!zstr(nick)) {
|
if (!zstr(nick)) {
|
||||||
context->overlay[i]->nick = switch_core_strdup(context->pool, nick);
|
context->overlay[i]->nick = switch_core_strdup(context->pool, nick);
|
||||||
}
|
}
|
||||||
if (!context->overlay[i]->shape_scale) context->overlay[i]->shape_scale = 1;
|
|
||||||
|
|
||||||
r = (int) i;
|
r = (int) i;
|
||||||
} else {
|
} else {
|
||||||
context->overlay[i]->png_path = NULL;
|
context->overlay[i]->png_path = NULL;
|
||||||
@ -236,6 +311,7 @@ static void uninit_context(cv_context_t *context)
|
|||||||
context->overlay[i]->png_path = NULL;
|
context->overlay[i]->png_path = NULL;
|
||||||
context->overlay_count = 0;
|
context->overlay_count = 0;
|
||||||
memset(context->overlay[i], 0, sizeof(struct overlay));
|
memset(context->overlay[i], 0, sizeof(struct overlay));
|
||||||
|
context->overlay[i]->shape_scale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_core_destroy_memory_pool(&context->pool);
|
switch_core_destroy_memory_pool(&context->pool);
|
||||||
@ -256,6 +332,7 @@ static void init_context(cv_context_t *context)
|
|||||||
for (int i = 0; i < MAX_OVERLAY; i++) {
|
for (int i = 0; i < MAX_OVERLAY; i++) {
|
||||||
context->overlay[i] = (struct overlay *) switch_core_alloc(context->pool, sizeof(struct overlay));
|
context->overlay[i] = (struct overlay *) switch_core_alloc(context->pool, sizeof(struct overlay));
|
||||||
context->overlay[i]->abs = POS_NONE;
|
context->overlay[i]->abs = POS_NONE;
|
||||||
|
context->overlay[i]->shape_scale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
create = 1;
|
create = 1;
|
||||||
@ -461,36 +538,36 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
|
|||||||
{
|
{
|
||||||
cv_context_t *context = (cv_context_t *) user_data;
|
cv_context_t *context = (cv_context_t *) user_data;
|
||||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!switch_channel_ready(channel)) {
|
if (!switch_channel_ready(channel)) {
|
||||||
return SWITCH_STATUS_FALSE;
|
return SWITCH_STATUS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame->img) {
|
if (!frame->img) {
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (context->cascade) {
|
||||||
|
switch_event_t *event;
|
||||||
|
|
||||||
if ((frame->img->d_w != context->w || frame->img->d_h != context->h) && context->rawImage) {
|
if ((frame->img->d_w != context->w || frame->img->d_h != context->h) && context->rawImage) {
|
||||||
cvReleaseImage(&context->rawImage);
|
cvReleaseImage(&context->rawImage);
|
||||||
cvReleaseImage(&context->yuvImage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context->rawImage) {
|
if (!context->rawImage) {
|
||||||
context->rawImage = cvCreateImage(cvSize(frame->img->d_w, frame->img->d_h), IPL_DEPTH_8U, 3);
|
context->rawImage = cvCreateImage(cvSize(frame->img->d_w, frame->img->d_h), IPL_DEPTH_8U, 3);
|
||||||
context->yuvImage = cvCreateImage(cvSize(frame->img->d_w, frame->img->d_h), IPL_DEPTH_8U, 3);
|
|
||||||
switch_assert(context->rawImage);
|
switch_assert(context->rawImage);
|
||||||
switch_assert(context->rawImage->width * 3 == context->rawImage->widthStep);
|
switch_assert(context->rawImage->width * 3 == context->rawImage->widthStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("context->rawImage: %dx%d stride: %d size: %d color:%s\n", context->rawImage->width, context->rawImage->height, context->rawImage->widthStep, context->rawImage->imageSize, context->rawImage->colorModel);
|
|
||||||
|
|
||||||
libyuv::I420ToRGB24(frame->img->planes[0], frame->img->stride[0],
|
libyuv::I420ToRGB24(frame->img->planes[0], frame->img->stride[0],
|
||||||
frame->img->planes[1], frame->img->stride[1],
|
frame->img->planes[1], frame->img->stride[1],
|
||||||
frame->img->planes[2], frame->img->stride[2],
|
frame->img->planes[2], frame->img->stride[2],
|
||||||
(uint8_t *)context->rawImage->imageData, context->rawImage->widthStep,
|
(uint8_t *)context->rawImage->imageData, context->rawImage->widthStep,
|
||||||
context->rawImage->width, context->rawImage->height);
|
context->rawImage->width, context->rawImage->height);
|
||||||
|
|
||||||
|
|
||||||
if (context->cascade) {
|
|
||||||
switch_event_t *event;
|
|
||||||
|
|
||||||
detectAndDraw(context);
|
detectAndDraw(context);
|
||||||
|
|
||||||
if (context->detected.simo_count > 20) {
|
if (context->detected.simo_count > 20) {
|
||||||
@ -595,9 +672,15 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
|
|||||||
context->rawImage->width, context->rawImage->height);
|
context->rawImage->width, context->rawImage->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->overlay_count && context->detect_event && context->shape[0].cx) {
|
int abs = 0;
|
||||||
int i;
|
|
||||||
|
|
||||||
|
for (i = 0; i < context->overlay_count; i++) {
|
||||||
|
if (context->overlay[i]->abs != POS_NONE) {
|
||||||
|
abs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->overlay_count && (abs || context->detect_event && context->shape[0].cx)) {
|
||||||
for (i = 0; i < context->overlay_count; i++) {
|
for (i = 0; i < context->overlay_count; i++) {
|
||||||
struct overlay *overlay = context->overlay[i];
|
struct overlay *overlay = context->overlay[i];
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
@ -607,6 +690,10 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
|
|||||||
int shape_w, shape_h;
|
int shape_w, shape_h;
|
||||||
int cx, cy;
|
int cx, cy;
|
||||||
|
|
||||||
|
if (context->overlay[i]->abs == POS_NONE && !context->detect_event && !context->shape[0].cx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
shape_w = context->shape[0].w;
|
shape_w = context->shape[0].w;
|
||||||
shape_h = context->shape[0].h;
|
shape_h = context->shape[0].h;
|
||||||
|
|
||||||
@ -615,11 +702,24 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
|
|||||||
|
|
||||||
|
|
||||||
if (overlay->abs != POS_NONE) {
|
if (overlay->abs != POS_NONE) {
|
||||||
if (overlay->shape_scale != 1) {
|
if (overlay->scale_w || overlay->scale_h) {
|
||||||
|
if (overlay->scale_w && !overlay->scale_h) {
|
||||||
|
scale_w = frame->img->d_w;
|
||||||
|
scale_h = ((overlay->png->d_h * scale_w) / overlay->png->d_w);
|
||||||
|
} else if (overlay->scale_h && !overlay->scale_w) {
|
||||||
|
scale_h = frame->img->d_h;
|
||||||
|
scale_w = ((overlay->png->d_w * scale_h) / overlay->png->d_h);
|
||||||
|
} else {
|
||||||
|
scale_w = frame->img->d_w;
|
||||||
|
scale_h = frame->img->d_h;
|
||||||
|
}
|
||||||
|
} else if (overlay->shape_scale != 1) {
|
||||||
scale_w = overlay->png->d_w * overlay->shape_scale;
|
scale_w = overlay->png->d_w * overlay->shape_scale;
|
||||||
|
|
||||||
if (scale_w > frame->img->d_w) {
|
if (scale_w > frame->img->d_w) {
|
||||||
scale_w = frame->img->d_w;
|
scale_w = frame->img->d_w;
|
||||||
}
|
}
|
||||||
|
|
||||||
scale_h = ((overlay->png->d_h * scale_w) / overlay->png->d_w);
|
scale_h = ((overlay->png->d_h * scale_w) / overlay->png->d_w);
|
||||||
} else {
|
} else {
|
||||||
scale_w = overlay->png->d_w;
|
scale_w = overlay->png->d_w;
|
||||||
@ -656,8 +756,6 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,7 +799,6 @@ static void parse_params(cv_context_t *context, int start, int argc, char **argv
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name && val) {
|
if (name && val) {
|
||||||
|
|
||||||
if (!strcasecmp(name, "xo")) {
|
if (!strcasecmp(name, "xo")) {
|
||||||
context->overlay[png_idx]->xo = atof(val);
|
context->overlay[png_idx]->xo = atof(val);
|
||||||
} else if (!strcasecmp(name, "nick")) {
|
} else if (!strcasecmp(name, "nick")) {
|
||||||
@ -714,6 +811,25 @@ static void parse_params(cv_context_t *context, int start, int argc, char **argv
|
|||||||
sort++;
|
sort++;
|
||||||
} else if (!strcasecmp(name, "abs")) {
|
} else if (!strcasecmp(name, "abs")) {
|
||||||
context->overlay[png_idx]->abs = parse_img_position(val);
|
context->overlay[png_idx]->abs = parse_img_position(val);
|
||||||
|
if (context->overlay[png_idx]->abs == POS_NONE) {
|
||||||
|
context->overlay[png_idx]->scale_w = context->overlay[png_idx]->scale_h = 0;
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(name, "scaleto") && context->overlay[png_idx]->abs != POS_NONE) {
|
||||||
|
if (strchr(val, 'W')) {
|
||||||
|
context->overlay[png_idx]->scale_w = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strchr(val, 'H')) {
|
||||||
|
context->overlay[png_idx]->scale_h = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strchr(val, 'w')) {
|
||||||
|
context->overlay[png_idx]->scale_w = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strchr(val, 'h')) {
|
||||||
|
context->overlay[png_idx]->scale_h = 0;
|
||||||
|
}
|
||||||
} else if (!strcasecmp(name, "scale")) {
|
} else if (!strcasecmp(name, "scale")) {
|
||||||
context->overlay[png_idx]->shape_scale = atof(val);
|
context->overlay[png_idx]->shape_scale = atof(val);
|
||||||
} else if (!strcasecmp(name, "skip")) {
|
} else if (!strcasecmp(name, "skip")) {
|
||||||
@ -728,10 +844,26 @@ static void parse_params(cv_context_t *context, int start, int argc, char **argv
|
|||||||
changed++;
|
changed++;
|
||||||
} else if (!strcasecmp(name, "png")) {
|
} else if (!strcasecmp(name, "png")) {
|
||||||
png_idx = add_overlay(context, val, nick);
|
png_idx = add_overlay(context, val, nick);
|
||||||
|
} else if (!strcasecmp(name, "txt")) {
|
||||||
|
int iargc = 0;
|
||||||
|
char *iargv[10] = { 0 };
|
||||||
|
|
||||||
|
iargc = switch_split(val, ':', iargv);
|
||||||
|
if (iargc >= 5) {
|
||||||
|
png_idx = add_text(context, nick, iargv[0], iargv[1], iargv[2], atoi(iargv[3]), iargv[4]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (name) {
|
} else if (name) {
|
||||||
if (!strcasecmp(name, "clear")) {
|
if (!strcasecmp(name, "clear")) {
|
||||||
png_idx = clear_overlay(context, png_idx);
|
png_idx = clear_overlay(context, png_idx);
|
||||||
|
} else if (!strcasecmp(name, "allclear")) {
|
||||||
|
for (int x = context->overlay_count - 1; x >= 0; x--) {
|
||||||
|
png_idx = clear_overlay(context, x);
|
||||||
|
context->overlay[x]->xo = context->overlay[x]->yo = context->overlay[x]->shape_scale = 0.0f;
|
||||||
|
context->overlay[x]->zidx = 0;
|
||||||
|
context->overlay[x]->scale_w = context->overlay[x]->scale_h = 0;
|
||||||
|
context->overlay[x]->shape_scale = 1;
|
||||||
|
}
|
||||||
} else if (!strcasecmp(name, "home")) {
|
} else if (!strcasecmp(name, "home")) {
|
||||||
context->overlay[png_idx]->xo = context->overlay[png_idx]->yo = context->overlay[png_idx]->shape_scale = 0.0f;
|
context->overlay[png_idx]->xo = context->overlay[png_idx]->yo = context->overlay[png_idx]->shape_scale = 0.0f;
|
||||||
context->overlay[png_idx]->zidx = 0;
|
context->overlay[png_idx]->zidx = 0;
|
||||||
|
@ -507,7 +507,22 @@ SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_create(switch_img_txt_hand
|
|||||||
|
|
||||||
new_handle->pool = pool;
|
new_handle->pool = pool;
|
||||||
new_handle->free_pool = free_pool;
|
new_handle->free_pool = free_pool;
|
||||||
|
|
||||||
|
if (!switch_is_file_path(font_family)) {
|
||||||
|
new_handle->font_family = switch_core_sprintf(new_handle->pool, "%s%s%s",SWITCH_GLOBAL_dirs.fonts_dir, SWITCH_PATH_SEPARATOR, font_family);
|
||||||
|
} else {
|
||||||
new_handle->font_family = switch_core_strdup(new_handle->pool, font_family);
|
new_handle->font_family = switch_core_strdup(new_handle->pool, font_family);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_file_exists(new_handle->font_family, new_handle->pool) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Font %s does not exist\n", new_handle->font_family);
|
||||||
|
if (free_pool) {
|
||||||
|
switch_core_destroy_memory_pool(&pool);
|
||||||
|
}
|
||||||
|
*handleP = NULL;
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
new_handle->font_size = font_size;
|
new_handle->font_size = font_size;
|
||||||
new_handle->angle = angle;
|
new_handle->angle = angle;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user