User Tools

Site Tools


tech:multimedia:avi_parser

AVI Parser

RIFF Header Parser

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
 
typedef struct avitag avitag_t;
struct avitag
{
    char fcc[4];
    int size;
    char flag[4];
    int nested;
    int has_sub;
    int (*parser)(FILE *fp, const avitag_t *tag);
}; 
 
typedef struct
{
    char fcc[4];
    int (*parser)(FILE *fp, const avitag_t *tag);
} parser_map_t;
 
int null_parser(FILE *fp, const avitag_t* tag); 
parser_map_t parser_list[] = 
{
    {{'J', 'U', 'N', 'K'}, null_parser}, 
};
 
int null_parser(FILE *fp, const avitag_t* tag)
{
    int size = tag->size + (tag->size&1);
 
    fseek(fp, size, SEEK_CUR);
    return ftell(fp);
}
 
int find_parser(avitag_t *tag)
{
    int i;
 
    for (i = 0; i < sizeof(parser_list)/sizeof(parser_map_t); i++)
    {
        if (memcmp(parser_list[i].fcc, tag->fcc, 4) == 0)
        {
            tag->parser = parser_list[i].parser;
            return 0;			
        }		
    }
   return -1;
}
 
int parse_tag(FILE *fp, avitag_t* tag)
{
    int i;
    unsigned char buf[8];
    unsigned int *pfcc;
 
    if (fread(buf, 1, 8, fp) != 8)
        return -1;  /* end of file */
    memset(tag, 0, sizeof(avitag_t)); 
    tag->fcc[0] = buf[0];
    tag->fcc[1] = buf[1];
    tag->fcc[2] = buf[2];
    tag->fcc[3] = buf[3];
    tag->size = buf[4] | (buf[5]<<8) | (buf[6]<<16) | (buf[7]<<24);
 
    pfcc = 	(unsigned int*) &tag->fcc;
    /* 'R' 'I' 'F' 'F' or 'L' 'I' 'S' 'T'*/
    if (*pfcc == 0x46464952 || *pfcc == 0x5453494c) 
    {
        if (fread(&tag->flag, 1, 4, fp) != 4)
            return -1; /* end of file */	
        tag->has_sub = 1;			
    }
    return ftell(fp);
}
 
void print_tag(const avitag_t *tag)
{
    int idx = tag->nested;
 
    while (idx-- >= 0)
    {
        putchar(0x20);
    }
    putchar(tag->fcc[0]);
    putchar(tag->fcc[1]);
    putchar(tag->fcc[2]);
    putchar(tag->fcc[3]);
    if (tag->has_sub)
    {
        putchar('[');
        putchar(tag->flag[0]);
        putchar(tag->flag[1]);
        putchar(tag->flag[2]);
        putchar(tag->flag[3]);
        putchar(']');	    
    }
    printf("+%dB\n", tag->size);
}
 
#define NEST_LENGTH 20 	
void parse_riff(FILE *fp)
{
    avitag_t tag;
    int end_chunk[NEST_LENGTH];
    int nested = 0;
 
    while(parse_tag(fp, &tag) >= 0)
    { 
        tag.nested = nested;
        print_tag(&tag);	
        if (tag.has_sub)  /* LIST or RIFF */
        {
            if (nested++ > NEST_LENGTH) abort();
            end_chunk[nested] = ftell(fp) + tag.size - 4;			    
            continue;
        }
        find_parser(&tag);		
        if (!tag.parser) 
            null_parser(fp, &tag); /* no parser found, skip... */
        else		
            tag.parser(fp, &tag);  /* parse data chunck */
        if (tag.nested && ftell(fp) >= end_chunk[tag.nested])
        {
            nested--;		
        }		
    }
    return;
}
 
int main(int argc, char**argv)
{
    FILE *fp; 
 
    if (argc <= 1)
    {
        printf("Usage: %s filename", argv[0]);
        return 0;
    }
 
    fp = fopen(argv[1], "wb");
    if (fp == NULL)
    {
        printf("Error in opening file %s", argv[1]);
        return -1;
    }
 
    parse_riff(fp);
    fclose(fp);
 
    return 0;
}

使用以上函数对一个常见的AVI文件进行解析,得到如下结果:

RIFF[AVI ]+734586272B
 LIST[hdrl]+8818B
  avih+56B
  LIST[strl]+4244B
   strh+56B
   strf+40B
   JUNK+4120B
  LIST[strl]+4222B
   strh+56B
   strf+18B
   JUNK+4120B
  LIST[odml]+260B
   dmlh+248B
  LIST[INFO]+28B
   ISFT+15B
  JUNK+1358B
 LIST[movi]+732428744B
  01wb+28000B
  00dc+3259B
  01wb+2335B
  00dc+163B
  01wb+2336B
  00dc+7B
  01wb+2335B
  ...
  00dc+10275B
  00dc+7B
 idx1+2147280B
JUNK+592B

AVI Header Parser

avih parser

int parse_avih(FILE *fp, const avitag_t *tag)
{
    unsigned char avih[56];
    unsigned int value;
    int idx = tag->nested+1;
 
    if (sizeof(avih) != fread(&avih, 1, sizeof(avih), fp))
        return -1;
 
    while (idx-- >= 0)
    {
        putchar(0x20);
    }
    putchar('{');
    value = avih[0] | (avih[1]<<8) | (avih[2]<<16) | (avih[3]<<24);  
    printf("%dms, ", value);
    value = avih[4] | (avih[5]<<8) | (avih[6]<<16) | (avih[7]<<24);  
    printf("%dbps, ", value*8);   
    value = avih[8] | (avih[9]<<8) | (avih[10]<<16) | (avih[11]<<24);
    printf("%d Byte Aligned, ", value);   
    value = avih[12] | (avih[13]<<8) | (avih[14]<<16) | (avih[15]<<24);
    if (value & 0x10) printf("/HASINDEX");
    if (value & 0x20) printf("/MUSTUSEINDEX");
    if (value & 0x100) printf("/INTERLEAVED");
    putchar(0x20);
    value = avih[16] | (avih[17]<<8) | (avih[18]<<16) | (avih[19]<<24);
    printf("%d frames, ", value);
    value = avih[20] | (avih[21]<<8) | (avih[22]<<16) | (avih[23]<<24);
    printf("Inital %d, ", value);
    value = avih[24] | (avih[25]<<8) | (avih[26]<<16) | (avih[27]<<24);
    printf("%d streams, ", value);
    value = avih[28] | (avih[29]<<8) | (avih[30]<<16) | (avih[31]<<24);
    printf("Buffer:%d Bytes, ", value);
    value = avih[32] | (avih[33]<<8) | (avih[34]<<16) | (avih[35]<<24);
    printf("%dx", value);
    value = avih[36] | (avih[37]<<8) | (avih[38]<<16) | (avih[39]<<24);
    printf("%d", value);
    putchar('}');
    putchar('\n');
 
    return ftell(fp);
}

strh parser

int parse_strh(FILE *fp, const avitag_t *tag)
{
    unsigned char strh[56];
    char fourcc[5];
    unsigned int value;
    unsigned long pos = ftell(fp);
    int idx= tag->nested+1;;
 
    if (sizeof(strh) != fread(&strh, 1, sizeof(strh), fp))
        return -1;
 
    while (idx-- >= 0)
    {
        putchar(0x20);
    }
 
    putchar('{');
    memcpy(fourcc, strh, 4);
    fourcc[4] = 0;
    printf("[%s], ", fourcc);
    memcpy(fourcc, strh+4, 4);
    fourcc[4] = 0;
    printf("[%s], ", fourcc);
    value = strh[16] | (strh[17]<<8) | (strh[18]<<16) | (strh[19]<<24);	
    printf("Initial %d, ", value);
    value = strh[20] | (strh[21]<<8) | (strh[22]<<16) | (strh[23]<<24);	
    printf("%d/", value);	
    value = strh[24] | (strh[25]<<8) | (strh[26]<<16) | (strh[27]<<24);	
    printf("%d, ", value);	
    value = strh[28] | (strh[29]<<8) | (strh[30]<<16) | (strh[31]<<24);	
    printf("%d+", value);
    value = strh[32] | (strh[33]<<8) | (strh[34]<<16) | (strh[35]<<24);	
    printf("%d, ", value);	
    value = strh[36] | (strh[37]<<8) | (strh[38]<<16) | (strh[39]<<24);	
    printf("Buffer:%d Bytes, ", value);
    value = strh[40] | (strh[41]<<8) | (strh[42]<<16) | (strh[43]<<24);		
    printf("quality:0x%x, ", value);
    value = strh[44] | (strh[45]<<8) | (strh[46]<<16) | (strh[47]<<24);		
    printf("Size of Sample:%d, ", value);	
    putchar('}');
    putchar('\n');
 
    fseek(fp, pos+tag->size+(tag->size&1), SEEK_SET);   
    return ftell(fp);
}

strf parser

int parse_strf(FILE *fp, const avitag_t *tag)
{
    unsigned char header[40];
    unsigned short v1;
    unsigned int v2;
    unsigned long pos = ftell(fp);
    int idx= tag->nested+1;
    int type = -1;
 
    if (20 != fread(&header, 1, 20, fp))
        return -1;
    v1 = header[0] | (header[1]<<8);
    if (v1 == 40 && tag->size >= 40) type = 1; /* guessed to be video */
    else 
    {
        v1 = header[16] | (header[17]<<8);
	    if (tag->size >= v1+18) type = 2; /* guessed to be audio */
    }	
 
    if (type == 1) 
    {
        while (idx-- >= 0)
        {
            putchar(0x20);
        }	
        putchar('{');		
        v2 = header[4] |(header[5]<<8) | (header[6]<<16) | (header[7]<<24); 	
        printf("%dx", v2);
        v2 = header[8] |(header[9]<<8) | (header[10]<<16) | (header[11]<<24); 	
        printf("%d, ", v2);		
        v1 = header[14] | (header[15]<<8);
        printf("%d Bits, ", v1);
        putchar(header[16]);	
        putchar(header[17]);	
        putchar(header[18]);	
        putchar(header[19]);			
        putchar('}');
        putchar('\n');			
 
	}
    else if (type == 2) 
    {
        while (idx-- >= 0)
        {
            putchar(0x20);
        }			
        putchar('{');
        v1 = header[0] | (header[1]<<8);	
        printf("id=0x%x, ", v1);
        v1 = header[2] | (header[3]<<8);
        printf("%d ch, ", v1);
        v2 = header[4] | (header[5]<<8) | (header[6]<<16) | (header[7]<<24);
        printf("Sample rate:%d, ", v2);
        v2 = header[8] | (header[9]<<8) | (header[10]<<16) | (header[11]<<24);
        printf("Bit rate:%d, ", v2*8);
        v1 = header[12] | (header[13]<<8);
        printf("%d block align, ", v1);      
        v1 = header[14] | (header[15]<<8);
        printf("%d bits, ", v1);
        putchar('}');
        putchar('\n');		
    }
 
    fseek(fp, pos+tag->size+(tag->size&1), SEEK_SET);   
    return ftell(fp);
}

Information Chunk Parser

ISFT parser

int parse_isft(FILE *fp, const avitag_t *tag)
{
    int idx = tag->nested+1;
    char *str;
 
    str = (char *)malloc(tag->size);
    if (!str) 
        return -1;
 
    if (tag->size != fread(str, 1, tag->size, fp))
        return -1;
 
    while (idx-- >= 0)
    {
        putchar(0x20);
    }   
    printf("{%s}\n", str);
 
    free(str);
    return ftell(fp);
}

Index Parser

int parse_indx(FILE *fp, const avitag_t *tag)
{
    unsigned char buffer[16];
    unsigned char fourcc[5];
    unsigned int flag;
    unsigned int pos;
    unsigned int len;
    int i;
    int idx;
    long end_indx = ftell(fp) + tag->size + (tag->size&1);
	int entries = tag->size/16;
 
    for (i = 0; i < entries; i++)
    {
        idx = tag->nested+1;	
        while (idx-- >= 0)
        {
            putchar(0x20);
        }	
        fread(buffer, 1, 16, fp);
        fourcc[0] = buffer[0];
        fourcc[1] = buffer[1];		
        fourcc[2] = buffer[2];		
        fourcc[3] = buffer[3];	
        fourcc[4] = 0;		
        flag = buffer[4] | (buffer[5]<<8) | (buffer[6]<<16) | (buffer[7]<<24);
        pos = buffer[8] | (buffer[9]<<8) | (buffer[10]<<16) | (buffer[11]<<24);		
        len = buffer[12] | (buffer[13]<<8) | (buffer[14]<<16) | (buffer[15]<<24);	
        printf("{fourcc=%s, flag=0x%x, pos=%d, len=%d}\n", fourcc, flag, pos, len);		
    }	
    fseek(fp, end_indx, SEEK_SET);
    return ftell(fp);	
}

ODML index parser

int parse_indx2(FILE *fp, const avitag_t *tag)
{
    unsigned char header[12]; /* for fixed header */
    int end = ftell(fp) + tag->size + (tag->size&1);
    int size1;
    int size2;
    unsigned char sub_type;
    unsigned char type;
    int data1;
    long long data2;
    int idx = tag->nested+1;
    int i;
    unsigned long pos = ftell(fp);	
 
    if (12 != fread(header, 1, 12, fp))
        return -1;
 
    size1 = header[0] | (header[1]<<8);
    sub_type = header[2];
    type = header[3];
    size2 = header[4] | (header[5]<<8) | (header[6]<<16) | (header[7]<<24);
	fseek(fp, 12, SEEK_CUR);  /* skip the reserved */
 
    while (idx-- >= 0) putchar(0x20);
    putchar('{');
 
    if (type == 1 && sub_type == 0) /* standard index chunk */ 
    {    
        for (i = 0; i < size2; i++)
        {
            fread((unsigned char *)&data1, 1, 4, fp);
            printf("offset:%d&", data1);
            fread((unsigned char *)&data1, 1, 4, fp);
            printf("size:%d;", data1);
        }
    }
    else if (type == 0) /* super index chunk */
    {
       for (i = 0; i < size2; i++)
        {
            fread((unsigned char *)&data2, 1, 8, fp);		
            fread((unsigned char *)&data1, 1, 4, fp);
            printf("size:%d&", data1);
            fread((unsigned char *)&data1, 1, 4, fp);
            printf("duration:%d;", data1);
        }	
    }    
 
    putchar('}');
    putchar('\n');
 
    fseek(fp, pos+tag->size+(tag->size&1), SEEK_SET);   
    return ftell(fp);	
}
tech/multimedia/avi_parser.txt · Last modified: 2014/11/10 08:22 (external edit)