// Riff.cpp : 콘솔응용프로그램에대한진입점을정의합니다.
//
#include "stdafx.h"
#include <string.h>
/////////////////////////////////////////////////////////////////////////////
//===========================================================================
typedef unsigned int uint32_t;
typedef unsigned short int uint16_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef unsigned char byte_t;
inline uint32_t convert_endian_4byte (uint32_t v)
{
return (((v>>24)&0xff) )|
(((v>>16)&0xff) << 8 )|
(((v>> 8)&0xff) << 16 )|
(((v )&0xff) << 24 );
}
/////////////////////////////////////////////////////////////////////////////
//===========================================================================
const uint32_t FOURCC_RIFF = 0x46464952;
const uint32_t FOURCC_AVI = 0x20495641;
const uint32_t FOURCC_LIST = 0x5453494C;
const uint32_t FOURCC_hdrl = 0x6C726468;
const uint32_t FOURCC_avih = 0x68697661;
const uint32_t FOURCC_strl = 0x6C727473;
const uint32_t FOURCC_strh = 0x68727473;
const uint32_t FOURCC_strf = 0x66727473;
const uint32_t FOURCC_STRD = 0x64727473;
const uint32_t FOURCC_vids = 0x73646976;
const uint32_t FOURCC_auds = 0x73647561;
const uint32_t FOURCC_INFO = 0x4F464E49;
const uint32_t FOURCC_ISFT = 0x54465349;
const uint32_t FOURCC_idx1 = 0x31786469;
const uint32_t FOURCC_movi = 0x69766F6D;
const uint32_t FOURCC_JUNK = 0x4B4E554A;
const uint32_t FOURCC_vprp = 0x70727076;
const uint32_t FOURCC_PAD = 0x20444150;
const uint32_t FOURCC_DIV3 = 861292868;
const uint32_t FOURCC_DIVX = 1482049860;
const uint32_t FOURCC_XVID = 1145656920;
const uint32_t FOURCC_DX50 = 808802372;
#define FOURCC(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d))
/////////////////////////////////////////////////////////////////////////////
//===========================================================================
typedef struct _riff_header_t
{
uint32_t riff ;
uint32_t size ;
uint32_t type ;
} riff_header_t;
typedef struct _list_header_t
{
uint32_t list ;
uint32_t size ;
uint32_t fourcc ;
} list_header_t;
typedef struct _chunk_header_t
{
uint32_t fourcc ;
uint32_t size ;
} chunk_header_t;
/////////////////////////////////////////////////////////////////////////////
//===========================================================================
typedef struct _MainAVIHeader_t
{
uint32_t MicroSecPerFrame; // frame display rate (or 0)
uint32_t MaxBytesPerSec; // max. transfer rate
uint32_t PaddingGranularity; // pad to multiples of this size;
uint32_t Flags; // the ever-present flags
uint32_t TotalFrames; // # frames in file
uint32_t InitialFrames;
uint32_t Streams;
uint32_t SuggestedBufferSize;
uint32_t Width;
uint32_t Height;
uint32_t Reserved[4];
} MainAVIHeader_t;
typedef struct _RECT_t
{
int16_t left;
int16_t top;
int16_t right;
int16_t bottom;
} RECT_t;
typedef struct _AVIStreamHeader_t
{
uint32_t fccType;
uint32_t fccHandler;
uint32_t Flags;
uint16_t Priority;
uint16_t Language;
uint32_t InitialFrames;
uint32_t Scale;
uint32_t Rate;
uint32_t Start;
uint32_t Length;
uint32_t SuggestedBufferSize;
uint32_t Quality;
uint32_t SampleSize;
RECT_t FrameRect;
} AVIStreamHeader_t;
// strl - strh==vids strf
typedef struct _BitmapInfoHeader_t
{
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} BitmapInfoHeader_t;
// strl - strh==auds strf
typedef struct _WaveFormatEx_t
{
uint16_t FormatTag;
uint16_t Channels;
uint32_t SamplesPerSec;
uint32_t AvgBytesPerSec;
uint16_t BlockAlign;
uint16_t BitsPerSample;
uint16_t Size;
} WaveFormatEx_t;
// AVI
typedef struct _avi_info_t
{
uint32_t HasVideo;
uint32_t HasAudio;
uint32_t avi_size;
uint32_t movi_size;
uint32_t audio_data_size;
uint32_t audio_data_count;
uint32_t video_data_size;
uint32_t video_data_count;
MainAVIHeader_t Header;
AVIStreamHeader_t Video; // strh
BitmapInfoHeader_t VideoBitmapInfo; // strf
AVIStreamHeader_t Audio; // strh
WaveFormatEx_t AudioWaveFormatEx; // strf
} avi_info_t;
bool read_avi_header (const char* filepath, avi_info_t* ai)
{
FILE* fp;
fp = fopen (filepath, "rb");
if (0==fp)
{
return false;
}
//--------------------------------------------------------------------------
// RIFF header
//--------------------------------------------------------------------------
riff_header_t riff_header;
// [RIFF] size [AVI ]
fread(&riff_header, sizeof(riff_header), 1, fp);
printf ("%c%c%c%c %d %c%c%c%c \r\n",
(riff_header.riff>> 0)&0xff,
(riff_header.riff>> 8)&0xff,
(riff_header.riff>>16)&0xff,
(riff_header.riff>>24)&0xff,
riff_header.size ,
(riff_header.type>> 0)&0xff,
(riff_header.type>> 8)&0xff,
(riff_header.type>>16)&0xff,
(riff_header.type>>24)&0xff
);
if (riff_header.riff != 0x46464952) // "RIFF"
{
fclose (fp);
return false;
}
if (riff_header.type != 0x20495641) // "AVI "
{
fclose (fp);
return false;
}
ai->avi_size = riff_header.size;
//--------------------------------------------------------------------------
// RIFF body
//--------------------------------------------------------------------------
int32_t seek_size;
uint32_t id;
int32_t size;
uint32_t fourcc;
uint32_t data_size;
MainAVIHeader_t MainAVIHeader;
AVIStreamHeader_t AVIStreamHeader;
BitmapInfoHeader_t BitmapInfoHeader;
WaveFormatEx_t WaveFormatEx;
uint32_t strh = 0;
while ( !feof(fp) )
{
printf ("%8d: ", ftell (fp));
if (0==fread(&id, 4, 1, fp))
{
break;
}
if (0==fread(&size,4, 1, fp))
{
break;
}
printf ("<%c%c%c%c> %d \r\n",
(id>> 0)&0xff,
(id>> 8)&0xff,
(id>>16)&0xff,
(id>>24)&0xff,
size );
if (0==id)
{
break;
}
if (0>=size)
{
break;
}
// "LIST"
if (id==0x5453494c)
{
if (0==fread(&fourcc, 4, 1, fp))
{
break;
}
printf (" %c%c%c%c\r\n",
(fourcc>> 0)&0xff,
(fourcc>> 8)&0xff,
(fourcc>>16)&0xff,
(fourcc>>24)&0xff);
if (fourcc == 0x69766F6D)
{
ai->movi_size = size;
}
}
else
{
seek_size = (int32_t) size;
data_size = (int32_t) size;
// "avih"
if (id==0x68697661)
{
data_size = sizeof(MainAVIHeader);
if (0==fread (&MainAVIHeader, data_size, 1, fp))
{
break;
}
memcpy (&ai->Header, &MainAVIHeader, data_size);
seek_size = ( size!=data_size ) ? size-data_size : 0;
}
// "strh"
if (id==0x68727473)
{
data_size = sizeof(AVIStreamHeader);
if (0==fread (&AVIStreamHeader, data_size, 1, fp))
{
break;
}
printf (" %c%c%c%c:%c%c%c%c\r\n",
(AVIStreamHeader.fccType >> 0)&0xff,
(AVIStreamHeader.fccType >> 8)&0xff,
(AVIStreamHeader.fccType >>16)&0xff,
(AVIStreamHeader.fccType >>24)&0xff,
(AVIStreamHeader.fccHandler>> 0)&0xff,
(AVIStreamHeader.fccHandler>> 8)&0xff,
(AVIStreamHeader.fccHandler>>16)&0xff,
(AVIStreamHeader.fccHandler>>24)&0xff);
strh = 0;
// "vids"
if (0x73646976==AVIStreamHeader.fccType)
{
strh = 1;
memcpy(&ai->Video, &AVIStreamHeader, data_size);
ai->HasVideo = 1;
}
// "auds"
if (0x73647561==AVIStreamHeader.fccType)
{
strh = 2;
memcpy(&ai->Audio, &AVIStreamHeader, data_size);
ai->HasAudio = 1;
}
seek_size = ( size!=data_size ) ? size-data_size : 0;
}
// "strf"
if (id==0x66727473)
{
data_size = 0;
if (1==strh)
{
data_size = sizeof(BitmapInfoHeader);
if (0==fread (&BitmapInfoHeader, data_size, 1, fp))
{
break;
}
memcpy(&ai->VideoBitmapInfo, &BitmapInfoHeader, data_size);
}
if (2==strh)
{
data_size = sizeof(WaveFormatEx);
if (0==fread (&WaveFormatEx, data_size, 1, fp))
{
break;
}
memcpy(&ai->AudioWaveFormatEx, &WaveFormatEx, data_size);
}
seek_size = ( size!=data_size ) ? size-data_size : 0;
}
// "00dc" : Compressed video frame
if ((id&0xffff0000)==0x63640000)
{
ai->video_data_size += size;
ai->video_data_count++;
}
// "00db" : Uncompressed video frame
if ((id&0xffff0000)==0x62640000)
{
ai->video_data_size += size;
ai->video_data_count++;
}
// "00pc" : Palette change
if ((id&0xffff0000)==0x63700000)
{
ai->video_data_size += size;
ai->video_data_count++;
}
// "00wb" : Audio data
if ((id&0xffff0000)==0x62770000)
{
ai->audio_data_size += size;
ai->audio_data_count++;
}
//
if ( 0!=seek_size )
{
if ( data_size != size )
{
printf (" # data_size(%d) != size(%d)\r\n", data_size, size);
}
if (0!=(seek_size%2))
{
seek_size+=(seek_size%2);
}
if (-1==fseek (fp, seek_size, SEEK_CUR))
{
break;
}
}
}
}
fclose (fp);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
avi_info_t avi;
memset (&avi,0,sizeof(avi));
if (true==read_avi_header ("d:\\test.avi", &avi))
{
printf ("\r\n");
printf ("OK\r\n");
double fps;
double duration;
double VideoFramesPerSec;
double AudioBlockPerSec ;
int HeaderSize;
int VideoSize ;
int AudioSize ;
double VideoBitRate;
double AudioBitRate;
double FileBitRate;
fps = 1000000.0f/(double)avi.Header.MicroSecPerFrame;
duration = avi.Header.TotalFrames / fps;
AudioBlockPerSec = (double)avi.Audio.Rate / (double)avi.Audio.Scale;
VideoFramesPerSec = (double)avi.Video.Rate / (double)avi.Video.Scale;
/*
HeaderSize = avi.Header.TotalFrames * 8 * (avi.audio_data_count + 1);
AudioSize = (int)((avi.Audio.Length * avi.AudioWaveFormatEx.AvgBytesPerSec)/AudioBlockPerSec) * avi.audio_data_count;
VideoSize = avi.movi_size - HeaderSize - AudioSize;
*/
HeaderSize = avi.movi_size - avi.video_data_size - avi.audio_data_size;
AudioSize = avi.audio_data_size;
VideoSize = avi.video_data_size;
FileBitRate = avi.avi_size * 8.0 / duration / 1000.0;
AudioBitRate = avi.AudioWaveFormatEx.AvgBytesPerSec*8.0/1000.0;
VideoBitRate = FileBitRate - AudioBitRate; // Windows AVI File Property
VideoBitRate = (VideoSize * VideoFramesPerSec * 8.0)/(avi.Header.TotalFrames*1000.0);
printf ("\r\n");
if (avi.HasVideo)
{
printf ("[비디오] \r\n");
printf ("길이 = %5.3f 초\r\n", duration);
printf ("프레임너비 = %d\r\n", avi.Header.Width);
printf ("프레임높이 = %d\r\n", avi.Header.Height);
printf ("데이터속도 = %5.3f kbps \r\n", VideoBitRate);
printf ("총비트전송률= %5.3f kbps\r\n", FileBitRate);
printf ("프레임속도 = %5.3f 프레임/초\r\n", fps);
printf ("\r\n");
}
if (avi.HasAudio)
{
printf ("[오디오] \r\n");
printf ("비트전송율 = %5.3f kbps \r\n", AudioBitRate);
printf ("채널 = %d \r\n", avi.AudioWaveFormatEx.Channels);
printf ("오디오샘플속도= %5.3f KHz\r\n", AudioBlockPerSec / 1000);
printf ("\r\n");
}
}
return 0;
}
/*
RIFF 2317980 AVI
12: <LIST> 8818
hdrl
24: <avih> 56
88: <LIST> 4244
strl
100: <strh> 56
vids:
164: <strf> 40
212: <JUNK> 4120
4340: <LIST> 4222
strl
4352: <strh> 56
auds:
4416: <strf> 18
# data_size(20) != size(18)
4442: <JUNK> 4120
8570: <LIST> 260
odml
8582: <dmlh> 248
8838: <LIST> 28
INFO
8850: <ISFT> 15
8874: <JUNK> 1358
10240: <LIST> 2281204
movi
10252: <01wb> 24000
34260: <00dc> 22306
56574: <01wb> 1920
58502: <00dc> 159
58670: <01wb> 1920
...
2290948: <00dc> 159
2291116: <00dc> 159
2291284: <00dc> 159
2291452: <idx1> 26528
2317988: <JUNK> 340
2318336:
OK
[비디오]
길이 = 33.400 초
프레임너비 = 640
프레임높이 = 480
데이터속도 = 159.297 kbps
총비트전송률= 555.205 kbps
프레임속도 = 25.000 프레임/초
[오디오]
비트전송율 = 384.000 kbps
채널 = 5
오디오샘플속도= 48.000 KHz
*/