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;
if( pthread_mutex_init(&controls_mutex, NULL) != 0 )// 初始化 controls_mutex,是互斥鎖相關的全局變量
{
IPRINT("could not initialize mutex variable\n");
exit(EXIT_FAILURE);
}
對指令行參數的解析
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;
}
}
}
}
}
for (i=0; i<argc; i++) {
DBG("argv[%d]=%s\n", i, argv[i]);
}
解析參數
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}
};
c = getopt_long_only(argc, argv, "", long_options, &option_index);
if (c == -1) break;
if (c == '?'){
help();
return 1;
}
switch (option_index) {
case 0:
case 1:
DBG("case 0,1\n");
help();
return 1;
break;
case 2:
case 3:
DBG("case 2,3\n");
dev = strdup(optarg);
break;
case 4:
case 5:
DBG("case 4,5\n");
width = -1;
height = -1;
for ( i=0; i < LENGTH_OF(resolutions); i++ ) {
if ( strcmp(resolutions[i].string, optarg) == 0 ) {
width = resolutions[i].width;
height = resolutions[i].height;
}
}
if(width != -1 && height != -1)
break;
width = strtol(optarg, &s, 10);
height = strtol(s+1, NULL, 10);
break;
case 6:
case 7:
DBG("case 6,7\n");
fps=atoi(optarg);
break;
case 8:
case 9:
DBG("case 8,9\n");
format = V4L2_PIX_FMT_YUYV;
break;
case 10:
case 11:
DBG("case 10,11\n");
format = V4L2_PIX_FMT_YUYV;
gquality = MIN(MAX(atoi(optarg), 0), 100);
break;
case 12:
case 13:
DBG("case 12,13\n");
minimum_size = MAX(atoi(optarg), 0);
break;
case 14:
case 15:
DBG("case 14,15\n");
dynctrls = 0;
break;
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;
}
}
pglobal = param->global;// 從 param中取出 global
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
列印出的值都是通過解析參數得到
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格式,還要列印出品質
調用init_videoIn函數,這是主要的調用函數。
if (init_videoIn(videoIn, dev, width, height, fps, format, 1) < 0)
{
IPRINT("init_VideoIn failed\n");
closelog();
exit(EXIT_FAILURE);
}
對于最新的linux核心的uVC 驅動,如果我們需要動态地控制攝像頭,調整焦距或顔色飽和度等,我們需要做一些初始化工作
if (dynctrls)
initDynCtrls(videoIn->fd);
通過指令行來動态控制攝像頭
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 )
{
pthread_cleanup_push(cam_cleanup, NULL);
while( !pglobal->stop )
{
if( uvcGrab(videoIn) < 0 )
{
IPRINT("Error grabbing frames\n");
exit(EXIT_FAILURE);
}
// 列印調試資訊,一幀資料有多大
DBG("received frame of size: %d\n", videoIn->buf.bytesused);
if ( videoIn->buf.bytesused < minimum_size )// 如果這一幀資料太小,則認為他是無效資料
{
DBG("dropping too small frame, assuming it as broken\n");
continue;
}
pthread_mutex_lock函數與pthread_mutex_unlock函數一起作用,其中間部分不能被兩個或兩個以上的線程同時操作,
pthread_mutex_lock( &pglobal->db );
if (videoIn->formatIn == V4L2_PIX_FMT_YUYV)
{
DBG("compressing frame\n");
pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality);
}
else
{
DBG("copying frame\n");
pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);
}
#if 0
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
pthread_cond_broadcast(&pglobal->db_update);// 發出一個資料更新的信号,通知發送通道來取資料
pthread_mutex_unlock( &pglobal->db );// 原子操作結束
DBG("waiting for next frame\n");// 列印出調試資訊
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;
}