海思摄像头架构并不支持标准Linux的V4L2架构,这对摄像头应用十分不友好,MPP学习曲线较为陡峭,为了大家能够方便获取摄像头数据,编写了为了兼容海思摄像头的V4L2驱动和中间件程序(暂时只支持开发板上的显示屏320x240像素),加载后就可以正常使用V4L2进行摄像头应用开发。
在使用出厂固件环境下进行如下操作
#hisilicon media driver
cd /ko && ./load3516ev200 -i -sensor imx307
#spi lcd driver
insmod /lib/modules/4.9.37/fb_ili9341.ko
modprobe fbtft_device name=ilitek,ili9341 gpios=reset:40,dc:70 busnum=0 mode=0 rotate=90
#v4l2
cd -
insmod hi3516ev200_v4l2.ko
./hi3516ev200_dopi_media /dev/video0 &
./app
最终,V4L2测试程序将会把摄像头数据呈现在LCD屏幕上
附件:
Dopi V4L2中间件驱动
离线
使用V4L2接口保存一帧YUV图像开发示例
#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 <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>
#include <stdlib.h>
#define VIDEO_NAME "/dev/video0"
struct videobuffer{
unsigned int length;
void* start;
};
int main()
{
//open video
int dev = open(VIDEO_NAME, O_RDWR | O_NONBLOCK, 0);
if(dev <0 ){
printf("open video0 fail.\n");
return -1;
}
//query capability
struct v4l2_capability cap;
ioctl(dev, VIDIOC_QUERYCAP, &cap);
printf("--------------capability------------------\n");
printf("driver:%s \ncard:%s \ncapabilities:%x\n",cap.driver,cap.card,cap.capabilities);
//set and get format
struct v4l2_fmtdesc fmtdesc;
int ret;
int i;
memset(&fmtdesc, 0, sizeof(fmtdesc));
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("-------------VIDIOC_ENUM_FMT--------------\n");
while((ioctl(dev, VIDIOC_ENUM_FMT, &fmtdesc)) != -1)
{
printf("index:%d \npixelformat:%c%c%c%c \ndescription:%s\n",fmtdesc.index, fmtdesc.pixelformat&0xff,(fmtdesc.pixelformat>>8)&0xff,(fmtdesc.pixelformat>>16)&0xff,
(fmtdesc.pixelformat>>24)&0xff,fmtdesc.description);
fmtdesc.index++;
}
int width = 320, height = 240;
struct v4l2_format format;
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = width;
format.fmt.pix.height = height;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; // 设置为yuyv格式数据
format.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(dev, VIDIOC_S_FMT, &format);
if(ret < 0){
printf("VIDIOC_S_FMT fail\n");
return -1;
}
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(dev, VIDIOC_G_FMT, &format);
if(ret < 0)
{
printf("VIDIOC_G_FMT fail\n");
return -1;
}
printf("-----------------VIDIOC_G_FMT----------------------\n");
printf("width:%d \nheight:%d \ntype:%x pixelformat:%c%c%c%c\n",format.fmt.pix.width,format.fmt.pix.height,
format.type,format.fmt.pix.pixelformat&0xff,(format.fmt.pix.pixelformat>>8)&0xff,(format.fmt.pix.pixelformat>>16)&0xff,
(format.fmt.pix.pixelformat>>24)&0xff);
//init mmap
struct videobuffer framebuf;
struct v4l2_requestbuffers reqbuf;
reqbuf.count = 1;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(dev, VIDIOC_REQBUFS, &reqbuf);
if(0 != ret){
printf("VIDIOC_REQBUFS fail\n");
return -1;
}
//v4l2_buffer
printf("----------------mmap----------------\n");
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.index = 1;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(dev, VIDIOC_QUERYBUF, &buf);
framebuf.length = buf.length;
framebuf.start = mmap(NULL, buf.length, PROT_READ|PROT_WRITE,
MAP_SHARED, dev, buf.m.offset);
if(framebuf.start == MAP_FAILED){
perror("mmap fail.\n");
return -1;
}
printf("start:%p length:%d\n",framebuf.start,framebuf.length);
for(i=0;i < 1; i++){
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ret = ioctl(dev, VIDIOC_QBUF, &buf);
if(0 != ret){
perror("VIDIOC_QBUF fail.\n");
return -1;
}
}
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(dev, VIDIOC_STREAMON, &type);
//usleep(500000);
struct pollfd pollfd;
for(;;i++){
memset(&pollfd, 0, sizeof(pollfd));
pollfd.fd = dev;
pollfd.events = POLLIN;
ret = poll(&pollfd, 1, 800);
printf("poll %d i=%d\n",pollfd.revents, i);
if(-1 == ret){
perror("VIDIOC_QBUF fail.\n");
return -1;
}else if(0 == ret){
printf("poll time out\n");
continue;
}
break;
}
//printf("-------------poll success---------------\n");
// static struct v4l2_buffer buf;
if(pollfd.revents & POLLIN){
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(dev, VIDIOC_DQBUF, &buf);
if(0 != ret){
perror("VIDIOC_QBUF fail.\n");
return -1;
}
}
printf("-------------capture success---------------\n");
FILE *fp = fopen("./yuv.yuv", "wb+");
loff_t pos = 0;
fwrite((char*)framebuf.start, 1, buf.length, fp);
fclose(fp);
close(dev);
return 0;
}
离线