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

来源:互联网 发布:2017手机淘宝修改差评 编辑:程序博客网 时间:2024/05/18 01:26

转载于http://blog.csdn.net/tandesir/article/details/8437272

【问题描述】在友善之臂视频监控方案源码学习(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/video0";  

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

[html] view plaincopy
  1. /* i, input */  
  2.       case 2:  
  3.       case 3:  
  4.         input = strdup(optarg);  
  5.         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
  1. char *argv[MAX_ARGUMENTS]={NULL}, *dev = "/dev/video0", *s;  
  2. int argc=1width=640height=480fps=5format=V4L2_PIX_FMT_MJPEG, i;  
  3. in_cmd_type led = IN_CMD_LED_AUTO;  
  4. char fourcc[5]={0,0,0,0,0};  

第二,初始化互斥锁:

[html] view plaincopy
  1. /* initialize the mutes variable */  
  2.  if( pthread_mutex_init(&controls_mutex, NULL) != 0 ) {  
  3.    IPRINT("could not initialize mutex variable\n");  
  4.    exit(EXIT_FAILURE);  
  5.  }  

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

(a) 读取参数

[html] view plaincopy
  1. argv[0] = INPUT_PLUGIN_NAME;  
  2.   if ( param->parameter_string != NULL && strlen(param->parameter_string) != 0 ) {  
  3.     char *arg=NULL, *saveptr=NULL, *token=NULL;  
  4.   
  5.     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.           }  
  13.         }  
  14.       }  
  15.     }  
  16.   }  

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

[html] view plaincopy
  1. reset_getopt();  
  2.   while(1) {  
  3.     int option_index = 0c=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 */  
  45.         width  = strtol(optarg, &s, 10);  
  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");  
  89.         if ( strcmp("on", optarg) == 0 ) {  
  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. /* keep a pointer to the global variables */  
  2.   pglobal = param->global;  

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

第五,构建videoIn结构

[html] view plaincopy
  1. videoIn = malloc(sizeof(struct vdIn));  
  2.   if ( videoIn == NULL ) {  
  3.     IPRINT("not enough memory for videoIn\n");  
  4.     exit(EXIT_FAILURE);  
  5.   }  
  6.   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. /* open video device and prepare data structure */  
  2.   if (init_videoIn(videoIn, dev, width, height, fps, format, 1) < 0) {  
  3.     IPRINT("init_VideoIn failed\n");  
  4.     closelog();  
  5.     exit(EXIT_FAILURE);  
  6.   }  

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. if (dynctrls)  
  2.     initDynCtrls(videoIn->fd);  

第八,LED初始化

[html] view plaincopy
  1. in_cmd_type led = IN_CMD_LED_AUTO;  
  2. ...  
  3. /*  
  4.    * switch the LED according to the command line parameters (if any)  
  5.    */  
  6.   input_cmd(led, 0);  
  7.    

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

[html] view plaincopy
  1. case IN_CMD_LED_AUTO:  
  2.       res = v4l2SetControl(videoIn, V4L2_CID_LED1_MODE_LOGITECH, 3);  
  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. int input_stop(void) {  
  2.   DBG("will cancel input thread\n");  
  3.   pthread_cancel(cam);  
  4.   
  5.   return 0;  
  6. }  

 

6 input_cmd分析

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

 


 【源码下载】

http://download.csdn.net/detail/tandesir/4915905

 

 

转载请标明出处,仅供学习交流,勿用于商业目的

Copyright @ http://blog.csdn.net/tandesir

阅读全文
0 0
原创粉丝点击