在linux下使用視頻採集卡

來源:互聯網
上載者:User
這一部分將會介紹如何在linux中對電視卡編程。
開始已經提到過,電視卡使用的是video for
linux驅動,簡稱v4l,實際上,現在已經有了video for linux two驅動
,即v4l2.它解決了v4l中存在的一些問題,並且提高了硬體效能。但是,目前來說,v4l2仍然沒有整合到linux的核心中,要使用v4l2的話,只有去下載v4l2補丁了,以下如無特別說明,所涉及的內容只針對v4l裝置而言。
我們都知道,在linux中,為了屏蔽使用者對裝置訪問的複雜性,採用了裝置檔案,即可以通過像訪問普通檔案一樣的方式來對裝置進行訪問讀寫。電視卡在linux中和印表機,滑鼠一樣,屬於字元裝置。其主裝置號是81,在實際操作上,存取控制電視卡也和一般的裝置檔案沒有什麼不同。用open開啟裝置,
int fd;
fd = open("/dev/video0",O_RDWR);
用一系列的ioctl發命令控制裝置。v4l支援的ioctl命令大概有二十幾個,為了儘快的編出一個
簡單的圖象捕捉程式,讓我們先來看看幾個主要的命令:
1. ioctl(fd,VIDIOCGCAP,&cap);
該命令主要是為了擷取電視卡的功能資訊。例如電視卡的名稱,類型,channel等。參數cap是一個結構,當ioctl命令返回時,結構的各成員就被賦值了,結構體的定義為:
struct video_capability
{
char name[32];
int type;
int channels; /* Num channels */
int audios; /* Num audio devices */
int maxwidth; /* Supported width */
int maxheight; /* And height */
int minwidth; /* Supported width */
int minheight; /* And height */
};
channel 指的是有幾個訊號輸入源,例如television,composite,s-video等。
2.ioctl(fd,VIDIOCGCHAN,&vc)
3.ioctl(fd,VIDIOCSCHAN.&vc)
這兩個命令用來取得和設定電視卡的channel資訊,例如使用那個輸入源,制式等。
vc 是一個video_channel結構,其定義為:
struct video_capability
{
char name[32];
int type;
int channels; /* Num channels */
int audios; /* Num audio devices */
int maxwidth; /* Supported width */
int maxheight; /* And height */
int minwidth; /* Supported width */
int minheight; /* And height */
};
struct video_channel
{
int channel;
char name[32];
int tuners;//number of tuners for this input
__u32 flags;
__u16 type;
__u16 norm;
};
成員channel代表輸入源,通常,0: television 1:composite1 2:s-video
name 表示該輸入源的名稱。
norm 表示制式,通常,0:pal 1:ntsc 2:secam 3:auto
4. ioctl(fd,VIDIOCGMBUF,*mbuf)
獲得電視卡緩衝的資訊,參數mbuf是video_mbuf結構。其定義如下:
struct video_mbuf
{
int size; /* Total memory to map */
int frames; /* Frames */
int offsets[VIDEO_MAX_FRAME];
};
size是緩衝的大小,frames表明該電視卡的緩衝可以容納的幀數,數組offsets則表明
對應一幀的起始位置,0幀對應offsets[0],1幀對應offsets[1]....
執行完該命令後,就可以用mmap函數將緩衝映射到記憶體中了。大致用法可以參考以下的代

struct video_mbuf mbuf;
unsigned char *buf1,*buf2;
if(ioctl(fd,VIDIOCGMBUF,&mbuf)<0)
{
perror("VIDIOCGMBUF");
return -1;
}
printf("the frame number is %d\n",mbuf.frames);
buf1 = (unsigned
char*)mmap(0,mbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,fd.0);
buf1 = buf1 + mbuf.offset[0];
buf2 = buf1 + mbuf.offset[1];//當然,如果mbuf.frames=1,就不需要下面的了。
......
5. ioctl(fd.VIDIOCMCAPTURE,&mm)
啟動硬體去捕捉圖象,mm 是video_mmap
結構,設定捕捉圖象需要設定的資訊。結構體
如下定義:
struct video_mmap
{
unsigned int frame; /* Frame (0 - n) for
double buffer */
int height,width;
unsigned int format; /* should be
VIDEO_PALETTE_* */
};
frame :設定當前是第幾幀
height,width:設定圖象的高和寬。
format :顏色模式
要注意的是,該命令是非阻塞的,也就是說,它僅僅設定了硬體,而不負責是否捕捉到圖象。
要確定是否捕捉到圖象,要用到下一個命令。
6. ioctl(fd,VIDIOCSYNC,&frame)
等待捕捉到這一幀圖象。frame
是要等待的圖象,它的值應和上一個命令中設定的frame相對應。
好了,說了這麼多,讀者大概也對視頻捕捉有了一個瞭解,是不是想親自動手試一下,那就讓我們
開始實際程式的編寫吧。
下面我們會編一個程式,將捕捉到的圖象存為jpeg檔案。為此,還要向大家介紹一個函數,
int write_jpeg(char *filename,unsigned char *buf,int quality,int width,
int height, int gray)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *fp;
int i;
unsigned char *line;
int line_length;
if (NULL == (fp = fopen(filename,"w")))
{
fprintf(stderr,"grab: can't open %s:
%s\n",filename,strerror(errno));
return -1;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fp);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = gray ? 1: 3;
cinfo.in_color_space = gray ? JCS_GRAYSCALE: JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
line_length = gray ? width : width * 3;
for (i = 0, line = buf; i < height; i++, line += line_length)
jpeg_write_scanlines(&cinfo, &line, 1);
jpeg_finish_compress(&(cinfo));
jpeg_destroy_compress(&(cinfo));
fclose(fp);
return 0;
}
這個函數很通用,它的作用是把buf中的資料壓縮成jpeg格式。
/* 下面是一個完整的程式 test.c
* gcc test.c -o test -ljpeg
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <linux/videodev.h>
#include <jpeglib.h>
#define WIDTH 320
#define HEIGHT 240
#define V4L_DEVICE "/dev/video0"
main()
{
unsigned char* buf;
int i,j;
int fd;
int re;
struct video_capability vcap;
struct video_channel vc;
struct video_mbuf mbuf;
struct video_mmap mm;
fd = open(V4L_DEVICE, O_RDWR);
if(fd<=0)
{
perror("open");
exit(1);
}
if(ioctl(fd, VIDIOCGCAP, &vcap)<0)
{
perror("VIDIOCGCAP");
exit(1);
}
fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name);
for(i=0;i<vcap.channels;i++)
{
vc.channel = i;
if(ioctl(fd, VIDIOCGCHAN, &vc)<0)
{
perror("VIDIOCGCHAN");
exit(1);
}
fprintf(stderr,"Video Source (%d) Name : %s\n",i, vc.name);
}
vc.channel =1;
vc.norm=1;
if(ioctl(fd, VIDIOCSCHAN, &vc) < 0)
{
perror("VIDIOCSCHAN");
exit(1);
}
if(ioctl(fd, VIDIOCGMBUF, &mbuf) < 0)
{
perror("VIDIOCGMBUF");
exit(1);
}
fprintf(stderr,"the frames number is %d\n",mbuf.frames);
buf = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
if((int)buf < 0)
{
perror("mmap");
exit(1);
}
mm.frame = 0;
mm.height = HEIGHT;
mm.width = WIDTH;
mm.format = VIDEO_PALETTE_RGB24;
if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
{
perror("VIDIOCMCAPTURE");
exit(1);
}
if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)
{
perror("VIDIOCSYNC");
exit(1);
}
if(-1 == (write_jpeg("./pic001.jpeg",buf,75,WIDTH,HEIGHT,0)))
{
printf("write_jpeg error\n");
exit(1);
}
munmap(buf,mbuf.size);
close(fd);
}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.