(转)c 多张图片生成avi视频

news/2024/4/16 3:00:32

https://www.cnblogs.com/songhe364826110/p/7619949.html

修改了几个参数,可以生成视频了。下载主要是为了学习avi视频格式。最后编一个摄像头生成视频的程序。

本程序自定义了含avi 视频的各种数据结构的文件头(JpegAVI.h),所以就不用去下载借用ffmpeg,mplayer等的头文件,库文件了。

main.c


#include "Jpeg2AVI.h"
#include <string.h>#define JPEG_MAX_SIZE 2000000   //JPEG图像最大字节数,这个数必须大于每一张图片的字节数
#define JPEG_NUM 59  //JPEG图像数量 这个数必须小于等于实际文件数int main()
{FILE *fp_jpg;FILE *fp_avi;int filesize;unsigned char jpg_data[JPEG_MAX_SIZE];      char filename[10];int i = 0;fp_avi = fopen("sample.avi","wb");jpeg2avi_start(fp_avi);for (i = 0; i < JPEG_NUM; i++){memset(filename, 0, 10);memset(jpg_data, 0, JPEG_MAX_SIZE);sprintf(filename, "%d", i);  //int转字符fp_jpg = fopen(filename, "rb");if (fp_jpg != NULL){/*获取JPEG数据大小*/fseek(fp_jpg, 0, SEEK_END);filesize = ftell(fp_jpg);fseek(fp_jpg, 0, SEEK_SET);/*将JPEG数据读到缓冲区*/fread(jpg_data, filesize, 1, fp_jpg);/*将JPEG数据写入AVI文件*/jpeg2avi_add_frame(fp_avi, jpg_data, filesize);}fclose(fp_jpg);}jpeg2avi_end(fp_avi, 1280, 720,1);fclose(fp_avi);printf("end\n");return 0;
}

Jpeg2AVI.h

#ifndef _JPEG2AVI_H_
#define _JPEG2AVI_H_#include <stdio.h>void jpeg2avi_start(FILE *fp);
void jpeg2avi_add_frame(FILE *fp, void *data, unsigned int len);
void jpeg2avi_end(FILE *fp, int width, int height, int fps);typedef struct avi_riff_head
{unsigned char id[4];unsigned int size;unsigned char type[4];
}AVI_RIFF_HEAD, AVI_LIST_HEAD;typedef struct avi_avih_chunk
{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即可
}AVI_AVIH_CHUNK;typedef struct avi_rect_frame
{short left;short top;short right;short bottom;
}AVI_RECT_FRAME;typedef struct avi_strh_chunk
{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即可AVI_RECT_FRAME rcFrame;         //这个流在视频主窗口中的显示位置,设为{0,0,width,height}即可
}AVI_STRH_CHUNK;/*对于视频流,strf块结构如下*/
typedef struct avi_strf_chunk
{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即可
}AVI_STRF_CHUNK;typedef struct avi_strl_list
{unsigned char id[4];    //块ID,固定为LISTunsigned int size;      //块大小,等于struct avi_strl_list去掉id和size的大小unsigned char type[4];  //块类型,固定为strlAVI_STRH_CHUNK strh;AVI_STRF_CHUNK strf;
}AVI_STRL_LIST;typedef struct avi_hdrl_list
{unsigned char id[4];    //块ID,固定为LISTunsigned int size;      //块大小,等于struct avi_hdrl_list去掉id和size的大小unsigned char type[4];  //块类型,固定为hdrlAVI_AVIH_CHUNK avih;AVI_STRL_LIST  strl;
}AVI_HDRL_LIST;#endif

Jepg2AVI.c

#include "Jpeg2AVI.h"
#include "list.h"
#include <stdlib.h>
#include <string.h>static int nframes;           //总帧数
static int totalsize;         //帧的总大小
static struct list_head list; //保存各帧图像大小的链表,用于写索引块/*链表宿主结构,用于保存真正的图像大小数据*/
struct ListNode
{int value;struct list_head head;
};static void write_index_chunk(FILE *fp)
{unsigned char index[4] = {'i', 'd', 'x', '1'};  //索引块IDunsigned int index_chunk_size = 16 * nframes;   //索引块大小unsigned int offset = 4;struct list_head *slider = NULL;struct list_head *tmpslider = NULL;fwrite(index, 4, 1, fp);fwrite(&index_chunk_size, 4, 1, fp);list_for_each_safe(slider, tmpslider, &list){unsigned char tmp[4] = {'0', '0', 'd', 'c'};  //00dc = 压缩的视频数据unsigned int keyframe = 0x10;                 //0x10表示当前帧为关键帧struct ListNode *node = list_entry(slider, struct ListNode, head);fwrite(tmp, 4, 1, fp);fwrite(&keyframe, 4, 1, fp);fwrite(&offset, 4, 1, fp);fwrite(&node->value, 4, 1, fp);offset = offset + node->value + 8;list_del(slider);free(node);}
}static void back_fill_data(FILE *fp, int width, int height, int fps)
{AVI_RIFF_HEAD riff_head ={{'R', 'I', 'F', 'F'},4 + sizeof(AVI_HDRL_LIST) + sizeof(AVI_LIST_HEAD) + nframes * 8 + totalsize,{'A', 'V', 'I', ' '}};AVI_HDRL_LIST hdrl_list ={{'L', 'I', 'S', 'T'},sizeof(AVI_HDRL_LIST) - 8,{'h', 'd', 'r', 'l'},{{'a', 'v', 'i', 'h'},sizeof(AVI_AVIH_CHUNK) - 8,1000000 / fps, 25000, 0, 0, nframes, 0, 1, 100000, 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, 23, 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}}};AVI_LIST_HEAD movi_list_head ={{'L', 'I', 'S', 'T'},4 + nframes * 8 + totalsize,{'m', 'o', 'v', 'i'}};//定位到文件头,回填各块数据fseek(fp, 0, SEEK_SET);fwrite(&riff_head, sizeof(riff_head), 1, fp);fwrite(&hdrl_list, sizeof(hdrl_list), 1, fp);fwrite(&movi_list_head, sizeof(movi_list_head), 1, fp);
}void jpeg2avi_start(FILE *fp)
{int offset1 = sizeof(AVI_RIFF_HEAD);  //riff head大小int offset2 = sizeof(AVI_HDRL_LIST);  //hdrl list大小int offset3 = sizeof(AVI_LIST_HEAD);  //movi list head大小//AVI文件偏移量设置到movi list head后,从该位置向后依次写入JPEG数据fseek(fp, offset1 + offset2 + offset3, SEEK_SET);//初始化链表list_head_init(&list);nframes = 0;totalsize = 0;
}void jpeg2avi_add_frame(FILE *fp, void *data, unsigned int len)
{unsigned char tmp[4] = {'0', '0', 'd', 'c'};  //00dc = 压缩的视频数据struct ListNode *node = (struct ListNode *)malloc(sizeof(struct ListNode));/*JPEG图像大小4字节对齐*/while (len % 4){len++;}fwrite(tmp, 4, 1, fp);    //写入是否是压缩的视频数据信息fwrite(&len, 4, 1, fp);   //写入4字节对齐后的JPEG图像大小fwrite(data, len, 1, fp); //写入真正的JPEG数据nframes += 1;totalsize += len;/*将4字节对齐后的JPEG图像大小保存在链表中*/if (node != NULL){node->value = len;list_add_tail(&node->head, &list);}
}void jpeg2avi_end(FILE *fp, int width, int height, int fps)
{//写索引块write_index_chunk(fp);//从文件头开始,回填各块数据back_fill_data(fp, width, height, fps);
}

list.h

#ifndef _LIST_H_
#define _LIST_H_struct list_head
{struct list_head *next;struct list_head *prev;
};void list_head_init(struct list_head *list);
void list_add_tail(struct list_head *_new, struct list_head *head);
void list_del(struct list_head *entry);#ifndef offsetof
#define offsetof(TYPE, MEMBER) \
((size_t) &((TYPE *)0)->MEMBER)
#endif#ifndef container_of
#define container_of(ptr, type, member) \
((type *)((char *)ptr - offsetof(type,member)))
#endif/*** list_entry - get the struct for this entry* @ptr:    the &struct list_head pointer.* @type:    the type of the struct this is embedded in.* @member:    the name of the list_struct within the struct.*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)/*** list_for_each_safe - iterate over a list safe against removal of list entry* @pos:    the &struct list_head to use as a loop cursor.* @n:        another &struct list_head to use as temporary storage* @head:    the head for your list.*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)#endif //_LIST_H_

list.c

#include "list.h"
#include <stdio.h>static void __list_add(struct list_head *_new, struct list_head *prev, struct list_head *next)
{next->prev = _new;_new->next = next;_new->prev = prev;prev->next = _new;
}static void __list_del(struct list_head *prev, struct list_head *next)
{next->prev = prev;prev->next = next;
}void list_head_init(struct list_head *list)
{list->next = list;list->prev = list;
}/*** list_add_tail - insert a new entry before the specified head* @_new: new entry to be added* @head: list head to add it before*/
void list_add_tail(struct list_head *_new, struct list_head *head)
{__list_add(_new, head->prev, head);
}/*** list_del - deletes entry from list.* @entry: the element to delete from the list.*/
void list_del(struct list_head *entry)
{__list_del(entry->prev, entry->next);entry->next = NULL;entry->prev = NULL;
}

 

 

 

 


http://www.ppmy.cn/news/1166814.html

相关文章

Stable Diffusion WebUI扩展之batch-face-swap

老样子,先上地址。 Ranting8323 / batch-face-swap GitCodehttps://gitcode.net/ranting8323/batch-face-swap上面是GitCode地址,下面是GitHub地址。 kex0/batch-face-swap: Automaticaly detects faces and replaces them (github.com)

Oracle数据库----第七周实验____循环与游标

目录 Oracle数据库----第七周实验 循环与游标 Oracle数据库----第七周实验 循环与游标 循环与游标  循环  首先设置显示输出结果Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 Connected as systemORCL SQL> set serveroutput on; 1.简单…

最新Tuxera NTFS2024破解版mac读写NTFS磁盘工具

Tuxera NTFS for Mac是一款Mac系统NTFS磁盘读写软件。在系统默认状态下&#xff0c;MacOSX只能实现对NTFS的读取功能&#xff0c;Tuxera NTFS可以帮助MacOS 系统的电脑顺利实现对NTFS分区的读/写功能。Tuxera NTFS 2024完美兼容最新版本的MacOS 11 Big Sur&#xff0c;在M1芯片…

【马蹄集】—— 概率论专题:第二类斯特林数

概率论专题&#xff1a;第二类斯特林数 目录 MT2224 矩阵乘法MT2231 越狱MT2232 找朋友MT2233 盒子与球MT2234 点餐 MT2224 矩阵乘法 难度&#xff1a;黄金    时间限制&#xff1a;5秒    占用内存&#xff1a;128M 题目描述 输入两个矩阵&#xff0c;第一个矩阵尺寸为 l…

C/S架构学习之使用select实现TCP小型并发服务器

select实现TCP小型并发服务器的流程&#xff1a;一、创建套接字&#xff08;socket函数&#xff09;&#xff1a;通信域选择IPV4网络协议、套接字类型选择流式&#xff1b; int sockfd socket(AF_INET,SOCK_STREAM,0); //通信域选择IPV4、套接字类型选择流式二、填充服务器的网…

大数据测试用例分析

基于大数据分析&#xff0c;对业务系统产生的日志进行智能分析&#xff0c;能够识别日志中的接口、参数、业务流&#xff0c;并依据分析的结果生成测试用例。 问题与背景 业务复杂 业务系统的复杂性&#xff0c;对测试人员的业务能力提出严格要求&#xff0c;加重测试成本。 …

文件目录(文件控制块FCB,目录结构,索引结点)

1.文件控制块&#xff08;实现文件目录的关键数据结构) 目录文件中的一条记录就是文件控制块&#xff08;FCB&#xff09; FCB的有序集合称为“文件目录”&#xff0c;一个FCB就是一个文件目录项。 1.FCB的组成 FCB中包含了文件的基本信息&#xff08;文件名、物理地址、逻…

交换机控制在同一个网段内的终端,用hybrid接口实现不同的IP通和不通。

实验效果&#xff1a;pc1和pc2不能通&#xff0c;但pc1和pc2分别可以和pc3通。 通过这个实验可以彻底掌握数据包在交换机上的进去的类型状态。 sw1配置&#xff1a; [sw1]dis current-configuration sysname sw1 vlan batch 10 20 100 interface GigabitEthernet0/0/1 port h…

字节面试题——计算机网络,附答案

1.TCP 三次握手和四次挥手 相关面试题&#xff1a; 计算机网络常见面试题总结(上) | JavaGuide(Java面试 学习指南) 为什么要三次握手?第 2 次握手传回了 ACK&#xff0c;为什么还要传回 SYN&#xff1f;为什么要四次挥手&#xff1f;为什么不能把服务器发送的 ACK 和 FIN…

RHCE---搭建博客网站

一.实验要求&#xff1a; Server-NFS-DNS主机配置NFS服务器&#xff0c;将博客网站资源文件共享给Server-web主机&#xff0c;Server-NFS-DNS主机配置DNS Server-web主机配置web服务&#xff0c;通过域名www.openlab.com可以访问到自建的博客网站 二.准备工作 创建两台虚拟机…

c++_learning-对象模型探索

c对象模型探索 深入理解面向对象&#xff1a;c类对象模型&#xff1a;类中的成员&#xff1a;对象的内存大小&#xff1a;类对象内存的组成&#xff1a;不在对象内存中存放的成员&#xff1a; 类与类对象的内存分配&#xff1a;数据部分和代码部分&#xff1a;类对象占用的内存…

安装.net framework报错“...扩展属性不一致”

Windows操作系统中安装.net framework4.8&#xff0c;双击安装文件直接报错“…扩展属性不一致”&#xff0c;最初以为是操作系统补丁没有装全或者是没有管理员权限造成的&#xff0c;但是打了几个补丁&#xff0c;同时以管理员身份运行安装文件后&#xff0c;依然报同样的错误…

【力扣周赛】第 367 场周赛(⭐二维数组当成一维数组,前后缀分解)

文章目录 竞赛链接Q1&#xff1a;100096. 找出满足差值条件的下标 I竞赛时代码——暴力双循环 Q2&#xff1a;100084. 最短且字典序最小的美丽子字符串竞赛时代码——双指针 Q3&#xff1a;100101. 找出满足差值条件的下标 II竞赛时代码——记录可用最大最小值下标 Q4&#xff…

Nmap端口服务 之 CentOS7 关于启动Apache(httpd)服务、telnet服务、smtp服务、ftp服务、sftp服务

Nmap端口服务 之 CentOS7 关于启动Apache(httpd)服务、telnet服务、smtp服务、ftp服务、sftp服务 一. CentOS7 安装配置SFTP服务器详解一、SFTP简介二、关闭防火墙三、安装SSH服务在CentOS7中,sftp只是ssh的一部分,所以采用yum来安装ssh服务即可1. 查看是否已经安装了ssh2.…

第十三届蓝桥杯模拟赛第三期

A.填空题 问题描述 请问十六进制数 2021ABCD 对应的十进制是多少&#xff1f; 参考答案 539077581 import java.math.*; public class Main {public static void main(String[] args) {String strnew BigInteger("2021ABCD",16).toString(10);System.out.printl…

M-BUS和modbus的区别是什么?

M-BUS与Modbus是两种在工业自动化和楼宇自动化领域广泛应用的通信协议。那么&#xff0c;这两种通信协议有哪些区别呢?下面&#xff0c;就由小编带大家一起来了解下吧! 一、简介 M-BUS(Multi-dropBus&#xff0c;多点通信总线)和Modbus(莫迪波特率)都是用于设备和系统之间通信…

矩阵置零(C++解法)

题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例 2&#xff1a; 输入…

【kaggle】AI Report 2023概览

备注&#xff1a; 内容源自GPT4对AI Report 2023的整理&#xff0c;做了部分手工校正。下文GPT翻译“笔记本”&#xff1a;指的是jupyter notebookKaggle AI Report 2023中只是各文章的介绍&#xff0c;文章详细内容在Link to notebook超链接中。Kaggle AI Report 2023原文&am…

几种常见的方法对数组进行排序

在 JavaScript 中,有几种常见的方法可以对数组进行排序,包括以下几种: 1:Array.prototype.sort(): sort() 方法是数组原生的排序方法。默认情况下,它将数组元素转换为字符串,并按照 Unicode 编码进行排序。你可以传递一个比较函数作为参数来指定自定义的排序规则。 co…

目标检测YOLO实战应用案例100讲-面向恶劣环境下的多模态 行人识别

目录 前言 国内外研究现状 可见光行人目标识别 红外行人目标识别
最新文章