c 摄像头利用v4l2直接生成avi视频(不利用ffmpeg)
自定义avi结构头文件。现在不能实时显示摄像头画面,准备参照fim(终端中显示图片),直接对显示framebuffer操作,显示视频。不用qt等。
生成的视频根据机子的性能不同,诂计要手动调一下生成视频的帧率。
播放: $ aplay musicdemo.wmv
录音: $ arecord -c 2 -r 44100 -f S16_LE musicdemo.wmv
调节音量大小: $ alsamixer
deepin安装 alsa-lib
sudo apt-get install libasound2-dev
main.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#include "Avi.h"
int main(void){
int fd = open("/dev/video0", O_RDWR);
if(fd < 0)
{
perror("打开设备失败");
return -1;
}
struct v4l2_format vfmt;
vfmt.type=1;
vfmt.fmt.pix.width=1680;
vfmt.fmt.pix.height=1080;
vfmt.fmt.pix.pixelformat=V4L2_PIX_FMT_MJPEG;
int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);
if(ret < 0)
{
perror("设置格式失败");
}
struct v4l2_requestbuffers reqbuffer;
reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuffer.count = 1;
reqbuffer.memory = V4L2_MEMORY_MMAP ;
ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuffer);
if(ret < 0)
{
perror("申请队列空间失败");
}
struct v4l2_buffer mapbuffer;
unsigned char *mptr;
unsigned int size;
mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
mapbuffer.index = 0;
ret = ioctl(fd, VIDIOC_QUERYBUF, &mapbuffer);//查询缓冲区状态
if(ret < 0)
{
perror("查询内核空间队列失败");
}
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_STREAMON, &type); //启动流
if(ret < 0)
{
perror("开启失败");
}
mptr= (unsigned char *)mmap(NULL, mapbuffer.length, PROT_READ|PROT_WRITE,
MAP_SHARED, fd,0); //设备映射到缓冲区内存
size=mapbuffer.length;
ret = ioctl(fd, VIDIOC_QBUF, &mapbuffer); //把缓冲区数据放入读队列中
if(ret < 0)
{
perror("放回失败");
}
//---------------------------------------------------------------------------
FILE *file=avi_ks();
while(nframes<100){
ret = ioctl(fd, VIDIOC_DQBUF, &mapbuffer); //读当前队列缓冲区的数据
if(ret < 0)
{
perror("提取数据失败");
}
int size=1280*720;
unsigned char tmp[4] = {'0', '0', 'd', 'c'}; //00dc = 压缩的视频数据
fwrite(tmp, 4, 1, file); //写入是否是压缩的视频数据信息
fwrite(&size, 4, 1, file); //写入4字节对齐后的JPEG图像大小
fwrite(mptr,size, 1, file); //写入真正的JPEG数据
ret = ioctl(fd, VIDIOC_QBUF, &mapbuffer); //把缓冲区数据放入读队列中
if(ret < 0)
{
perror("放回失败");
}
nframes++;
totalsize++;
}
//---------------------------------------------------------
ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
avi_end(file);
munmap(mptr, size);
close(fd);
return 0;
}
avi.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "Avi.h"
FILE * avi_ks(void){
FILE *fp= fopen("sample.avi","wb");
fseek(fp,sizeof(HEAD),SEEK_SET);
return fp;
}
//--------------------------------------------------------
int avi_add(FILE*fp,char *data,int size){
unsigned char tmp[4] = {'0', '0', 'd', 'c'}; //00dc = 压缩的视频数据
fwrite(tmp, 4, 1, fp); //写入是否是压缩的视频数据信息
fwrite(&size, 4, 1, fp); //写入4字节对齐后的JPEG图像大小
fwrite(data,size, 1, fp); //写入真正的JPEG数据
return 0;
}
//----------------------------------------------------------------------------------
int avi_end(FILE *f_file){
int width=1280;
int height=720;
typedef struct hdrl AVI_HDRL_LIST;
typedef struct movi AVI_LIST_HEAD;
typedef struct avih AVI_AVIH_CHUNK;
typedef struct strl AVI_STRL_LIST;
typedef struct strh AVI_STRH_CHUNK;
typedef struct strf AVI_STRF_CHUNK;
typedef struct avi AVI_HEAD;
AVI_HEAD avi_head={
{
{'R', 'I', 'F', 'F'},
4 + sizeof(AVI_HDRL_LIST) + sizeof(AVI_LIST_HEAD) +nframes * 8 + totalsize,
{'A', 'V', 'I', ' '}
},
{
{'L', 'I', 'S', 'T'},
sizeof(AVI_HDRL_LIST) - 8,
{'h', 'd', 'r', 'l'},
{
{'a', 'v', 'i', 'h'},
sizeof(AVI_AVIH_CHUNK) - 8,
1000000, 25000, 0, 0,nframes, 0, 1, 1000000, width, height,
{0, 0, 0, 0}
},
{
{'L', 'I', 'S', 'T'},
sizeof(AVI_STRL_LIST) - 8,
{'s', 't', 'r', 'l'},
{
{'s', 't', 'r', 'h'},
sizeof(AVI_STRH_CHUNK) - 8,
{'v', 'i', 'd', 's'},
{'J', 'P', 'E', 'G'},
0, 0, 0, 0, 1, 15, 0, nframes, 100000, 0xFFFFFF, 0,
{0, 0, width, height}
},
{
{'s', 't', 'r', 'f'},
sizeof(AVI_STRF_CHUNK) - 8,
sizeof(AVI_STRF_CHUNK) - 8,
width, height, 1, 24,
{'J', 'P', 'E', 'G'},
width * height * 3, 0, 0, 0, 0
}
}
},
{
{'L', 'I', 'S', 'T'},
4 + nframes * 8 + totalsize,
{'m', 'o', 'v', 'i'}
}
};
fseek(f_file, 0, SEEK_SET);
fwrite(&avi_head,sizeof(HEAD),1,f_file);
fclose(f_file);
printf("endn");
}
avi.h
#ifndef AVI_H
#define AVI_H
#include <stdio.h>
static int nframes; //总帧数
static int totalsize;
FILE * avi_ks(void);
int avi_add(FILE*fp,char *data,int size);
int avi_end(FILE *f_file);
struct avi{
struct riff{
unsigned char id[4];
unsigned int size;
unsigned char type[4];
}r1;
struct hdrl{
unsigned char id[4]; //块ID,固定为LIST
unsigned int size; //块大小,等于struct avi_hdrl_list去掉id和size的大小
unsigned char type[4]; //块类型,固定为hdrl
struct avih{
unsigned char id[4]; //块ID,固定为avih
unsigned int size; //块大小,等于struct avi_avih_chunk去掉id和size的大小
unsigned int us_per_frame; //视频帧间隔时间(以微秒为单位)
unsigned int max_bytes_per_sec; //AVI文件的最大数据率
unsigned int padding; //设为0即可
unsigned int flags; //AVI文件全局属性,如是否含有索引块、音视频数据是否交叉存储等
unsigned int total_frames; //总帧数
unsigned int init_frames; //为交互格式指定初始帧数(非交互格式应该指定为0)
unsigned int streams; //文件包含的流的个数,仅有视频流时为1
unsigned int suggest_buff_size; //指定读取本文件建议使用的缓冲区大小,通常为存储一桢图像 //以及同步声音所需的数据之和,不指定时设为0
unsigned int width; //视频主窗口宽度(单位:像素)
unsigned int height; //视频主窗口高度(单位:像素)
unsigned int reserved[4]; //保留段,设为0即可
}a1;
struct strl{
unsigned char id[4]; //块ID,固定为LIST
unsigned int size; //块大小,等于struct avi_strl_list去掉id和size的大小
unsigned char type[4]; //块类型,固定为strl
struct strh{
unsigned char id[4]; //块ID,固定为strh
unsigned int size; //块大小,等于struct avi_strh_chunk去掉id和size的大小
unsigned char stream_type[4]; //流的类型,vids表示视频流,auds表示音频流
unsigned char codec[4]; //指定处理这个流需要的解码器,如JPEG
unsigned int flags; //标记,如是否允许这个流输出、调色板是否变化等,一般设为0即可
unsigned short priority; //流的优先级,视频流设为0即可
unsigned short language; //音频语言代号,视频流设为0即可
unsigned int init_frames; //为交互格式指定初始帧数(非交互格式应该指定为0)
unsigned int scale; //
unsigned int rate; //对于视频流,rate / scale = 帧率fps
unsigned int start; //对于视频流,设为0即可
unsigned int length; //对于视频流,length即总帧数
unsigned int suggest_buff_size; //读取这个流数据建议使用的缓冲区大小
unsigned int quality; //流数据的质量指标
unsigned int sample_size; //音频采样大小,视频流设为0即可
struct rcFrame{ //这个流在视频主窗口中的显示位置,设为{0,0,width,height}即可
short left;
short top;
short right;
short bottom;
} AVI_RECT_FRAME;
}s1;
struct strf{
unsigned char id[4]; //块ID,固定为strf
unsigned int size; //块大小,等于struct avi_strf_chunk去掉id和size的大小
unsigned int size1; //size1含义和值同size一样
unsigned int width; //视频主窗口宽度(单位:像素)
unsigned int height; //视频主窗口高度(单位:像素)
unsigned short planes; //始终为1
unsigned short bitcount; //每个像素占的位数,只能是1、4、8、16、24和32中的一个
unsigned char compression[4]; //视频流编码格式,如JPEG、MJPG等
unsigned int image_size; //视频图像大小,等于width * height * bitcount / 8
unsigned int x_pixels_per_meter; //显示设备的水平分辨率,设为0即可
unsigned int y_pixels_per_meter; //显示设备的垂直分辨率,设为0即可
unsigned int num_colors; //含义不清楚,设为0即可
unsigned int imp_colors; //含义不清楚,设为0即可
}q1;
}w1;
}a1;
struct movi{
unsigned char id[4];
unsigned int size;
unsigned char type[4];
}movi1;
}HEAD;
#endif