代码解析
数据结构:
1、typedef struct def_avi_file_header
{
def_avi_dword cb_file_type;
def_avi_dword cb_file_size;
def_avi_dword cb_video_type;
def_avi_dword cb_file_list;
def_avi_word cb_file_char;
def_avi_word cb_file_conut;
}def_avi_file_header;
2、'avih'块的数据结构
用于记录AVI文件的全局信息,比如流的数量、视频图像的宽和高等,可以使用一个avi_mainheader数据结构来操作
typedef structdef_avi_mainheader
{
def_avi_fourcc fcc_avih;// 必须为'avi ’
def_avi_dword cb_struct_size;// 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
def_avi_dword dwMicroSecPerFrame;// 视频帧间隔时间(以毫秒为单位)
def_avi_dword dwMaxBytesPerSec;// 这个AVI文件的最大数据率
def_avi_dword dwPaddingGranularity; //数据填充的粒度
def_avi_dword dwFlags;// AVI文件的全局标记,比如是否含有索引块等
/*Index at end of file? */
#defineBAVI_F_HASINDEX 0x00000010u
#defineBAVI_F_MUSTUSEINDEX 0x00000020u
#defineBAVI_F_ISINTERLEAVED 0x00000100u
/*Use CKType to find key frames */
#defineBAVI_F_TRUSTCKTYPE 0x00000800u
#defineBAVI_F_WASCAPTUREFILE 0x00010000u
#defineBAVI_F_COPYRIGHTED 0x00020000u
def_avi_dword dwTotalFrames;// 总帧数
def_avi_dword dwInitialFrames;// 为交互格式指定初始帧数(非交互格式应该指定为0)
def_avi_dword dwStreams;// 本文件包含的流的个数
def_avi_dword dwSuggestedBufferSize;//建议读取本文件的缓存大小(应能容纳最大的块)
def_avi_dword dwWidth;// 视频图像的宽(以像素为单位)
def_avi_dword dwHeight;// 视频图像的高(以像素为单位)
def_avi_dword dwReserved[4];// 保留
}def_avi_mainheader;
3、'strl'子列表数据结构--'strh'块
在'avi'块之后'就是一个或多个'strl'子列表。(文件中有多少个流,这里就对应有多少个'strl'子列表)每个'strl'子列表至少包含一个'strh' 块和一个'strf'块,而'strd'块(保存编解码器需要的一些配置信息)和'strn'块(保存流的名字)是可选的。首先是'strh'块,用于说明这个流的头信息,可以使用一个avi_streamheader数据结构来操作:
typedef structdef_avi_streamheader
{
def_avi_fourccfcc_strh; // 必须为'strh'
def_avi_dwordcb_struct_size;// 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
def_avi_fourcc fccType; // 流的类型:'auds'(音频流).'vids'(视频流).'mids'(MIDI流).'txts(文字流)
def_avi_fourccfccHandler;// 指定流的处理者,对于音视频来说就是解码器
def_avi_dword dwFlags;// 标记:是否允许这个流输出?调色板是否变化?
#defineBAVI_SF_DISABLED 0x00000001u
#defineBAVI_SF_VIDEO_PALCHANGES 0x00010000u
def_avi_word wPriority; // 流的优先级(当有多个相同类型的流时优先级最高的为默认流)
def_avi_word wLanguage;
def_avi_word dwInitialFrames;// 为交互格式指定初始帧数
def_avi_dword dwScale;// 这个流使用的时间尺度
def_avi_dword dwRate;
def_avi_dword dwStart;// 流的开始时间
def_avi_dword dwLength;// 流的长度(单位与dwScale和dwRate的定义有关)
def_avi_dword dwSuggestedBufferSize;//读取这个流数据建议使用的缓存大小
def_avi_dword dwQuality; // 流数据的质量指标(0 ~ 10,000)
def_avi_dword dwSampleSize;// Sample的大小
struct
{
// 指定这个流(视频流或文字流)在视频主窗口中的显示位置
// 视频主窗口由avi_mainheader结构中的dwWidth和dwHeight决定
def_avi_short_intleft;
def_avi_short_inttop;
def_avi_short_intright;
def_avi_short_intbottom;
} rcFrame;
} def_avi_streamheader;
4、'strf'块数据结构
在'strh'块之后是'strf'块,用于说明流的具体格式。主要是根据'strh'块中的参数来的如果是视频流,则使用一个avi_bitmapinfo数据结构来描述;如果是音频流,则使用一个avi_waveformatex数据结构来描述.
typedef structdef_avi_waveformatex
{
def_avi_word wFormatTag;
def_avi_word nChannels;//声道数
def_avi_dword nSamplesPerSec;//采样率
def_avi_dword nAvgBytesPerSec;//wave声音中每秒的数据量
def_avi_word nBlockAlign;//数据块的对其标志
def_avi_word wBitsPerSample;
def_avi_word cbSize;
def_avi_dword meta_length;
def_avi_byte meta[48];
}def_avi_waveformatex;
typedef structdef_avi_bitmapinfo
{
def_avi_dword biSize;
def_avi_long biWidth;
def_avi_long biHeight;
def_avi_word biPlanes;
def_avi_word biBitCount;
def_avi_dword biCompression;
def_avi_dword biSizeImage;
def_avi_long biXPelsPerMeter;
def_avi_long biYPelsPerMeter;
def_avi_dword biClrUsed;
def_avi_dword biClrImportant;
}def_avi_bitmapinfo;
解码流程:
1、avi_stream_verify
D_UINT32avi_stream_verify(D_UINT8 *buffer)
{
D_UINT32 tempdata;
D_UINT32 pos;
D_UINT32 riff_flag=0x52494646; //AVI文件标识"RIFF"ascii码
D_UINT32 avi_flag = 0x41564920; //AVI文件标识"AVI "ascii码 。后面含有一个空格的ASCII码,0x20
if(buffer == NULL)
{
stb_printf("paramter is error !\n");
return D_FAILURE;
}
for(int i=0;i<20;i++)
{
stb_printf("0x%X ",buffer[i]);
}
//读取avi文件的前四个字节,解析,如果是一个四字符码'RIFF',表示这是一个RIFF文件
pos =0;
tempdata =(buffer[pos]<<24)|(buffer[pos+1]<<16)|(buffer[pos+2]<<8)|(buffer[pos+3]);
if(tempdata != 0x52494646)
{
stb_printf("tempdata=0x%X\n",tempdata);
stb_printf("the file is not RIFF !\n");
return D_FAILURE;
}
//跳过保存文件大小的4字节
pos +=4;
//文件大小之后的4字节是表明文件类型的四字符码如果是avi文件就是"AVI " ,avi后面有个空格
pos +=4;
tempdata =(buffer[pos]<<24)|(buffer[pos+1]<<16)|(buffer[pos+2]<<8)|(buffer[pos+3]);
if(tempdata != 0x41564920)
{
return D_FAILURE;
}
return D_SUCCESS;
}
2、void stream_file_avi_head_parser(char *file_name,DG_MEDIA_FILE_INFO *file_info)
{
FILE *file_handle = NULL;
char *temp;
int32_t rc;
uint32_t count_tmp;
def_avi_file_header file_header;
def_avi_streamheader stream_header;
def_avi_bitmapinfo video_info;
def_avi_waveformatex audio_info;
char * tmp_char1 = "strh";//流的头信息数据块的ID号
char * video_flag = "vids";
char * audio_flag = "auds";
char * tmp_char4 = "strf";
D_UINT32 video_pid,video_codec,audio_pid,audio_codec;
D_UINT8 StreamNum=0;
D_UINT32 OffSet=0;
D_UINT8 AudioTrackCount=0;
D_BOOL ContinueFlag;
temp = (char *)malloc(buffer_size);
if((file_handle =fopen(file_name,"r")) == NULL)
{
stb_printf( "===== fopen error !====\n");
}
rc = fread(temp, 1, buffer_size,file_handle); //读取256k数据到内存
if(rc<0)
{
stb_printf("=== freaderror!===\n");
}
while(feof(file_handle) == 0)
{
ContinueFlag = D_FALSE;
count_tmp = 0;
count_tmp = find_char_buffer(temp,tmp_char1,0, buffer_size);
//如果在读入的数据里面找到了'strh'块,返回找到的位置
stb_printf("strh count_tmp:0x%x\n",count_tmp);
//def_avi_streamheader包括了list和list size
//如果找到的位置加上def_avi_streamheader数据结构(用于说明strh流的头信息)的大小大于当前读入的数据大小,
//跳转到Continue继续读取数据到内存
if((count_tmp +sizeof(def_avi_streamheader)) > buffer_size)
{
goto Continue;
}
//如果找到的位置加上def_avi_streamheader数据结构(用于说明strh流的头信息)的大小不大于当前读入的数据大小,做整体的结构体赋值,
char_data_copy(temp,&stream_header, sizeof(def_avi_streamheader), count_tmp);
count_tmp = count_tmp + 8 +stream_header.cb_struct_size;
//8是头id加size的大小,cb_struct_size是整个结构体去掉id和size的大小
stb_printf("stream_header.fccType:0x%x\n",stream_header.fccType);
//如果当前流的类型是音频
if(stream_header.fccType == AUDS)
{
//def_avi_waveformatex不包括list和list size
if((count_tmp + 8 +sizeof(def_avi_waveformatex)) > buffer_size)
//8是strf子块的标志'strf'和size的总大小
{
goto Continue;
}
//如果在后面的数据中找到了"strf"标志,表明strf子块数据开始
count_tmp = find_char_buffer(temp,tmp_char4,count_tmp, buffer_size);
count_tmp +=8;//加上strf子块的标志'strf'和size的总大小
char_data_copy(temp,&audio_info, sizeof(def_avi_waveformatex), count_tmp);
//整体拷贝后面的数据给audio_info结构体
count_tmp +=sizeof(def_avi_waveformatex);
StreamNum++;//audio pid
//解析音频的编码格式
avi_audio_codec_get(&audio_codec,audio_info);
file_info[0].audio_pid[AudioTrackCount] = StreamNum;
file_info[0].audio_codec[AudioTrackCount] = audio_codec;
AudioTrackCount++;
ContinueFlag = D_TRUE;
}
//如果当前流的类型是视频
else if(stream_header.fccType == VIDS)
{
//def_avi_bitmapinfo不包括list和list size
if((count_tmp + 8 +sizeof(def_avi_bitmapinfo)) > buffer_size)
{
goto Continue;
}
count_tmp = find_char_buffer(temp,tmp_char4,count_tmp, buffer_size);
count_tmp +=8;
char_data_copy(temp,&video_info, sizeof(def_avi_bitmapinfo), count_tmp);
count_tmp +=sizeof(def_avi_bitmapinfo);
StreamNum++;
stb_printf("video codec:0x%x\n",video_info.biCompression);
//解析视频的编码格式
avi_video_codec_get(&video_codec,video_info);
file_info[0].file_type =DG_FILE_TYPE_AVI;
file_info[0].video_pid = StreamNum;
file_info[0].video_codec =video_codec;
stb_printf("v_pid:0x%x,video_codec:0x%x\n",file_info->video_pid,file_info->video_codec);
ContinueFlag = D_TRUE;
}
if(D_FALSE == ContinueFlag)
{
break;
}
Continue:
memset(temp,0x00,buffer_size);
OffSet += count_tmp;
fseek(file_handle,OffSet,SEEK_SET);
rc = fread(temp, 1, buffer_size,file_handle);
if(rc<0)
{
stb_printf("=== freaderror!===\n");
}
}
free(temp);
temp = NULL;
fclose(file_handle);
}
3、其他函数
#defineBAVI_DIVX5_CODEC(fourcc) (\
CHAR_TO_DWORD_FOURCC('d','i','v','x')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('D','I','V','X')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('d','i','v','5')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('D','I','V','5')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('d','i','v','6')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('D','I','V','6')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('d','x','5','0')==(fourcc)|| \
CHAR_TO_DWORD_FOURCC('D','X','5','0')==(fourcc))
#defineBAVI_XVID_CODEC(fourcc) (\
CHAR_TO_DWORD_FOURCC('x','v','i','d')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('X','V','I','D')==(fourcc)|| \
CHAR_TO_DWORD_FOURCC('F','M','P','4')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('f','m','p','4')==(fourcc))
#defineBAVI_3IVX_CODEC(fourcc) (\
CHAR_TO_DWORD_FOURCC('3','I','V','1')==(fourcc)|| \
CHAR_TO_DWORD_FOURCC('3','i','v','1')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('3','I','V','2')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('3','i','v','2')==(fourcc))
#defineBAVI_H264_CODEC(fourcc) (\
CHAR_TO_DWORD_FOURCC('v','s','s','h')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('V','S','S','H')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('A','V','C',' ')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('a','v','c',' ')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('A','V','C','1')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('a','v','c','1')==(fourcc)|| \
CHAR_TO_DWORD_FOURCC('H','2','6','4')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('h','2','6','4')==(fourcc))
#defineBAVI_DIVX3_CODEC(fourcc) (\
CHAR_TO_DWORD_FOURCC('d','i','v','3')==(fourcc)|| \
CHAR_TO_DWORD_FOURCC('D','I','V','3')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('m','p','4','3')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('M','P','4','3')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('d','i','v','4')==(fourcc) || \
CHAR_TO_DWORD_FOURCC('D','I','V','4')==(fourcc))
#define AUDS (0X73647561) //little-endian
#define VIDS (0X73646976) //little-endian
static intfind_char_buffer(char * src, char * dest, uint32_t start_offset, uint32_tlength)
{
uint32_t i;
for(i = start_offset;i < (length-start_offset);i++)
{
if((src[i] == dest[0]) &&(src[i+1] == dest[1]) && (src[i+2] == dest[2]) && (src[i+3] ==dest[3]))
{
return i;
}
}
return 0;
}
static voidchar_data_copy(char * src, char * dest, uint32_t len, uint32_t offset)
{
memcpy(dest,src+offset, len);
}
static void avi_audio_codec_get(D_UINT32*audio_codec,def_avi_waveformatex audio_info)//获取音频编码方式
{
if(audio_codec == NULL)
{
return D_FAILURE;
}
switch(audio_info.wFormatTag)
{
case 0x0050:
*audio_codec =0x3;//baudio_format_mpeg;
break;
case 0x0055:
*audio_codec =0x1;//baudio_format_mp3;
break;
case 0x2000:
*audio_codec =0x81;//baudio_format_ac3;
break;
case 0x2001:
*audio_codec = 0x82;//baudio_format_dts;
break;
case 0x0161:
*audio_codec =0x86;//baudio_format_wma_std;
break;
case 0x0162:
*audio_codec =0x87;//baudio_format_wma_pro;
break;
case 0x00ff:
*audio_codec =DG_STREAM_TYPE_aac_AUDIO;//0x0f;
break;
case 0x0001:
*audio_codec =DG_STREAM_TYPE_pcm_wav_AUDIO;//0x89
break;
default:
*audio_codec =0x0;//baudio_format_unknown;
break;
}
}
static void avi_video_codec_get(D_UINT32*video_codec, def_avi_bitmapinfovideo_info)//获取视频编码方式
{
if(video_codec == NULL)
{
return D_FAILURE;
}
if(BAVI_DIVX5_CODEC(video_info.biCompression)
|| BAVI_XVID_CODEC(video_info.biCompression)|| BAVI_3IVX_CODEC(video_info.biCompression) )
{
*video_codec =0x10;//bvideo_codec_mpeg4_part2;
}
elseif(BAVI_DIVX3_CODEC(video_info.biCompression))
{
*video_codec = 0x311;//bvideo_codec_divx_311;
}
elseif(BAVI_H264_CODEC(video_info.biCompression))
{
*video_codec =0x1B;//bvideo_codec_h264;
}
else
{
*video_codec =0x0;//bvideo_codec_unknown;
}
}