]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-10050: [core] chromakey
authorAnthony Minessale <anthm@freeswitch.org>
Thu, 2 Mar 2017 02:01:36 +0000 (20:01 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Thu, 2 Mar 2017 02:01:36 +0000 (20:01 -0600)
src/include/switch_core_video.h
src/mod/applications/mod_video_filter/mod_video_filter.c
src/switch_core_video.c

index 2e965c0003c772fdef0a3db9ef649eea3069b60b..676e909bbfaf68ab283ff010ed4c2d568fd88e64 100644 (file)
@@ -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
 *
index 52044bec1bbd2f516420e5d71cb76b9886bc3083..82ca612a20383cfa471c76996b74f004cb9b1611 100644 (file)
@@ -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);
 
index 052ad98f674f5ba8eab389a57a88cf79cf09acdf..dcfe17d8ff14d5d1ec2ed7414834f7232f954529 100644 (file)
@@ -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