当前位置: 首页 > news >正文

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时间控制是指&#xff1a;生成了n张图片帧用了多少时间m。帧率等于n/m。对应于头文件&#xff0c;m等于scale, n等于rate.为了精确&#xff0c;采用微秒计时。 I此程序生成的视频远好于ffmpeg&#xff0c;可能是此程序没有压缩数据原因吧。 现在的帧率不高&#xff0c;是因…...

Web后端开发_01

Web后端开发 请求响应 SpringBoot提供了一个非常核心的Servlet 》DispatcherServlet&#xff0c;DispatcherServlet实现了servlet中规范的接口 请求响应&#xff1a; 请求&#xff08;HttpServletRequest&#xff09;&#xff1a;获取请求数据响应&#xff08;HttpServletRe…...

二十、泛型(6)

本章概要 问题 任何基本类型都不能作为类型参数实现参数化接口转型和警告重载基类劫持接口 自限定的类型 古怪的循环泛型自限定参数协变 问题 本节将阐述在使用 Java 泛型时会出现的各类问题。 任何基本类型都不能作为类型参数 正如本章早先提到的&#xff0c;Java 泛型的…...

Java18新增特性

前言 前面的文章&#xff0c;我们对Java9、Java10、Java11、Java12 、Java13、Java14、Java15、Java16、Java17 的特性进行了介绍&#xff0c;对应的文章如下 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位的机器&#xff0c;所以选择下载32位的SDKCEF Automated Builds 选择 Current Stable Build (Preferred) &#xff0c;这是当前稳定版本&#xff0c;CEF版本118 下载成功解压 2.下载编译工具 CMake 下载地址&#xff1a;CMake 配置CMake指向…...

数字货币swap交易所逻辑系统开发分析方案

随着数字货币市场的快速发展&#xff0c; Swap交易所已成为一种重要的交易方式。本文将对数字货币Swap交易所逻辑系统开发进行分析&#xff0c;并探讨其优势、开发难点和解决方案。 一、数字货币Swap交易所逻辑系统开发的优势 数字货币Swap交易所是一种点对点的交易方式&#x…...

spring boot中使用Bean Validation做优雅的参数校验

一、Bean Validation简介 Bean Validation是Java定义的一套基于注解的数据校验规范&#xff0c;目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本&#xff0c;再到JSR 380的2.0版本&#xff08;2.0完成于2017.08&#xff09;&#xff0c;目前最新稳定版2.0.2&#xff08;201…...

搜索引擎项目

认识搜索引擎 1、有一个主页、有搜索框。在搜索框中输入的内容 称为“查询词” 2、还有搜索结果页&#xff0c;包含了若干条搜索结果 3、针对每一个搜索结果&#xff0c;都会包含查询词或者查询词的一部分或者和查询词具有一定的相关性 4、每个搜索结果包含好几个部分&…...

7.外部存储器,Cache,虚拟存储器

目录 一. 外部存储器 &#xff08;1&#xff09;磁盘存储器 1.磁盘的组成 2.磁盘的性能指标 3.磁盘地址 4.硬盘的工作过程 5.磁盘阵列 &#xff08;2&#xff09;固态硬盘&#xff08;SSD&#xff09; 二. Cache基本概念与原理 三. Cache和主存的映射方式 &#xff…...

UITableView的style是UITableViewStyleGrouped

一般情况下&#xff0c;UITableViewStylePlain和UITableViewStyleGrouped是UITableView常用到的style&#xff0c; 之前都是用到的时候&#xff0c;遇到问题直接用度娘&#xff0c;差不多就够用了&#xff0c;今天在修复UI提出的间隙问题&#xff0c;来回改&#xff0c;总觉得…...

Java17新增特性

前言 前面的文章&#xff0c;我们对Java9、Java10、Java11、Java12 、Java13、Java14、Java15、Java16 的特性进行了介绍&#xff0c;对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 Java14新增特性 Java15新增特性 Java16新增特…...

VR全景技术在城市园区发展中有哪些应用与帮助

引言&#xff1a; 在数字化时代的浪潮中&#xff0c;虚拟现实&#xff08;VR&#xff09;全景技术逐渐融入各个领域&#xff0c;也为城市园区展示带来了全新的可能性。 一&#xff0e;VR全景技术简介 虚拟现实全景技术是一种通过全景图像和视频模拟真实环境的技术。通过相关设…...

在 SQL 中,当复合主键成为外键时应该如何被其它表引用

文章目录 当研究一个问题慢慢深入时&#xff0c;一个看起来简单的问题也暗藏玄机。在 SQL 中&#xff0c;主键成为外键这是一个很平常的问题&#xff0c;乍一看没啥值得注意的。但如果这个主键是一种复合主键&#xff0c;而另一个表又引用这个键作为它的复合主键&#xff0c;问…...

Ps:通过显示大小了解图像的打印尺寸

在 Photoshop 中&#xff0c;如果想了解文档窗口中的图像打印出来之后的实质大小&#xff0c;只要知道两个数值即可。 第一个数值是图像分辨率&#xff08;也称“文档分辨率”&#xff09;的大小&#xff0c;可在Ps菜单&#xff1a;图像/图像大小 Image Size对话框中查询或设置…...

Linux - 驱动开发 - watchdog - SMP机制下多核确活

说明 理论上&#xff1a;不管IC是单核还是多核&#xff0c;只要watchdog有被循环feed&#xff0c;就不会触发超时重启&#xff0c;因此watchdog在SMP机制下的多核环境显得比较宽松&#xff0c;只要任意核存活&#xff08;喂狗&#xff09;就不会重启设备。 实际情况 有客户反…...

概念解析 | LoRA:低秩矩阵分解在神经网络微调中的魔力

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:基于低秩矩阵分解的神经网络微调方法LoRA LoRA:低秩矩阵分解在神经网络微调中的魔力 Low-Rank Adaptation of Large Language Models LoRA由如下论文提出,详细信息请参见论文原…...

量子计算和量子通信技术:引领潜力无限的未来

近年来&#xff0c;随着量子计算和量子通信技术的迅速发展&#xff0c;它们在各个领域的广泛应用前景引起了人们的极大兴趣。本文将深入探讨量子计算和量子通信技术的普遍应用&#xff0c;以及它们预示的未来&#xff0c;同时提出业内人士需要注意的事项。 介绍&#xff1a;量子…...

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技术可行性&#xff1a;…...

LightDB23.4支持mysql aes_encrypt/aes_decrypt/hex/unhex函数

背景介绍 为了兼容mysql数据库的功能&#xff0c;在LightDB23.4版本上支持hex/unhex/aes_encrypt/aes_decrypt函数。 函数原型如下&#xff1a; hex(data bytea) returns textunhex(data varchar) returns byteaaes_encrypt(data bytea, key bytea) returns byteaaes_encryp…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

Oracle11g安装包

Oracle 11g安装包 适用于windows系统&#xff0c;64位 下载路径 oracle 11g 安装包...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...