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;
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;
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);
}
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));
}
}
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");
} 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;
}
}
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");
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 */
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 *);