读书人

视频文件头解析-avi-代码解析

发布时间: 2013-01-23 10:44:50 作者: rapoo

视频文件头解析--avi-代码解析

代码解析

数据结构:

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;

}

}

读书人网 >编程

热点推荐