-
代码分析
Mjpeg-
streamer
程序流程图:
main()
1
参数分析
2
初始化全局变量
= 0;
= NULL;
=
0;
= NULL;
/*
this mutex and the conditional variable are used
to synchronize access to the global picture
buffer */
3
初始化互斥体
和条件变量,来同步对
global
buffer
的访问
if( pthread_mutex_init(&,
NULL) != 0 ) {
LOG(
closelog();
exit(EXIT_FAILURE);
}
if( pthread_cond_init(&_update, NULL)
!= 0 ) {
LOG(
closelog();
exit(EXIT_FAILURE);
}
忽略管道断裂信号
接受
ctrl +c
中止信号,并关闭系统日志服务的连接
打开输入插件,并通过
dlopen
函数在
< br>RTLD_LAZY
指定模式打开指定的动态连接库文件,并
< br>返回一个句柄给调用进程
使用
dlsym
获取函数入口地址,使
gloabl
的输入与动态库相关函数相关联。
input_init()
打开输出插件并通过
dlopen
函数,
使用
dlsym
获取函数入口地址,使
gl
obal
的输出与相关函数关联
output_init()
input_run()
开始读取,将图片存放在
global
buffer
。
ouput_run()
pause()
Intput_init()
一分配视频数据结构
二调用
init_videoIn(videoIn,
dev, width, height, fps,
format,1)
进行初始化,参数设置。
*dev =
width=640, height=480, fps=5,
format=V4L2_PIX_FMT_MJPEG,
三
init_v4l2()
1
打开设备文件。
int
fd=open(
2.
取得设备的
capability
,看看设备具
有什么功能,比如是否具有视频输入
,
或者音频输入
输出等。
VIDIOC_QUERYCAP
,st
ruct v4l2_capability
3.
选择视频输入,一个视频设备可以有多个视频输入。
VIDIOC_S_INPUT,struct v4l2_input
4.
设
置视频的制式和帧格式,制式包括
PAL
,
NTSC
,帧的格式个包括宽度和高度、帧格式
等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct
v4l2_std_id,struct v4l2_format
memset(&vd->fmt, 0, sizeof(struct
v4l2_format));
vd-> = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd-> =
vd->width;
vd->
= vd->height;
vd->ormat = vd->formatIn;
vd-> = V4L2_FIELD_ANY;
ret =
ioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt);
5
设置帧速率
/*set framerate
*/
struct v4l2_streamparm *setfps;
setfps =
(struct v4l2_streamparm *) calloc(1, sizeof(struct
v4l2_streamparm));
memset(setfps, 0, sizeof(struct
v4l2_streamparm));
setfps->type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
setfps->tor = 1;
setfps->nator =
vd->fps;
ret =
ioctl(vd->fd, VIDIOC_S_PARM, setfps);
6.
向驱动申请帧缓冲,
NB_BUFFER=4
/*
* request buffers
*/
memset(&vd->rb, 0,
sizeof(struct v4l2_requestbuffers));
vd-> = NB_BUFFER;
vd-> =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd-> = V4L2_MEMORY_MMAP;
ret =
ioctl(vd->fd, VIDIOC_REQBUFS, &vd->rb);
7.
将申请到的帧缓冲映射到用户
空间,
这样就可以直接操作采集到的帧了,
而不必去复制。
p>
vd->mem[i] = mmap(0 /* start
anywhere */ ,
vd->, PROT_READ, MAP_SHARED, vd->fd,
vd->);
if (vd->mem[i] == MAP_FAILED) {
perror(
goto fatal;
}
8.
将申请到的帧缓冲全部入队列,以便存放采集到的数据
.VIDIOC_QBUF,struct v4l2_buffer
ret =
ioctl(vd->fd, VIDIOC_QBUF, &vd->buf);
四分配一个
tempbuffer
来重现图片
Input_run()
1
为
glo
bal
全局变量分配一个
buf
,
p>
pglobal->buf =
malloc(videoIn->framesizeIn);
2
pthread_create(&cam, 0, cam_thread, NULL);
< br>创建
cam_thread
线程
3pthread_detach(cam);
Cam_thread()
1
使用<
/p>
uvcGrab
来获取图像信息,若是
m
jpeg
格式存入
tmpbuffer
若是
YUYV
格式存入
framebu
ffer
。
while(
!pglobal->stop ) {
/* grab a frame
*/
if( uvcGrab(videoIn) < 0 )
//
用于获取图像信息
{
IPRINT(
exit(EXIT_FAILURE);
}
2
若视频格式为
YUYV,
需要进行视频格式转换,
compress_yuyv_to_jpeg
,
装换为
JPEG
格式并
存储在
pglobal->buf
< br>中;
若视频格式是
MJPEG
则
memcpy_picture
将
tm
pbuffer
中的数据复制
到
pgl
obal->buf
if (videoIn->formatIn ==
V4L2_PIX_FMT_YUYV) {
DBG(
pglobal->size
=
compress_yuyv_to_jpeg(videoIn,
pglobal->buf,
videoIn->framesizeIn,
gquality);
}
else {
DBG(
pglobal->size
=
memcpy_picture(pglobal->buf,
videoIn->tmpbuffer,
videoIn->sed);
}
3
pthread_cond_broadcast
信
号
,
给
等
待
的
输
出
线
程
发
送
信
号
。
pthread_cond_b
roadcast(&pglobal->db_update);
uvcGrab()
1
查看
isstreaming
是否为
0
,是
0
则开启视频捕获,
否则获取出队中的缓冲区的数据
if
(!vd->isstreaming
if (video_enable(vd))
goto err;
memset(&vd->buf, 0, sizeof(struct
v4l2_buffer));
vd-> = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd-> =
V4L2_MEMORY_MMAP;
ret = ioctl(vd->fd, VIDIOC_DQBUF,
&vd->buf);
switch (vd->formatIn) {
case V4L2_PIX_FMT_MJPEG:
if (vd->sed <=
HEADERFRAME1) {
/* Prevent crash
* on empty
image */
fprintf(stderr,
return 0;
}
2
若数据帧格式是
MJPEG
则
将映射内存中
的数据复制到
tmpbuffer
,
否则是
Yuyv,
将映射内存中的数据
复制到
framebuffer
switch
(vd->formatIn) {
case
V4L2_PIX_FMT_MJPEG:
if
(vd->sed
<=
HEADERFRAME1)
{/*
Prevent
crash
on empty image */
fprintf(stderr,
return 0;
}
memcpy(vd->tmpbuffer,
vd->mem[vd->], vd->sed);
if (debug)
fprintf(stderr,
break;
case V4L2_PIX_FMT_YUYV:
if (vd->sed >
vd->framesizeIn)
memcpy
(vd->framebuffer, vd->mem[vd->], (size_t)
vd->framesizeIn);
else
memcpy
(vd->framebuffer, vd->mem[vd->], (size_t)
vd->sed);
break;
default:
goto err;
break;
}
3
把可用的缓冲区重新入队,
ret = ioctl(vd->fd, VIDIOC_QBUF,
&vd->buf);