diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index 2e965c0003..676e909bbf 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -204,6 +204,17 @@ SWITCH_DECLARE(int) switch_img_set_rect(switch_image_t *img, */ SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y); +/*!\brief patch a small img to a big IMG at position x,y +* +* Both IMG and img must be non-NULL +* +* \param[in] IMG The BIG Image descriptor +* \param[in] img The small Image descriptor +* \param[in] x Leftmost pos to patch to +* \param[in] y Topmost pos to patch to +* \param[in] noalpha skip writing to non-transparent pixels +*/ +SWITCH_DECLARE(void) switch_img_patch_rgb(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_bool_t noalpha); /*!\brief patch part of a small img (x,y,w,h) to a big IMG at position X,Y * diff --git a/src/mod/applications/mod_video_filter/mod_video_filter.c b/src/mod/applications/mod_video_filter/mod_video_filter.c index 52044bec1b..82ca612a20 100644 --- a/src/mod/applications/mod_video_filter/mod_video_filter.c +++ b/src/mod/applications/mod_video_filter/mod_video_filter.c @@ -48,7 +48,9 @@ typedef struct chromakey_context_s { switch_image_t *imgfg; switch_image_t *imgbg; void *data; + void *patch_data; switch_size_t datalen; + switch_size_t patch_datalen; switch_file_handle_t vfh; switch_rgb_color_t bgcolor; switch_rgb_color_t mask[MAX_MASK]; @@ -80,6 +82,7 @@ static void uninit_context(chromakey_context_t *context) switch_img_free(&context->last_img); switch_safe_free(context->data); + switch_safe_free(context->patch_data); } static void parse_params(chromakey_context_t *context, int start, int argc, char **argv, const char **function, switch_media_bug_flag_t *flags) @@ -155,7 +158,7 @@ static void parse_params(chromakey_context_t *context, int start, int argc, char if (argv[i][0] == '#') { // bgcolor switch_color_set_rgb(&context->bgcolor, argv[i]); } else if (switch_stristr(".png", argv[i])) { - if (!(context->bgimg = switch_img_read_png(argv[i], SWITCH_IMG_FMT_I420))) { + if (!(context->bgimg = switch_img_read_png(argv[i], SWITCH_IMG_FMT_ARGB))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening png\n"); } } else { @@ -216,6 +219,7 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi switch_channel_t *channel = switch_core_session_get_channel(session); switch_image_t *img = NULL; switch_size_t bytes; + void *patch_data; if (!switch_channel_ready(channel)) { return SWITCH_STATUS_FALSE; @@ -246,6 +250,8 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi switch_assert(context->data); + patch_data = context->data; + switch_img_to_raw(frame->img, context->data, frame->img->d_w * 4, SWITCH_IMG_FMT_ARGB); img = switch_img_wrap(NULL, SWITCH_IMG_FMT_ARGB, frame->img->d_w, frame->img->d_h, 1, context->data); @@ -256,6 +262,8 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi switch_img_copy(img, &context->last_img); if (context->bgimg) { + switch_image_t *tmp = NULL; + if (context->bgimg_scaled && (context->bgimg_scaled->d_w != frame->img->d_w || context->bgimg_scaled->d_h != frame->img->d_h)) { switch_img_free(&context->bgimg_scaled); } @@ -264,7 +272,28 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi switch_img_scale(context->bgimg, &context->bgimg_scaled, frame->img->d_w, frame->img->d_h); } - switch_img_patch(frame->img, context->bgimg_scaled, 0, 0); + if (context->imgbg) { + switch_img_copy(img, &tmp); + } + + switch_img_patch_rgb(img, context->bgimg_scaled, 0, 0, SWITCH_TRUE); + + if (context->imgbg) { + int x = 0, y = 0; + + if (context->imgbg->d_w != frame->img->d_w && context->imgbg->d_h != frame->img->d_h) { + switch_img_fit(&context->imgbg, frame->img->d_w, frame->img->d_h, SWITCH_FIT_SIZE); + } + + switch_img_find_position(POS_CENTER_BOT, frame->img->d_w, frame->img->d_h, context->imgbg->d_w, context->imgbg->d_h, &x, &y); + switch_img_patch(img, context->imgbg, x, y); + + if (tmp) { + switch_img_patch(img, tmp, 0, 0); + switch_img_free(&tmp); + } + } + } else if (switch_test_flag(&context->vfh, SWITCH_FILE_OPEN)) { switch_image_t *use_img = NULL; switch_frame_t file_frame = { 0 }; @@ -284,7 +313,34 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi } if (use_img) { - switch_img_patch(frame->img, use_img, 0, 0); + switch_image_t *i2; + + bytes = use_img->d_w * use_img->d_h * 4; + + if (bytes > context->patch_datalen) { + context->patch_data = realloc(context->patch_data, bytes); + context->patch_datalen = bytes; + } + + switch_img_to_raw(use_img, context->patch_data, use_img->d_w * 4, SWITCH_IMG_FMT_ARGB); + i2 = switch_img_wrap(NULL, SWITCH_IMG_FMT_ARGB, use_img->d_w, use_img->d_h, 1, context->patch_data); + + + + if (context->imgbg) { + int x = 0, y = 0; + + if (context->imgbg->d_w != frame->img->d_w && context->imgbg->d_h != frame->img->d_h) { + switch_img_fit(&context->imgbg, frame->img->d_w, frame->img->d_h, SWITCH_FIT_SIZE); + } + switch_img_find_position(POS_CENTER_BOT, frame->img->d_w, frame->img->d_h, context->imgbg->d_w, context->imgbg->d_h, &x, &y); + switch_img_patch(i2, context->imgbg, x, y); + } + + switch_img_patch(i2, img, 0, 0); + switch_img_free(&img); + img = i2; + patch_data = context->patch_data; } if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { @@ -309,19 +365,6 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi switch_img_fill(frame->img, 0, 0, img->d_w, img->d_h, &context->bgcolor); } - - if (context->imgbg) { - int x = 0, y = 0; - - if (context->imgbg->d_w != frame->img->d_w && context->imgbg->d_h != frame->img->d_h) { - switch_img_fit(&context->imgbg, frame->img->d_w, frame->img->d_h, SWITCH_FIT_SIZE); - } - switch_img_find_position(POS_CENTER_BOT, frame->img->d_w, frame->img->d_h, context->imgbg->d_w, context->imgbg->d_h, &x, &y); - switch_img_patch(frame->img, context->imgbg, x, y); - } - - switch_img_patch(frame->img, img, 0, 0); - if (context->imgfg) { int x = 0, y = 0; @@ -329,8 +372,10 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi switch_img_fit(&context->imgfg, frame->img->d_w, frame->img->d_h, SWITCH_FIT_SIZE); } switch_img_find_position(POS_CENTER_BOT, frame->img->d_w, frame->img->d_h, context->imgfg->d_w, context->imgfg->d_h, &x, &y); - switch_img_patch(frame->img, context->imgfg, x, y); + switch_img_patch(img, context->imgfg, x, y); } + + switch_img_from_raw(frame->img, patch_data, SWITCH_IMG_FMT_ARGB, frame->img->d_w, frame->img->d_h); switch_img_free(&img); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index 052ad98f67..dcfe17d8ff 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -302,11 +302,58 @@ SWITCH_DECLARE(void) switch_img_free(switch_image_t **img) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif +SWITCH_DECLARE(void) switch_img_patch_rgb(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_bool_t noalpha) +{ + int i; + + if (img->fmt == SWITCH_IMG_FMT_ARGB && IMG->fmt == SWITCH_IMG_FMT_ARGB) { + int max_w = MIN(img->d_w, IMG->d_w - abs(x)); + int max_h = MIN(img->d_h, IMG->d_h - abs(y)); + int j; + uint8_t alpha; + switch_rgb_color_t *rgb, *RGB; + + for (i = 0; i < max_h; i++) { + for (j = 0; j < max_w; j++) { + rgb = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->stride[SWITCH_PLANE_PACKED] + j * 4); + RGB = (switch_rgb_color_t *)(IMG->planes[SWITCH_PLANE_PACKED] + (y + i) * IMG->stride[SWITCH_PLANE_PACKED] + (x + j) * 4); + + alpha = rgb->a; + + if (noalpha && RGB->a != 0) { + continue; + } + + if (alpha == 255) { + *RGB = *rgb; + } else if (alpha != 0) { + + int tmp_a; + + if (RGB->a != 255) { + tmp_a = ((RGB->a * (255 - alpha)) >> 8) + ((rgb->a * alpha) >> 8); + RGB->a = RGB->a > tmp_a ? RGB->a : tmp_a; + } + + RGB->r = ((RGB->r * (255 - alpha)) >> 8) + ((rgb->r * alpha) >> 8); + RGB->g = ((RGB->g * (255 - alpha)) >> 8) + ((rgb->g * alpha) >> 8); + RGB->b = ((RGB->b * (255 - alpha)) >> 8) + ((rgb->b * alpha) >> 8); + } + } + } + } +} + SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y) { int i, len, max_h; int xoff = 0, yoff = 0; + if (img->fmt == SWITCH_IMG_FMT_ARGB && IMG->fmt == SWITCH_IMG_FMT_ARGB) { + switch_img_patch_rgb(IMG, img, x, y, SWITCH_FALSE); + return; + } + switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420); if (img->fmt == SWITCH_IMG_FMT_ARGB) { @@ -932,7 +979,7 @@ SWITCH_DECLARE(void) switch_img_chromakey(switch_image_t *img, switch_rgb_color_ static inline void switch_img_draw_pixel(switch_image_t *img, int x, int y, switch_rgb_color_t *color) { #ifdef SWITCH_HAVE_YUV - switch_yuv_color_t yuv; + switch_yuv_color_t yuv = {0}; if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return; @@ -1163,9 +1210,14 @@ SWITCH_DECLARE(void) switch_color_set_rgb(switch_rgb_color_t *color, const char #ifdef SWITCH_HAVE_YUV static inline void switch_color_rgb2yuv(switch_rgb_color_t *rgb, switch_yuv_color_t *yuv) { - yuv->y = (uint8_t)(((rgb->r * 4897) >> 14) + ((rgb->g * 9611) >> 14) + ((rgb->b * 1876) >> 14)); - yuv->u = (uint8_t)(- ((rgb->r * 2766) >> 14) - ((5426 * rgb->g) >> 14) + rgb->b / 2 + 128); - yuv->v = (uint8_t)(rgb->r / 2 -((6855 * rgb->g) >> 14) - ((rgb->b * 1337) >> 14) + 128); + + yuv->y = ( ( 66 * rgb->r + 129 * rgb->g + 25 * rgb->b + 128) >> 8) + 16; + yuv->u = ( ( -38 * rgb->r - 74 * rgb->g + 112 * rgb->b + 128) >> 8) + 128; + yuv->v = ( ( 112 * rgb->r - 94 * rgb->g - 18 * rgb->b + 128) >> 8) + 128; + + //yuv->y = (uint8_t)(((rgb->r * 4897) >> 14) + ((rgb->g * 9611) >> 14) + ((rgb->b * 1876) >> 14)); + //yuv->u = (uint8_t)(- ((rgb->r * 2766) >> 14) - ((5426 * rgb->g) >> 14) + rgb->b / 2 + 128); + //yuv->v = (uint8_t)(rgb->r / 2 -((6855 * rgb->g) >> 14) - ((rgb->b * 1337) >> 14) + 128); } #endif