相关概念
avatar: 针对没有摄像头的用户,使用一个默认头像作为视频来显示,显示给其他人看。
conference flags
video-muxing-personal-canvas:只能看到自己视频(看到自己的canvas),看不到彼此。
video-bridge-first-two:适用于mux模式,如果会议室中只有2个人了,他们只能互相看到对方(应该是全屏都是对方的脸)
video-mute-exit-canvas:视频被mute的用户,就没必要显示在画布上了。
video-required-for-canvas:只显示真实的视频,不显示avatar(无摄像头用户,连个头像都不能显示,阔怜!)
minimize-video-encoding:每个通道的编码输出,都使用独立的视频编码器
avatar:相关属性变量
conference profile parameters: 针对某个会议室的无视频用户
video-no-video-avatar: Path to PNG file for member without video to display.
channel variable: 针对从某个拨号方案入会的无视频用户
video_avatar_png:Path to PNG file to use when an avatar image is needed.
基本的数据结构
会议:conference_obj(核心对象)
下面是将conference里面一些基础的属性去掉,剩下的重要对象。
typedef struct conference_obj {
char *name;
...
switch_event_t *variables;
conference_video_mode_t conference_video_mode;
...
switch_codec_settings_t video_codec_settings;
...
uint32_t announce_count;
...
conference_flag_t flags[CFLAG_MAX];
member_flag_t mflags[MFLAG_MAX];
...
conference_member_t *members;
...
conference_file_node_t *fnode;
conference_file_node_t *async_fnode;
...
switch_call_cause_t cancel_cause;
conference_cdr_node_t *cdr_nodes;
conference_cdr_reject_t *cdr_rejected;
...
struct vid_helper vh[2];
struct vid_helper mh;
conference_record_t *rec_node_head;
...
mcu_canvas_t *canvases[MAX_CANVASES+1];
...
switch_fps_t video_fps;
...
video_layout_t *new_personal_vlayout;
...
} conference_obj_t;
画布:mcu_canvas_t
typedef struct mcu_canvas_s {
int width;
int height;
switch_image_t *img;
mcu_layer_t layers[MCU_MAX_LAYERS];
int res_count;
int role_count;
int total_layers;
int layers_used;
int layout_floor_id;
int refresh;
int send_keyframe;
int play_file;
int video_count;
char *video_layout_group;
switch_rgb_color_t bgcolor;
switch_rgb_color_t border_color;
switch_rgb_color_t letterbox_bgcolor;
switch_mutex_t *mutex;
switch_mutex_t *write_mutex;
switch_timer_t timer;
switch_memory_pool_t *pool;
video_layout_t *vlayout;
video_layout_t *new_vlayout;
int canvas_id;
struct conference_obj *conference;
switch_thread_t *video_muxing_thread;
int video_timer_reset;
switch_queue_t *video_queue;
int recording;
switch_image_t *bgimg;
switch_image_t *fgimg;
int playing_video_file;
int overlay_video_file;
codec_set_t *write_codecs[MAX_MUX_CODECS];
int write_codecs_count;
switch_bool_t disable_auto_clear;
} mcu_canvas_t;
图层:mcu_layer_t
typedef struct mcu_layer_s {
mcu_layer_geometry_t geometry;
int member_id;
int idx;
int tagged;
int bugged;
uint32_t screen_w;
uint32_t screen_h;
int x_pos;
int y_pos;
int banner_patched;
int mute_patched;
int avatar_patched;
int refresh;
int clear;
int is_avatar;
int crop_x;
int crop_y;
int crop_w;
int crop_h;
int last_w;
int last_h;
uint32_t img_count;
switch_image_t *img;
switch_image_t *cur_img;
switch_image_t *overlay_img;
switch_image_t *banner_img;
switch_image_t *logo_img;
switch_image_t *mute_img;
switch_img_txt_handle_t *txthandle;
conference_file_node_t *fnode;
switch_img_position_t logo_pos;
switch_img_fit_t logo_fit;
struct mcu_canvas_s *canvas;
int need_patch;
conference_member_t *member;
switch_frame_t bug_frame;
switch_frame_geometry_t last_geometry;
switch_frame_geometry_t auto_geometry;
switch_frame_geometry_t zoom_geometry;
switch_frame_geometry_t pan_geometry;
switch_frame_geometry_t manual_geometry;
mcu_layer_cam_opts_t cam_opts;
switch_mutex_t *overlay_mutex;
switch_core_video_filter_t overlay_filters;
int manual_border;
} mcu_layer_t;
会议、画布、图层关系
- 一个会议室,包含多个画布,最多为MAX_CANVASES+1 = 21
- 一个画布,包含多个图层,最多为MCU_MAX_LAYERS = 64
简陋的时序图
放音方法调用时序
conference_video_muxing_thread_run代码主要流程
- 首先来一个死循环
只要conference模块还在跑,刚申请的会议室还么释放,会议室还是mux模式,就循环到地老天荒。while (conference_globals.running && !conference_utils_test_flag(conference, CFLAG_DESTRUCT) && conference_utils_test_flag(conference, CFLAG_VIDEO_MUXING)) {
...
}
conference_function:
2456行调用conference_video_launch_muxing_write_thread
conference_video_muxing_write_thread_run:
用于启动视频帧发送线程,不断的从pop视频帧,然后发送:pop_status = switch_frame_buffer_pop(member->fb, &pop);