mjpg-streamer学习笔记5----输入通道

来源:互联网 发布:搞笑网络神曲排行榜 编辑:程序博客网 时间:2024/06/11 01:02

input_uvc.c

1、input_init函数

int input_init(input_parameter *param)

设置默认参数
{
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;


/* initialize the mutes variable */
if( pthread_mutex_init(&controls_mutex, NULL) != 0 )// 初始化 controls_mutex,是互斥锁相关的全局变量
{
IPRINT("could not initialize mutex variable\n");
exit(EXIT_FAILURE);
}

对命令行参数的解析
/* convert the single parameter-string to an array of strings */
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);


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


/* show all parameters for DBG purposes */
for (i=0; i<argc; i++) {
DBG("argv[%d]=%s\n", i, argv[i]);
}


/* parse the parameters */解析参数
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);


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


/* keep a pointer to the global variables */
pglobal = param->global;// 从 param中取出 global


/* allocate webcam datastructure */
videoIn = malloc(sizeof(struct vdIn));// 分配一个 vdIn 结构体
if ( videoIn == NULL )
{
IPRINT("not enough memory for videoIn\n");
exit(EXIT_FAILURE);
}
memset(videoIn, 0, sizeof(struct vdIn));// 将该结构体清为0


/* display the parsed values */打印出的值都是通过解析参数得到

IPRINT("Using V4L2 device.: %s\n", dev);// 打印出使用的是哪个设备节点
IPRINT("Desired Resolution: %i x %i\n", width, height);// 打印出分辨率
IPRINT("Frames Per Second.: %i\n", fps);// 打印出帧率
IPRINT("Format............: %s\n", (format==V4L2_PIX_FMT_YUYV)?"YUV":"MJPEG");// 打印出格式
if ( format == V4L2_PIX_FMT_YUYV )
IPRINT("JPEG Quality......: %d\n", gquality);// 如果是YUV格式,还要打印出质量


/* open video device and prepare data structure */调用init_videoIn函数,这是主要的调用函数。
if (init_videoIn(videoIn, dev, width, height, fps, format, 1) < 0)
{
IPRINT("init_VideoIn failed\n");
closelog();
exit(EXIT_FAILURE);
}


/*
* recent linux-uvc driver (revision > ~#125) requires to use dynctrls
* for pan/tilt/focus/...
* dynctrls must get initialized
*/

对于最新的linux内核的uVC 驱动,如果我们需要动态地控制摄像头,调整焦距或颜色饱和度等,我们需要做一些初始化工作
if (dynctrls)
initDynCtrls(videoIn->fd);


/*
* switch the LED according to the command line parameters (if any)
*/

通过命令行来动态控制摄像头
input_cmd(led, 0);


return 0;

}

2.input_run函数

(1)函数主体

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

(2)线程cam_thread

void *cam_thread( void *arg )
{
/* set cleanup handler to cleanup allocated ressources */
/* 当线程执行完后,会调用 cam_cleanup 来做些清理工作 */
pthread_cleanup_push(cam_cleanup, NULL);


/*
1. 如果 pglobal->stop 为0,则一直执行该while()语句.


2.
问:什么时候pglobal->stop被设置为1?
答:当我们按 <CTRL>+C 时,该while被终止.


*/

while( !pglobal->stop )
{


/* grab a frame */
/*
获得一帧数据:
MJPEG:则将一帧视频数据存放到 videoIn->tempbuffer 中
YUV:则将一帧数据存放到 videoIn->framebuffer 中
*/


if( uvcGrab(videoIn) < 0 )
{
IPRINT("Error grabbing frames\n");
exit(EXIT_FAILURE);
}


// 打印调试信息,一帧数据有多大
DBG("received frame of size: %d\n", videoIn->buf.bytesused);


/*
* Workaround for broken, corrupted frames:
* Under low light conditions corrupted frames may get captured.
* The good thing is such frames are quite small compared to the regular pictures.
* For example a VGA (640x480) webcam picture is normally >= 8kByte large,
* corrupted frames are smaller.
*/
if ( videoIn->buf.bytesused < minimum_size )// 如果这一帧数据太小,则认为他是无效数据
{
DBG("dropping too small frame, assuming it as broken\n");
continue;
}


/* copy JPG picture to global buffer */
/* 进行原子操作 */pthread_mutex_lock函数与pthread_mutex_unlock函数一起作用,其中间部分不能被两个或两个以上的线程同时操作,
pthread_mutex_lock( &pglobal->db );


/*
* If capturing in YUV mode convert to JPEG now.
* This compression requires many CPU cycles, so try to avoid YUV format.
* Getting JPEGs straight from the webcam, is one of the major advantages of
* Linux-UVC compatible devices.
*/
if (videoIn->formatIn == V4L2_PIX_FMT_YUYV)
{
/* 如果摄像头输出的视频数据为YUV格式,则执行该分支 */
/* 最终的MJPEG数据存放到 pglobal->buf 中 */

DBG("compressing frame\n");
pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality);
}
else
{
/*
如果摄像头输出的数据为MJPEG格式,则直接将它拷贝到  pglobal->buf 中
*/

DBG("copying frame\n");
pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);
}


#if 0
/* motion detection can be done just by comparing the picture size, but it is not very accurate!! */
if ( (prev_size - global->size)*(prev_size - global->size) > 4*1024*1024 ) {
DBG("motion detected (delta: %d kB)\n", (prev_size - global->size) / 1024);
}
prev_size = global->size;
#endif


/* signal fresh_frame */
pthread_cond_broadcast(&pglobal->db_update);// 发出一个数据更新的信号,通知发送通道来取数据
pthread_mutex_unlock( &pglobal->db );// 原子操作结束


DBG("waiting for next frame\n");// 打印出调试信息


/* only use usleep if the fps is below 5, otherwise the overhead is too long */
if ( videoIn->fps < 5 )// 如果我们的帧率小于5,则要做一个小的延时操
{
usleep(1000*1000/videoIn->fps);
}
}


DBG("leaving input thread, calling cleanup function now\n");
pthread_cleanup_pop(1);


return NULL;
}

0 0
原创粉丝点击