从 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 位无符号小端整数。我建议重写你的程序来单独处理每个块,而不是假设一个固定的块序列。这样你就可以跳过你不感兴趣或还没有想出如何完全解码的块。
我想了解有关 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 位无符号小端整数。我建议重写你的程序来单独处理每个块,而不是假设一个固定的块序列。这样你就可以跳过你不感兴趣或还没有想出如何完全解码的块。