📄 avireader.cpp
字号:
// AviReader.cpp: implementation of the CAviReader class.
//
//////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdlib.h>
#include "common.h"
#include "AviReader.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define PAD_EVEN(x) ( ((x)+1) & ~1 )
#define ERR_EXIT(x) \
{ \
CloseAviFile(); \
m_nAviErrNo = x; \
return 0; \
}
#define I_FRAME MAKEFOURCC('0', '0', 'd', 'b')
//##ModelId=4753BE280233
CAviReader::CAviReader()
{
m_pAviFile = (avi_t *) malloc(sizeof(avi_t));
memset((void *)m_pAviFile, 0, sizeof(avi_t));
m_pVideoBuf = (BYTE *)malloc(VIDEO_BUFFER_MAX_SIZE);
memset(m_pVideoBuf, 0, VIDEO_BUFFER_MAX_SIZE);
m_pAudioBuf = (BYTE *)malloc(AUDIO_BUFFER_MAX_SIZE);
memset(m_pAudioBuf, 0, AUDIO_BUFFER_MAX_SIZE);
m_nCurAudioPos = m_nCurVideoPos = 0;
}
//##ModelId=4753BE280242
CAviReader::~CAviReader()
{
if( m_pAudioBuf )
free(m_pAudioBuf);
if( m_pVideoBuf )
free(m_pVideoBuf);
if( m_pAviFile )
free(m_pAviFile);
}
/*******************************************************************
* *
* Utilities for reading video and audio from an m_pAviFile File *
* *
*******************************************************************/
/* Copy n into dst as a 4 byte, little endian number.
Should also work on big endian machines */
//##ModelId=4753BE280295
void CAviReader::Long2Str(BYTE *dst, int n)
{
dst[0] = (n )&0xff;
dst[1] = (n>> 8)&0xff;
dst[2] = (n>>16)&0xff;
dst[3] = (n>>24)&0xff;
}
/* Convert a string of 4 or 2 bytes to a number,
also working on big endian machines */
//##ModelId=4753BE2802A1
unsigned long CAviReader::Str2ULong(BYTE *str)
{
return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
}
//##ModelId=4753BE2802AF
unsigned long CAviReader::Str2UShort(BYTE *str)
{
return ( str[0] | (str[1]<<8) );
}
/* Calculate audio sample size from number of bits and number of channels.
This may have to be adjusted for eg. 12 bits and stereo */
//##ModelId=4753BE2802BF
int CAviReader::Sampsize()
{
int s;
s = ((m_pAviFile->a_bits+7)/8)*m_pAviFile->a_chans;
if(s==0)
s=1; /* avoid possible zero divisions */
return s;
}
//##ModelId=4753BE2802C0
int CAviReader::AddIndexEntry(BYTE *tag, LONG flags, LONG pos, LONG len)
{
void *ptr;
if(m_pAviFile->n_idx>=m_pAviFile->max_idx)
{
ptr = realloc((void *)m_pAviFile->idx,(m_pAviFile->max_idx+4096)*16);
if(ptr == 0)
{
m_nAviErrNo = AVI_ERR_NO_MEM;
return -1;
}
m_pAviFile->max_idx += 4096;
m_pAviFile->idx = (BYTE((*)[16]) ) ptr;
}
/* Add index entry */
memcpy(m_pAviFile->idx[m_pAviFile->n_idx],tag,4);
Long2Str(m_pAviFile->idx[m_pAviFile->n_idx]+ 4,flags);
Long2Str(m_pAviFile->idx[m_pAviFile->n_idx]+ 8,pos);
Long2Str(m_pAviFile->idx[m_pAviFile->n_idx]+12,len);
/* Update counter */
m_pAviFile->n_idx++;
return 0;
}
//##ModelId=4753BE280244
int CAviReader::OpenAviFile(const char *filename)
{
long i, n, rate, scale, idx_type;
BYTE *hdrl_data;
long hdrl_len = 0;
long nvi, nai, ioff;
long audtot, vidtot;
DWORD dwRead;
int lasttag = 0;
int vids_strh_seen = 0;
int vids_strf_seen = 0;
int auds_strh_seen = 0;
int auds_strf_seen = 0;
int num_stream = 0;
char data[256];
/* Create avi_t structure */
if(m_pAviFile == NULL)
{
m_nAviErrNo = AVI_ERR_NO_MEM;
return -1;
}
memset((void *)m_pAviFile,0,sizeof(avi_t));
/* Open the file */
m_pAviFile->fDes = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if(m_pAviFile->fDes == INVALID_HANDLE_VALUE)
{
m_nAviErrNo = AVI_ERR_OPEN;
free(m_pAviFile);
m_pAviFile = NULL;
return -1;
}
/* Read first 12 bytes and check that this is an m_pAviFile file */
ReadFile(m_pAviFile->fDes, data, 12, &dwRead, NULL);
if( dwRead != 12 )
ERR_EXIT(AVI_ERR_READ)
if( strncmp(data ,"RIFF",4) !=0 ||
strncmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI)
/* Go through the m_pAviFile file and extract the header list,
the start position of the 'movi' list and an optionally
present idx1 tag */
hdrl_data = 0;
while(1)
{
ReadFile(m_pAviFile->fDes, data, 8, &dwRead, NULL);
if( dwRead != 8 ) break; /* We assume it's EOF */
n = Str2ULong((BYTE*)data+4);
n = PAD_EVEN(n);
if(strncmp(data,"LIST",4) == 0)
{
ReadFile(m_pAviFile->fDes, data, 4, &dwRead, NULL);
if( dwRead != 4 ) ERR_EXIT(AVI_ERR_READ)
n -= 4;
if(strncmp(data,"hdrl",4) == 0)
{
hdrl_len = n;
hdrl_data = (BYTE *) malloc(n);
if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM)
ReadFile(m_pAviFile->fDes, hdrl_data, n, &dwRead, NULL);
if( (long)dwRead != n ) ERR_EXIT(AVI_ERR_READ)
}
else if(strncmp(data,"movi",4) == 0)
{
m_pAviFile->movi_start = SetFilePointer(m_pAviFile->fDes, 0, NULL, FILE_CURRENT);
SetFilePointer(m_pAviFile->fDes, n, NULL, FILE_CURRENT);
}
else
SetFilePointer(m_pAviFile->fDes, n, NULL, FILE_CURRENT);
}
else if(strncmp(data,"idx1",4) == 0)
{
/* n must be a multiple of 16, but the reading does not
break if this is not the case */
m_pAviFile->n_idx = m_pAviFile->max_idx = n/16;
m_pAviFile->idx = (BYTE((*)[16]) ) malloc(n);
if(m_pAviFile->idx==0)
ERR_EXIT(AVI_ERR_NO_MEM)
ReadFile(m_pAviFile->fDes, m_pAviFile->idx, n, &dwRead, NULL);
if( (long)dwRead != n )
ERR_EXIT(AVI_ERR_READ)
}
else
SetFilePointer(m_pAviFile->fDes, n, NULL, FILE_CURRENT);
}
if(!hdrl_data ) ERR_EXIT(AVI_ERR_NO_HDRL)
if(!m_pAviFile->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
/* Interpret the header list */
for(i=0;i<hdrl_len;)
{
/* List tags are completly ignored */
if(strncmp((const char*)hdrl_data+i,"LIST",4)==0) { i+= 12; continue; }
n = Str2ULong(hdrl_data+i+4);
n = PAD_EVEN(n);
/* Interpret the tag and its args */
if(strncmp((const char*)hdrl_data+i,"strh",4)==0)
{
i += 8;
if(strncmp((const char*)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
{
scale = Str2ULong(hdrl_data+i+20);
rate = Str2ULong(hdrl_data+i+24);
if(scale!=0) m_pAviFile->fps = (double)rate/(double)scale;
m_pAviFile->video_frames = Str2ULong(hdrl_data+i+32);
m_pAviFile->video_strn = num_stream;
vids_strh_seen = 1;
lasttag = 1; /* vids */
}
else if (strncmp ((const char*)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
{
m_pAviFile->audio_bytes = Str2ULong(hdrl_data+i+32)*Sampsize();
m_pAviFile->audio_strn = num_stream;
auds_strh_seen = 1;
lasttag = 2; /* auds */
}
else
lasttag = 0;
num_stream++;
}
else if(strncmp((const char*)hdrl_data+i,"strf",4)==0)
{
i += 8;
if(lasttag == 1)
{
m_pAviFile->width = Str2ULong(hdrl_data+i+4);
m_pAviFile->height = Str2ULong(hdrl_data+i+8);
memcpy(m_pAviFile->compressor,hdrl_data+i+16,4);
m_pAviFile->compressor[4] = 0;
vids_strf_seen = 1;
}
else if(lasttag == 2)
{
m_pAviFile->a_fmt = Str2UShort(hdrl_data+i );
m_pAviFile->a_chans = Str2UShort(hdrl_data+i+2);
m_pAviFile->a_rate = Str2ULong (hdrl_data+i+4);
m_pAviFile->a_bits = Str2UShort(hdrl_data+i+14);
m_pAviFile->acps = m_pAviFile->a_rate / 1024.0;
//temp code for aac decode
if( Str2ULong(hdrl_data+i-4) > 16 )
{
m_pAviFile->a_extradata_size = Str2UShort(hdrl_data+i+16);
memcpy(m_pAviFile->a_extradata, hdrl_data+i+18, 2);
}
auds_strf_seen = 1;
}
lasttag = 0;
}
else
{
i += 8;
lasttag = 0;
}
i += n;
}
free(hdrl_data);
if(!vids_strh_seen || !vids_strf_seen || m_pAviFile->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS)
m_pAviFile->video_tag[0] = m_pAviFile->video_strn/10 + '0';
m_pAviFile->video_tag[1] = m_pAviFile->video_strn%10 + '0';
m_pAviFile->video_tag[2] = 'd';
m_pAviFile->video_tag[3] = 'b';
/* Audio tag is set to "99wb" if no audio present */
if(!m_pAviFile->a_chans) m_pAviFile->audio_strn = 99;
m_pAviFile->audio_tag[0] = m_pAviFile->audio_strn/10 + '0';
m_pAviFile->audio_tag[1] = m_pAviFile->audio_strn%10 + '0';
m_pAviFile->audio_tag[2] = 'w';
m_pAviFile->audio_tag[3] = 'b';
SetFilePointer(m_pAviFile->fDes, m_pAviFile->movi_start, NULL, FILE_BEGIN);
/* if the file has an idx1, check if this is relative
to the start of the file or to the start of the movi list */
idx_type = 0;
if(m_pAviFile->idx)
{
long pos;
unsigned long len;
/* Search the first videoframe in the idx1 and look where
it is in the file */
for(i=0;i<m_pAviFile->n_idx;i++)
if( strncmp((const char*)m_pAviFile->idx[i],m_pAviFile->video_tag,3)==0 ) break;
if(i>=m_pAviFile->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
pos = Str2ULong(m_pAviFile->idx[i]+ 8);
len = Str2ULong(m_pAviFile->idx[i]+12);
SetFilePointer(m_pAviFile->fDes, pos, NULL, FILE_BEGIN);
ReadFile(m_pAviFile->fDes, data, 8, &dwRead, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -