#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <main.h>
struct buf
{
void *start;
int len;
};
struct cam
{
struct v4l2_dev *v4_dev;
struct buf tran_frm; /* 帧转移 */
__u32 tran_frm_max_size;
};
struct v4l2_dev
{
int fd;
__u8 name[32];
__u8 drv[16];
struct buf *buf;
struct event_ext *ev;
void* arg;//arg即cam
};
//图像的位置
static void handle_jpeg_img_proc(const void *p, int size, void *arg)//arg即cam
{
struct cam *v = arg;//arg即cam
// 重新定义写入的图像数据
v->tran_frm.start = (void*)p;
v->tran_frm.len = size;
}
/*事件处理函数*/
void cam_handler(int fd,void *arg)
{
struct v4l2_buffer buf;
struct v4l2_dev *v = arg;//arg即cam
int file_fd;
file_fd = open("test.jpg",O_RDWR|O_CREAT,0777);
/*帧出列*/
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ioctl (v->fd, VIDIOC_DQBUF, &buf);//从缓冲区取出一个缓冲帧
// buffer中已使用的字节数
handle_jpeg_img_proc(v->buf[buf.index].start, buf.bytesused, v->arg);
//通过v->buf映射的的图像缓冲区,通过buf.index取到对应的图像
/*buf入列*/
ioctl(v->fd, VIDIOC_QBUF, &buf); //从缓冲区写入一个缓冲帧
}
struct v4l2_dev * v4l2_init()
{
struct v4l2_capability cap;
struct v4l2_dev *v;
struct v4l2_format fmt;//四字符代码,为了标示视频数据流格式
struct v4l2_requestbuffers req;
int i;
struct v4l2_buffer buf;
//1. 初始化摄像头
v = calloc(1,sizeof(struct v4l2_dev));
v->fd = open("/dev/video3",O_RDWR|O_NONBLOCK);
//1.1 获取驱动信息
ioctl (v->fd, VIDIOC_QUERYCAP, &cap);
// int ioctl(int handle, int cmd,[int *argdx, int argcx]);返回值:成功为0,出错为-1
//ioctl主要是调用后完成更改驱动中的参数 ******************* 重要概念 **********************
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) //检测摄像头
{
printf("this is not a video device\n");
return -1;
}
strcpy((char *)v->name,(char *)cap.card);
strcpy((char *)v->drv,(char *)cap.driver);
//1.2 设置图像格式
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 1280;
fmt.fmt.pix.height = 1024;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;//四字符代码,为了标示视频数据流格式
//这个结构体在设置格式和获取当然格式时会用到。
//struct v4l2_format {
//enum v4l2_buf_type type;//类型,已说过
//union {
// struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
// struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
// struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
// struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
// struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
// __u8 raw_data[200]; /* user-defined */
//} fmt;
ioctl (v->fd, VIDIOC_S_FMT, &fmt) ;
//1.3 申请图像缓冲区
req.count = 4;//4个连续缓冲区
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl (v->fd, VIDIOC_REQBUFS, &req);
//1.4 把内核空间中的图像缓冲区映射到用户空间
v->buf = calloc(4,sizeof(struct buf));
for (i = 0; i < req.count; i++)
{
/*获取图像缓冲区的信息*/
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl (v->fd, VIDIOC_QUERYBUF, &buf);
v->buf[i].len = buf.length;
// 把内核空间中的图像缓冲区映射到用户空间
v->buf[i].start = mmap (NULL , //通过mmap建立映射关系
buf.length,
PROT_READ | PROT_WRITE ,//可读可写标志
MAP_SHARED ,//与其它所有映射这个对象的进程共享映射空间。
v->fd,
buf.m.offset);//被映射对象内容的起点。
}
//1.5 图像缓冲入队
for (i = 0; i < 4; ++i)
{
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i; //取到对应的图像缓冲区的图像入队
ioctl (v->fd, VIDIOC_QBUF, &buf);
}
//2. 注册事件到epoll
v->ev = epoll_event_create(v->fd,EPOLLIN,cam_handler,v);
// 可读类型
epoll_add_event(srv_main->epfd,v->ev);
return v;
}
void v4l2_start_capture(struct v4l2_dev *v)
{
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl (v->fd, VIDIOC_STREAMON, &type);
}
struct cam * cam_sys_init()
{
struct cam *cam = calloc(1,sizeof(struct cam));
//1. 初始化
cam->v4_dev = v4l2_init();
cam->v4_dev->arg = cam; // arg在这里得到了cam
//2. 开始采集
v4l2_start_capture(cam->v4_dev);
//3. 第2课加入
return cam;
}
void cam_get_fmt(struct cam *v, __u8 *rsp)
{
__u32 fmt = V4L2_PIX_FMT_JPEG;
memcpy(rsp, &fmt, 4);
}
__u32 cam_get_trans_frame(struct cam *v, __u8 *rsp)
{
memcpy(rsp, v->tran_frm.start, v->tran_frm.len);
return v->tran_frm.len;
}
int process_incoming(struct tcp_cli * c)
{
struct cam *v = srv_main->cam;
__u8 *req = c->req;
__u8 *rsp = c->rsp;
__u8 id = req[CMD1_POS];
__u8 status = ERR_SUCCESS;
__u8 data[FRAME_DAT_MAX];//保存格式
__u32 pos, len, size;
switch (id) {
case REQUEST_ID(VID_GET_FMT)://发送图像格式
cam_get_fmt(v, data);
build_ack(rsp, (TYPE_SRSP << TYPE_BIT_POS) | SUBS_VID, id, 4, data);
// VID_GET_FMT = REQUEST(0x0, TYPE_SREQ, SUBS_VID, 0x11)
// #define REQUEST(len, type, subs, id) (((len) << (8*LEN_POS)) | \
// (((type) << TYPE_BIT_POS | (subs)) << (8*CMD0_POS)) | ((id) << (8*CMD1_POS)))
net_send(c, rsp, 4 + FRAME_HDR_SZ);
break;
case REQUEST_ID(VID_REQ_FRAME)://发送一帧图像
pos = FRAME_HDR_SZ + 4;
size = cam_get_trans_frame(v, &rsp[pos]);//这样一来图像就被保存到协议要求的位置来了
build_ack(rsp, (TYPE_SRSP << TYPE_BIT_POS) | SUBS_VID, id, 4, (__u8*)&size);//
//这里就是要保存len,之前没有保存,没有这一步会出错
net_send(c, rsp, pos + size);
break;
default:
status = ERR_CMD_ID;
break;
}
return status;
}
国嵌实时监控系统代码笔记(一)cam.c
最新推荐文章于 2019-01-02 15:12:59 发布