]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-10050 cont
authorAnthony Minessale <anthm@freeswitch.org>
Tue, 21 Feb 2017 21:52:53 +0000 (15:52 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Tue, 21 Feb 2017 21:52:59 +0000 (15:52 -0600)
src/include/switch_core_video.h
src/include/switch_module_interfaces.h
src/mod/applications/mod_av/avformat.c
src/mod/applications/mod_video_filter/mod_video_filter.c
src/switch_core_video.c

index 198d5f17207b5e0bd2953bf8528b6c623a278acf..9101975ad00618c64f7eeb8efdf534ffee1387f0 100644 (file)
@@ -391,6 +391,7 @@ SWITCH_DECLARE(switch_status_t) switch_I420_copy2(uint8_t *src_planes[], int src
 /*!\brief chromakey an img, img must be RGBA and return modified img */
 
 SWITCH_DECLARE(void) switch_img_chromakey(switch_image_t *img, switch_rgb_color_t *mask, int threshold);
+SWITCH_DECLARE(void) switch_img_chromakey_multi(switch_image_t *img, switch_rgb_color_t *mask, int *thresholds, int count);
 
 
 SWITCH_END_EXTERN_C
index 79758ccf33296a58f7f2fa8261508116e0bb4540..90c2a9052d6d9c41aeb4d88fe06a66a42345f812 100644 (file)
@@ -336,6 +336,8 @@ typedef struct switch_mm_s {
        switch_video_profile_t vprofile;
        switch_video_encode_speed_t vencspd;
        uint8_t try_hardware_encoder;
+       int scale_w;
+       int scale_h;
 } switch_mm_t;
 
 /*! an abstract representation of a file handle (some parameters based on compat with libsndfile) */
index 4d87a5073882d4c513684ff023de53c25b15593a..f96b7b2f1b95f8e6a12d9e38212751264740f323 100644 (file)
@@ -1286,6 +1286,7 @@ struct av_file_context {
        int64_t seek_ts;
        switch_bool_t read_paused;
        int errs;
+       switch_file_handle_t *handle;
 };
 
 typedef struct av_file_context av_file_context_t;
@@ -1574,6 +1575,7 @@ again:
                                }
 
                                img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, vframe->width, vframe->height, 1);
+
                                if (img) {
                                        int64_t *pts = malloc(sizeof(int64_t));
 
@@ -1706,6 +1708,8 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
        context->pool = handle->memory_pool;
        context->seek_ts = -1;
        context->offset = DFT_RECORD_OFFSET;
+       context->handle = handle;
+
        if (handle->params && (tmp = switch_event_get_header(handle->params, "av_video_offset"))) {
                context->offset = atoi(tmp);
        }
@@ -2180,6 +2184,13 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
                context->vid_ready = 1;
 
                frame->img = (switch_image_t *) pop;
+
+               if (frame->img && context->handle->mm.scale_w && context->handle->mm.scale_h) {
+                       if (frame->img->d_w != context->handle->mm.scale_w || frame->img->d_h != context->handle->mm.scale_h) {
+                               switch_img_fit(&frame->img, context->handle->mm.scale_w, context->handle->mm.scale_h, SWITCH_FIT_SIZE);
+                       }
+               }
+               
                return SWITCH_STATUS_SUCCESS;
        }
 
index aae716149f7d9fcc2e710155d3a7d57ab2acbd61..2e0e5737240d1b8dff6fd2d2bc59c1e42d95f50d 100644 (file)
@@ -38,26 +38,36 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_video_filter_load);
 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_video_filter_shutdown);
 SWITCH_MODULE_DEFINITION(mod_video_filter, mod_video_filter_load, mod_video_filter_shutdown, NULL);
 
+#define MAX_MASK 25
+
 typedef struct chromakey_context_s {
        int threshold;
        switch_image_t *bgimg;
        switch_image_t *bgimg_scaled;
+       switch_file_handle_t vfh;
        switch_rgb_color_t bgcolor;
-       switch_rgb_color_t mask;
+       switch_rgb_color_t mask[MAX_MASK];
+       int thresholds[MAX_MASK];
+       int mask_len;
        switch_core_session_t *session;
+       switch_mutex_t *command_mutex;
 } chromakey_context_t;
 
 static void init_context(chromakey_context_t *context)
 {
        switch_color_set_rgb(&context->bgcolor, "#000000");
-       switch_color_set_rgb(&context->mask, "#FFFFFF");
        context->threshold = 300;
+       switch_mutex_init(&context->command_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(context->session));
 }
 
 static void uninit_context(chromakey_context_t *context)
 {
        switch_img_free(&context->bgimg);
        switch_img_free(&context->bgimg_scaled);
+       if (switch_test_flag(&context->vfh, SWITCH_FILE_OPEN)) {
+               switch_core_file_close(&context->vfh);
+               memset(&context->vfh, 0, sizeof(context->vfh));
+       }
 }
 
 static void parse_params(chromakey_context_t *context, int start, int argc, char **argv, const char **function, switch_media_bug_flag_t *flags)
@@ -65,32 +75,89 @@ static void parse_params(chromakey_context_t *context, int start, int argc, char
        int n = argc - start;
        int i = start;
 
+       switch_mutex_lock(context->command_mutex);
+
        if (n > 0 && argv[i]) { // color
-               switch_color_set_rgb(&context->mask, argv[i]);
+               int j = 0;
+               char *list[MAX_MASK];
+               int list_argc;
+
+               list_argc = switch_split(argv[i], ':', list);
+
+               context->mask_len = 0;
+               memset(context->thresholds, 0, sizeof(context->thresholds[0]) * MAX_MASK);
+
+               for (j = 0; j < list_argc; j++) {
+                       char *p;
+                       int thresh = 0;
+
+                       if ((p = strchr(list[j], '+'))) {
+                               *p++ = '\0';
+                               thresh = atoi(p);
+                               if (thresh < 0) thresh = 0;
+                       }
+                       
+                       switch_color_set_rgb(&context->mask[j], list[j]);
+                       if (thresh) {
+                               context->thresholds[j] = thresh;
+                       }
+                       context->mask_len++;
+               }
        }
 
        i++;
 
        if (n > 1 && argv[i]) { // thresh
                int thresh = atoi(argv[i]);
+               int j;
+
+               if (thresh > 0) {
+                       context->threshold = thresh;
 
-               if (thresh > 0) context->threshold = thresh;
+                       for (j = 0; j < context->mask_len; j++) {
+                               if (!context->thresholds[j]) context->thresholds[j] = context->threshold;
+                       }
+               }
        }
 
        i++;
 
        if (n > 2 && argv[i]) {
+
+               if (switch_test_flag(&context->vfh, SWITCH_FILE_OPEN)) {
+                       switch_core_file_close(&context->vfh);
+                       memset(&context->vfh, 0, sizeof(context->vfh));
+               }
+
                if (context->bgimg) {
                        switch_img_free(&context->bgimg);
                }
+
                if (context->bgimg_scaled) {
                        switch_img_free(&context->bgimg_scaled);
                }
 
+               
                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))) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening png\n");
+                       }
                } else {
-                       context->bgimg = switch_img_read_png(argv[i], SWITCH_IMG_FMT_I420); 
+
+                       if (switch_core_file_open(&context->vfh, argv[i], 1, 8000,
+                                                                         SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT | SWITCH_FILE_FLAG_VIDEO, 
+                                                                         switch_core_session_get_pool(context->session)) != SWITCH_STATUS_SUCCESS) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening video file\n");
+                       } else {
+                               switch_vid_params_t vp = { 0 };
+
+                               switch_core_media_get_vid_params(context->session, &vp);
+                               context->vfh.mm.scale_w = vp.width;
+                               context->vfh.mm.scale_h = vp.height;
+                               context->vfh.mm.fps = vp.fps;
+                       }
                }
        }
 
@@ -102,6 +169,12 @@ static void parse_params(chromakey_context_t *context, int start, int argc, char
        }
 
        i++;
+
+       switch_mutex_unlock(context->command_mutex);
+
+       switch_core_session_request_video_refresh(context->session);
+       switch_core_media_gen_key_frame(context->session);
+
 }
 
 static switch_status_t video_thread_callback(switch_core_session_t *session, switch_frame_t *frame, void *user_data)
@@ -119,13 +192,15 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
                return SWITCH_STATUS_SUCCESS;
        }
 
+       switch_mutex_lock(context->command_mutex);
+
        data = malloc(frame->img->d_w * frame->img->d_h * 4);
        switch_assert(data);
 
        switch_img_to_raw(frame->img, 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, data);
        switch_assert(img);
-       switch_img_chromakey(img, &context->mask, context->threshold);
+       switch_img_chromakey_multi(img, context->mask, context->thresholds, context->mask_len);
 
        if (context->bgimg) {
                if (context->bgimg_scaled && (context->bgimg_scaled->d_w != frame->img->d_w || context->bgimg_scaled->d_h != frame->img->d_h)) {
@@ -137,6 +212,46 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
                }
 
                switch_img_patch(frame->img, context->bgimg_scaled, 0, 0);
+       } else if (switch_test_flag(&context->vfh, SWITCH_FILE_OPEN)) {
+               switch_image_t *use_img = NULL;
+               switch_frame_t file_frame = { 0 };
+               switch_status_t status;
+
+               context->vfh.mm.scale_w = frame->img->d_w;
+               context->vfh.mm.scale_h = frame->img->d_h;
+
+               status = switch_core_file_read_video(&context->vfh, &file_frame, SVR_FLUSH);
+               switch_core_file_command(&context->vfh, SCFC_FLUSH_AUDIO);
+
+               if (file_frame.img) {
+                       switch_img_free(&context->bgimg_scaled);
+                       use_img = context->bgimg_scaled = file_frame.img;
+               } else {
+                       use_img = context->bgimg_scaled;
+               }
+
+               if (use_img) {
+                       switch_img_patch(frame->img, use_img, 0, 0);
+               }
+
+               if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+                       int close = 1;
+
+                       if (context->vfh.params) {
+                               const char *loopstr = switch_event_get_header(context->vfh.params, "loop");
+                               if (switch_true(loopstr)) {
+                                       uint32_t pos = 0;
+                                       switch_core_file_seek(&context->vfh, &pos, 0, SEEK_SET);
+                                       close = 0;
+                               }
+                       }
+
+                       if (close) {
+                               switch_core_file_close(&context->vfh);
+                       }
+               }
+
+
        } else {
                switch_img_fill(frame->img, 0, 0, img->d_w, img->d_h, &context->bgcolor);
        }
@@ -145,6 +260,8 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
        switch_img_free(&img);
        free(data);
 
+       switch_mutex_unlock(context->command_mutex);
+
        return SWITCH_STATUS_SUCCESS;
 }
 
index 9994af91341fe9d5bcc9fe4dee8dc45215b4a016..bb18cf417177c5b762b5dedd5afd01601fd893fb 100644 (file)
@@ -80,6 +80,15 @@ static inline void switch_color_yuv2rgb(switch_yuv_color_t *yuv, switch_rgb_colo
 */
 static inline int switch_color_distance(switch_rgb_color_t *c1, switch_rgb_color_t *c2);
 
+/*!\brief compute distance between a color and a list of colors
+*
+* \param[in]    c1        RGB color1
+* \param[in]    clist     RGB color list
+* \param[in]    count     number of colors in list
+* \param[in]    threshold hint of target threshold to stop processing list
+*/
+static inline int switch_color_distance_multi(switch_rgb_color_t *c1, switch_rgb_color_t *clist, int count, int *thresholds);
+
 /*!\brief Draw a pixel on an image
 *
 * \param[in]    img       Image descriptor
@@ -534,9 +543,41 @@ SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, uint3
 #endif
 }
 
+SWITCH_DECLARE(void) switch_img_chromakey_multi(switch_image_t *img, switch_rgb_color_t *mask, int *thresholds, int count)
+{
+       uint8_t *pixel, *last_pixel = NULL;
+       int last_hits = 0;
+       switch_assert(img);
+
+       if (img->fmt != SWITCH_IMG_FMT_ARGB) return;
+
+       pixel = img->planes[SWITCH_PLANE_PACKED];
+
+       for (; pixel < (img->planes[SWITCH_PLANE_PACKED] + img->d_w * img->d_h * 4); pixel += 4) {
+               switch_rgb_color_t *color = (switch_rgb_color_t *)pixel;
+               int hits = 0;
+
+               if (last_pixel && (*(uint32_t *)pixel & 0xFFFFFF) == (*(uint32_t *)last_pixel & 0xFFFFFF)) {
+                       hits = last_hits;
+               } else {
+                       hits = switch_color_distance_multi(color, mask, count, thresholds);
+               }
+
+               last_hits = hits;
+               last_pixel = pixel;
+
+               if (hits) {
+                       *pixel = 0;
+               }
+       }
+
+       return;
+}
+
 SWITCH_DECLARE(void) switch_img_chromakey(switch_image_t *img, switch_rgb_color_t *mask, int threshold)
 {
-       uint8_t *pixel;
+       uint8_t *pixel, *last_pixel = NULL;
+       int last_threshold = 0;
        switch_assert(img);
 
        if (img->fmt != SWITCH_IMG_FMT_ARGB) return;
@@ -545,9 +586,18 @@ SWITCH_DECLARE(void) switch_img_chromakey(switch_image_t *img, switch_rgb_color_
 
        for (; pixel < (img->planes[SWITCH_PLANE_PACKED] + img->d_w * img->d_h * 4); pixel += 4) {
                switch_rgb_color_t *color = (switch_rgb_color_t *)pixel;
-               int distance = switch_color_distance(color, mask);
+               int threshold = 0;
 
-               if (distance <= threshold) {
+               if (last_pixel && (*(uint32_t *)pixel & 0xFFFFFF) == (*(uint32_t *)last_pixel & 0xFFFFFF)) {
+                       threshold = last_threshold;
+               } else {
+                       threshold = switch_color_distance(color, mask);
+               }
+
+               last_threshold = threshold;
+               last_pixel = pixel;
+
+               if (threshold) {
                        *pixel = 0;
                }
        }
@@ -805,6 +855,23 @@ static inline int switch_color_distance(switch_rgb_color_t *c1, switch_rgb_color
     return sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
 }
 
+static inline int switch_color_distance_multi(switch_rgb_color_t *c1, switch_rgb_color_t *clist, int count, int *thresholds)
+{
+       int x = 0, hits = 0;
+
+       for (x = 0; x < count; x++) {
+               int distance = switch_color_distance(c1, &clist[x]);
+
+               if (distance < thresholds[x]) {
+                       hits++;
+               }
+       }
+
+       return hits;
+}
+
+
+
 #define CLAMP(val) MAX(0, MIN(val, 255))
 
 #ifdef SWITCH_HAVE_YUV