• avi视频协议的理解


    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <unistd.h>
    5. #include <malloc.h>
    6. #include <wait.h>
    7. #include <sys/types.h>
    8. #include <sys/stat.h>
    9. #include <fcntl.h>
    10. #include <sys/ioctl.h>
    11. #include <sys/mman.h>
    12. #define JPEG_MAX_SIZE 2000000 //JPEG图像最大字节数
    13. #define JPEG_NUM 400 //JPEG图像数量
    14. static int nframes; //总帧数
    15. static int totalsize; //帧的总大小
    16. int main(void){
    17. struct avi{
    18. struct riff{
    19. unsigned char id[4];
    20. unsigned int size;
    21. unsigned char type[4];
    22. }r1;
    23. struct hdrl{
    24. unsigned char id[4]; //块ID,固定为LIST
    25. unsigned int size; //块大小,等于struct avi_hdrl_list去掉id和size的大小
    26. unsigned char type[4]; //块类型,固定为hdrl
    27. struct avih{
    28. unsigned char id[4]; //块ID,固定为avih
    29. unsigned int size; //块大小,等于struct avi_avih_chunk去掉id和size的大小
    30. unsigned int us_per_frame; //视频帧间隔时间(以微秒为单位)
    31. unsigned int max_bytes_per_sec; //AVI文件的最大数据率
    32. unsigned int padding; //设为0即可
    33. unsigned int flags; //AVI文件全局属性,如是否含有索引块、音视频数据是否交叉存储等
    34. unsigned int total_frames; //总帧数
    35. unsigned int init_frames; //为交互格式指定初始帧数(非交互格式应该指定为0)
    36. unsigned int streams; //文件包含的流的个数,仅有视频流时为1
    37. unsigned int suggest_buff_size; //指定读取本文件建议使用的缓冲区大小,通常为存储一桢图像 //以及同步声音所需的数据之和,不指定时设为0
    38. unsigned int width; //视频主窗口宽度(单位:像素)
    39. unsigned int height; //视频主窗口高度(单位:像素)
    40. unsigned int reserved[4]; //保留段,设为0即可
    41. }a1;
    42. struct strl{
    43. unsigned char id[4]; //块ID,固定为LIST
    44. unsigned int size; //块大小,等于struct avi_strl_list去掉id和size的大小
    45. unsigned char type[4]; //块类型,固定为strl
    46. struct strh{
    47. unsigned char id[4]; //块ID,固定为strh
    48. unsigned int size; //块大小,等于struct avi_strh_chunk去掉id和size的大小
    49. unsigned char stream_type[4]; //流的类型,vids表示视频流,auds表示音频流
    50. unsigned char codec[4]; //指定处理这个流需要的解码器,如JPEG
    51. unsigned int flags; //标记,如是否允许这个流输出、调色板是否变化等,一般设为0即可
    52. unsigned short priority; //流的优先级,视频流设为0即可
    53. unsigned short language; //音频语言代号,视频流设为0即可
    54. unsigned int init_frames; //为交互格式指定初始帧数(非交互格式应该指定为0)
    55. unsigned int scale; //
    56. unsigned int rate; //对于视频流,rate / scale = 帧率fps
    57. unsigned int start; //对于视频流,设为0即可
    58. unsigned int length; //对于视频流,length即总帧数
    59. unsigned int suggest_buff_size; //读取这个流数据建议使用的缓冲区大小
    60. unsigned int quality; //流数据的质量指标
    61. unsigned int sample_size; //音频采样大小,视频流设为0即可
    62. struct rcFrame{ //这个流在视频主窗口中的显示位置,设为{0,0,width,height}即可
    63. short left;
    64. short top;
    65. short right;
    66. short bottom;
    67. } AVI_RECT_FRAME;
    68. }s1;
    69. struct strf{
    70. unsigned char id[4]; //块ID,固定为strf
    71. unsigned int size; //块大小,等于struct avi_strf_chunk去掉id和size的大小
    72. unsigned int size1; //size1含义和值同size一样
    73. unsigned int width; //视频主窗口宽度(单位:像素)
    74. unsigned int height; //视频主窗口高度(单位:像素)
    75. unsigned short planes; //始终为1
    76. unsigned short bitcount; //每个像素占的位数,只能是148162432中的一个
    77. unsigned char compression[4]; //视频流编码格式,如JPEG、MJPG等
    78. unsigned int image_size; //视频图像大小,等于width * height * bitcount / 8
    79. unsigned int x_pixels_per_meter; //显示设备的水平分辨率,设为0即可
    80. unsigned int y_pixels_per_meter; //显示设备的垂直分辨率,设为0即可
    81. unsigned int num_colors; //含义不清楚,设为0即可
    82. unsigned int imp_colors; //含义不清楚,设为0即可
    83. }q1;
    84. }w1;
    85. }a1;
    86. struct movi{
    87. unsigned char id[4];
    88. unsigned int size;
    89. unsigned char type[4];
    90. }movi1;
    91. }HEAD;
    92. //--------------------------------------------------------------------------------------
    93. FILE *fp_jpg;
    94. FILE *fp;
    95. int filesize;
    96. unsigned char jpg_data[JPEG_MAX_SIZE];
    97. char filename[10];
    98. int i = 0;
    99. fp= fopen("sample.avi","wb");
    100. //AVI文件偏移量设置到movi list head后,从该位置向后依次写入JPEG数据
    101. fseek(fp,sizeof(HEAD),SEEK_SET);
    102. //--------------------------------------------------------
    103. for (i = 0; i < JPEG_NUM; i++)
    104. {
    105. memset(filename, 0, 10);
    106. memset(jpg_data, 0, JPEG_MAX_SIZE);
    107. sprintf(filename, "%d", i); //int转字符
    108. fp_jpg = fopen(filename, "rb");
    109. if (fp_jpg != NULL)
    110. {
    111. /*获取JPEG数据大小*/
    112. fseek(fp_jpg, 0, SEEK_END);
    113. filesize = ftell(fp_jpg);
    114. fseek(fp_jpg, 0, SEEK_SET);
    115. /*将JPEG数据读到缓冲区*/
    116. fread(jpg_data, filesize, 1, fp_jpg);
    117. /*将JPEG数据写入AVI文件*/
    118. unsigned char tmp[4] = {'0', '0', 'd', 'c'}; //00dc = 压缩的视频数据
    119. fwrite(tmp, 4, 1, fp); //写入是否是压缩的视频数据信息
    120. fwrite(&filesize, 4, 1, fp); //写入4字节对齐后的JPEG图像大小
    121. fwrite(jpg_data, filesize, 1, fp); //写入真正的JPEG数据
    122. nframes += 1;
    123. totalsize += filesize;
    124. }
    125. fclose(fp_jpg);
    126. }
    127. int width=1280;
    128. int height=720;
    129. typedef struct hdrl AVI_HDRL_LIST;
    130. typedef struct movi AVI_LIST_HEAD;
    131. typedef struct avih AVI_AVIH_CHUNK;
    132. typedef struct strl AVI_STRL_LIST;
    133. typedef struct strh AVI_STRH_CHUNK;
    134. typedef struct strf AVI_STRF_CHUNK;
    135. typedef struct avi AVI_HEAD;
    136. AVI_HEAD avi_head={
    137. {
    138. {'R', 'I', 'F', 'F'},
    139. 4 + sizeof(AVI_HDRL_LIST) + sizeof(AVI_LIST_HEAD) +nframes * 8 + totalsize,
    140. {'A', 'V', 'I', ' '}
    141. },
    142. {
    143. {'L', 'I', 'S', 'T'},
    144. sizeof(AVI_HDRL_LIST) - 8,
    145. {'h', 'd', 'r', 'l'},
    146. {
    147. {'a', 'v', 'i', 'h'},
    148. sizeof(AVI_AVIH_CHUNK) - 8,
    149. 1000000/23, 25000, 0, 0,nframes, 0, 1, 1000000, width, height,
    150. {0, 0, 0, 0}
    151. },
    152. {
    153. {'L', 'I', 'S', 'T'},
    154. sizeof(AVI_STRL_LIST) - 8,
    155. {'s', 't', 'r', 'l'},
    156. {
    157. {'s', 't', 'r', 'h'},
    158. sizeof(AVI_STRH_CHUNK) - 8,
    159. {'v', 'i', 'd', 's'},
    160. {'J', 'P', 'E', 'G'},
    161. 0, 0, 0, 0, 1, 23, 0, nframes, 100000, 0xFFFFFF, 0,
    162. {0, 0, width, height}
    163. },
    164. {
    165. {'s', 't', 'r', 'f'},
    166. sizeof(AVI_STRF_CHUNK) - 8,
    167. sizeof(AVI_STRF_CHUNK) - 8,
    168. width, height, 1, 24,
    169. {'J', 'P', 'E', 'G'},
    170. width * height * 3, 0, 0, 0, 0
    171. }
    172. }
    173. },
    174. {
    175. {'L', 'I', 'S', 'T'},
    176. 4 + nframes * 8 + totalsize,
    177. {'m', 'o', 'v', 'i'}
    178. }
    179. };
    180. fseek(fp, 0, SEEK_SET);
    181. fwrite(&avi_head,sizeof(avi_head),1,fp);
    182. fclose(fp);
    183. printf("end\n");
    184. return 0;
    185. }

    特别注意,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, 再写文件长度,最后直接写入帧数据,这样就完成一帧图片的写入,前面的几个结构需要全部要写入的总帧数和总字节数,都是在最后写入数据完成后再回写回去的。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    实体属性映射框架mapstruct
    ElasticSearch(八)【过滤查询】
    SIP中继与VoIP:有何不同?
    后端程序员必备:书写高质量SQL的30条建议
    机器学习中常用的评价指标
    Leetcode1579-保证图可完全遍历
    分布式session ——Spring Session原理、实战解决 子域之间的 session 共享问题、不同服务器 session 共享解决方案
    BP神经网络算法基本原理,bp神经网络算法的原理
    手机技巧:推荐一款手机省电、提升流畅度APP
    【NSArray数组的持久化 Objective-C语言】
  • 原文地址:https://blog.csdn.net/m0_59802969/article/details/133963213