CAVE系统是在GamingAnyWhere平台的服务端上进行搭建的,因此首先要对这个平台有一定的了解。GamingAnywhere的服务端包括RTSP server,audio source,video source,input replayer四部分。video source模块获取游戏画面有两种方式,分别是ga-server-periodic的录屏方式和ga-sever-event-driven的hook方式,ga-server-perodic方式介绍如下:
ga-server-perodic线程整体流程图
(1)ga_conf_load用于解析出server.d3dex-rc.conf文件里include的各种conf文件,并将所有的配置加载到ga_vars变量中去。ga_conf_readv(key, buf, sizeof(buf))函数的作用是从ga_vars中找到key对应的值,并存储在buf中。
(2)rtspconf_parse将主要用到的配置加载到变量conf中去。
(3)ga_crop_window找到满足要求的窗口。
一、重点关注run_modules函数
主线程如以下流程图所示:
vsource_start和filter_RGB2YUV_start
- vsource_start创建线程,执行vsource_threadproc()函数,
函数作用为创建video source线程,检测encoder是否运行,没有运行则不断等待;encoder运行后开始捕捉画面。 - filter_RGB2YUV_start()创建线程,执行 filter_RGB2YUV_threadproc函数,函数作用为将捕获的RGB画面转化为YUV。函数在dpipe_load()处等待客户端的连接。
register
(1)encoder_register_vencoder传递vencoder_param;
(2)encoder_register_rc传递rc_param
live_server_start(live555)
- env->taskScheduler().doEventLoop()
程序开始进入无限循环,不断查看事件队列中是否有事件去处理,有则处理,没有则短暂休眠。
- 接收到client的连接请求后,调用位于encoder-common.cpp中的函数encoder_register_client(),如下图所示,能从堆栈中看出调用该函数的顺序:
encode_register_client()内部工作流程图:
(vrc_init,vrc_start在rc.cpp中,aencoder_init在encoder-audio.cpp中)
(1)vrc_start创建新线程,执行vrc_cave_roi_lambda_threadproc函数:
计算得到的qp_map要存储在rc_map-0 pipe中,在vencoder_start中被读取。
(2)vencoder_start在dipe_load(filter-0)处等待,
二、需要特别关注的pipe
- 注意服务端整个处理过程中存储画面和声音的buffer:
(1)相关函数:
dpipe_get()提供可以存放帧的地址;
dpipe_load从buffer中load出output的第一帧(当output pool buffer中没有帧时需要等待);
dpipe_lookup()根据name查找相应的dpipe。
(2)vencoder_param有四种pipe:filter-0,rc_filter-0,bitrates-0,rc_map-0.
(3)rc_param有四种pipe:rc_filter-0,filter_d-0,rc_map-0,bitrates-0.
存在的问题
- rc.cpp中打开roi0.txt文件,roi0.txt应该放在什么位置?debug路径下打开失败。
参考文献
[1] M. Hegazy, K. Diab, M. Saeedi, B. Ivanovic, I. Amer, Y. Liu, G. Sines, and M. Hefeeda. Content-aware video encoding for cloud gaming. In Proceedings of the 10th ACM Multimedia Systems Conference,2019.
[2] https://github.com/mohamedhegazy/CAVE.git.