📄 v4l.c
字号:
/**********************************************************************
*
*
* 文 件 名: v4l.c
*
* 内容描述: 视频监控系统源文件
*
*
*/
#include "v4l.h"
/*********************************************************************
*
*
* 函数名:v4l_open
*
* 功 能: 打开设备
*
* 输 入: dev
* vd
*
*
* 输 出: 无
*
* 返 回: -1----失败
* 0----成功
*
*/
int v4l_open(const char *dev, v4l_device *vd )
{
if( !dev )
{
dev=DEFAULT_DEVICE ;
}
if( ( vd->fd = open( dev, O_RDWR ) ) < 0 )
{
perror( "v4l_open error" );
return -1;
}
#ifdef DEBUG_PRINT
printf( "you have open dev successfully" );
#endif
return 0;
}
/*********************************************************************
*
*
* 函数名: v4l_get_capability
*
* 功 能: 获取设备属性
*
* 输 入: vd
*
* 输 出: 无
*
* 返 回: -1----失败
* 0----成功
*
*/
int v4l_get_capability( v4l_device *vd )
{
if( ioctl( vd->fd, VIDIOCGCAP, &( vd->capability ) ) <0 )
{
perror( "v4l_get_capability" );
return -1 ;
}
#ifdef DEBUG_PRINT
printf( "\nname=%s\n,maxwidth=%d, maxheight=%d\nminwidth=%d, minheight=%d\nchannels=%d, type=%d,audios=%d\n",
vd->capability.name,
vd->capability.maxwidth,vd->capability.maxheight,vd->capability.minwidth,
vd->capability.minheight,vd->capability.channels, vd->capability.type,
vd->capability.audios );
#endif
return 0;
}
/*********************************************************************
*
*
* 函数名:v4l_get_picture
*
* 功 能:获取图片属性
*
* 输 入: vd
*
* 输 出: 无
*
* 返 回: -1----失败
* 0----成功
*
*/
int v4l_get_picture( v4l_device *vd )
{
if( ioctl( vd->fd,VIDIOCGPICT,&( vd->picture ) ) < 0 )
{
return -1;
}
#ifdef DEBUG_PRINT
printf("brightness=%d,hue=%d \ncolour=%d,contrast=%d \nwhiteness=%d,depth=%d,palette=%d\n" ,
vd->picture.brightness,vd->picture.hue,
vd->picture.colour,vd->picture.contrast,vd->picture.whiteness,
vd->picture.depth,vd->picture.palette ) ;
#endif
return 0;
}
/*********************************************************************
*
*
* 函数名:v4l_set_picture
*
* 功 能:设置图片属性
*
* 输 入: vd
*
* 输 出: 无
*
* 返 回: -1----失败
* 0----成功
*
*/
int v4l_set_picture( v4l_device *vd )
{
if( ioctl( vd->fd, VIDIOCSPICT, &( vd->picture ) ) < 0 )
{
return -1;
}
return 0;
}
/*********************************************************************
*
*
* 函数名:v4l_get_channels
*
* 功 能:获取通道信息
*
* 输 入: vd
*
* 输 出: 无
*
* 返 回: -1----失败
* 0----成功
*
*/
int v4l_get_channels( v4l_device *vd )
{
int i;
for( i=0;i < vd->capability.channels ; i++ )
{
vd->channel[i].channel = i; //确定通道
if( ioctl( vd->fd , VIDIOCGCHAN, &( vd->channel[i] ) ) <0 )
{
perror( "v4l_get_channel" );
return -1;
}
}
return 0;
}
/*********************************************************************
*
*
* 函数名:v4l_get_window(v4l_device *vd);
*
* 功 能:获取window信息
*
* 输 入: vd
*
* 输 出: 无
*
* 返 回: -1----失败
* 0----成功
*
*/
int v4l_get_window(v4l_device *vd)
{
if( ioctl( vd->fd, VIDIOCGWIN, &( vd->window ) ) < 0 )
{
return -1;
}
return 0;
}
/*********************************************************************
*
*
* 函数名:v4l_get_mbuf
*
* 功 能:获取内存映射信息
*
* 输 入: vd
*
* 输 出: 无
*
* 返 回: -1----失败
* 0----成功
*
*/
int v4l_get_mbuf( v4l_device *vd )
{
if( ioctl( vd->fd,VIDIOCGMBUF,&( vd->mbuf ) ) <0 )
{
perror( "get_mbuf:" );
return -1;
}
if ( ( vd->map = ( unsigned char * )mmap( 0, vd->mbuf.size,
PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, 0 ) ) < 0 )
{
perror("v4l_mmap_init:mmap");
return -1;
}
return 0 ;
}
/*********************************************************************
*
*
* 函数名: v4l_init_mbuff
*
* 功 能:初始化内存映射信息
*
* 输 入: vd
*
* 输 出: 无
*
* 返 回: 0----成功
*
*/
int v4l_init_mbuf(v4l_device *vd)
{
//vd->mmap.frame = 10 ;
vd->mmap.width = MAX_WIDTH;
vd->mmap.height = MAX_HEIGHT;
vd->mmap.format = vd->picture.palette;
vd->frame_current = 0;
vd->frame_using[0] = 0;
vd->frame_using[1] = 0;
#ifdef DEBUG_PRINT
printf( "\nbegin to init device:" );
#endif
return 0;
}
/*********************************************************************
*
*
* 函数名: v4l_get_address
*
* 功 能:获取数据在图像的地址
*
*
*/
unsigned char *v4l_get_address(v4l_device *vd)
{
return (vd->map + vd->mbuf.offsets[vd->frame_current]);
}
/*********************************************************************
*
*
* 函数名: v4l_grab_frame
* 功 能:捕获帧
*
*
*/
int v4l_grab_frame(v4l_device *vd, int frame)
{
#ifdef DEBUG_PRINT
printf("enter grab_frame\n");
#endif
if (vd->frame_using[frame])
{
fprintf(stderr, "v4l_grab_frame: frame %d is already used.\n", frame);
return -1;
}
vd->mmap.frame = frame;
if ( ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap ) ) < 0 )
{
perror( "v4l_grab_frame" );
return -1;
}
vd->frame_using[frame] = 1;
vd->frame_current = frame;
return 0;
}
/*********************************************************************
*
*
* 函数名: v4l_grab_sync
*
* 功 能:与内存映射捕获一致
*
*
*/
int v4l_grab_sync(v4l_device *vd)
{
// printf("enter grab_sync\n");
if (ioctl(vd->fd, VIDIOCSYNC, &(vd->frame_current)) < 0)
{
perror("v4l_grab_sync");
}
vd->frame_using[vd->frame_current] = 0;
// printf("leave grab_sync\n");
return 0;
}
/*********************************************************************
*
*
* 函数名: v4l_munmap
*
* 功 能:停止内存映射
*
*
*/
int v4l_munmap( v4l_device *vd )
{
if ( munmap( vd->map, vd->mbuf.size ) < 0 )
{
perror( "v4lmunmap:munmap" );
return -1;
}
return 0;
}
/*********************************************************************
*
*
* 函数名: v4l_close
*
* 功 能:关闭设备
*
*
*/
int v4l_close(v4l_device *vd)
{
close(vd->fd);
return 0;
}
/*********************************************************************
*
*
* 函数名: v4l_grab_movie
*
* 功 能:捕获连续图像
*
*/
void v4l_grab_movie(v4l_device *vd)
{
#ifdef DEBUG_PRINT
{
printf("video_mbuf include size=%u,frame=%d,offdet=%d\n", \
vd->mbuf.size, vd->mbuf.frames, vd->mbuf.offsets[1]);
}
#endif
v4l_grab_frame(vd, vd->frame_current);/*获取下一 帧*/
v4l_grab_sync(vd);/*等待传完一 帧*/
vd->buffer = v4l_get_address(vd);/*得到这一帧的地址*/
vd->frame_current = (vd->frame_current+1)%2; /* 下一帧的frame*/
}
/*
YUV420转RGB
*/
#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
static inline void
v4l_copy_420_block (int yTL, int yTR, int yBL, int yBR, int u, int v,
int rowPixels, unsigned char * rgb, int bits)
{
const int rvScale = 91881;
const int guScale = -22553;
const int gvScale = -46801;
const int buScale = 116129;
const int yScale = 65536;
int r, g, b;
g = guScale * u + gvScale * v;
r = rvScale * v;
b = buScale * u;
yTL *= yScale; yTR *= yScale;
yBL *= yScale; yBR *= yScale;
if (bits == 24) {
/* Write out top two pixels */
rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
/* Skip down to next line to write out bottom two pixels */
rgb += 3 * rowPixels;
rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
} else if (bits == 16) {
/* Write out top two pixels */
rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) | ((LIMIT(g+yTL) << 3) & 0xE0);
rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) | (LIMIT(r+yTL) & 0xF8);
rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) | ((LIMIT(g+yTR) << 3) & 0xE0);
rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) | (LIMIT(r+yTR) & 0xF8);
/* Skip down to next line to write out bottom two pixels */
rgb += 2 * rowPixels;
rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F) | ((LIMIT(g+yBL) << 3) & 0xE0);
rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07) | (LIMIT(r+yBL) & 0xF8);
rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F) | ((LIMIT(g+yBR) << 3) & 0xE0);
rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07) | (LIMIT(r+yBR) & 0xF8);
}
}
int
v4l_yuv420p2rgb (unsigned char *rgb_out, unsigned char *yuv_in,
int width, int height, int bits)
{
const int numpix = width * height;
const unsigned int bytes = bits >> 3;
int h, w, y00, y01, y10, y11, u, v;
unsigned char *pY = yuv_in;
unsigned char *pU = pY + numpix;
unsigned char *pV = pU + numpix / 4;
unsigned char *pOut = rgb_out;
if (!rgb_out || !yuv_in)
return -1;
for (h = 0; h <= height - 2; h += 2) {
for (w = 0; w <= width - 2; w += 2) {
y00 = *(pY);
y01 = *(pY + 1);
y10 = *(pY + width);
y11 = *(pY + width + 1);
u = (*pU++) - 128;
v = (*pV++) - 128;
v4l_copy_420_block (y00, y01, y10, y11, u, v, width, pOut, bits);
pY += 2;
pOut += bytes << 1;
}
pY += width;
pOut += width * bytes;
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -