宝安商城网站建设,汕头建筑信息网,智慧城市,北京竞价托管代运营https://www.cnblogs.com/songhe364826110/p/7619949.html
修改了几个参数#xff0c;可以生成视频了。下载主要是为了学习avi视频格式。最后编一个摄像头生成视频的程序。
本程序把标准avi 视频格式的各种数据结构自定义在文件头(JpegAVI.h)中#xff0c;所以就不用去下载…https://www.cnblogs.com/songhe364826110/p/7619949.html
修改了几个参数可以生成视频了。下载主要是为了学习avi视频格式。最后编一个摄像头生成视频的程序。
本程序把标准avi 视频格式的各种数据结构自定义在文件头(JpegAVI.h)中所以就不用去下载借用ffmpeg,mplayer等的头文件库文件了。现在发现其实编写程序不难难的是理解定义的各种数据结构和怎样按avi协议去用这些定义的结构。
现在有点明白了为什么学编程要数学好数学不好就想不出这些数据结构和怎样构建这些文件体系。就象现在虽然有些c的编程知识可什么也干不了解决不了实际问题。想创新是不可能的只有复制别人的成果。
图片文件名为数字从0开始不含后缀。
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.hvoid 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,0width,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.hstatic 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.hstatic 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;
}