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)。由于avi对g711a格式的不支持型,所以再读取一帧语音数据时,对其格式解压缩转换成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; //文件大小,不包括riff,file_size
unsigned char file_type[4]; //文件类型,四个字符avif
}RIFF_HEADER;
/* Start the header list */
typedef struct //avi头部信息块的开始
{
unsigned char list[4]; //四个字符list,表示列表
long list_size; //列表大小,不包括list,size_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个字节(fcc和cb两个域)
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; //列表大小,不包括list,size_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个字节(fcc和cb两个域)
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; // 流的长度(单位与dwScale和dwRate的定义有关)
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结构中的dwWidth和dwHeight决定
} 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个字节(fcc和cb两个域)
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; //列表大小,不包括list,size_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,从RIFF到movi截止;
关于avi打包的程序demo也是可以在网上搜索的,不过因用途差异,有些demo需要修改一下才能使用的。
---------------------
作者:edw200
来源:CSDN
原文:https://blog.csdn.net/edw200/article/details/52179481
版权声明:本文为博主原创文章,转载请附上博文链接!