喀什百度做网站多少钱,外包是做什么的,网站自己推广,无锡专业网站制作的公司利用mmap 内存共享#xff0c;用另一个进程来控制录像循环的退出。
时间控制是指#xff1a;生成了n张图片帧用了多少时间m。帧率等于n/m。对应于头文件#xff0c;m等于scale, n等于rate.为了精确#xff0c;采用微秒计时。
I此程序生成的视频远好于ffmpeg#xff0c;…利用mmap 内存共享用另一个进程来控制录像循环的退出。
时间控制是指生成了n张图片帧用了多少时间m。帧率等于n/m。对应于头文件m等于scale, n等于rate.为了精确采用微秒计时。
I此程序生成的视频远好于ffmpeg可能是此程序没有压缩数据原因吧。
我的摄像头支持 YUYV422 和MJPG 两种格式YUYV是不压缩的MJPG是压缩的查v4l2.h
头文件得知YUV422有4种可任选一种看到视频采样宽度为16 字节。也就是说每个像素点用16个字节的数据表示图像的亮度色彩。mjpg 没有说用多少个字节表示一个像素点。我用16 24试过都可以用。如果实际观看时帧率不对则大方向是此值没置错误。
#define V4L2_PIX_FMT_YUYV v4l2_fourcc(Y, U, Y, V) /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_YYUV v4l2_fourcc(Y, Y, U, V) /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_YVYU v4l2_fourcc(Y, V, Y, U) /* 16 YVU 4:2:2 */ #define V4L2_PIX_FMT_UYVY v4l2_fourcc(U, Y, V, Y) /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_VYUY v4l2_fourcc(V, Y, U, Y) /* 16 YUV 4:2:2 */
/* compressed formats 压缩格式 */ #define V4L2_PIX_FMT_MJPEG v4l2_fourcc(M, J, P, G) /* Motion-JPEG */
MJPG 格式为压缩格式
这两种支持格式可任选一种摄像头与avi文件的视频格式必须一致
也就是程序中 vfmt.fmt.pix.pixelformat 与 strh .codec strf.compression ,这三者要一致。 avi 头文件 #ifndef AVI_H
#define AVI_H
#include stdio.h//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];}ri1;struct hdrl{unsigned char id[4]; //块ID固定为LISTunsigned int size; //块大小等于struct avi_hdrl_list去掉id和size的大小unsigned char type[4]; //块类型固定为hdrlstruct avih{unsigned char id[4]; //块ID固定为avihunsigned 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; //文件包含的流的个数仅有视频流时为1unsigned int suggest_buff_size; //指定读取本文件建议使用的缓冲区大小通常为存储一桢图像 //以及同步声音所需的数据之和不指定时设为0unsigned int width; //视频主窗口宽度单位像素unsigned int height; //视频主窗口高度单位像素unsigned int reserved[4]; //保留段设为0即可}ah1;struct strl{unsigned char id[4]; //块ID固定为LISTunsigned int size; //块大小等于struct avi_strl_list去掉id和size的大小unsigned char type[4]; //块类型固定为strlstruct strh{unsigned char id[4]; //块ID固定为strhunsigned int size; //块大小等于struct avi_strh_chunk去掉id和size的大小unsigned char stream_type[4]; //流的类型vids表示视频流auds表示音频流unsigned char codec[4]; //指定处理这个流需要的解码器如JPEGunsigned int flags; //标记如是否允许这个流输出、调色板是否变化等一般设为0即可unsigned short priority; //流的优先级视频流设为0即可unsigned short language; //音频语言代号视频流设为0即可unsigned int init_frames; //为交互格式指定初始帧数(非交互格式应该指定为0)unsigned int scale; //unsigned int rate; //对于视频流rate / scale 帧率fpsunsigned int start; //对于视频流设为0即可unsigned int length; //对于视频流length即总帧数unsigned int suggest_buff_size; //读取这个流数据建议使用的缓冲区大小unsigned int quality; //流数据的质量指标unsigned int sample_size; //音频采样大小视频流设为0即可struct rcFrame{ //这个流在视频主窗口中的显示位置设为{0,0width,height}即可short left;short top;short right;short bottom;} AVI_RECT_FRAME; }sh1;struct strf{unsigned char id[4]; //块ID固定为strfunsigned int size; //块大小等于struct avi_strf_chunk去掉id和size的大小unsigned int size1; //size1含义和值同size一样unsigned int width; //视频主窗口宽度单位像素unsigned int height; //视频主窗口高度单位像素unsigned short planes; //始终为1unsigned short bitcount; //每个像素占的位数只能是1、4、8、16、24和32中的一个unsigned char compression[4]; //视频流编码格式如JPEG、MJPG等unsigned int image_size; //视频图像大小等于width * height * bitcount / 8unsigned int x_pixels_per_meter; //显示设备的水平分辨率设为0即可unsigned int y_pixels_per_meter; //显示设备的垂直分辨率设为0即可unsigned int num_colors; //含义不清楚设为0即可unsigned int imp_colors; //含义不清楚设为0即可}sf1;}sl1;}hd1;struct movi{unsigned char id[4];unsigned int size;unsigned char type[4];}movi1;}HEAD;#endif
主程序 #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
#include sys/time.h#define wid 1920 //摄像头图像宽度
#define hei 1080 //图像高度
#define bitlen 16 //图像采样宽度 如不正确会影响帧率必须设置正确一般是8,16,24,32 之一可试
#define perframe 50 //先预估一帧率可设为摄像头最大帧率实际使用时的帧率小于次值主要用于程序设定数据缓冲区大小
#define jhframe 2000 //准备要录像的图片帧数控制录像的时间长度#define HCQ 10 //v4l2 缓冲区个数#define vcodes {M,J,P,G}
//#define vcodes {Y,U,Y,V}static int nframes 0; //总帧数
static int totalsize 0; //总字节数FILE * avi_ks(void) {chdir(/home/wzpc/Videos/);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 压缩的视频数据00db:未压缩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 wid;int height hei;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 / perframe, width*height*bitlen*perframe / 8, 0, 0, nframes,0, 1, width*height*bitlen / 8, 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},vcodes,// {J,P,E,G},// {Y, U, Y, V},0, 0, 0, 0,1, //4750perframe, //200000, nframes, width*height*bitlen*perframe / 8, 10000, 0,{0, 0, width, height}},{{s, t, r, f},sizeof(AVI_STRF_CHUNK) - 8,sizeof(AVI_STRF_CHUNK) - 8,width, height, 1,bitlen,vcodes,// {J, P, E, G},// {Y,U,Y,V},width * height *bitlen / 8, 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);return 0;
}int main(void) {int fd1open(/home/wzpc/1.txt,O_RDWR); //进程mmap共享用于控制录像的停止char *pmmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd1,0);// memcpy(p,bz,4); int fd open(/dev/video0, O_RDWR);if (fd 0) {perror(打开设备失败);return -1;}struct v4l2_format vfmt;vfmt.type 1;vfmt.fmt.pix.width wid;vfmt.fmt.pix.height hei;vfmt.fmt.pix.pixelformat V4L2_PIX_FMT_MJPEG;// vfmt.fmt.pix.pixelformatV4L2_PIX_FMT_YUYV; //重要 MJPG YUYV422
// vfmt.fmt.pix.pixelformatv4l2_fourcc(Y,U,Y,V);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 HCQ;reqbuffer.memory V4L2_MEMORY_MMAP ;ret ioctl(fd, VIDIOC_REQBUFS, reqbuffer);if (ret 0) {perror(申请队列空间失败);}//我理解以下部分struct v4l2_buffer mapbuffer; //相当于在为mapbuffer 设置读写规则还没有开始数据传输怎样从摄像头buf传输数据保存在多少个mmap中mapbuffer.type V4L2_BUF_TYPE_VIDEO_CAPTURE;unsigned char *mptr[HCQ];unsigned size[HCQ];for (int t 0; t HCQ; t) {mapbuffer.index t;ret ioctl(fd, VIDIOC_QUERYBUF, mapbuffer);//读摄像头缓冲区数据为映射mmap准备if(ret 0){perror(查询内核空间队列失败);}mptr[t] mmap(NULL, mapbuffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mapbuffer.m.offset); //摄像头缓冲区映射到内存size[t] mapbuffer.length;ret ioctl(fd, VIDIOC_QBUF, mapbuffer); //释放一个buf缓冲区空间摄像头可以为此buf写入数据if (ret 0) {perror(放回失败);}}
//--------------------------我的理解以上都是设置---------------------------------------------
// int type V4L2_BUF_TYPE_VIDEO_CAPTURE;ret ioctl(fd, VIDIOC_STREAMON, type); //启动流数据开始传输if (ret 0) {perror(开启失败);}//---------------------------------------------------------------------------FILE *file avi_ks();struct v4l2_buffer readbuffer;readbuffer.type V4L2_BUF_TYPE_VIDEO_CAPTURE; //安装mapbuffer设置的规矩来读数据从mmap中提取struct timeval start, end;gettimeofday(start, NULL ); //微秒记时开始int bz1;while ((nframes jhframe)(bz)) { //开另一进程控制录像停止puts(录像中.....);ret ioctl(fd, VIDIOC_DQBUF, readbuffer); //读当前队列缓冲区的数据 index循环1,VIDIOC_DQBUF执行一次index加1if (ret 0) {perror(提取数据失败);}int ireadbuffer.index;// printf(%d\n,mapbuffer.index); //验证index的循环变化int len readbuffer.length; //每一个mapbuff等于一帧字节,每一帧的字节数都是相同的// int lenwid*hei*bitlen/8;unsigned char tmp[4] {0, 0, d, c}; //00dc 压缩的视频数据fwrite(tmp, 4, 1, file);fwrite(len, 4, 1, file);fwrite(mptr[i],len, 1, file); //写入真正的JPEG数据ret ioctl(fd, VIDIOC_QBUF, readbuffer); //把缓冲区数据放入读队列中if (ret 0) {perror(放回失败);}nframes;totalsize;memcpy(bz,p,4);}static float timeuse1 0;gettimeofday(end, NULL ); //记时结束timeuse1 1000 * (1000000 * ( end.tv_sec - start.tv_sec ) end.tv_usec - start.tv_usec);int timeuse (int)(timeuse1 / 1000000); //转换为豪秒//---------------------------------------------------------ret ioctl(fd, VIDIOC_STREAMOFF, type);avi_end(file);int scale timeuse;int rate nframes * 1000; //重写实际帧率rate/scale ,乘1000是timeuse 为毫秒转换为秒printf(帧率:%d\n, rate / timeuse);fseek(file, 128, SEEK_SET); //128 为scale 在文件中的字节位数偏移fwrite(scale, 4, 1, file);fwrite(rate, 4, 1, file); //rate 为1284 位fclose(file);for (int n 0; n HCQ; n) {munmap(mptr, size[n]);}int kz11; //控制位复位1memcpy(p,kz1,4);munmap(p,4);close(fd);puts(end);return 0;
}3.停止录像进程
#include sys/mman.h#include stdio.h#include string.h#include fcntl.h#include unistd.hint main(void){int fdopen(/home/wzpc/1.txt,O_RDWR);char *pmmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);puts(start:t0\n);int t0; memcpy(p,t,4);return 0;}