从AVI文件解析BITMAPINFO结构

时间:2015-02-11 06:36:29

标签: c bitmap avi

我正在尝试了解有关AVI结构的更多信息,因此我开始介绍位于此处的Microsoft obtuse文档:

https://msdn.microsoft.com/en-us/library/ms779636.aspx

我希望能够根据未压缩的位图图像编写AVI创建器。但是我发现如果不尝试分解现有的AVI,很难理解这种格式。所以,我抓住了一个躺在我的硬盘上并开始从文件中提取字节。这是构建的代码和命令:

// Read an unsigned
//
static unsigned get_dword(FILE *fp)
{
    unsigned tmp;
    unsigned char buf[4];
    unsigned char *p;

    p = (unsigned char *) &tmp;

    if (fread(&buf, 1, sizeof(buf), fp) != sizeof(buf)) {
        printf("Error: Unexpected EOF\n");
        exit(1);
    }

    p[0] = buf[0];
    p[1] = buf[1];
    p[2] = buf[2];
    p[3] = buf[3];

    return tmp;
}

static unsigned short get_word(FILE *fp)
{
    unsigned short tmp;
    unsigned char buf[2];
    unsigned char *p;

    p = (unsigned char *) &tmp;

    if (fread(&buf, 1, sizeof(buf), fp) != sizeof(buf)) {
        printf("Error: Unexpected EOF\n");
        exit(1);
    }

    p[0] = buf[0];
    p[1] = buf[1];

    return tmp;
}

static char *get_fourcc(char *str, FILE *fp)
{
    if (fread(str, 1, 4, fp) != 4) {
        printf("Error: Unexpected EOF\n");
        exit(1);
    }

    return str;
}

//
//
int main(int argc, char *argv[])
{
    if (argc > 1) {
        FILE *fp = fopen(argv[1], "rb");

        if (fp) {
            char buf[5] = { 0 };

            printf("%s (\n", get_fourcc(buf, fp));

            printf("fileSize=%u\n", get_dword(fp));

            printf("fileType='%s'\n", get_fourcc(buf, fp));

            printf("'%s'\n", get_fourcc(buf, fp));

            printf("listSize=%u\n", get_dword(fp));

            printf("listType='%s'\n", get_fourcc(buf, fp));
            // avih

            printf("listData='%s'\n", get_fourcc(buf, fp));

            printf("cb=%u\n", get_dword(fp));
            printf("dwMicroSecPerFrame=%u\n", get_dword(fp));
            printf("dwMaxBytesPerSec=%u\n", get_dword(fp));
            printf("dwPaddingGranularity=%u\n", get_dword(fp));
            printf("dwFlags=0x%x\n", get_dword(fp));
            printf("dwTotalFrames=%u\n", get_dword(fp));
            printf("dwInitialFrames=%u\n", get_dword(fp));
            printf("dwStreams=%u\n", get_dword(fp));
            printf("dwSuggestedBufferSize=%u\n", get_dword(fp));
            printf("dwWidth=%u\n", get_dword(fp));
            printf("dwHeight=%u\n", get_dword(fp));
            printf("dwReserved = { %u, %u, %u, %u }\n", get_dword(fp),
                get_dword(fp), get_dword(fp), get_dword(fp));

            printf("'%s'\n", get_fourcc(buf, fp));
            printf("listSize=%u\n", get_dword(fp));
            printf("listType='%s'\n", get_fourcc(buf, fp));

            // strh
            printf("listData='%s'\n", get_fourcc(buf, fp));
            printf("cb=%u\n", get_dword(fp));
            printf("fccType='%s'\n", get_fourcc(buf, fp));
            printf("fccHandler='%s'\n", get_fourcc(buf, fp));
            printf("dwFlags=0x%x\n", get_dword(fp));
            printf("wPriority=%d\n", get_word(fp));
            printf("wLanguage=%d\n", get_word(fp));
            printf("dwInitialFrames=%u\n", get_dword(fp));
            printf("dwScale=%u\n", get_dword(fp));
            printf("dwRate=%u\n", get_dword(fp));
            printf("dwStart=%u\n", get_dword(fp));
            printf("dwLength=%u\n", get_dword(fp));
            printf("dwSuggestedBufferSize=%u\n", get_dword(fp));
            printf("dwQuality=%u\n", get_dword(fp));
            printf("dwSampleSize=%u\n", get_dword(fp));
            printf("rcFrame={ %u, %u, %u, %u }\n", get_word(fp),
                get_word(fp), get_word(fp), get_word(fp));

            // strf
            printf("'%s'\n", get_fourcc(buf, fp));
            printf("biSize=%u\n", get_dword(fp));
            printf("?=%d\n", get_dword(fp));
            printf("biWidth=%d\n", get_dword(fp));
            printf("biHeight=%d\n", get_dword(fp));
            printf("biPlanes=%d\n", get_word(fp));
            printf("biBitCount=%d\n", get_word(fp));
            printf("biCompression=0x%x\n", get_dword(fp));
            printf("biSizeImage=%u\n", get_dword(fp));
            printf("biXPelsPerMeter=%d\n", get_dword(fp));
            printf("biYPelsPerMeter=%d\n", get_dword(fp));
            printf("biClrUsed=%u\n", get_dword(fp));
            printf("biClrImportant=%u\n", get_dword(fp));

            printf("%s\n", get_fourcc(buf, fp));

            fclose(fp);
        } else {
            printf("Unable to open '%s'\n", argv[1]);
        }
    }
}

$ g++ -g -o avi -Wall -ansi avi.cc
$ ./avi avifile.avi
RIFF (
fileSize=68054008
fileType='AVI '
'LIST'
listSize=796
listType='hdrl'
listData='avih'
cb=56
dwMicroSecPerFrame=33367
dwMaxBytesPerSec=3724404
dwPaddingGranularity=512
dwFlags=0x810
dwTotalFrames=545
dwInitialFrames=0
dwStreams=2
dwSuggestedBufferSize=120008
dwWidth=720
dwHeight=480
dwReserved = { 0, 0, 0, 0 }
'LIST'
listSize=228
listType='strl'
listData='strh'
cb=56
fccType='vids'
fccHandler='dvsd'
dwFlags=0x0
wPriority=0
wLanguage=0
dwInitialFrames=0
dwScale=1001
dwRate=30000
dwStart=0
dwLength=545
dwSuggestedBufferSize=120008
dwQuality=4294967295
dwSampleSize=0
rcFrame={ 0, 0, 720, 480 }
'strf'
biSize=40
?=40
biWidth=720
biHeight=480
biPlanes=1
biBitCount=24
biCompression=0x64737664
biSizeImage=120000
biXPelsPerMeter=0
biYPelsPerMeter=0
biClrUsed=0
biClrImportant=0
indx

我担心的是'?'的具体条目通过它。对于标题大小,40个字节应该是正确的,但是在进入位图帧的宽度和高度之前,第二次重复40个字节。我运行了hexdump,这不是代码中的错误。我看了两次。我试图理解这是否只是我对格式的解释中的错误,或者这是否是其他的。

这里记录了BITMAPINFOHEADER结构:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx

如果有人有任何指示,那就太棒了......

1 个答案:

答案 0 :(得分:2)

第一个数字40不是第二个40的biBytes。第一个数字实际上是strf块中包含的数据的大小。对于这个块,这两个数字恰好相同。

AVI文件基于微软的RIFF format(反过来基于电子艺界的IFF format)。在RIFF格式中,所有内容都以块的形式存储。每个块以4个字节开始,用于标识块的类型,紧接着是4个字节,指定块中数据的长度为32位无符号小端整数。我建议重写你的程序来单独处理每个块,而不是假设一个固定的块序列。这样你就可以跳过你不感兴趣的块,或者还没弄明白如何完全解码。