c 实用化的摄像头生成avi视频程序(加入精确的时间控制)
I时间控制是指:生成了n张图片帧用了多少时间m。帧率等于n/m。对应于头文件,m等于scale, n等于rate.为了精确,采用微秒计时。
I此程序生成的视频远好于ffmpeg,可能是此程序没有压缩数据原因吧。
现在的帧率不高,是因为只用了一个摄像头缓存区。
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,0,width,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 1280 //摄像头图像宽度
#define hei 720 //图像高度
#define bitlen 24 //图像采样宽度
#define perframe 30 //先预估一帧率,可以为摄像头最大帧率,实际使用时的帧率小于次值
#define jhframe 30 //准备要录像的图片帧数,控制录像的时间长度static int nframes=0; //总帧数
static int totalsize=0; //总字节数FILE * avi_ks(void) {FILE *fp = fopen("sample.avi", "w+b");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 = 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'},{'J', 'P', 'E', 'G'},0, 0, 0, 0, 1, //475020000, //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,{'J', 'P', 'E', 'G'},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 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; 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();struct timeval start,end; gettimeofday(&start, NULL ); //微秒记时开始while(nframes<jhframe){ret = ioctl(fd, VIDIOC_DQBUF, &mapbuffer); //读当前队列缓冲区的数据if(ret < 0){perror("提取数据失败");}int size=wid*hei*bitlen/8;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++; }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 为毫秒,转换为秒fseek(file,128,SEEK_SET); //128 为scale 在文件中的字节位数(偏移)fwrite(&scale,4,1,file);fwrite(&rate,4,1,file); //rate 为128+4 位fclose(file);munmap(mptr, size);/* FILE *ss=fopen("sample.avi","rb"); //检验scale ,rate 新值fseek(ss,0,SEEK_END);int len=ftell(ss);int ff=fileno(ss);char *tf=mmap(NULL,len,PROT_READ,MAP_SHARED,ff,0);memcpy(&HEAD,&tf[0],sizeof(HEAD));printf("scale:%d\n",HEAD.hd1.sl1.sh1.scale);printf("rate:%d\n",HEAD.hd1.sl1.sh1.rate);printf("end\n");
*/ close(fd);return 0;
}
相关文章:
c 实用化的摄像头生成avi视频程序(加入精确的时间控制)
I时间控制是指:生成了n张图片帧用了多少时间m。帧率等于n/m。对应于头文件,m等于scale, n等于rate.为了精确,采用微秒计时。 I此程序生成的视频远好于ffmpeg,可能是此程序没有压缩数据原因吧。 现在的帧率不高,是因…...
Web后端开发_01
Web后端开发 请求响应 SpringBoot提供了一个非常核心的Servlet 》DispatcherServlet,DispatcherServlet实现了servlet中规范的接口 请求响应: 请求(HttpServletRequest):获取请求数据响应(HttpServletRe…...
二十、泛型(6)
本章概要 问题 任何基本类型都不能作为类型参数实现参数化接口转型和警告重载基类劫持接口 自限定的类型 古怪的循环泛型自限定参数协变 问题 本节将阐述在使用 Java 泛型时会出现的各类问题。 任何基本类型都不能作为类型参数 正如本章早先提到的,Java 泛型的…...
Java18新增特性
前言 前面的文章,我们对Java9、Java10、Java11、Java12 、Java13、Java14、Java15、Java16、Java17 的特性进行了介绍,对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 Java14新增特性 Java15新增特性 Java…...
springboot容器
1.主要指的是servlet容器 servlet组件由sevlet Filter Listener等 2.自动配置原理 通过ServletWebServerFactoryAutoConfiguration 配置这些内容 (自动配置类开始分析功能) conditionalOnclass开启条件 ServletRequest类 import导入嵌入式的tomcat Jetty等 这些是配置类&…...
Windows 10 下使用Visual Studio 2017 编译CEF SDK
1.下载CEF SDK 由于需要跑在32位的机器,所以选择下载32位的SDKCEF Automated Builds 选择 Current Stable Build (Preferred) ,这是当前稳定版本,CEF版本118 下载成功解压 2.下载编译工具 CMake 下载地址:CMake 配置CMake指向…...
数字货币swap交易所逻辑系统开发分析方案
随着数字货币市场的快速发展, Swap交易所已成为一种重要的交易方式。本文将对数字货币Swap交易所逻辑系统开发进行分析,并探讨其优势、开发难点和解决方案。 一、数字货币Swap交易所逻辑系统开发的优势 数字货币Swap交易所是一种点对点的交易方式&#x…...
spring boot中使用Bean Validation做优雅的参数校验
一、Bean Validation简介 Bean Validation是Java定义的一套基于注解的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),目前最新稳定版2.0.2(201…...
搜索引擎项目
认识搜索引擎 1、有一个主页、有搜索框。在搜索框中输入的内容 称为“查询词” 2、还有搜索结果页,包含了若干条搜索结果 3、针对每一个搜索结果,都会包含查询词或者查询词的一部分或者和查询词具有一定的相关性 4、每个搜索结果包含好几个部分&…...
7.外部存储器,Cache,虚拟存储器
目录 一. 外部存储器 (1)磁盘存储器 1.磁盘的组成 2.磁盘的性能指标 3.磁盘地址 4.硬盘的工作过程 5.磁盘阵列 (2)固态硬盘(SSD) 二. Cache基本概念与原理 三. Cache和主存的映射方式 ÿ…...
UITableView的style是UITableViewStyleGrouped
一般情况下,UITableViewStylePlain和UITableViewStyleGrouped是UITableView常用到的style, 之前都是用到的时候,遇到问题直接用度娘,差不多就够用了,今天在修复UI提出的间隙问题,来回改,总觉得…...
Java17新增特性
前言 前面的文章,我们对Java9、Java10、Java11、Java12 、Java13、Java14、Java15、Java16 的特性进行了介绍,对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 Java14新增特性 Java15新增特性 Java16新增特…...
VR全景技术在城市园区发展中有哪些应用与帮助
引言: 在数字化时代的浪潮中,虚拟现实(VR)全景技术逐渐融入各个领域,也为城市园区展示带来了全新的可能性。 一.VR全景技术简介 虚拟现实全景技术是一种通过全景图像和视频模拟真实环境的技术。通过相关设…...
在 SQL 中,当复合主键成为外键时应该如何被其它表引用
文章目录 当研究一个问题慢慢深入时,一个看起来简单的问题也暗藏玄机。在 SQL 中,主键成为外键这是一个很平常的问题,乍一看没啥值得注意的。但如果这个主键是一种复合主键,而另一个表又引用这个键作为它的复合主键,问…...
Ps:通过显示大小了解图像的打印尺寸
在 Photoshop 中,如果想了解文档窗口中的图像打印出来之后的实质大小,只要知道两个数值即可。 第一个数值是图像分辨率(也称“文档分辨率”)的大小,可在Ps菜单:图像/图像大小 Image Size对话框中查询或设置…...
Linux - 驱动开发 - watchdog - SMP机制下多核确活
说明 理论上:不管IC是单核还是多核,只要watchdog有被循环feed,就不会触发超时重启,因此watchdog在SMP机制下的多核环境显得比较宽松,只要任意核存活(喂狗)就不会重启设备。 实际情况 有客户反…...
概念解析 | LoRA:低秩矩阵分解在神经网络微调中的魔力
注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:基于低秩矩阵分解的神经网络微调方法LoRA LoRA:低秩矩阵分解在神经网络微调中的魔力 Low-Rank Adaptation of Large Language Models LoRA由如下论文提出,详细信息请参见论文原…...
量子计算和量子通信技术:引领潜力无限的未来
近年来,随着量子计算和量子通信技术的迅速发展,它们在各个领域的广泛应用前景引起了人们的极大兴趣。本文将深入探讨量子计算和量子通信技术的普遍应用,以及它们预示的未来,同时提出业内人士需要注意的事项。 介绍:量子…...
nodejs+vue+python+PHP+微信小程序-安卓- 电影在线订票系统的设计与实现-计算机毕业设计推荐
目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性:…...
LightDB23.4支持mysql aes_encrypt/aes_decrypt/hex/unhex函数
背景介绍 为了兼容mysql数据库的功能,在LightDB23.4版本上支持hex/unhex/aes_encrypt/aes_decrypt函数。 函数原型如下: hex(data bytea) returns textunhex(data varchar) returns byteaaes_encrypt(data bytea, key bytea) returns byteaaes_encryp…...
Swift-All快速上手:RM模型评测保姆级教程,小白也能搞定
Swift-All快速上手:RM模型评测保姆级教程,小白也能搞定 1. 前言:为什么要评测RM模型? 想象你训练了一个AI裁判,专门给AI生成的回答打分。但你怎么知道这个裁判判得准不准?这就是RM(Reward Mod…...
使用OpenGL纹理数组实现高精度实时Lut滤镜
之前写过的文章(使用OpenGL实现滤镜转换的一种思路_轮子初级玩家-CSDN博客),我把一整个Lut滤镜图作为单个纹理贴图,把图像原颜色采样后当作坐标,然后从lut纹理中查找出替换颜色实现滤镜功能,这是最简易的一种滤镜实现方式…...
Nunchaku FLUX.1 CustomV3实战教程:多LoRA并行加载与动态权重切换操作指南
Nunchaku FLUX.1 CustomV3实战教程:多LoRA并行加载与动态权重切换操作指南 1. 认识Nunchaku FLUX.1 CustomV3 Nunchaku FLUX.1 CustomV3是一个基于Nunchaku FLUX.1-dev模型的文生图工作流程,通过整合FLUX.1-Turbo-Alpha和Ghibsky Illustration两个LoRA…...
小程序支付实名认证跳转:从安卓兼容到iOS限制的实战处理方案
1. 小程序支付实名认证跳转的痛点解析 最近在开发一个保险行业的小程序时,遇到了一个让人头疼的问题:支付环节需要跳转到微支保小程序进行实名认证。最初的做法很简单粗暴,直接在页面加载时就调用wx.navigateToMiniProgram跳转。测试时发现&a…...
2.5MW ANPC拓扑储能变流器PCS整流器仿真搭建之旅
储能变流器pcs整流器仿真模型,联系默认发百度,ANPC电路拓扑,2.5MW,电压外环,电流内环,2016版本的matlab在电力电子领域,储能变流器PCS(Power Conversion System)的整流器…...
作家使用AI写小说:写作者必须接纳人工智能但我们依然珍贵
我最近在游乐场听到一段对话,这比任何分析师对泡沫的预测都更应该让AI公司高管担忧。一个男孩和一个女孩,大概10岁,正在争吵。"那是AI!那是AI!"女孩喊道。她的意思是男孩在沉溺于一种新的特殊胡言乱语&#…...
针对双SMC控制的四轮转向轨迹跟踪模型优化与效果评估研究
四轮转向4WS轨迹跟踪控制模型 采用双SMC控制 4WS通过积分滑模控制跟踪期望横摆角速度和质心侧偏角,效果很好~ 轨迹跟踪为双移线输入,采用积分滑模控制 【特别说明】 是针对两篇论文的控制进行复现哦~ 提供参考文献及模型文件 最近在复现四轮转向轨迹跟踪…...
Android学习资源与成长指南
Android学习资源与成长指南 概述 本文将Android开发者的成长路径、学习资源、开源项目、技术社区、推荐书籍和面试准备整合为一份完整指南,覆盖从入门到架构师的全阶段。一、学习路线图:从入门到架构师 1.1 第一阶段:初级开发(0-6…...
霸王餐外卖接口对接中的签名校验、加密传输 Java 后端实现细节
霸王餐外卖接口对接中的签名校验、加密传输 Java 后端实现细节 在霸王餐(免费试吃)及外卖CPS分销系统的开发中,数据的安全性是核心命脉。由于涉及用户的隐私信息(如手机号、OpenId)以及核心的佣金计算逻辑,…...
魔方财务批量拉取产品信息教程
使用魔方财务,有时候经常上级【变化了ip】或者批量【补时间】什么的,我们这里因为我们的财务换过域名,导致上级无法给我们推送需要我们手动拉取信息,一个两个还好,几百个怎么办? 本教程就是【欧云服务器】…...
