友善之臂视频监控方案源码学习(5) - 输入控制

更新时间:2023-05-19 22:52:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

友善之臂视频监控方案源码学习(5) - 输入控制

【问题描述】在友善之臂视频监控方案源码学习(4) - 数据流向一文中,对视频数据流向进行了简要阐述。本文对输入控制进行解析。

【解析】

1 涉及到的文件和目录

mjpg-streamer-mini2440-read-only/start_uvc.sh

mjpg-streamer-mini2440-read-only/mjpg_streamer.c

mjpg-streamer-mini2440-read-only/mjpg_streamer.h

mjpg-streamer-mini2440-read-only/plugins/input.h

mjpg-streamer-mini2440-read-only/plugins/input_uvc

2 输入结构

mjpg-streamer-mini2440-read-only/plugins目录下input.h中对input结构描述如下:

[html] view plaincopy 1. /* structure to store variables/functions for input plugin */

2. typedef struct _input input;

3. struct _input {

4. char *plugin;

5. void *handle;

6. input_parameter param;

7.

8. int (*init)(input_parameter *);

9. int (*stop)(void);

10. int (*run)(void);

11. int (*cmd)(in_cmd_type, int);

12. };

友善之臂视频监控方案源码学习(1) - 架构分析一文,指出了该方案实质上就是实现了输入、输出的接口。从输入看,就是实现了init、stop、run、cmd函数指针。主程序中实际上,只调用了init、run接口。stop接口是在信号的回调函数void signal_handler(int sig);中调用的。 3 input_init分析

(1) 定义在mjpg-streamer-mini2440-read-only/plugins/input_uvc/Input_uvc.c文件中

(2) 在mjpg-streamer-mini2440-read-only/mjpg_streamer.c 的main函数中,默认的输入为:

[html] view plaincopy

1. char *input = "input_uvc.so --resolution 640x480 --fps 5 --device /dev/vide

o0";

若-i参数不为空,则采用下述方法更新输入:

[html] view plaincopy

1.

2. 3.

4.

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

传送给Input_uvc.c中input_init的参数为:

[html] view plaincopy

1. global.in.param.parameter_string = strchr(input, ' ');

下面分析mjpg-streamer-mini2440-read-only/plugins/input_uvc/input_uvc.c中的input_init接口。接口定义如下:

[html] view plaincopy

1. int input_init(input_parameter *param);

首先,定义了一系列默认的参数:

[html] view plaincopy

2.

3.

4. int argc=1, width=640, height=480, fps=5, format=V4L2_PIX_FMT_MJPEG, i; in_cmd_type led = IN_CMD_LED_AUTO; char fourcc[5]={0,0,0,0,0};

第二,初始化互斥锁:

[html] view plaincopy

1.

2.

3.

4.

5. /* initialize the mutes variable */ if( pthread_mutex_init(&controls_mutex, NULL) != 0 ) { IPRINT("could not initialize mutex variable\n"); exit(EXIT_FAILURE); }

第三,参数解析。参数解析又分为下面几个步骤:

(a) 读取参数

[html] view plaincopy 1. 2.

3.

4.

5. argv[0] = INPUT_PLUGIN_NAME; if ( param->parameter_string != NULL && strlen(param->parameter_string) != 0 ) { char *arg=NULL, *saveptr=NULL, *token=NULL; arg=(char *)strdup(param->parameter_string);

(b) 将字符串形式的参数分解为字符串数组

[html] view plaincopy 1. if ( strchr(arg, ' ') != NULL ) {

2. token=strtok_r(arg, " ", &saveptr);

3. if ( token != NULL ) {

4. argv[argc] = strdup(token);

5. argc++;

6. while ( (token=strtok_r(NULL, " ", &saveptr)) != NULL ) { 7. argv[argc] = strdup(token);

8. argc++;

9. if (argc >= MAX_ARGUMENTS) {

10. IPRINT("ERROR: too many arguments to input plugin\n"); 11. return 1;

12. }

14. } 15. }

16. }

(c) 利用getopt函数解析参数

[html] view plaincopy 1. reset_getopt();

2. while(1) {

3. int option_index = 0, c=0;

4. static struct option long_options[] = \

5. {

6. {"h", no_argument, 0, 0},

7. {"help", no_argument, 0, 0},

8. {"d", required_argument, 0, 0},

9. {"device", required_argument, 0, 0},

10. {"r", required_argument, 0, 0},

11. {"resolution", required_argument, 0, 0},

12. {"f", required_argument, 0, 0},

13. {"fps", required_argument, 0, 0},

14. {"y", no_argument, 0, 0},

15. {"yuv", no_argument, 0, 0},

16. {"q", required_argument, 0, 0},

17. {"quality", required_argument, 0, 0},

18. {"m", required_argument, 0, 0},

19. {"minimum_size", required_argument, 0, 0},

20. {"n", no_argument, 0, 0},

21. {"no_dynctrl", no_argument, 0, 0},

22. {"l", required_argument, 0, 0},

23. {"led", required_argument, 0, 0},

24. {0, 0, 0, 0}

25. };

26.

27. /* parsing all parameters according to the list above is sufficent */ 28. c = getopt_long_only(argc, argv, "", long_options, &option_index); 该过程详细请参考友善之臂视频监控方案源码学习(2) - 主程序实现细节一文描述。 (d) 根据输入的参数执行相应的操作:

[html] view plaincopy

1. /* no more options to parse */

2. if (c == -1) break;

3.

4. /* unrecognized option */

5. if (c == '?'){

6. help();

7. return 1;

8. }

9.

10. /* dispatch the given options */

11. switch (option_index) {

12. /* h, help */

13. case 0:

14. case 1:

15. DBG("case 0,1\n");

16. help();

17. return 1;

18. break;

19.

20. /* d, device */

21. case 2:

22. case 3:

23. DBG("case 2,3\n");

24. dev = strdup(optarg);

25. break;

26.

27. /* r, resolution */

28. case 4:

29. case 5:

30. DBG("case 4,5\n");

31. width = -1;

32. height = -1;

33.

34. /* try to find the resolution in lookup table "resolutions" */ 35. for ( i=0; i < LENGTH_OF(resolutions); i++ ) {

36. if ( strcmp(resolutions[i].string, optarg) == 0 ) { 37. width = resolutions[i].width;

38. height = resolutions[i].height;

39. }

40. }

41. /* done if width and height were set */

42. if(width != -1 && height != -1)

43. break;

44. /* parse value as decimal value */

46. height = strtol(s+1, NULL, 10);

47. break;

48.

49. /* f, fps */

50. case 6:

51. case 7:

52. DBG("case 6,7\n");

53. fps=atoi(optarg);

54. break;

55.

56. /* y, yuv */

57. case 8:

58. case 9:

59. DBG("case 8,9\n");

60. format = V4L2_PIX_FMT_YUYV;

61. break;

62.

63. /* q, quality */

64. case 10:

65. case 11:

66. DBG("case 10,11\n");

67. format = V4L2_PIX_FMT_YUYV;

68. gquality = MIN(MAX(atoi(optarg), 0), 100);

69. break;

70.

71. /* m, minimum_size */

72. case 12:

73. case 13:

74. DBG("case 12,13\n");

75. minimum_size = MAX(atoi(optarg), 0);

76. break;

77.

78. /* n, no_dynctrl */

79. case 14:

80. case 15:

81. DBG("case 14,15\n");

82. dynctrls = 0;

83. break;

84.

85. /* l, led */

86. case 16:

87. case 17:

88. DBG("case 16,17\n");

90. led = IN_CMD_LED_ON;

91. } else if ( strcmp("off", optarg) == 0 ) {

92. led = IN_CMD_LED_OFF;

93. } else if ( strcmp("auto", optarg) == 0 ) {

94. led = IN_CMD_LED_AUTO;

95. } else if ( strcmp("blink", optarg) == 0 ) {

96. led = IN_CMD_LED_BLINK;

97. }

98. break;

99.

100. default:

101. DBG("default case\n");

102. help();

103. return 1;

104. }

注:步骤(c)和(d)是在while(1)循环内检测的。

第四,使全局指针指向param->param->global

[html] view plaincopy

1.

2. /* keep a pointer to the global variables */ pglobal = param->global;

这一步非常重要,视频数据信息就存储在global结构的buf变量中。

第五,构建videoIn结构

[html] view plaincopy

1.

2.

3.

4.

5.

6. videoIn = malloc(sizeof(struct vdIn)); if ( videoIn == NULL ) { IPRINT("not enough memory for videoIn\n"); exit(EXIT_FAILURE); } memset(videoIn, 0, sizeof(struct vdIn));

该结构描述如下:

[html] view plaincopy

1. struct vdIn {

2. int fd;

3. char *videodevice ;

4. unsigned char *pFramebuffer;

5. unsigned char *ptframe[OUTFRMNUMB];

6. unsigned char *mem[NB_BUFFER];

7.

8. int framelock[OUTFRMNUMB];

9. pthread_mutex_t grabmutex;

10. int framesizeIn ; 11. volatile int frame_cour;

12. int bppIn;

13. int hdrwidth; 14. int hdrheight;

15. int formatIn;

16. int signalquit;

17. struct v4l2_capability cap;

18. struct v4l2_format fmt;

19. struct v4l2_buffer buf;

20. struct v4l2_requestbuffers rb;

21.

22. int grayscale;

23. uint32_t quality;

24.

25. };

主要定义了视频输入控制变量。

第六,打开视频设备

[html] view plaincopy

1.

2.

3.

4.

5.

6. /* open video device and prepare data structure */ if (init_videoIn(videoIn, dev, width, height, fps, format, 1) < 0) { IPRINT("init_VideoIn failed\n"); closelog(); exit(EXIT_FAILURE); }

init_videoIn具体实现如下:

[html] view plaincopy

1. int init_videoIn(struct vdIn *vd, char *device, int width, int height, int fps, int format, int grabmethod)

2. {

3. if (vd == NULL || device == NULL)

4. return -1;

5. if (width == 0 || height == 0)

6. return -1;

7. if (grabmethod < 0 || grabmethod > 1)

8. grabmethod = 1; //mmap by default;

9. vd->videodevice = NULL;

10. vd->status = NULL;

11. vd->pictName = NULL;

12. vd->videodevice = (char *) calloc (1, 16 * sizeof (char)); 13. vd->status = (char *) calloc (1, 100 * sizeof (char));

14. vd->pictName = (char *) calloc (1, 80 * sizeof (char));

15. snprintf (vd->videodevice, 12, "%s", device);

16. vd->toggleAvi = 0;

17. vd->getPict = 0;

18. vd->signalquit = 1;

19. vd->width = width;

20. vd->height = height;

21. vd->fps = fps;

22. vd->formatIn = format;

23. vd->grabmethod = grabmethod;

24. if (init_v4l2 (vd) < 0) {

25. fprintf (stderr, " Init v4L2 failed !! exit fatal \n"); 26. goto error;;

27. }

28. /* alloc a temp buffer to reconstruct the pict */

29. vd->framesizeIn = (vd->width * vd->height << 1);

30. switch (vd->formatIn) {

31. case V4L2_PIX_FMT_MJPEG:

32. vd->tmpbuffer = (unsigned char *) calloc(1, (size_t) vd->framesizeIn); 33. if (!vd->tmpbuffer)

34. goto error;

35. vd->framebuffer =

36. (unsigned char *) calloc(1, (size_t) vd->width * (vd->height + 8) *

2);

37. break;

38. case V4L2_PIX_FMT_YUYV:

39. default:

40. vd->framebuffer =

41. (unsigned char *) calloc(1, (size_t) vd->framesizeIn); 42. break;

43. //fprintf(stderr, " should never arrive exit fatal !!\n"); 44. //goto error;

45. //break;

46. }

47. if (!vd->framebuffer)

48. goto error;

49. return 0;

50. error:

51. free(vd->videodevice);

52. free(vd->status);

53. free(vd->pictName);

54. close(vd->fd);

55. return -1;

56. }

主要是完成了vdIn结构的初始化操作。

第七,动态控制初始化

[html] view plaincopy

1.

2. if (dynctrls) initDynCtrls(videoIn->fd);

第八,LED初始化

[html] view plaincopy

1.

2.

3.

4.

5.

6.

7. in_cmd_type led = IN_CMD_LED_AUTO; ... /* * switch the LED according to the command line parameters (if any) */ input_cmd(led, 0);

其执行的命令定义在input_cmd函数中:

[html] view plaincopy

1.

2.

3.

case IN_CMD_LED_AUTO: res = v4l2SetControl(videoIn, V4L2_CID_LED1_MODE_LOGITECH, 3); break;

4 input_run分析

input_run看上去十分简单: [html] view plaincopy 1. int input_run(void) {

2. pglobal->buf = malloc(videoIn->framesizeIn); 3. if (pglobal->buf == NULL) {

4. fprintf(stderr, "could not allocate memory\n"); 5. exit(EXIT_FAILURE);

6. }

7.

8. pthread_create(&cam, 0, cam_thread, NULL);

9. pthread_detach(cam);

10.

11. return 0;

12. }

input_run只做了两件事:

(1) 分配视频数据存储空间

(2) 开辟视频采集线程。后续文章详细分析。

5 input_stop分析

input_stop主要功能是关闭视频采集线程

[html] view plaincopy

1.

2.

3.

4.

5.

6.

int input_stop(void) { DBG("will cancel input thread\n"); pthread_cancel(cam); return 0; }

6 input_cmd分析

该函数完成了视频输入的命令控制。在后续文章中将进行详细分析。

本文来源:https://www.bwwdw.com/article/rvq4.html

Top