音视频(H264+G711)打包AVI文件

1.简单分析avi格式

使用ultraedit打开Avi文件,二进制显示如下:

 [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0123456789012345]

000000000: 52 49 46 46 DC 6C 57 09 41 56 49 20 4C 49 53 54 

|RIFF.lW.AVI LIST|  RIFF fileSize fileType LIST

000000016: CC 41 00 00 68 64 72 6C 61 76 69 68 38 00 00 00  

 |.A..hdrlavih8...|l  istSize listType avih 结构大小

000000032: 50 C3 00 00 00 B0 04 00 00 00 00 00 10 00 00 00 

 |P...............|  帧间时间 最大数据率 填充粒度 全局标记

000000048: A8 02 00 00 00 00 00 00 01 00 00 00 00 84 03 00 

    |................|  总帧数 交互帧数 流个数 建议缓存

000000064: 40 01 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 

  |@...............|  width height 保留

000000080: 00 00 00 00 00 00 00 00


avi文件格式:

RIFF (AVI
      LIST (hdrl
            avih(AVI信息头数据)
            LIST (strl
                  strh(流的头信息数据)
                  strf(流的格式信息数据)
                   [strd(可选的额外的头信息数据) ]
                   [strn(可选的流的名字) ]
                   ...
                  )
             ...
           )
      LIST (movi
            { SubChunk | LIST (rec
                              SubChunk1
                              SubChunk2
                              ...
                             )
               ...
            }
            ...
           )
      [idx1(可选的AVI索引块数据) ]
     )

2.打包说明

海思媒体库:

海思媒体视屏帧中起始数据包中连续出现SPS PPS SEI I + SPS PPS SEI I 两个IDR帧。

一帧的语音实际长度为A0(十进制为160)。由于avig711a格式的不支持型,所以再读取一帧语音数据时,对其格式解压缩转换成pcm,其长度变为320,位宽为16,采样率为8000,海思音频帧的每个包头四个字节是海思的特定头,如帧长为160,海思实际为164我们在将音频写入avi文件时长度也需要改成320.


海思媒体库中出来的视频格式为H264音频格式为G711a,但是目前avi不支持G711a音频打包,所以我们需要将G711a转换成pcm格式(网上搜索有现成的转换代码)。

关于打包avi格式文件音视频不同步的问题(工作中的BUG),原因如下

AVI格式文件,播放时音视频播放时间,avi文件是没有保存时间戳的,是以文件写入的索引个数为标准,多少个索引就有多长时间

在原来的medairct媒体处理程序中获取视频时,将海思的视频(SPS+PPS+SEI+I +P帧)固定的写入avi文件中(固定循环写入avi文件5次),如数据帧是SPS时,PPS必然是空的,但也写进去的话,虽然不占内存,但是索引增加了,才导致视频和音频的时间不同步原因(视频滞后)。

 

avi格式 - 机器打印:

 

---------- RIFF_HEADER-----------

riff            RIFF

file_size       445050

file_type       AVI

 

 ---------- HEADER_LIST-----------

list            LIST

list_size       294

list_type       hdrl

    ---------- AVIMAINHEADER-----------

    fcc:                 avih

    cb:                  56

    dwMicroSecPerFrame:  66667

    dwMaxBytesPerSec:    0

    dwPaddingGranularity:0

    dwFlags:             272

    dwTotalFrames:       60

    dwInitialFrames:     0

    dwStreams:           2

    dwSuggestedBufferSize:0

    dwWidth              720

    dwHeight             576

    dwReserved           0

    dwReserved           0

    dwReserved           0

    dwReserved           0

        ---------- start video-----------

        ---------- video STREAM_HEADER_LIST-----------

        list:       LIST

        list_size:  116

        list_type:  strl

        ---------- video AVISTREAMHEADER-----------

        block:              strh

        list_size:          56

        fccType:            vids

        fccHandler:         h264

        dwFlags:            0

        wPriority:          0

        wLanguage:          0

        dwInitialFrames:    0

        dwScale:            1000000

        dwRate:             15000001

        dwStart:            0

        dwLength            60

        dwSuggestedBufferSize            0

        dwQuality           -1

        dwSampleSize        0

        left                0

        top                 0

        right               0

        bottom              0

        ---------- STREAM_FORMAT-----------

        block:       strf

        block_size:  40

        ---------- BIT_MAP_INFO-----------

        size:       40

        width:      720

        height:     576

        planes:     1

        bit_count:  24

        compression:      h264

        size_image:       1244160

        xpels_per_meter:  0

        ypels_per_meter:  0

        clr_used:         0

        clr_important:    0

        ---------- end video -----------

 

        ---------- start audio -----------

        ---------- audio STREAM_HEADER_LIST-----------

        list:       LIST

        list_size:  94

        list_type:  strl

        ---------- audio AVISTREAMHEADER-----------

        block:              strh

        list_size:          56

        fccType:            auds

        fccHandler:         

        dwFlags:            0

        wPriority:          0

        wLanguage:          0

        dwInitialFrames:    0

        dwScale:            2

        dwRate:             16000

        dwStart:            0

        dwLength            407

        dwSuggestedBufferSize            0

        dwQuality           -1

        dwSampleSize        1

        left                0

        top                 0

        right               0

        bottom              0

       ----------audio STREAM_FORMAT-----------

        block:       strf

        block_size:  18

        ----------audio WAVE_FORMATEX-----------

        format_tag:       1

        channels:         1

        samples_per_sec:  8000

        bytes_per_sec:    16000

        block_align:      2

        bits_per_sample:  16

        cb_size:          0

        ---------- end audio -----------

 

 3.Avi头结构体

 

Avi头结构体如下:

 

/* The RIFF header */

typedef struct     //AVI文件的开始

{

    unsigned char riff[4];       //四个字符RIFF

    long file_size;              //文件大小,不包括rifffile_size

    unsigned char file_type[4];  //文件类型,四个字符avif

}RIFF_HEADER;

 

/* Start the header list */

typedef struct         //avi头部信息块的开始

{

    unsigned char list[4];          //四个字符list,表示列表

    long list_size;                 //列表大小,不包括listsize_list

    unsigned char list_type[4];     //四个字符,列表类型,如hdrl

}HEADER_LIST;

 

/* The main AVI header */

/* The Flags in AVI File header */

typedef struct _avimainheader {

    unsigned char  fcc[4];// 必须为‘avih

    long cb;// 本数据结构的大小,不包括最初的8个字节(fcccb两个域)

    long dwMicroSecPerFrame;// 视频帧间隔时间(以毫秒为单位)

    long dwMaxBytesPerSec;// 这个AVI文件的最大数据率

    long dwPaddingGranularity; // 数据填充的粒度

    long dwFlags; // AVI文件的全局标记,比如是否含有索引块等

    long dwTotalFrames; // 总帧数

    long dwInitialFrames; // 为交互格式指定初始帧数(非交互格式应该指定为0

    long dwStreams;// 本文件包含的流的个数

    long dwSuggestedBufferSize; // 建议读取本文件的缓存大小(应能容纳最大的块)

    long dwWidth; // 视频图像的宽(以像素为单位)

    long dwHeight; // 视频图像的高(以像素为单位)

    long dwReserved[4]; // 保留

} AVIMAINHEADER;

 

/* Start the video audio stream list  */

typedef struct         //avi头部信息块的开始

{

    unsigned char list[4];          //四个字符list,表示列表

    long list_size;                 //列表大小,不包括listsize_list

    unsigned char list_type[4];     //四个字符,子列表类型,如strl

}STREAM_HEADER_LIST;

 

/* The video stream header */

typedef struct _avistreamheader {

    unsigned char block[4];     // 必须为‘strh

    long list_size;   // 本数据结构的大小,不包括最初的8个字节(fcccb两个域)

    unsigned char fccType[4]; // 流的类型:‘auds’(音频流)、‘vids’(视频流)、

                                                  //mids’(MIDI流)、‘txts’(文字流)

    unsigned char fccHandler[4]; // 指定流的处理者,对于音视频来说就是解码器

    long dwFlags; // 标记:是否允许这个流输出?调色板是否变化?

    short int wPriority; // 流的优先级(当有多个相同类型的流时优先级最高的为默认流)

    short int wLanguage;

    long dwInitialFrames; // 为交互格式指定初始帧数

    long dwScale; // 这个流使用的时间尺度

    long dwRate;

    long dwStart; // 流的开始时间

    long dwLength; // 流的长度(单位与dwScaledwRate的定义有关)

    long dwSuggestedBufferSize; // 读取这个流数据建议使用的缓存大小

    long dwQuality;      // 流数据的质量指标(0 ~ 10,000

    long dwSampleSize; // Sample的大小

    struct {

        short int left;

        short int top;

        short int right;

        short int bottom;

    }rcFrame; // 指定这个流(视频流或文字流)在视频主窗口中的显示位置

// 视频主窗口由AVIMAINHEADER结构中的dwWidthdwHeight决定

} AVISTREAMHEADER;

 

 

typedef struct     //流格式块

{

    unsigned char block[4];      //strf

    long block_size;        /* # of bytes to follow */

}STREAM_FORMAT;

 

/* The video stream format */

typedef struct

{

    /*bitmapinfoheader*/

    long size;                       //位图信息头部文件

    long width;      //图像宽度

    long height;    //图像高度

    short int planes;      //目标设备位面熟,设为1

    short int bit_count;    //单位像素的位数,即图像的位深度

    char compression[4];      //图像的压缩类型

    long size_image;     //图像的大小,以字节为单位

    long xpels_per_meter;  //水平方向每米像素数

    long ypels_per_meter;  //垂直方向每米像素数

    long clr_used;    //实际使用的色彩表中的颜色索引数

    long clr_important;  //重要的颜色数,此值为0时所有颜色double重要

}BIT_MAP_INFO;

 

/* The audio stream format */

typedef struct

{

    short int format_tag;    //指定格式类型,默认WAVE_FORMAT_PCM=1

    short int channels;      //指出波形数据的声道数;单声道为1,立体声为2

    long samples_per_sec;   //指定采样频率(每秒的样本数)

    long bytes_per_sec;     //指定数据传输的传输速率(每秒的字节数)

    short int block_align;       //指定块对齐是数据的最小单位=channel*bits_per_sample/8

    short int bits_per_sample;    //采样大小

    short int cb_size;       //附加信息的字节大小

}WAVE_FORMATEX;

 

/* 索引信息  */

typedef struct _avioldindex {

    unsigned char fcc[4];  // 必须为‘idx1

    long cb; // 本数据结构的大小,不包括最初的8个字节(fcccb两个域)

    struct _avioldindex_entry {

        long dwChunkId;  // 表征本数据块的四字符码  00db表示视频,00dc表示压缩视频,00wb表示音频

        long dwFlags;    // 说明本数据块是不是关键帧、是不是‘rec ’列表等信息   

        long dwOffset;   // 本数据块在文件中的偏移量

        long dwSize;     // 本数据块的大小

    }aIndex[];      // 这是一个数组!为每个媒体数据块都定义一个索引信息

} AVIOLDINDEX;

 

typedef struct     //option可选

{

    unsigned char list[4];      //四个字符JUNK

    long list_size;             //列表大小,不包括listsize_list

    unsigned char list_type[4]; //四个字符,列表类型,如movi

}JUNK;

 

typedef struct           //媒体数据整体数据的开始

{

    unsigned char list[4];          //四个字符list

    long list_size;                 //整个媒体块的大小,字节数

    unsigned char list_type[4];     //movi表示视频媒体块的开始

}MOVIE_LIST;


结构体大小为2048,从RIFFmovi截止;


关于avi打包的程序demo也是可以在网上搜索的,不过因用途差异,有些demo需要修改一下才能使用的。


  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,首先需要了解一下AVI文件格式的结构。AVI文件格式是由一个RIFF头和多个块构成的。其中,RIFF头用于标识文件类型和文件大小,块用于存储音视频数据。在本次任务中,我们需要将G711u格式的音频数据和H264格式的视频数据融合起来,生成一个AVI文件。 下面是一个简单的伪代码示例: ```c // 打开G711u文件H264文件 FILE *g711u_file = fopen("audio.g711u", "rb"); FILE *h264_file = fopen("video.h264", "rb"); // 创建AVI文件 FILE *avi_file = fopen("output.avi", "wb"); // 写入RIFF头 avi_header_t avi_header; create_avi_header(&avi_header); fwrite(&avi_header, sizeof(avi_header), 1, avi_file); // 写入音视频数据 while (!eof(g711u_file) && !eof(h264_file)) { // 读取G711u格式的音频数据 fread(audio_data, 1, audio_data_size, g711u_file); // 读取H264格式的视频数据 fread(video_data, 1, video_data_size, h264_file); // 写入音频块 avi_audio_chunk_t audio_chunk; create_avi_audio_chunk(&audio_chunk, audio_data, audio_data_size); fwrite(&audio_chunk, sizeof(audio_chunk), 1, avi_file); fwrite(audio_data, 1, audio_data_size, avi_file); // 写入视频块 avi_video_chunk_t video_chunk; create_avi_video_chunk(&video_chunk, video_data, video_data_size); fwrite(&video_chunk, sizeof(video_chunk), 1, avi_file); fwrite(video_data, 1, video_data_size, avi_file); } // 关闭文件 fclose(g711u_file); fclose(h264_file); fclose(avi_file); ``` 需要注意的是,上述代码中的`create_avi_header`、`create_avi_audio_chunk`和`create_avi_video_chunk`函数需要根据AVI文件格式的规范进行实现。另外,还需要根据实际情况确定音频和视频数据的大小、采样率、帧率等参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值