从 AVI 文件解析 BITMAPINFO 结构

Parsing BITMAPINFO structure from an AVI file

我想了解有关 AVI 结构的更多信息,所以我开始浏览位于此处的 Microsoft 的晦涩文档:

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 个字节对于 header 大小应该是正确的,但是 40 在您进入位图帧的宽度和高度之前重复了第二次。我 运行 hexdump 并且它不是代码中的错误。我看了两次。我想了解这是否只是我对格式的解释错误,或者这是其他原因。

此处记录了 BITMAPINFOHEADER 结构:

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

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

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

AVI 文件基于微软的 RIFF format (which in turn is based on the Electronic Arts's IFF format)。在 RIFF 格式中,所有内容都存储在块中。每个块以标识块类型的 4 个字节开始,紧随其后的 4 个字节指定块中数据的长度为 32 位无符号小端整数。我建议重写你的程序来单独处理每个块,而不是假设一个固定的块序列。这样你就可以跳过你不感兴趣或还没有想出如何完全解码的块。