]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-8406 #comment add options to scale down cavas size, fps and bandwidth
authorSeven Du <dujinfang@gmail.com>
Thu, 4 Feb 2016 00:30:00 +0000 (08:30 +0800)
committerSeven Du <dujinfang@gmail.com>
Fri, 18 Mar 2016 01:05:10 +0000 (09:05 +0800)
src/mod/applications/mod_conference/conference_video.c
src/mod/applications/mod_conference/mod_conference.c
src/mod/applications/mod_conference/mod_conference.h

index e4b9ff5b019ecae063bec52ec1162203554fdbae..cb64053aaf06f1478b3336a2fe9f565936fd5955 100644 (file)
@@ -1233,6 +1233,7 @@ void conference_video_write_canvas_image_to_codec_group(conference_obj_t *confer
        conference_member_t *imember;
        switch_frame_t write_frame = { 0 }, *frame = NULL;
        switch_status_t encode_status = SWITCH_STATUS_FALSE;
+       switch_image_t *scaled_img = codec_set->scaled_img;
 
        write_frame = codec_set->frame;
        frame = &write_frame;
@@ -1254,6 +1255,16 @@ void conference_video_write_canvas_image_to_codec_group(conference_obj_t *confer
                switch_core_codec_control(&codec_set->codec, SCC_VIDEO_GEN_KEYFRAME, SCCT_NONE, NULL, SCCT_NONE, NULL, NULL, NULL);
        }
 
+       if (scaled_img) {
+               if (!send_keyframe && codec_set->fps_divisor > 1 && (codec_set->frame_count++) % codec_set->fps_divisor) {
+                       // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Skip one frame, total: %d\n", codec_set->frame_count);
+                       return;
+               }
+
+               switch_img_scale(frame->img, &scaled_img, scaled_img->d_w, scaled_img->d_h);
+               frame->img = scaled_img;
+       }
+
        do {
 
                frame->data = ((unsigned char *)frame->packet) + 12;
@@ -2320,6 +2331,28 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
                                                                write_codecs[i]->frame.data = ((uint8_t *)write_codecs[i]->frame.packet) + 12;
                                                                write_codecs[i]->frame.packetlen = buflen;
                                                                write_codecs[i]->frame.buflen = buflen - 12;
+                                                               if (conference->scale_h264_canvas_width > 0 && conference->scale_h264_canvas_height > 0 && !strcmp(check_codec->implementation->iananame, "H264")) {
+                                                                       int32_t bw = -1;
+
+                                                                       write_codecs[i]->fps_divisor = conference->scale_h264_canvas_fps_divisor;
+                                                                       write_codecs[i]->scaled_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->scale_h264_canvas_width, conference->scale_h264_canvas_height, 16);
+
+                                                                       if (conference->scale_h264_canvas_bandwidth) {
+                                                                               if (strcasecmp(conference->scale_h264_canvas_bandwidth, "auto")) {
+                                                                                       bw = switch_parse_bandwidth_string(conference->scale_h264_canvas_bandwidth);
+                                                                               }
+                                                                       }
+
+                                                                       if (bw == -1) {
+                                                                               float fps = conference->video_fps.fps;
+
+                                                                               if (write_codecs[i]->fps_divisor) fps /= write_codecs[i]->fps_divisor;
+
+                                                                               bw = switch_calc_bitrate(conference->scale_h264_canvas_width, conference->scale_h264_canvas_height, conference->video_quality, fps);
+                                                                       }
+
+                                                                       switch_core_codec_control(&write_codecs[i]->codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, &bw, SCCT_NONE, NULL, NULL, NULL);
+                                                               }
                                                                switch_set_flag((&write_codecs[i]->frame), SFF_RAW_RTP);
 
                                                        }
@@ -2984,6 +3017,7 @@ pp                                                conference_video_set_incoming_bitrate(imember, kps, SWITCH_TRUE);
        for (i = 0; i < MAX_MUX_CODECS; i++) {
                if (write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec)) {
                        switch_core_codec_destroy(&write_codecs[i]->codec);
+                       switch_img_free(&(write_codecs[i]->scaled_img));
                }
        }
 
index 1e9902a0488aba20087e0a4ae90d4166c4e83065..791b722ce456c154205c12afa446caa7ff3d483d 100644 (file)
@@ -2411,7 +2411,12 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
        const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = NULL;
        uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = 0, video_auto_floor_msec = 0;
        switch_event_t *event;
-       
+
+       int scale_h264_canvas_width = 0;
+       int scale_h264_canvas_height = 0;
+       int scale_h264_canvas_fps_divisor = 0;
+       char *scale_h264_canvas_bandwidth = NULL;
+
        /* Validate the conference name */
        if (zstr(name)) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Record! no name.\n");
@@ -2720,6 +2725,28 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
                                } else {
                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "video-mode invalid, valid settings are 'passthrough', 'transcode' and 'mux'\n");
                                }
+                       } else if (!strcasecmp(var, "scale-h264-canvas-size") && !zstr(val)) {
+                               char *p;
+
+                               if ((scale_h264_canvas_width = atoi(val))) {
+                                       if ((p = strchr(val, 'x'))) {
+                                               p++;
+                                               if (*p) {
+                                                       scale_h264_canvas_height = atoi(p);
+                                               }
+                                       }
+                               }
+
+                               if (scale_h264_canvas_width < 320 || scale_h264_canvas_width < 180) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid scale-h264-canvas-size, falling back to 320x180\n");
+                                       scale_h264_canvas_width = 320;
+                                       scale_h264_canvas_width = 180;
+                               }
+                       } else if (!strcasecmp(var, "scale-h264-canvas-fps-divisor") && !zstr(val)) {
+                               scale_h264_canvas_fps_divisor = atoi(val);
+                               if (scale_h264_canvas_fps_divisor < 0) scale_h264_canvas_fps_divisor = 0;
+                       } else if (!strcasecmp(var, "scale-h264-canvas-bandwidth") && !zstr(val)) {
+                               scale_h264_canvas_bandwidth = val;
                        }
                }
 
@@ -2783,6 +2810,11 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
 
        conference->conference_video_mode = conference_video_mode;
 
+       conference->scale_h264_canvas_width = scale_h264_canvas_width;
+       conference->scale_h264_canvas_height = scale_h264_canvas_height;
+       conference->scale_h264_canvas_fps_divisor = scale_h264_canvas_fps_divisor;
+       conference->scale_h264_canvas_bandwidth = switch_core_strdup(conference->pool, scale_h264_canvas_bandwidth);
+
        if (!switch_core_has_video() && (conference->conference_video_mode == CONF_VIDEO_MODE_MUX || conference->conference_video_mode == CONF_VIDEO_MODE_TRANSCODE)) {
                conference->conference_video_mode = CONF_VIDEO_MODE_PASSTHROUGH;
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "video-mode invalid, only valid setting is 'passthrough' due to no video capabilities\n");
index a32510254a3e1ed89aadbe7d3a511f5f2c14c054..c7407391fdc6d4abb93460dc06c6725d6c0a52b6 100644 (file)
@@ -663,6 +663,12 @@ typedef struct conference_obj {
        video_layout_t *new_personal_vlayout;
        int max_bw_in;
        int force_bw_in;
+
+       /* special use case, scalling shared h264 canvas*/
+       int scale_h264_canvas_width;
+       int scale_h264_canvas_height;
+       int scale_h264_canvas_fps_divisor;
+       char *scale_h264_canvas_bandwidth;
 } conference_obj_t;
 
 /* Relationship with another member */
@@ -794,6 +800,9 @@ typedef struct codec_set_s {
        switch_codec_t codec;
        switch_frame_t frame;
        uint8_t *packet;
+       switch_image_t *scaled_img;
+       uint8_t fps_divisor;
+       uint32_t frame_count;
 } codec_set_t;
 
 typedef void (*conference_key_callback_t) (conference_member_t *, struct caller_control_actions *);