Mjpeg-streamer源码学习笔记-Main-get_long_only(一)

2023-11-30 12:18

本文主要是介绍Mjpeg-streamer源码学习笔记-Main-get_long_only(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目标文件:mjpg-stream/mjpg-stream.c

这一篇的主要难点是get_long(),get_long_only().

新手写,有不对的请大神指正,鼓励。

本人参考文章:

http://www.360doc.com/content/13/0913/13/13876325_314174121.shtml

http://blog.sina.com.cn/s/blog_a31ff26901013l22.html


---------------------------------------------------------------------------------------------------------------------------

一:直接对主函数main分析。遇到具体情况,具体往下延伸。

//char *input  = "input_uvc.so --resolution 640x480 --fps 5 --device /dev/video0";
    char *input[MAX_INPUT_PLUGINS];/* 这里MAX_INPUT_PLUGINS在.h文件中定为10 */
    char *output[MAX_OUTPUT_PLUGINS]; /* 一个输入最大可以对应10个输出 */
    int daemon = 0, i;/* 守护进程变量,守护进程作为重点,下一篇详述 */
    size_t tmp = 0;
    output[0] = "output_http.so --port 8080";/* 默认情况下将video0作为输入,http的8080端口作为输出 */
    global.outcnt = 0;/* 代码中 参数行操作的计数 */

---------------------------------------------------------------------------------------------------------------------------

二:下面是一个while()循环,来解析main()函数后面所带的参数

/* parameter parsing */
 while(1) {
 int option_index = 0, c=0;
 static struct option long_options[] = \ /* 长选项表,进行长选项的比对 */
 {
  {"h", no_argument, 0, 0},  /* 第一个参数为选项名,前面没有短横线。譬如"help"、"verbose"之类 */
  {"help", no_argument, 0, 0},  /* 第二个参数描述了选项是否有选项参数 |no_argument 0 选项没有参数|required_argument 1 选项需要参数|optional_argument 2 选项参数可选|*/
  {"i", required_argument, 0, 0},  /* 第三个参数指明长选项如何返回,如果flag为NULL,则getopt_long返回val。
  {"input", required_argument, 0, 0},  * 否则返回0,flag指向一个值为val的变量。如果该长选项没有发现,flag保持不变.
  {"o", required_argument, 0, 0},   */
  {"output", required_argument, 0, 0}, /* 第四个参数是发现了长选项时的返回值,或者flag不是NULL时载入*flag中的值 */
  {"v", no_argument, 0, 0},
  {"version", no_argument, 0, 0},
  {"b", no_argument, 0, 0},  /* 每个长选项在长选项表中都有一个单独条目,该条目里需要填入正确的数值。数组中最后的元素的值应该全是0。
  {"background", no_argument, 0, 0},  *数组不需要排序,getopt_long()会进行线性搜索。但是,根据长名字来排序会使程序员读起来更容易. 
  {0, 0, 0, 0}     */     
 };

---------------------------------------------------------------------------------------------------------------------------

三:接下来是getopt_long_only函数,重点分析

---------------------------------------------------------------------------------------------------------------------------

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;
 }
 }

---------------------------------------------------------------------------------------------------------------------------

代码里出现了help自定义函数,一个switch选择结构,c为flag作为判断标准,同时c也是getopt_long_only的返回值。

strdup函数,变量optarg,变量daemon


3.1 get_long_only函数:


#include <getopt.h>

int getopt_long_only(int argc, char * const argv[],

                     const char *optstring, const struct option *longopts, int *longindex);


说明:函数中的参数说明

~1+2 argc和argv通常直接从main()到两个参数传递而来

~3 optsting是选项参数组成的字符串,如果该字符串里任一字母后有冒号,那么这个选项就要求有参数

~4 下一个参数是指向数组的指针,这个数组是option结构数组,option结构称为长选项表,

其声明如下:

struct option 

{

     const char *name;

     int has_arg;

     int *flag;

     int val;

};

_1 const char *name:选项名,前面没有短横线。譬如"help"、"verbose"之类。

_2 int has_arg:描述长选项是否有选项参数,如果有,是哪种类型的参数,其值见下表:

----------------------------------------------------

符号常量             数值            含义

no_argument            0            选项没有参数

required_argument      1            选项需要参数

optional_argument      2            选项参数是可选的

----------------------------------------------------

_3 int *flag:

如果该指针为NULL,那么getopt_long返回val字段的值;

如果该指针不为NULL,那么会使得它所指向的结构填入val字段的值,同时getopt_long返回0

_4 int val:

如果flag是NULL,那么val通常是个字符常量,如果短选项和长选项一致,那么该字符就应该与optstring中出现的这个选项的参数相同;


~5 :longindex参数一般赋为NULL即可;如果没有设置为NULL,那么它就指向一个变量,这个变量会被赋值为寻找到的长选项在longopts中的索引值,这可以用于错误诊断。


对于options类型参数可以有两种方式:

1)短选项(short options):顾名思义,就是短小参数。它们通常包含一个连字号和一个字母(大写或小写字母)。例如:-s,-h等。

2)长选项(long options):长选项,包含了两个连字号和一些大小写字母组成的单词。例如,--size,--help等。


记住几种常见返回值:

(a)每次调用该函数,它都会分析一个选项,并且返回它的短选项,如果分析完毕,即已经没有选项了,则会返回-1

(b)如果getopt_long_only或者getopt_long在分析选项时,遇到一个没有定义过的选项,则返回值为‘?’,此时,程序员可以打印出所定义命令行的使用信息给用户。

(c)当处理一个带参数的选项时,全局变量optarg会指向它的参数

(d)当函数分析完所有参数时,全局变量optind(into argv)会指向第一个‘非选项’的位置


讲了这么多。还是抽象。上实例解析getopt:

(getopt_long和getopt_long_only类似,以getlong讲解,参数是一样的)

实例1:

#include <stdio.h>

#include <getopt.h>

char *l_opt_arg;

char* const short_options = "nbl:";

struct option long_options[] = {

{ "name",     0,   NULL,    'n'     },

{ "bf_name",  0,   NULL,    'b'     },

{ "love",     1,   NULL,    'l'     },

     0,     0,     0,     0},

};

int main(int argc, char *argv[])

{

int c;

while((c = getopt_long (argc, argv, short_options, long_options, NULL)) != -1)

{

switch (c)

{

case 'n':

printf("My name is XL.\n");

break;

case 'b':

printf("His name is ST.\n");

break;

case 'l':

l_opt_arg = optarg;

printf("Our love is %s!\n", l_opt_arg);

break;

}

}

return 0;

}

编译并运行:

[root@localhost liuxltest]# gcc -o getopt getopt.c

[root@localhost liuxltest]# ./getopt -n -b -l forever

My name is XL.

His name is ST.

Our love is forever!

[root@localhost liuxltest]#

[root@localhost liuxltest]# ./getopt -nb -l forever

My name is XL.

His name is ST.

Our love is forever!

[root@localhost liuxltest]# ./getopt -nbl forever

My name is XL.

His name is ST.

Our love is forever!


编译结果分析:

char* const short_options = "nbl:";这一句,表示nb不需要参数,l需要参数  

无冒号不要参数,一个冒号需要参数,两个冒号参数可选.

所以forever是-l命令的参数.故需要char *l_opt_arg;

如我有一个程序,有两个选项,-a, -b, 我输入的时候是  ./a.out  -a -b, 那么中间会处理成这种 ab这种字符串的形式

这就解释了-nbl的输入

现在对于处理命令行参数的操作是不是明朗一点了。


再看个例子

实例2:

#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
char *l_opt_arg;
const char* const short_options = "myl:";
struct option long_options[] = {
        { "name",      0,   NULL,    'm'}, //长选项对应的短选项参数, 第二个0表示选项后面无参数, 1为有参数,2为可选
        { "yourname",  0,   NULL,    'y'},
        { "love",      1,   NULL,    'l'},
        {      0,      0,      0,     0},
};
int main(int argc, char *argv[])
{
        int c, i;

        printf("before:\n");
        for (i = 1; i < argc; i++)
                printf("arg:%d\r\targv:%s\n", i, argv[i]);
        printf("\n");

        while((c = getopt_long (argc, argv, short_options, long_options, NULL)) != -1)
        {
               
                switch (c)
                {
                        case 'm':
                                printf("My name is A.\n");
                                break;
                        case 'y':
                                printf("His name is B.\n");
                                break;
                        case 'l':
                                l_opt_arg = optarg;
                                printf("Our love is %s!\n", l_opt_arg);
                                break;
                }
        }
        printf("optind:%d\n", optind);

        printf("\nafter:\n");
        for (i=1; i<argc; i++)
                printf("arg:%d\r\targv:%s\n", i, argv[i]);
        printf("................................\n");
        for (i = optind; i < argc; i++)
                printf("arg:%d\rargv:%s\n",i,argv[i]);
        return 0;
}

注意,此程序可接收的的选项有三个, 一个是m ,不带参数, y 不带参数, l  要求有参数。

那如果-m 不带参数,如果我写了参数,会怎么样呢?下面看测试

第一种:

$ ./a.out -m -y
before:
arg:1 : -m
arg:2 : -y
My name is A.
His name is B.
optind:3
after:
arg:1 : -m
arg:2 : -y

第二种:

$ ./a.out -m -y -l banana
before:
arg:1 : -m
arg:2 : -y
arg:3 : -l
arg:4 : banana
My name is A.
His name is B.
Our love is banana!
optind:5
after:
arg:1 : -m
arg:2 : -y
arg:3 : -l
arg:4 : banana

第三种

$./a.out -m lisi -y zhangsan  -l banana  aaa
before:
arg:1 : -m
arg:2 : lisi
arg:3 : -y
arg:4 : zhangsan
arg:5 : -l
arg:6 : banana
arg:7 : aaa
My name is A.
His name is B.
Our love is banana!
optind:5
after:
arg:1 : -m
arg:2 : -y
arg:3 : -l
arg:4 : banana
arg:5 : lisi
arg:6 : zhangsan
arg:7 : aaa

第三种里:注意 argv 里面值的顺序已经和原来不一样了,对命令行的参数重新组织了一下顺序,也就是不认识的命令行参数,都放在了argv的最后,其中 optind 指向了这些没有被解释的参数的第一个。

optind有作用吧!因为5,6,7不通过解析。


附:如果是长参数,则使用 --, 如 --help, 因为 -help时,(选项不需要参数的情况) 会把它当成 四个选项, -h -e -l -p. 所以使用长参数时,要用两个 横线 --。


小结末尾。提一下optind,optarg,opterr三个参数.

optind:每当解析完一个argv,optind就会递增

optarg:如果选项带参数,参数保存在optarg中。如果选项带可选参数,而实际无参数时,optarg为NULL

opterr:当解析错误时,如果opterr为1则自动打印一条错误消息(默认),否则不打印。

这里是getopt.h中的注释。有兴趣的自己翻译翻译哦.

/* For communication from `getopt' to the caller.When `getopt' finds an option that takes an argument,the argument value is returned here.Also, when `ordering' is RETURN_IN_ORDER,each non-option ARGV-element is returned here.  */extern char *optarg;/* Index in ARGV of the next element to be scanned.This is used for communication to and from the callerand for communication between successive calls to `getopt'.On entry to `getopt', zero means this is the first call; initialize.When `getopt' returns EOF, this is the index of the first of thenon-option elements that the caller should itself scan.Otherwise, `optind' communicates from one call to the nexthow much of ARGV has been scanned so far.  */extern int optind;/* Callers store zero here to inhibit the error message `getopt' printsfor unrecognized options.  */extern int opterr;


3.2 Help函数

就在这个c文件里.代码就不全贴了。就只贴一部分

---------------------------------------------------------------------------------------------------------------------------

fprintf(stderr, "Usage: %s\n" \
            "  -i | --input \"<input-plugin.so> [parameters]\"\n" \
            "  -o | --output \"<output-plugin.so> [parameters]\"\n" \
            " [-h | --help ]........: display this help\n" \
            " [-v | --version ].....: display version information\n" \
            " [-b | --background]...: fork to the background, daemon mode\n", progname);

---------------------------------------------------------------------------------------------------------------------------

大家应该很熟悉的格式,就是Linux的help结构  一个命令的延伸,如ls -l ,ls -c,ls -u等等。

总之,他就是一个Switch帮助函数。


3.3 strdup函数

 /* i, input */
 case 2:
 case 3:
 input = strdup(optarg);
 break;

没见过strdup这个函数。故度娘之~

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

extern char *strdup(char *s);

头文件:string.h

功  能: 将串拷贝到新建的位置处

strdup()在内部调用了malloc()为变量分配内存,不需要使用返回的字符串时,需要用free()释放相应的内存空间,否则会造成内存泄漏。

返回一个指针,指向为复制字符串分配的空间;如果分配空间失败,则返回NULL值。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------


既然提到malloc,那就比较一下,而且都是和free()搭配使用的。


---------------------------------------------------------------------------------------------------------------------------------------------------------------------

extern void *malloc(unsigned int num_bytes);

如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

可以看到区别,前者返回字符串,后者返回的是一个空指针,故malloc范围比strdup大。同时malloc中运用类型强制转换

也是家常便饭。

OK,继续下一段代码解析。


四:系统记录相关

--------------------------------------------------------------------------------------------------------------------

    openlog("MJPG-streamer ", LOG_PID | LOG_CONS, LOG_USER);
//openlog("MJPG-streamer ", LOG_PID|LOG_CONS|LOG_PERROR, LOG_USER);
    syslog(LOG_INFO, "starting application");

--------------------------------------------------------------------------------------------------------------------

2次度娘后。

--------------------------------------------------------------------------------------------------------------------

功能:记录至系统记录。
头文件:#include <syslog.h>
语法: int syslog(int priority, string message);
返回值: 整数

LOG_INFO:情报信息,正常的系统消息,比如骚扰报告,带宽数据等,不需要处理。
--------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------

功能:用于打开系统记录。
头文件:#include <syslog.h>
语法: void openlog(const char *ident, int option, int facility);

LOG_CONS
直接写入系统控制台,如果有一个错误,同时发送到系统日志记录。

LOG_PID
包括每个消息的PID。

LOG_USER (default)
generic user-level messages

--------------------------------------------------------------------------------------------------------------------

更多可能参数值,度娘~

由于接下来的代码和守护进程有关,而本人又不熟悉。故在下一篇中详细学习以及总结。

转自:http://blog.csdn.net/s419101357/article/details/11827699

这篇关于Mjpeg-streamer源码学习笔记-Main-get_long_only(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/436996

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识