您的位置:首页 > 运维架构

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

2013-09-21 13:49 375 查看
转载于/article/1409493.html

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

/* structure to store variables/functions for input plugin */

typedef struct _input input;

struct _input {

char *plugin;

void *handle;

input_parameter param;

int (*init)(input_parameter *);

int (*stop)(void);

int (*run)(void);

int (*cmd)(in_cmd_type, int);

};

友善之臂视频监控方案源码学习(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

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

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

[html] view
plaincopy

/* i, input */

case 2:

case 3:

input = strdup(optarg);

break;

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

[html] view
plaincopy

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

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

[html] view
plaincopy

int input_init(input_parameter *param);

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

[html] view
plaincopy

char *argv[MAX_ARGUMENTS]={NULL}, *dev = "/dev/video0", *s;

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

/* 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

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

if ( strchr(arg, ' ') != NULL ) {

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

if ( token != NULL ) {

argv[argc] = strdup(token);

argc++;

while ( (token=strtok_r(NULL, " ", &saveptr)) != NULL ) {

argv[argc] = strdup(token);

argc++;

if (argc >= MAX_ARGUMENTS) {

IPRINT("ERROR: too many arguments to input plugin\n");

return 1;

}

}

}

}

}

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

[html] view
plaincopy

reset_getopt();

while(1) {

int option_index = 0, c=0;

static struct option long_options[] = \

{

{"h", no_argument, 0, 0},

{"help", no_argument, 0, 0},

{"d", required_argument, 0, 0},

{"device", required_argument, 0, 0},

{"r", required_argument, 0, 0},

{"resolution", required_argument, 0, 0},

{"f", required_argument, 0, 0},

{"fps", required_argument, 0, 0},

{"y", no_argument, 0, 0},

{"yuv", no_argument, 0, 0},

{"q", required_argument, 0, 0},

{"quality", required_argument, 0, 0},

{"m", required_argument, 0, 0},

{"minimum_size", required_argument, 0, 0},

{"n", no_argument, 0, 0},

{"no_dynctrl", no_argument, 0, 0},

{"l", required_argument, 0, 0},

{"led", required_argument, 0, 0},

{0, 0, 0, 0}

};

/* parsing all parameters according to the list above is sufficent */

c = getopt_long_only(argc, argv, "", long_options, &option_index);

该过程详细请参考友善之臂视频监控方案源码学习(2) - 主程序实现细节一文描述。

(d) 根据输入的参数执行相应的操作:

[html] view
plaincopy

/* no more options to parse */

if (c == -1) break;

/* unrecognized option */

if (c == '?'){

help();

return 1;

}

/* dispatch the given options */

switch (option_index) {

/* h, help */

case 0:

case 1:

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

help();

return 1;

break;

/* d, device */

case 2:

case 3:

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

dev = strdup(optarg);

break;

/* r, resolution */

case 4:

case 5:

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

width = -1;

height = -1;

/* try to find the resolution in lookup table "resolutions" */

for ( i=0; i < LENGTH_OF(resolutions); i++ ) {

if ( strcmp(resolutions[i].string, optarg) == 0 ) {

width = resolutions[i].width;

height = resolutions[i].height;

}

}

/* done if width and height were set */

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

break;

/* parse value as decimal value */

width = strtol(optarg, &s, 10);

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

break;

/* f, fps */

case 6:

case 7:

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

fps=atoi(optarg);

break;

/* y, yuv */

case 8:

case 9:

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

format = V4L2_PIX_FMT_YUYV;

break;

/* q, quality */

case 10:

case 11:

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

format = V4L2_PIX_FMT_YUYV;

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

break;

/* m, minimum_size */

case 12:

case 13:

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

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

break;

/* n, no_dynctrl */

case 14:

case 15:

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

dynctrls = 0;

break;

/* l, led */

case 16:

case 17:

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

if ( strcmp("on", optarg) == 0 ) {

led = IN_CMD_LED_ON;

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

led = IN_CMD_LED_OFF;

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

led = IN_CMD_LED_AUTO;

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

led = IN_CMD_LED_BLINK;

}

break;

default:

DBG("default case\n");

help();

return 1;

}

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

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

[html] view
plaincopy

/* keep a pointer to the global variables */

pglobal = param->global;

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

第五,构建videoIn结构

[html] view
plaincopy

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

struct vdIn {

int fd;

char *videodevice ;

unsigned char *pFramebuffer;

unsigned char *ptframe[OUTFRMNUMB];

unsigned char *mem[NB_BUFFER];

int framelock[OUTFRMNUMB];

pthread_mutex_t grabmutex;

int framesizeIn ;

volatile int frame_cour;

int bppIn;

int hdrwidth;

int hdrheight;

int formatIn;

int signalquit;

struct v4l2_capability cap;

struct v4l2_format fmt;

struct v4l2_buffer buf;

struct v4l2_requestbuffers rb;

int grayscale;

uint32_t quality;

};

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

第六,打开视频设备

[html] view
plaincopy

/* 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

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

{

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

return -1;

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

return -1;

if (grabmethod < 0 || grabmethod > 1)

grabmethod = 1; //mmap by default;

vd->videodevice = NULL;

vd->status = NULL;

vd->pictName = NULL;

vd->videodevice = (char *) calloc (1, 16 * sizeof (char));

vd->status = (char *) calloc (1, 100 * sizeof (char));

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

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

vd->toggleAvi = 0;

vd->getPict = 0;

vd->signalquit = 1;

vd->width = width;

vd->height = height;

vd->fps = fps;

vd->formatIn = format;

vd->grabmethod = grabmethod;

if (init_v4l2 (vd) < 0) {

fprintf (stderr, " Init v4L2 failed !! exit fatal \n");

goto error;;

}

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

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

switch (vd->formatIn) {

case V4L2_PIX_FMT_MJPEG:

vd->tmpbuffer = (unsigned char *) calloc(1, (size_t) vd->framesizeIn);

if (!vd->tmpbuffer)

goto error;

vd->framebuffer =

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

break;

case V4L2_PIX_FMT_YUYV:

default:

vd->framebuffer =

(unsigned char *) calloc(1, (size_t) vd->framesizeIn);

break;

//fprintf(stderr, " should never arrive exit fatal !!\n");

//goto error;

//break;

}

if (!vd->framebuffer)

goto error;

return 0;

error:

free(vd->videodevice);

free(vd->status);

free(vd->pictName);

close(vd->fd);

return -1;

}

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

第七,动态控制初始化

[html] view
plaincopy

if (dynctrls)

initDynCtrls(videoIn->fd);

第八,LED初始化

[html] view
plaincopy

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

case IN_CMD_LED_AUTO:

res = v4l2SetControl(videoIn, V4L2_CID_LED1_MODE_LOGITECH, 3);

break;

4 input_run分析

input_run看上去十分简单:

[html] view
plaincopy

int input_run(void) {

pglobal->buf = malloc(videoIn->framesizeIn);

if (pglobal->buf == NULL) {

fprintf(stderr, "could not allocate memory\n");

exit(EXIT_FAILURE);

}

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

pthread_detach(cam);

return 0;

}

input_run只做了两件事:

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

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

5 input_stop分析

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

[html] view
plaincopy

int input_stop(void) {

DBG("will cancel input thread\n");

pthread_cancel(cam);

return 0;

}

6 input_cmd分析

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

【源码下载】

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

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

Copyright @ http://blog.csdn.net/tandesir
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: