美文网首页
AVI文件格式

AVI文件格式

作者: 客昂康 | 来源:发表于2020-12-07 12:34 被阅读0次
AVI文件由一个个Chunk组成,每个Chunk由4字节的ChunkID、4字节的ChunkSize和ChunkData三部分组成,其中ChunkSize仅仅是ChunkData的大小,不包含ChunkID和ChunkSize。如图:
只有ChunkID等于"RIFF"或"LIST"的Chunk才能包含子Chunk,并在ChunkData的首部用一个4字节的type字段标记他自己的类型,如图:
整个AVI文件各个Chunk的嵌套关系如图:
以下代码可以初步分解AVI文件结构:
#include <stdio.h>
#include <stdint.h>

#define  AVICHUNKTYPE_LIST  0x4c495354
#define  AVICHUNKTYPE_RIFF  0x52494646
#define  AVICHUNKTYPE_hdrl  0x6864726c
#define  AVICHUNKTYPE_avih  0x61766968
#define  AVICHUNKTYPE_strl  0x7374726c
#define  AVICHUNKTYPE_strh  0x73747268
#define  AVICHUNKTYPE_strf  0x73747266
#define  AVICHUNKTYPE_strn  0x7374726e
#define  AVICHUNKTYPE_vprp  0x76707270
#define  AVICHUNKTYPE_INFO  0x494e464f
#define  AVICHUNKTYPE_ISFT  0x49534654
#define  AVICHUNKTYPE_JUNK  0x4a554e4b
#define  AVICHUNKTYPE_movi  0x6d6f7669
#define  AVICHUNKTYPE_idx1  0x69647831

static int64_t getFileSize(FILE *fp){
    _fseeki64(fp, 0, SEEK_END);
    return _ftelli64(fp);
}

static uint32_t readU32BE(FILE *fp, int64_t offset){
    uint8_t buffer[8];
    if(offset >= 0){
        _fseeki64(fp, offset, SEEK_SET);
    }
    fread(buffer, 4, 1, fp);
    uint32_t value = buffer[0];
    value = (value << 8) | buffer[1];
    value = (value << 8) | buffer[2];
    value = (value << 8) | buffer[3];
    return value;
}

static uint32_t readU32LE(FILE *fp, int64_t offset){
    uint8_t buffer[8];
    if(offset >= 0){
        _fseeki64(fp, offset, SEEK_SET);
    }
    fread(buffer, 4, 1, fp);
    uint32_t value = buffer[3];
    value = (value << 8) | buffer[2];
    value = (value << 8) | buffer[1];
    value = (value << 8) | buffer[0];
    return value;
}

static void typeToString(char *buffer, uint32_t type){
    char *p = (char*)&type;
    buffer[0] = p[3];
    buffer[1] = p[2];
    buffer[2] = p[1];
    buffer[3] = p[0];
    buffer[4] = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

static void readChunk_avih(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    
}

static void readChunk_strh(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    
}

static void readChunk_strf(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    
}

static void readChunk_strn(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    
}

static void readChunk_vprp(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    
}

static void readChunk_ISFT(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    
}

static void readChunk_movi(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    
}

static void readChunk_idx1(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    
}

////////////////////////////////////////////////////////////////////////////////////////////////////

static void printAVIStruct(int64_t fileStart, uint32_t chunkSize, char *typeStr, uint8_t depth){
    printf("%10lld ", fileStart);
    while(depth--) printf("-----");
    printf(" %s %u\n", typeStr, chunkSize);
}

static void readChunk_xxxx(FILE *fp, int64_t fileStart, int64_t fileEnd, uint8_t depth){
    char typeBuffer[8];
    uint32_t type;
    uint32_t size;
    while(fileStart+8 <= fileEnd){
        type = readU32BE(fp, fileStart+0);
        size = readU32LE(fp, fileStart+4);
        if(size > fileEnd-fileStart-8){
            size = fileEnd - fileStart - 8;
        }
        if(type == AVICHUNKTYPE_RIFF){
            if(fileEnd > fileStart+8+size){
                fileEnd = fileStart+8+size;
            }
            fileStart += 12;
            size -= 4;
        }else if(type == AVICHUNKTYPE_LIST){
            type = readU32BE(fp, fileStart+8);
            fileStart += 12;
            size -= 4;
        }else{
            fileStart += 8;
        }
        
        typeToString(typeBuffer, type);
        printAVIStruct(fileStart, size, typeBuffer, depth);
        
        switch(type){
            case AVICHUNKTYPE_RIFF:
            readChunk_xxxx(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_hdrl:
            readChunk_xxxx(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_avih:
            readChunk_avih(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_strl:
            readChunk_xxxx(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_strh:
            readChunk_strh(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_strf:
            readChunk_strf(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_strn:
            readChunk_strn(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_vprp:
            readChunk_vprp(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_INFO:
            readChunk_xxxx(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_ISFT:
            readChunk_ISFT(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_movi:
            readChunk_movi(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_idx1:
            readChunk_idx1(fp, fileStart, fileStart+size, depth+1);
            break;
            
            case AVICHUNKTYPE_JUNK:
            break;
            
            default:
            printf("#define  AVICHUNKTYPE_%s  0x%08x\n", typeBuffer, type);
            break;
        }
        
        fileStart += size+(size%2);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

int main(int argc, char *argv[]){
    if(argc < 2) return 0;
    FILE *fp = fopen(argv[1], "rb");
    if(fp == NULL) return -1;
    int64_t fileSize = getFileSize(fp);
    if(fileSize <= 8){
        fclose(fp);
        return -2;
    }
    
    readChunk_xxxx(fp, 0, fileSize, 1);
    
    fclose(fp);
    return 0;
}

运行效果如图:


相关文章

网友评论

      本文标题:AVI文件格式

      本文链接:https://www.haomeiwen.com/subject/kvgzwktx.html