/* ignore SIGPIPE (send by OS if transmitting to closed TCP sockets) */signal(SIGPIPE, SIG_IGN);// 用于忽略 SIGPIPE 信号/* register signal handler for <CTRL>+C in order to clean up */if(signal(SIGINT, signal_handler)== SIG_ERR){// SIGINT信号代表由InterruptKey产生 ,当按下 ctrl+c时,调用 signal_handler,做清理工作......}....../* open input plugin */for(i =0; i < global.incnt; i++){/* this mutex and the conditional variable are used to synchronize access to the global picture buffer 即用于传输新的帧信号 */if(pthread_mutex_init(&global.in[i].db,NULL)!=0){......}if(pthread_cond_init(&global.in[i].db_update,NULL)!=0){......}
tmp =(size_t)(strchr(input[i],' ')- input[i]);// tmp = "input_uvc.so" 字符串的长度
global.in[i].stop =0;
global.in[i].context =NULL;
global.in[i].buf =NULL;
global.in[i].size =0;
global.in[i].plugin =(tmp >0)?strndup(input[i], tmp):strdup(input[i]);// 复制前 tmp 的字符,即 global.in[i].plugin = "input_uvc.so"
global.in[i].handle =dlopen(global.in[i].plugin, RTLD_LAZY);// 打开 "input_ucv.so" 动态链接库 if(!global.in[i].handle){......}
global.in[i].init =dlsym(global.in[i].handle,"input_init");// global.in[i].init = "input_ucv.c" 里面的 input_init 函数......
global.in[i].stop =dlsym(global.in[i].handle,"input_stop");// global.in[i].stop = "input_ucv.c" 里面的 input_stop 函数......
global.in[i].run =dlsym(global.in[i].handle,"input_run");// global.in[i].run = "input_ucv.c" 里面的 input_run 函数....../* try to find optional command */
global.in[i].cmd =dlsym(global.in[i].handle,"input_cmd");// global.in[i].cmd = "input_ucv.c" 里面的 input_cmd 函数
global.in[i].param.parameters =strchr(input[i],' ');// 参数字符串为 ' ' 后面的内容,即global.in[i].param.parameters = " -f 30 -r 1080*720"for(j =0; j<MAX_PLUGIN_ARGUMENTS; j++){
global.in[i].param.argv[j]=NULL;}split_parameters(global.in[i].param.parameters,&global.in[i].param.argc, global.in[i].param.argv);// 分割参数,方便后续使用
global.in[i].param.global =&global;
global.in[i].param.id = i;if(global.in[i].init(&global.in[i].param, i)){// 调用input_uvc.c 中的 input_init 函数LOG("input_init() return value signals to exit\n");closelog();exit(0);}}/* start to read the input, push pictures into global buffer */DBG("starting %d input plugin\n", global.incnt);for(i =0; i < global.incnt; i++){......if(global.in[i].run(i)){// 启动读取数据......}}for(i =0; i < global.outcnt; i++){......
global.out[i].run(global.out[i].param.id);}/* wait for signals */pause();// 等待信号
输出组件同理
2.3.1 程序手动中断信号
/* ignore SIGPIPE (send by OS if transmitting to closed TCP sockets) */signal(SIGPIPE, SIG_IGN);// 用于忽略 SIGPIPE 信号/* register signal handler for <CTRL>+C in order to clean up */if(signal(SIGINT, signal_handler)== SIG_ERR){// SIGINT信号代表由InterruptKey产生 ,当按下 ctrl+c时,调用 signal_handler,做清理工作
void*cam_thread(void*arg){......// 当线程执行完后,会调用 cam_cleanup,做一些清理回收工作pthread_cleanup_push(cam_cleanup, in);......// 使能视频捕获设备if(video_enable(pcontext->videoIn)){......}// 当 pglobal->stop = 0时,一直执行while,当按下 Crtl+C时(signal_handler函数),pglobal->stop = 1,停止执行while(!pglobal->stop){while(pcontext->videoIn->streamingState == STREAMING_PAUSED){usleep(1);// maybe not the best way so FIXME}......if(FD_ISSET(pcontext->videoIn->fd,&rd_fds)){// 获取一帧数据if(uvcGrab(pcontext->videoIn)<0){......}......}}}
根据 main 函数传递的参数进行设置,省略的部分为解析命令参数,可以看到该函数主要为 给相关变量进行赋值
主要为 指定 端口号、IP地址、文件路径等
4.2 output_run
intoutput_run(int id){....../* create thread and pass context to thread function */pthread_create(&(servers[id].threadID),NULL, server_thread,&(servers[id]));// 等待线程结束,以便回收资源pthread_detach(servers[id].threadID);return0;}