转载于http://blog.csdn.net/tandesir/article/details/8373205
【问题描述】在 友善之臂视频监控方案源码学习(1) - 架构分析一文中,对程序执行的步骤简单的进行了描述,本文对该过程的一些细节进行总结。
【解析】
(1) 日志代码
日志记录可调用syslog.h提供的syslog,closelog函数。syslog()接口定义如下:
- int syslog(int priority, string message);
该函数指定了优先级和日志信息。
closelog()接口定义如下:
- void closelog( void ) ;
该方案对日志进行了封装:
- #define LOG(...) { char _bf[1024] = {0}; snprintf(_bf, sizeof(_bf)-1, __VA_ARGS__); fprintf(stderr, "%s", _bf); syslog(LOG_INFO, "%s", _bf); }
该封装使用了可变参数。
示例1
- LOG("setting signal to stop\n");
经展开得:
- { char _bf[1024] = {0}; snprintf(_bf, sizeof(_bf)-1, "setting signal to stop\n"); fprintf(stderr, "%s", _bf); syslog(6, "%s", _bf); };
示例2
- #define SOURCE_VERSION "2.0"
- LOG("MJPG Streamer Version.: %s\n", SOURCE_VERSION);
经展开得:
- { char _bf[1024] = {0}; snprintf(_bf, sizeof(_bf)-1, "MJPG Streamer Version.: %s\n", "2.0"); fprintf(stderr, "%s", _bf); syslog(6, "%s", _bf); };
(2) 调试技巧
调试代码进行了封装:
- #ifdef DEBUG
- #define DBG(...) fprintf(stderr, " DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); fprintf(stderr, __VA_ARGS__)
- #else
- #define DBG(...)
- #endif
示例
- DBG("all plugin handles closed\n");
经展开得:
- fprintf(stderr, " DBG(%s, %s(), %d): ", "test.c", __FUNCTION__, 9);;
(3) 参数解析的具体实现
参数解析实现代码如下所示:
- /* parameter parsing */
- while(1) {
- int option_index = 0, c=0;
- static struct option long_options[] = \
- {
- {"h", no_argument, 0, 0},
- {"help", no_argument, 0, 0},
- {"i", required_argument, 0, 0},
- {"input", required_argument, 0, 0},
- {"o", required_argument, 0, 0},
- {"output", required_argument, 0, 0},
- {"v", no_argument, 0, 0},
- {"version", no_argument, 0, 0},
- {"b", no_argument, 0, 0},
- {"background", no_argument, 0, 0},
- {0, 0, 0, 0}
- };
- c = getopt_long_only(argc, argv, "", long_options, &option_index);
- /* no more options to parse */
- if (c == -1) break;
- /* unrecognized option */
- if(c=='?'){ help(argv[0]); return 0; }
- switch (option_index) {
- /* h, help */
- case 0:
- case 1:
- help(argv[0]);
- return 0;
- break;
- /* i, input */
- case 2:
- case 3:
- input = strdup(optarg);
- break;
- /* o, output */
- case 4:
- case 5:
- output[global.outcnt++] = strdup(optarg);
- break;
- /* v, version */
- case 6:
- case 7:
- printf("MJPG Streamer Version: %s\n" \
- "Compilation Date.....: %s\n" \
- "Compilation Time.....: %s\n", SOURCE_VERSION, __DATE__, __TIME__);
- return 0;
- break;
- /* b, background */
- case 8:
- case 9:
- daemon=1;
- break;
- default:
- help(argv[0]);
- return 0;
- }
- }
(a) struct option的原型
- struct option
- {
- #if defined (__STDC__) && __STDC__
- const char *name;
- #else
- char *name;
- #endif
- /* has_arg can't be an enum because some compilers complain about
- type mismatches in all the code that assumes it is an int. */
- int has_arg;
- int *flag;
- int val;
- };
name:不带短横线的选项名,前面没有短横线。譬如“help”、“verbose”之类。
ihas_arg: 描述了选项是否有选项参数。如果有,是哪种类型的参数。此时,它的值一定是下表中的一个。符号常量数值含义
no_argument 0 选项没有参数
required_argument 1 选项需要参数
optional_argument 2 选项参数可选
flag:指明长选项如何返回,如果flag为NULL,则getopt_long返回val。否则返回0,flag指向一个值为val的变量。如果该长选项没有发现,flag保持不变;
val:指明返回的值,或者需要加载到被flag所指示的变量中。
(b) getopt_long_only原型
- int getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
具体实现:http://download.csdn.net/detail/tandesir/4917037
若解析成功,则返回0。错误情况(包括选项含糊不明确或者无关参数),返回'?。若解析终止,则返回-1。
(c) 过程分析
start_uvc_yuv.sh之类的shell脚本执行类似语句:
- ./mjpg_streamer -o "output_http.so -w ./www" -i "input_uvc.so -y -d /dev/video2"
main函数执行后,首先利用getopt_long_only查看传入的参数是否在定义的long_options列表中。若存在于列表中,则解析对应的索引值option_index,然后根据索引值判断执行何种命令。
(4) 默认插件
默认的输入插件为
- char *input = "input_uvc.so --resolution 640x480 --fps 5 --device /dev/video0";
默认的输出插件为
- output[0] = "output_http.so --port 8080";
输出插件结构中包含一个插件计数器,如果在main的参数列表中没有新的插件,则采用默认插件
- /* check if at least one output plugin was selected */
- if ( global.outcnt == 0 ) {
- /* no? Then use the default plugin instead */
- global.outcnt = 1;
- }
【源码下载】
http://download.csdn.net/detail/tandesir/4915905
转载请标明出处,仅供学习交流,勿用于商业目的
Copyright @ http://blog.csdn.net/tandesir