-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <malloc.h>
- #include <wait.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/mman.h>
-
- #define JPEG_MAX_SIZE 2000000 //JPEG图像最大字节数
- #define JPEG_NUM 400 //JPEG图像数量
- static int nframes; //总帧数
- static int totalsize; //帧的总大小
-
- int main(void){
-
- struct avi{
- struct riff{
- unsigned char id[4];
- unsigned int size;
- unsigned char type[4];
- }r1;
-
-
- struct hdrl{
- unsigned char id[4]; //块ID,固定为LIST
- unsigned int size; //块大小,等于struct avi_hdrl_list去掉id和size的大小
- unsigned char type[4]; //块类型,固定为hdrl
-
- struct avih{
- unsigned char id[4]; //块ID,固定为avih
- unsigned 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; //文件包含的流的个数,仅有视频流时为1
- unsigned int suggest_buff_size; //指定读取本文件建议使用的缓冲区大小,通常为存储一桢图像 //以及同步声音所需的数据之和,不指定时设为0
- unsigned int width; //视频主窗口宽度(单位:像素)
- unsigned int height; //视频主窗口高度(单位:像素)
- unsigned int reserved[4]; //保留段,设为0即可
- }a1;
-
- struct strl{
- unsigned char id[4]; //块ID,固定为LIST
- unsigned int size; //块大小,等于struct avi_strl_list去掉id和size的大小
- unsigned char type[4]; //块类型,固定为strl
-
- struct strh{
- unsigned char id[4]; //块ID,固定为strh
- unsigned int size; //块大小,等于struct avi_strh_chunk去掉id和size的大小
- unsigned char stream_type[4]; //流的类型,vids表示视频流,auds表示音频流
- unsigned char codec[4]; //指定处理这个流需要的解码器,如JPEG
- unsigned int flags; //标记,如是否允许这个流输出、调色板是否变化等,一般设为0即可
- unsigned short priority; //流的优先级,视频流设为0即可
- unsigned short language; //音频语言代号,视频流设为0即可
- unsigned int init_frames; //为交互格式指定初始帧数(非交互格式应该指定为0)
- unsigned int scale; //
- unsigned int rate; //对于视频流,rate / scale = 帧率fps
- unsigned 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;
- }s1;
-
- struct strf{
- unsigned char id[4]; //块ID,固定为strf
- unsigned int size; //块大小,等于struct avi_strf_chunk去掉id和size的大小
- unsigned int size1; //size1含义和值同size一样
- unsigned int width; //视频主窗口宽度(单位:像素)
- unsigned int height; //视频主窗口高度(单位:像素)
- unsigned short planes; //始终为1
- unsigned short bitcount; //每个像素占的位数,只能是1、4、8、16、24和32中的一个
- unsigned char compression[4]; //视频流编码格式,如JPEG、MJPG等
- unsigned int image_size; //视频图像大小,等于width * height * bitcount / 8
- unsigned int x_pixels_per_meter; //显示设备的水平分辨率,设为0即可
- unsigned int y_pixels_per_meter; //显示设备的垂直分辨率,设为0即可
- unsigned int num_colors; //含义不清楚,设为0即可
- unsigned int imp_colors; //含义不清楚,设为0即可
- }q1;
-
- }w1;
-
- }a1;
-
- struct movi{
- unsigned char id[4];
- unsigned int size;
- unsigned char type[4];
- }movi1;
-
- }HEAD;
-
-
- //--------------------------------------------------------------------------------------
- FILE *fp_jpg;
- FILE *fp;
- int filesize;
- unsigned char jpg_data[JPEG_MAX_SIZE];
-
- char filename[10];
- int i = 0;
-
- fp= fopen("sample.avi","wb");
-
- //AVI文件偏移量设置到movi list head后,从该位置向后依次写入JPEG数据
-
- fseek(fp,sizeof(HEAD),SEEK_SET);
- //--------------------------------------------------------
-
- 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文件*/
- unsigned char tmp[4] = {'0', '0', 'd', 'c'}; //00dc = 压缩的视频数据
-
- fwrite(tmp, 4, 1, fp); //写入是否是压缩的视频数据信息
- fwrite(&filesize, 4, 1, fp); //写入4字节对齐后的JPEG图像大小
- fwrite(jpg_data, filesize, 1, fp); //写入真正的JPEG数据
-
- nframes += 1;
- totalsize += filesize;
- }
-
- fclose(fp_jpg);
- }
-
- int width=1280;
- int height=720;
-
-
- 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/23, 25000, 0, 0,nframes, 0, 1, 1000000, 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
- }
- }
-
- },
-
- {
- {'L', 'I', 'S', 'T'},
- 4 + nframes * 8 + totalsize,
- {'m', 'o', 'v', 'i'}
- }
- };
-
-
- fseek(fp, 0, SEEK_SET);
-
- fwrite(&avi_head,sizeof(avi_head),1,fp);
-
- fclose(fp);
- printf("end\n");
-
- return 0;
- }
-
特别注意,avi没有时间戳,它的帧率由strh中的rate/scale=帧率决定,通过这个比率可以操控制作视频的快进与慢放。
下一步加入ALSA音频
可以把avi文件理解为由无数个struct结构组成的:
1. struct avifile { 'RIFF', 'AVI', struct. movi, struct hdrl}
2. struct hdrl { 'LIST', 'hdal', struct avih, struct stream0,struct stream1,struct stream2};
3. struct stream {'LIST' , 'STRL', struct strh, struct strf }
4. struct movi { 'LIST' , 'movi'}
5. n* struct data { '00db' ,data} 循环写入帧数据
在avi文件中都是按照这个镶嵌顺序顺序写入的。
1. avifile:
struct avifile
{
unsigned char id[4];
unsigned int size;
unsigned char type[4];
struct. movi;
struct hdrl avi_hdrl;
}
2. struct hdrl
typedef struct hdrl
{
unsigned char id[4]; //块ID,固定为LIST
unsigned int size; //块大小,等于struct avi_hdrl_list去掉id和size的大小
unsigned char type[4]; //块类型,固定为hdrl
struct avih;
struct stream;
}
3. struct avih
struct avih
{
unsigned char id[4]; //块ID,固定为avih
unsigned 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; //文件包含的流的个数,仅有视频流时为1
unsigned int suggest_buff_size; //指定读取本文件建议使用的缓冲区大小,通常为存储一桢图像 //以及同步声音所需的数据之和,不指定时设为0
unsigned int width; //视频主窗口宽度(单位:像素)
unsigned int height; //视频主窗口高度(单位:像素)
unsigned int reserved[4]; //保留段,设为0即可
}
4 . 含两个struct strh,struct strf
struct stream {
struct strh
{
unsigned char id[4]; //块ID,固定为strh
unsigned int size; //块大小,等于struct avi_strh_chunk去掉id和size的大小
unsigned char stream_type[4]; //流的类型,vids表示视频流,auds表示音频流
unsigned char codec[4]; //指定处理这个流需要的解码器,如JPEG
unsigned int flags; //标记,如是否允许这个流输出、调色板是否变化等,一般设为0即可
unsigned short priority; //流的优先级,视频流设为0即可
unsigned short language; //音频语言代号,视频流设为0即可
unsigned int init_frames; //为交互格式指定初始帧数(非交互格式应该指定为0)
unsigned int scale; //
unsigned int rate; //对于视频流,rate / scale = 帧率fps
unsigned 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}即可
},
struct strf
{
unsigned char id[4]; //块ID,固定为strf
unsigned int size; //块大小,等于struct avi_strf_chunk去掉id和size的大小
unsigned int size1; //size1含义和值同size一样
unsigned int width; //视频主窗口宽度(单位:像素)
unsigned int height; //视频主窗口高度(单位:像素)
unsigned short planes; //始终为1
unsigned short bitcount; //每个像素占的位数,只能是1、4、8、16、24和32中的一个
unsigned char compression[4]; //视频流编码格式,如JPEG、MJPG等
unsigned int image_size; //视频图像大小,等于width * height * bitcount / 8
unsigned int x_pixels_per_meter; //显示设备的水平分辨率,设为0即可
unsigned int y_pixels_per_meter; //显示设备的垂直分辨率,设为0即可
unsigned int num_colors; //含义不清楚,设为0即可
unsigned int imp_colors; //含义不清楚,设为0即可
}
}
typedef struct avi_rect_frame
{
short left;
short top;
short right;
short bottom;
}AVI_RECT_FRAME;
上面的4个结构体都是镶嵌的,在文件中都是顺序写入的,甚至可以把这几个组织称一个 struct
5. struct movi
struct movi
{
unsigned char id[4]; //块ID,固定为LIST
unsigned int size;
unsigned char type[4]; //固定为MOVI
}
6. 写data
struct data {
unsigned char id[4]; // 00dc 表示第一个流为视频压缩数据
unsigned int len; // 每帧数据大小
void *data ; //数据
}
最后写数据可以理解为是struct,但不用结构处理,而是直接先写4字节的00dc, 再写文件长度,最后直接写入帧数据,这样就完成一帧图片的写入,前面的几个结构需要全部要写入的总帧数和总字节数,都是在最后写入数据完成后再回写回去的。