格式初始化部分
预定义及头文件部分
# include <opencv2/opencv.hpp>
# include <iostream>
# include <fstream>
# include <stdio.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <sys/ioctl.h>
# include <string.h>
# include <errno.h>
# include <sys/mman.h>
# include <linux/videodev2.h>
# include <linux/fb.h>
# include <assert.h>
# include <limits.h>
# define FB_DEV "/dev/fb0"
# define FRAMEBUFFER_COUNT 3
typedef struct camera_format {
unsigned char description[ 32 ] ;
unsigned int pixelformat;
} cam_fmt;
typedef struct cam_buf_info {
unsigned short * start;
unsigned long length;
} cam_buf_info;
static int width;
static int height;
static int line_length;
static unsigned short * screen_base = NULL ;
static int fb_fd = - 1 ;
static int v4l2_fd = - 1 ;
static cam_buf_info buf_infos[ FRAMEBUFFER_COUNT] ;
static cam_fmt cam_fmts[ 10 ] ;
static int frm_width, frm_height;
LCD缓冲初始化
static int fb_dev_init ( void )
{
struct fb_var_screeninfo fb_var = { 0 } ;
struct fb_fix_screeninfo fb_fix = { 0 } ;
unsigned long screen_size;
fb_fd = open ( FB_DEV, O_RDWR) ;
if ( 0 > fb_fd) {
fprintf ( stderr , "open error: %s: %s\n" , FB_DEV, strerror ( errno) ) ;
return - 1 ;
}
ioctl ( fb_fd, FBIOGET_VSCREENINFO, & fb_var) ;
ioctl ( fb_fd, FBIOGET_FSCREENINFO, & fb_fix) ;
screen_size = fb_fix. line_length * fb_var. yres;
width = fb_var. xres;
height = fb_var. yres;
line_length = fb_fix. line_length / ( fb_var. bits_per_pixel / 8 ) ;
screen_base = mmap ( NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0 ) ;
if ( MAP_FAILED == ( void * ) screen_base) {
perror ( "mmap error" ) ;
close ( fb_fd) ;
return - 1 ;
}
memset ( screen_base, 0xFF , screen_size) ;
return 0 ;
}
v4l2设备初始化
static int v4l2_dev_init ( const char * device)
{
struct v4l2_capability cap = { 0 } ;
v4l2_fd = open ( device, O_RDWR) ;
if ( 0 > v4l2_fd) {
fprintf ( stderr , "open error: %s: %s\n" , device, strerror ( errno) ) ;
return - 1 ;
}
ioctl ( v4l2_fd, VIDIOC_QUERYCAP, & cap) ;
if ( ! ( V4L2_CAP_VIDEO_CAPTURE & cap. capabilities) ) {
fprintf ( stderr , "Error: %s: No capture video device!\n" , device) ;
close ( v4l2_fd) ;
return - 1 ;
}
return 0 ;
}
v4l2列举可用格式
static void v4l2_enum_formats ( void )
{
struct v4l2_fmtdesc fmtdesc = { 0 } ;
fmtdesc. index = 0 ;
fmtdesc. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while ( 0 == ioctl ( v4l2_fd, VIDIOC_ENUM_FMT, & fmtdesc) ) {
cam_fmts[ fmtdesc. index] . pixelformat = fmtdesc. pixelformat;
strcpy ( cam_fmts[ fmtdesc. index] . description, fmtdesc. description) ;
fmtdesc. index++ ;
}
}
v4l2打印可用格式
static void v4l2_print_formats ( void )
{
struct v4l2_frmsizeenum frmsize = { 0 } ;
struct v4l2_frmivalenum frmival = { 0 } ;
int i;
frmsize. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
frmival. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
for ( i = 0 ; cam_fmts[ i] . pixelformat; i++ ) {
printf ( "format<0x%x>, description<%s>\n" , cam_fmts[ i] . pixelformat, cam_fmts[ i] . description) ;
frmsize. index = 0 ;
frmsize. pixel_format = cam_fmts[ i] . pixelformat;
frmival. pixel_format = cam_fmts[ i] . pixelformat;
while ( 0 == ioctl ( v4l2_fd, VIDIOC_ENUM_FRAMESIZES, & frmsize) ) {
printf ( "size<%d*%d> " , frmsize. discrete. width, frmsize. discrete. height) ;
frmsize. index++ ;
frmival. index = 0 ;
frmival. width = frmsize. discrete. width;
frmival. height = frmsize. discrete. height;
while ( 0 == ioctl ( v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, & frmival) ) {
printf ( "<%dfps>" , frmival. discrete. denominator / frmival. discrete. numerator) ;
frmival. index++ ;
}
printf ( "\n" ) ;
}
printf ( "\n" ) ;
}
}
v4l2设置图像格式
static int v4l2_set_format ( void )
{
struct v4l2_format fmt = { 0 } ;
struct v4l2_streamparm streamparm = { 0 } ;
fmt. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt. fmt. pix. width = 640 ;
fmt. fmt. pix. height = 480 ;
fmt. fmt. pix. pixelformat = V4L2_PIX_FMT_YUYV;
if ( 0 > ioctl ( v4l2_fd, VIDIOC_S_FMT, & fmt) ) {
fprintf ( stderr , "ioctl error: VIDIOC_S_FMT: %s\n" , strerror ( errno) ) ;
return - 1 ;
}
if ( V4L2_PIX_FMT_YUYV != fmt. fmt. pix. pixelformat) {
fprintf ( stderr , "Error: the device does not support YUYV format!\n" ) ;
return - 1 ;
}
frm_width = fmt. fmt. pix. width;
frm_height = fmt. fmt. pix. height;
printf ( "视频帧大小<W,H>:<%d * %d>\n" , frm_width, frm_height) ;
streamparm. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl ( v4l2_fd, VIDIOC_G_PARM, & streamparm) ;
if ( V4L2_CAP_TIMEPERFRAME & streamparm. parm. capture. capability) {
streamparm. parm. capture. timeperframe. numerator = 1 ;
streamparm. parm. capture. timeperframe. denominator = 30 ;
if ( 0 > ioctl ( v4l2_fd, VIDIOC_S_PARM, & streamparm) ) {
fprintf ( stderr , "ioctl error: VIDIOC_S_PARM: %s\n" , strerror ( errno) ) ;
return - 1 ;
}
}
return 0 ;
}
v4l2初始化缓冲器
static int v4l2_init_buffer ( void )
{
struct v4l2_requestbuffers reqbuf = { 0 } ;
struct v4l2_buffer buf = { 0 } ;
reqbuf. count = FRAMEBUFFER_COUNT;
reqbuf. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf. memory = V4L2_MEMORY_MMAP;
if ( 0 > ioctl ( v4l2_fd, VIDIOC_REQBUFS, & reqbuf) ) {
fprintf ( stderr , "ioctl error: VIDIOC_REQBUFS: %s\n" , strerror ( errno) ) ;
return - 1 ;
}
buf. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf. memory = V4L2_MEMORY_MMAP;
for ( buf. index = 0 ; buf. index < FRAMEBUFFER_COUNT; buf. index++ ) {
ioctl ( v4l2_fd, VIDIOC_QUERYBUF, & buf) ;
buf_infos[ buf. index] . length = buf. length;
buf_infos[ buf. index] . start = mmap ( NULL , buf. length, PROT_READ | PROT_WRITE, MAP_SHARED, v4l2_fd, buf. m. offset) ;
if ( MAP_FAILED == buf_infos[ buf. index] . start) {
perror ( "mmap error" ) ;
return - 1 ;
}
}
for ( buf. index = 0 ; buf. index < FRAMEBUFFER_COUNT; buf. index++ ) {
if ( 0 > ioctl ( v4l2_fd, VIDIOC_QBUF, & buf) ) {
fprintf ( stderr , "ioctl error: VIDIOC_QBUF: %s\n" , strerror ( errno) ) ;
return - 1 ;
}
}
return 0 ;
}
v4l2开启视频流
static int v4l2_stream_on ( void )
{
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( 0 > ioctl ( v4l2_fd, VIDIOC_STREAMON, & type) ) {
fprintf ( stderr , "ioctl error: VIDIOC_STREAMON: %s\n" , strerror ( errno) ) ;
return - 1 ;
}
return 0 ;
}
yuyv格式数据转换为RGB565
unsigned short yuyv_to_rgb565 ( unsigned short y, unsigned short u, unsigned short v) {
int16_t r, g, b;
int16_t y1 = y;
int16_t u1 = u - 128 ;
int16_t v1 = v - 128 ;
r = y1 + 1.042 * ( v1) ;
g = y1- 0.34414 * ( u1) - 0.71414 * v1;
b = y1+ 1.772 * u1;
r = r < 0 ? 0 : ( r > 255 ? 255 : r) ;
g = g < 0 ? 0 : ( g > 255 ? 255 : g) ;
b = b < 0 ? 0 : ( b > 255 ? 255 : b) ;
return ( ( r >> 3 ) << 11 ) | ( ( g >> 2 ) << 5 ) | ( b >> 3 ) ;
}
数据读取
读取图像帧用lcd显示
static void v4l2_read_data ( void )
{
struct v4l2_buffer buf = { 0 } ;
unsigned short * base;
unsigned short * start;
int min_w, min_h;
int j;
if ( width > frm_width)
min_w = frm_width;
else
min_w = width;
if ( height > frm_height)
min_h = frm_height;
else
min_h = height;
buf. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf. memory = V4L2_MEMORY_MMAP;
for ( ; ; ) {
for ( buf. index = 0 ; buf. index < FRAMEBUFFER_COUNT; buf. index++ ) {
ioctl ( v4l2_fd, VIDIOC_DQBUF, & buf) ;
printf ( "length:%d\n" , buf_infos[ buf. index] . length) ;
for ( j = 0 , base= screen_base, start= buf_infos[ buf. index] . start; j < min_h; j++ ) {
for ( int i = 0 ; i < min_w; i += 2 ) {
unsigned short y0 = start[ i] & 0x00ff ;
unsigned short u = start[ i] >> 8 ;
unsigned short y1 = start[ i + 1 ] & 0x00ff ;
unsigned short v = start[ i + 1 ] >> 8 ;
unsigned short rgb0 = yuyv_to_rgb565 ( y0, u, v) ;
unsigned short rgb1 = yuyv_to_rgb565 ( y1, u, v) ;
* ( unsigned short * ) base = rgb0;
base += 1 ;
* ( unsigned short * ) base = rgb1;
base += 1 ;
}
base = screen_base+ ( j+ 1 ) * line_length;
start += frm_width;
}
ioctl ( v4l2_fd, VIDIOC_QBUF, & buf) ;
}
}
}
使用opencv保存图像
cv:: Mat convertYUYVtoBGR ( unsigned short * yuyvData, int w, int h) {
printf ( "frame:<w,h>:<%d,%d>\n" , w, h) ;
cv:: Mat bgrImage ( w, h, CV_8UC3) ;
unsigned short * start;
int j= 0 ;
for ( start= yuyvData; j < h; j++ ) {
for ( int i = 0 ; i< w; i += 2 ) {
unsigned short Y1 = start[ i] & 0x00ff ;
unsigned short U = start[ i] >> 8 ;
unsigned short Y2 = start[ i + 1 ] & 0x00ff ;
unsigned short V = start[ i + 1 ] >> 8 ;
int U_ = U - 128 ;
int V_ = V - 128 ;
int R1 = Y1 + 1.402 * V_;
int G1 = Y1 - 0.34414 * U_ - 0.71414 * V_;
int B1 = Y1 + 1.772 * U_;
int R2 = Y2 + 1.402 * V_;
int G2 = Y2 - 0.34414 * U_ - 0.71414 * V_;
int B2 = Y2 + 1.772 * U_;
bgrImage. at< cv:: Vec3b> ( j, i) [ 0 ] = std:: min ( std:: max ( B1, 0 ) , 255 ) ;
bgrImage. at< cv:: Vec3b> ( j, i) [ 1 ] = std:: min ( std:: max ( G1, 0 ) , 255 ) ;
bgrImage. at< cv:: Vec3b> ( j, i) [ 2 ] = std:: min ( std:: max ( R1, 0 ) , 255 ) ;
bgrImage. at< cv:: Vec3b> ( j, i+ 1 ) [ 0 ] = std:: min ( std:: max ( B2, 0 ) , 255 ) ;
bgrImage. at< cv:: Vec3b> ( j, i+ 1 ) [ 1 ] = std:: min ( std:: max ( G2, 0 ) , 255 ) ;
bgrImage. at< cv:: Vec3b> ( j, i+ 1 ) [ 2 ] = std:: min ( std:: max ( R2, 0 ) , 255 ) ;
}
start += w;
}
return bgrImage;
}
主函数
int main ( int argc, char * argv[ ] )
{
if ( 2 != argc) {
fprintf ( stderr , "Usage: %s <video_dev>\n" , argv[ 0 ] ) ;
exit ( EXIT_FAILURE) ;
}
if ( fb_dev_init ( ) )
exit ( EXIT_FAILURE) ;
if ( v4l2_dev_init ( argv[ 1 ] ) )
exit ( EXIT_FAILURE) ;
v4l2_enum_formats ( ) ;
v4l2_print_formats ( ) ;
if ( v4l2_set_format ( ) )
exit ( EXIT_FAILURE) ;
if ( v4l2_init_buffer ( ) )
exit ( EXIT_FAILURE) ;
if ( v4l2_stream_on ( ) )
exit ( EXIT_FAILURE) ;
v4l2_read_data ( ) ;
exit ( EXIT_SUCCESS) ;
}