相关概念
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);
