日期:2014-05-16  浏览次数:21170 次

【GamingAnywhere源码分析之知识补充六】Windows多线程信号通信与GA整体框架修改

        关于GamingAnywhere整体框架的修改也已经结束了一段时间了,这段时间云游戏项目暂时停滞了,原因是:别的项目组人员不足,上级领导又被boss催的紧,直属上级领导都调去别的组了,so,我也不能幸免。但是,已经做了的东西,一定要把自己的思路与理解记录下来,不然等自己回过头来看的时候又会花很多时间去理解原本已经明白的事情。这一篇涉及到GamingAnywhere整体大的框架,虽然改动的不多,而且现在回过头来看,对它的整个实现框架也很清晰明了了。

        在改篇文章中,将会涉及以下内容:

        1> GamingAnywhere整体框架修改需求

        2> GamingAnywhere整体框架运作流程与修改思路

        3> Windows多线程信号通信介绍(互斥锁、条件变量)

第一部分:GamingAnywhere整体框架修改需求

        GamingAnywhere整体框架修改的目的是实现捕捉方式的动态可配置性,即GamingAnywhere原有的捕捉方式和当前我们使用的采用nvidia显卡进行捕捉的方式的动态可配置性,具体来说就是我从一款游戏的配置文件中通过设置,可以决定它的捕捉方式,采用或不采用nvidia进行捕捉。

第二部分:GamingAnywhere整体框架运作流程与修改思路

        下面我认为是GamingAnywhere最核心的运作流程图(不包含具体捕捉和协议层的通信):

                                             

        GamingAnywhere中的核心模块拆开来看无非就是这么几个:窗口挂载钩子实现游戏画面捕捉模块、图像格式转换(由rgb转为yuv)模块、数据进行h.264压缩模块以及涉及到协议的通信模块,其中游戏画面捕捉后源数据的存放、图像格式的转换,以及数据压缩的实现就是由上面这几个线程实现的。

        下面简单描述一下这几个模块的运作方式以及是如何协同工作的,GA中模块都是进行动态加载的,即:分别经历load_modules()、init_modules()以及run_modules()实现动态加载。load_modules()完成的工作是:1) 加载对应模块的dll文件。2) 获取模块中实现函数的函数指针,GamingAnywhere中的模块一般就实现两个函数,即初始化以及线程处理函数,以filter_RGB2YUV模块为例:它实现了filter_RGB2YUV_init()和filter_RGB2YUV_threadproc()函数。load_modules的核心代码,一看便知:

struct ga_module *
ga_load_module(const char *modname, const char *prefix) {
	char fn[1024];
	struct ga_module m, *pm;
#ifdef WIN32
	snprintf(fn, sizeof(fn), "%s.dll", modname);
#elif defined __APPLE__
	snprintf(fn, sizeof(fn), "%s.dylib", modname);
#else
	snprintf(fn, sizeof(fn), "%s.so", modname);
#endif
	if((m.handle = dlopen(fn, RTLD_NOW|RTLD_LOCAL)) == NULL) {
		ga_error("ga_load_module: load module (%s) failed - %s.\n", fn, dlerror());
		return NULL;
	}
	//
	m.init = (int (*)(void*)) ga_module_loadfunc(m.handle, prefix, "init");
	m.threadproc = (void* (*)(void*)) ga_module_loadfunc(m.handle, prefix, "threadproc");;
	m.deinit = (void (*)(void*)) ga_module_loadfunc(m.handle, prefix, "deinit");
	m.notify = (int (*)(void*,int)) ga_module_loadfunc(m.handle, prefix, "notify");
	// nothing exports?
	if(m.init == NULL
	&& m.threadproc == NULL
	&& m.deinit == NULL
	&& m.notify == NULL) {
		ga_error("ga_load_module: [%s] does not export nothing.\n", fn);
		ga_unload_module(&m);
		return NULL;
	}
	//
	if((pm = (struct ga_module*) malloc(sizeof(m))) == NULL) {
		ga_error("ga_load_module: [%s] malloc failed - %s\n", fn, strerror(errno));
		return NULL;
	}
	bcopy(&m, pm, sizeof(m));
	mlist[pm] = pm;
	//
	return pm;
}
         init_modules()负责执行模块的初始化工作,核心代码很简单,就是根据init的函数指针执行init的函数:

int
ga_init_single_module(const char *name, struct ga_module *m, void *arg) {
	if(m->init == NULL)
		return 0;
	if(m->init(arg) < 0) {
		ga_error("%s init failed.\n", name);
		return -1;
	}
	return 0;
}
        run_modules()就是实现模块的实际运行,实质上它是创建一个线程,然后去执行模块中的threadproc函数,即: