天天看點

mjpg-streamer學習筆記5----輸入通道

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;

}