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

来源:互联网 发布:阿里云服务器增加带宽 编辑:程序博客网 时间:2024/05/09 19:51

代码解析

数据结构:

1typedef 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;

}

 

2void 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;

    }

}

0 0
原创粉丝点击