2024年4月10日发(作者:)
…… …… … ……… … … ……………… ……………
实用第一 智慧密集
一 .… 一 …
A 厂I 播放器开发
洪
摘 要:使用XVID编解码库xvidcore.dU和微软的winmm.1ib多媒体开发库中放音的相关函数,
以及LAME库中的MP3解码函数,结合AVI文件的结构,开发了可以实现AVI文件播放功能的
实用程序。
关键词:XVID;MP3;AVI;LAME;播放器
AVI文件是Windows系统下一种很常见的视频文件,由微
软公司首先推出.用于保存图像和声音信息。其中的图像和声
音数据大都经过编码后进行存放。大部分媒体播放器都支持此
类文件的播放。下面将开发一个实用的AVI文件播放器,可进
行AVI视频文件的播放。
本播放器目前只支持AVI文件。其中图像编码必须为
XVID.声音编码必须为MP3,且图像帧速率应介于20—30之
间。其他编码暂不支持。
进行图像解码,需用到xvidcore.dll这个动态链接库。这是
一
个开源的XVID编码解码库,可以从www.xvid.org下载该库
的源代码。
播放图像则使用Windows提供的图形设备对象。
进行声音解码,需用到lame库,这是另一个开源的MP3
编码解码库,可从lame.sourceforge.net下载。
播放声音则使用微软的winmm.1ib这个多媒体开发库中的
声音播放函数。
1 AVl文件结构
AVI文件是微软公司推出的一种多媒体文件格式。该文件
通常包括一个视频流和一个音频流。
AVI文件南一个RIFF头,两个列表hdrl(用于描述媒体
流格式)和movi列表(用于保存媒体流数据),以及一个可选
的索弓I块组成。
hdd列表包括一个主信息头和两个strl子列表(分别用于
描述视频和音频流),其中主信息头结构如下:
typedef struct avimainheader(
DWORD fcc;//必须为‘avih’
DWORD cb://本数据结构的大小,不包括最初的8字节
DW0RD dwMicroSecPerFrame;
∥视频帧间隔时间(以微秒为单位)
DWORD dwMaxBytesPerSec;//这个AVI文件的最大数据率
DWORD dwPaddingGranularity;//数据填充的粒度
DWORD dwFlags;//AVI文件的全局标记,比如是否含有索引
9 毫扁20螭11穗 .蔽09砖与壤 i2;
|f块等
DWORD dwTotatFrames;//总帧数
DWORD dwlnitialFrames;//为交互格式指定初始帧数
DWORD dwStreams;//本文件包含的流的个数
DWORD dwSuggestedBufferSize;//建议读取本文件的缓存
”大,\\
DWORD dwWidth;//视频图像的宽(以像素为单位)
DW0RD dwHeight;//视频图像的高(以像素为单位)
DWORD dwReserved[4];//保留
1 AVIMAlNHEADER;
视频流和音频流子列表中包括一些基本的视频和音频参
数.如编码格式、声道数、采样频率等。
movi列表中保存实际的视频和音频数据。其中视频和音
频数据都是交错存放的。视频数据以00dc开头,其后4个字
节是该块数据长度,然后是实际的视频数据。音频数据以
01wb开头.其后4个字节是该块数据长度,然后是实际的音频
数据。
索引段以idxl开头.用于保存movi列表中各块的索引信息。
2 LAME库
开发利用LAME库提供的API进行MP3的解码。
LAME库提供的解码部分API如下:
进行MP3解码前执行lame—decode—initO;
完成MP3解码后执行lame—decode_exit();
进行MP3解码使用函数为
size=lame
—
decode(buf,r,leftpcm.rightpcm);
此函数中buf为MP3编码的数据,r为bur的大小,完成解
码后数据放在leftpcm和rightpcm中,分别对应左右卢道的数
据,返回值为解码后的大小。
3微软多媒体开发库
微软提供了多媒体开发库,名为winmlT1.1ib,头文件名为
mmsystem.h。
这个库中waveOut系列函数用于声音输出。
……
PROGRAM LANG哪B …………………………………………………………………… … ……………… ・
t
ve
rsio
n
n
n
t
∥
tV
pe=
4 Xk/ID编码解码库
XVID库巾提供了数据的解码操作。
解码前首先调用xvid
global(NULL,XVID—GBLINIT,
号
u oni
int generaI:∥通用标志
&xvid
gbl_init,NULL);进行初始化。其中XVID—GBL_INIT表示
—
int timebase:
int time
increment;
—
进行初始化。xvid一_gbl init是一个xvid_gb]_inik—t类型的变量,
该类型用于XVID初始化。 int qscale;
然后调用x rid__dec。re(NULL,.XVID—DEC—CREATE,&x、,id—d
ec
int qscale_stride;
. .
crea NuLL);创建一个解码实例。其中XVID~DEc—cRF_ 。。p://描述一个视频对象平面
ATE表示创建解码实例。xvid—dec—create是一个xvid dec—cre—
ate
—
t类型的变量,该类型用于建立解码实例。如果
xvid
d, ̄eC01", 返回0,则可从xvid—d,ec
create中取得解码实例的
句柄。
xvid dec create t结构定义如下:
:y
pedei‘ ,truct
{
.
...
…
Int version;//股 丐
int width;∥图像宽度
int h 图
void handle;∥解码实例句柄
概
)Xvid dec create t:
调用x、5d.decore fdec handle.XVID DEC DECODE,
&xviddec
frame,&xV
一
dec
stals);进行XVID解码。该函
数通常在一个循环中被反复调用,直到解出实际的图像。
其中XVID_DE ̄一DECODE表示进行XVID解码。
xviddec
frame是一个xvid—dec frame_t类型的变量,该类
型用于描述解出的帧。
xvid
dec
frame
_t定义如下:
typedef struct(
int version;||版苓号
int general;//:通用标志
void bitstream;//输入缓冲区
int length;∥输入缓冲长度
xvid
—
image t output;//@出图像
int brightness;
:txvid dec fYame_t;
其中xvid
jmage_t是另一个结构,表示输出图像,其定义
如下:
typedef structt【
int csp;//使用的色场空间
void plane[4];//图像平面,最多4个,一般只使用plane[O]
int stride[4];//表示每行像素占用字节数
] ̄xvid—image—t
xviddec
stats是一个xvid
dec
stats
t类型的变量,该类型
—
用于表示解码帧的状态。
xvid dec stats
t定义如下
typedef structi【
nt generaI:∥通用标志
int width;//解码后宽度
int height;//解码后高度
int par;
int par_width;
Nol;//描述一个视频对象层
1data.
) id ec stats t:
iNN—
xvidd
ec。
… 、…一……“ ……~
∽
han ,xvID~DEC—DESTR0Y'NuLL
一 …… … ’
NULL);结束一个解码实例。其中dec
handle是先前得到的解
码实例句柄,XVID
DEC
DESTROY表示撤销解码实例。
5 程序代码
程序中定义如下全局变量
CPlayaviApp theApp=new CPlayaviApp;/D立用程序指针
char ffilename=new char[250];N多媒体文件名
unsigned long timespan;//帧时间间隔 毫秒
unsigned long totaltime;//,总播放时间
unsigned long timespan1://帧时间间隔,微秒
HANDLE ha;N文件句柄,用于音频解码
unsigned short channel
count;∥声道数
LPSTR soundbufl,soundbuf2;//声音缓冲区
unsigned long soundlenl=O,soundlen2=0;//声音缓冲长度
unsigned long starttime;/L声音开始播放时间
unsigned long avgbytespersec://每秒声音字节数
int endflag;//:声音结束标志
int playing;//播放标志
HWAVEOUT hwo;//声音输出句柄
\^f△VEHDR wawehdr;//:声音输出头
HDC mydc:∥图形设备对象句柄
CDC dcl=new CDC;∥图形设备对象
CDC dc2=new CDC;N图形设备对象
HANDLE hv;//文件句柄,用于视频解码
unsigned long showwidth showheight:∥图像显示宽度,长度
DWORD starttick;//图像开始时钟数
unsigned long framenumber;//帧号
播放声音线程如下:
UINT PlavAudio《LPVOID pParam)∥播放声音线程
嘲 乌 、:9
……… … 一 ………… ”…” … ………… 一………
实用第一 智慧密集
, … …………… … … ~ … … … …… … ……
{
unsigned char buf[20000],chl,ch2,ch3,ch4,pcm1:
DWORD ReadCOunt=0:
short int leftpcm[1 00000],rightpcm[1 00000];
unsigned int i:
unsigned short channels,code,blockalign;
unsigned long len,size1,audlen,samplerate,bytespersec,pos;
WAVEFORMATEX wfx;
int count;
|帆 文忤
ha=CreateFile(filename,GENERIC—READ.FILE—SHARE—R
EAD,NUL LJ
OPEN
EXISTING,FILE
一
△L1-rRlBUTE
—
NORMAL,NULL);
—
if(ha==lNVALID—HANDLE_VALUE)return O:
ReadFile(ha,buf,10000,&ReadCount,NULL);∥读一块数据
for(i=1:i<:1 O000;i++)//定位movi列表
{
if(buf[i一1】_= m &&buf[i】_=一0&&buf[i+l】-='V &&buf +
2】== )
{
pos=i一1;break;
)
)
for(i=1: <=1 O000;i++)
{
if(buf[i一1l_:~S&&buf[i】_=~t&&buf[i+l】== r &&buf[i+2】
==
&&
buf【i十3 = S &&buf【i+4】== t &&bu +5】== r &&buf【 十
6】_= h &&
buf【i+1 1】== V &&buf【i+12】== &&buf I +13】==
d &&buf[i+l4】_= S )
(
memcpy(&audlen,buf+i+7,4);break;
)
}
for(i=1:i<=1 O000;i++)//取声音参数
{
if(buf[i一1】== s &&buf【i】== t &&buf[i+1】== r &&buf[i+2】
==
&&
buf[i+3]== S &&buf¨+4】==~t&&buf[i+5】== r &&buf【 +
6】_= h &&
buf【i+11】== a &&buf【i+12】== U &&buf【i+13】==
d &&buf[i+l4】_= S &&
buf[i+audlen+l 1】==~S&&buf[i+audlen+l 2】== t&&
buf[i+audlen+l 3】== r &&buf【i+audIen+1 4】== f )
{
memcpy(&code,buf+i+audlen+l 9,2)
memcpy(&channels.buf+i+audlen+21,2):
channel
cOunt=channe}s:
memcpy(&samplerate.buf+i+audlen+23,4);
avgbytespersec=samplerate 1 6 channel
_
cound8;
breaK:
l o
i
,
:电麓20藉11寝.交09砖与娥 i ;
}
)
if(code!=0x55)//声音编码不为MP3则返回
{
C{OseHandIe(ha) retum 0:
)
starttime=GetTickCountO;
soundbufl=new char【5O0OOOO0】:sOundbuf2=new char
【50000000];
waveOutUnprepareHeader《hwo,&wavehdr,sizeof(WAVE—
HDR)):
wave0utCIose(hwo);
soundlenl=O:sOundlen2=O:
lame
—
decode
initO;∥开始声音解码
SetF lePointer{ha,pos,NULL,FILE
—
BEGIN);
wfx.cbSize=O;
blockalign=l 6 channels/8;
//设置声音文件头
wfx.nBIOckAIign=b10ckaIign:
bytespersec=bIOckaIign samplerate;
wfx.nAvgBytesPerSec=bytespersec:
wfx.nChanneIs=channeIs:
wfx nSamplesPerSec=samplerate;
wfx.wBitsPerSample=l 6:
wfx.wFormatTag=1:
f 开声音输出
waveOutOpen(&hwo,《UINT)V、/AVE—MAPPER,&wfx,
(DWORD)waveOutCaltback,0,CALLBACK
FUNCTION);
endflag=O;
while《1)
{
ReadFite(ha &ch1,1,&ReadCount,NULL):
if(ReadCount!:1)break;
if(ch1== 0 )
{
ReadFile(ha,&ch2,1,&ReadCount,NULL);
if(ch2== 1 )
{
ReadFile(ha,&ch3,1,&ReadCount,NULL);
if(ch3== W )
(
ReadFile(ha,&ch4,1,&ReadCount,NULL);
if(ch4== b )∥读出声音数据
{
ReadFiIe(ha,&len,4,&ReadCount,NULL);
ReadFile(ha,buf,len,&ReadCount.NULL):
size1 =lame
—
decode(buf,ten,leftpcm,right-
pcm)://声音解码
if《channeIs==2)
{
for(i=1;i<=sizel:i++)
{
…
PROGRAM LANGUAGE … +, 一 ……
pcm l=(unsigned char)(1eftpcm[i一1】&OxOOFF);
soundbufl Isoundlen l】=pcm l:
pcm1=(unsigned char)((1eftpcm[i-1】>>8)&0×FF):
soundbufl【soundlenl+1】=pcml:
pcml=(unsigned char)(rightpcm[i-1】&OxOOFF);
soundbufl lsoundlenl+2]=pcml:
pcml=(unsigned char)((rightpcm[i-1】>>8)&OxFF):
soundbufl【soundlenl+3]=pcm1:
soundlen l=soundlen l+4:
}
)
if(channels==1)
(
for(i=1;i<=sizel:;十+)
(
pcml=(unsigned char)(1eftpcm[i-1】&OxOOFF);
soundbufl Isoundlen 1】=pcm 1:
pcm1=(unsigned char)((1eftpcm[i-1 l>>8)&OxFF):
soundbufl【soundlen 1+1】=pcm 1:
soundlen1=soundlenl+2:
)
)
if(soundlen 1>40000000)break;
}
else SetFiIePOinter《ha,一3L,NULL,FILE—CURRENT);
}
else SetFi『ePOinter《ha,一2L,NULL,FILE—CURRENT);
}
else SetF;1ePointer(ha,一1 L,NULL,FILE—CURRENT);
)
if(chl== )∥读到索引段则退出
{
ReadFile(ha &ch2,1,&ReadCount,NULL);
jf(ch2== d )
{
ReadFile(ha,&ch3,1,&ReadCount,NULL);
if(ch3== X )
(
ReadFile(ha,&ch4,1,&ReadCount,NULL);
if(ch4== 1 )break;
else SetFilePointer(ha 一3L,NULL,FILE—CURRENT);
)
else SetF 『ePointer(ha,一2L,NULL,FILE—CURRENT);
}
else SetFi『ePointer(ha,一1 L,NULL,FILE—CURRENT);
)
)
count=O;
while(1)
{
if(count%2==O)
{
. . …, …一… “ 一 , , .
if(count==O)playing=l:
“话嵌soundbufl
waveOutUnprepareHeader(hwo,&wavehdr,sizeof(WAVE—
HDR)):
wavehdr.IpData=SOundbuf1:
wavehdr dwBufferLength=soundlen 1—4000;
wavehdr dwBytesRecorded=O;
wavehdr.dwUser=O;wavehdr.dwFlags=O;wavehdr.
dwLoops=O;
waveOutPrepareHeader《hwo,&wavehdr,sizeof(WAVE—
HDR)):
waveOutWrite(hwo,&wavehdr,sizeof(WAVEHDR));
soundlen1=0:
∥填充soundbuf2
while(”
{
ReadFile(ha,&ch1,1,&ReadCount.NULL)
f(ReadCountl=1)
{
pfaying=O:break
1
f(ch1:= 0 )
{
ReadFile(ha &ch2 1 &ReadCount,NULL);
if(ch2== 1 )
{
ReadFile(ha,&ch3,1,&ReadCount,NULL);
if(ch3== W )
{
ReadFile(ha,&ch4,1,&ReadCount,NULL);
if(ch4== b )
(
ReadFile(ha,&fen,4,&ReadCount,NULL);
ReadFile(ha,buf,『en,&ReadCount,NULL);
size1=lame
—
decode(buf,len,leftpcm,rightpcm);
//声音解码
If(channeIs==2)
{
for(i=1;i<=size1:i+十)
{
pcml=(unsigned char)(1eftpcm[i-1 1&OxOOFF);
soundbuf2[soundlen2]=pcm1;
pcml=(unsigned char)((1eftpcm[i一1】>>8)&OxFF):
soundbuf2lsOund1en2+1】=pcml:
pcml=(unsigned char)(rightpcm[i一1 J&OxOOFF);
soundbuf2[soundlen2+2]=pcm 1;
pcm1=(unsigned char)((rightpcm[i-1】>>8)&0xFF)
soundbuf2[soundlen2+3]=pcml:
sOundIen2=sOundfen2+4:
)
)
If(channels==1)
【 。, 一 IA I… 一 ‘ … u .
≈
实用第一 智慧密集
{
for(i=1;i<=sizel:j十+)
l
pcm l=(unsigned char)(1eftpcm【i一1 j&Ox0OFF)
soundbuf2[soundlen2]=pcml:
pcml=(unsigned char)((Ieftpcm【i一1】>>8)&OxFF):
soundbuf2【soundlen2+1】=pcml;
sOundlen2=sOundIen2+2:
}
)
if《sOundIen2>40OOOO0O)break;
)
else SetFilePointer(ha,一3L,NULL,FILE—CURRENT);
)
else SetFiIePointer(ha,一2L,NULL,FILE—CURRENT);
)
else SetF lePOinter(ha,一1 L,NULL,FILE
_
CURRENT);
)
if(ch1== )∥读到索引段则退出
{
ReadFile(ha,&ch2,1.&ReadCount,NULL);
f(ch2== d )
{
ReadFile(ha,&ch3,1,&ReadCount,NULL);
if(ch3== X )
{
ReadFile(ha,&ch4 1,&ReadCount,NULL):
if(ch4== 1 )break;
else SetF IePo nte ha,一3L NULL,FILE
—
CURRENT);
)
else SetFi1ePointer{ha,一2L,NULL,FILE—CURRENT);
)
else SetFiIeP0inter(ha,一1 L,NULL,FILE
—
CURRENT);
)
)
)
else
(
f}播设soundbuf2
waveOutUnprepareHeader(hwo,&wavehdr,sizeof(WAVE
HDR)):
wavehdr.1DData sOundbu{2:
wavehdr.dwBufferLength=soundlen2-4000;
wavehdr.dwBytesRecOrded=O
wavehdr dwUser=O;wavehdr.dwFlags=O;wavehdr.
dwLoops=O;
waveOutPrepareHeader (hwo,&wavehdr,sizeof(WAVE
HDR))
waveOutWrite(hwo,&wavehdr,sizeof(WAVEHDR));
sOundlen2=0:
/#8充soundbufl
while(1)
。12 2电脑缡毽技巧与 011.Og 壤
(
ReadFile(ha,&chl,1,&ReadCount,NULL);
if(ReadCount!=1 1
(
playing=O:break:
)
f(chl:= 0 )
{
ReadFile(ha.&ch2,1,&ReadCount,NULL);
if(ch2== 1 )
{
ReadFile(ha,&ch3,1,&ReadCount,NULL);
if(ch3== W )
{
ReadFile(ha,&ch4,1,&ReadCount,NULL);
if(ch4== b )
{
ReadFile(ha,&ten,4,&ReadCount,NULL):
ReadFile(ha,buf,len,&ReadCount,NULL);
size1=lame
decode(buf,len.1eftpcm,rightpcm)
//声音解码
if(channe1s==2)
{
for(i=1;i<=sizel: ++)
(
pcml=(unsigned char)(1eftpcm[i一1】&OxOOFF);
soundbufl【soundlenl】=pcm1:
pcml=(unsigned char)((1eftpcm[i-1】>>8)&OxFF):
soundbuflfsoundlenl 4-1】=pcm1
pcml=(unsigned char)(rightpcm[i-1】&OxOOFF)
soundbufl【soundlenl+2}=pcml:
pcml=(unsigned char)((rightpcm[i一1】>>8)&0xFF):
soundbufl【soundlenl+3]=pcm1:
soundlen 1=soundlen 1+4:
}
)
if(channels==1)
{
for(J=1;i<=sizel:j++)
{
pcml=(unsigned char)(1eftpcm[i-1】&OxOOFF);
soundbufl【soundlenl l=pcml
pcml=(unsigned char)((1eftpcm[i一1】>>8)&0xFF):
soundbuflfsoundlen1+1】=pcml
soundlen1=soundlenl+2:
)
)
if(soundlenl>40000000)break;
}
else SetFiIePo nter(ha,一3L,NULL,FILE—CURRENT);
}
else SetFiIePointer(ha,一2L,NULL,FILE
—
CURRENT);
.
PR0GB^M LANGUAGE … ……一…一一一……… …………… … ~- ………~……………-.一一…………+.1 ^uv h¨ … ……
)
else SetFi1ePointer(ha,一1 L,NULL,FILE—CURRENT);
)
if(ch1-= )∥读到索引段则退出
{
ReadFile(ha,&ch2,1,&ReadCount,NULL);
if(ch2== d )
{
ReadFile(ha,&ch3,1,&ReadCount,NULL)
if(ch3== X )
{
ReadFile(ha,&ch4,1,&ReadCount,NULL);
if(ch4== 1 )break;
else SetFiIePOinter《ha,~3L,NULL,FILE—CURRENT);
)
else SetFilePointer(ha,一2L,NULL,FILE—CURRENT);
}
else SetFjIePointer(ha,一1 L,NULL.FILE~CURRENT)
}
)
)
endflag=0;∥设置声音结束标志
count++
while(1)∥循环直至声音播放结束
{
if(endflag==1)break;
Sleep(1):
)
if(playing==0)break;
}
lame
—
decode
—
exit();//结束声音解码
delete soundbufl;delete soundbuf2;
waveOutCIose(hwo);
C10seHandIe(ha):∥关闭文件
rettjrn 0-
)
视频播放线程女I】下:
UINT PIavVideO(LPV0ID pParam)
∥播放图像线程
(
HlNSTANCE hHandle;
typedef int 《 Txvid—globa1)
《void handle,int opt,void
param 1,void param2);
Txvid globaI xvid
.
globa
l:
typedef int ( Txvid—decore)(void handle,int opt,void
param1 void param2)
Txviddecore xvid
——
decore;
——
xvid gbI init t xvid gb Jinit;
xvid
——
dec
create
t xvid
dec
——
create;
void dec handle=NULL;
xvid
—
decframet xvid
—
dec
—
frame:
xvid dec stats t xvid dec stats:
unsigned char chl,ch2,ch3,ch4, buf=NULL, bufl=NULL,
buf2[1 0000];
LPSTR buf3;
DW0RD ReadCOunt=0.WriteCount=O;
unsigned long filesize,imgsize,offset,used
—
bytes,use
ful
bytes;
unsigned tong len,width,height,i.totaltime,framespersec.
pos,totalframes;
LONGLONG number.number1:
CString str;
HBITMAP hbmp;
CBitmap hbmpl, pOIdBitmap;
BITMAP bm;
LARGElNTEGER freq,freql,tl,t2,t3;
CStatic static2. static3;
char s[1 0O】:
static2=(CStatic )AfxGetMainWnd 0->GetDIgltem
(IDC—STATIC2):
static3=(CStatic )AfxGetMainWnd 0一>GetDIgltem
(IDC
—
STATIC3);
hv=CreateFile(filename.GENERIC—READ.FILE—SHARE—REA
D,NULL,
OPEN EXISTING.FILE A‘丌RIBUTE N0R—
MAL.NULL);}m开文件
if(hv==INVALID—HANDLE_、,ALUE)return O:
ReadFite(hv,buf2,10000,&ReadCount NULL);//读一块数据
for(i=1:i<=1 0000;i++)
{
if(buf2 I 一1】== m &&buf2Ⅲ== o &&bur2 Ii+1】==
V &&buf2【i+2】一=丁)
(
pos=i一1;break;
)
)
for(i=1:i<=10000;i++)//保证图像编码是×VlD
(
f(buf2【i一1】== S &&buf2【_】== t &&buf2【 +1j_= r &&buf2
fi+2】_= &&
buf2【i+3]== S &&buf2 fi+4】== t &&buf2【i+5】==
r &&buf2【i+6】_= h &&
buf2【i+1 1】==~ &&buf2 fi+12】== &&buf2【i+13】==
d &&buf2[i+l 4】== S )
{
f(f(buf2[i+l5】==,× &&buf2【 +16】== V &&buf2[i+17l==
&&buf2[i+l 8】== D,))
(
CIoseHandle(hv):return 0:
}
)
)
for(i=1: <:1 O000;i++)脓图像参数
{
if(buf2li一1】_= a &&buf2[i]== V &&buf2[i+1】== &&buf2[i+
;
9 煞缡趣2掘0涵11乌.0i蠹9 13j
… …… … ……………
实用第一 智慧密集
2J== h )
{
memcpy(&totalframes,buf2+i+23,4)
memcpy(&timespan,buf2+i+7 4):
tlmespan1=timespan;
totaltime=timespan totalframes/1 O00000L;
timespan=timespan/1 000;
framespersec=l O00Aimespan;
if(framespersec<2OIIframespersec>30)
∥保证帧速率在2O一30之间
{
CIoseHandIe(hv);return 0;
)
str=ConvertTime(totaltime);
memcpy(&width,buf2+i+39,4):
memcpy(&height,buf2+i+43,4):
break;
)
)
hHandle=LoadLibrary(”xvidcore.dlt”) //力日载动态库
xvid
—
global=(Txvid
_
globat)GetProcAddress(hHandle,“
xvid
global ):
xvid
—
decore =(Txvid
—
dec0re)GetProcAddress (hHandle,
xvid decore“):
memset(&xvid
gbl
init 0,sizeof(xvid
gbl
——
init
_
t));
xvid
——
gbl
——
init.version=XVID
_
VERSION;
xvid
——
gbl
——
init.cpu
flags=O;
xvid
gblinit.debug=O;
xvid
——
global(NULL,XVlD
—
GBL
+
INIT,&xvid
——
gbl
——
init,NULL);
//解码初始化
memset(&xvid
dec
create,0,sizeof(xvid
dec
—
create
_
t))
xvid
_
dec
.
create version=XVID
——
VERSION;
xvid
——
dec
——
create.width=O;
xvid
——
dec
——
create.height=O;
if(xvid—decore(NULL,XVlD—DEC—CREATE,&xvid
—
dec
—
create,
NULL)==0)
dec
handle=xviddec
create.handle;//创建解码实例
buf=(unsigned char )malloc(5000000);
bufl=(unsigned char )malloc(5000000);
buf3=new cha r【5OOOOOO】:
SetFilePointer(hv,O,NULL,FILE
—
BEGIN):
memset(&xvid
dec
frame,0,sizeof(xvid
decframe
t));
memset(&xvid——dec——stats,0,sizeof(xvid dec stats
_
t));
xvid
——
dec
——
frame.version=XVID
VERSION;
_
xvid
—
dec
—
stats.version=×VID
VERS10N:
xvid
——
dec
_
frame.general=O;
xvid
—
dec
—
frame.output.ptane[O]=bufl:
xviddec
_
frame.output.strideiO]=width 3:
xvid
—
dec
_
frame.outputcsp=XVlD
—
CSP
—
BGRlXVID—CSP_VFLI P=
Set ePo_nter(hv,pos,NULL,FILE
—
BEGIN);
framenumber=O;
while(1)
14
、0
电魅螭褪技巧与
2O1 1.O9
维鹣
{
ReadFile(hv,&chl,1,&ReadCount,NULL);
if(ReadCount!=1)break;
if(chl== 0 )
{
ReadFile(hv,&ch2,1,&ReadCount,NULL);
if(ch2== 0 )
{
ReadFile(hv,&ch3,1,&ReadCount,NULL);
if(ch3== d )
{
ReadFile(hv,&ch4,1,&ReadCount NULL);
if(ch4== C )
(
ReadFile(hv,&len,4,&ReadCount,NULL);
if(1en>=O)
{
ReadFile(hv,buf,len,&ReadCount,NULL);
useful
—
bytes=len;
used
bytes=O;
do//循环解码图像
{
xvid
——
dec
_
frame.bitstream=buf+used
——
bytes;
xvid
—
decframe.1ength=useful
_——
bytes;
usedbytes =xvid
decore (dec
handle
XVI D
——
DEC
——
DECODE,
&xvid
dec
_
frame.&xvid
dec
stats);
usefulbytes=usefulbytes-usedbytes;
}
white(xvid
—
dec
—
stats.type<=0&&used
bytes>O);
if(framenumber==O)
{
while(1)
{
if(playing==1)break;
Sleep(1):
)
QueryPerformanceCounter(&t1)
)
framenumber++;
,/保证每帧在指定时间显示
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&t2);
number=(LONG LONG}(((double)t2.Quad—
Part一(double)t1.QuadPart)/
(double)freq QuadPa ̄ (double)l 000000);
number=number/timespanl;
if(number<framenumber)
{
while(1)
f
QueryPerformanceFrequency(&freq1):
……
PROGRA啊LANGUAGE…”……………………………………… ………………… ……………¨ l… … ………
QueryPerformanceCounter(&t3);
number1 =(LONGL0NG)(((double)t3.
QuadPart一(double)t1.QuadPart)/
(double)freq1.QuadPart (double)1 000000);
number1=number1/timespan1:
if(numberl>=framenumber)break;
Sleep(1):
)
if(number1>framenumber)continue;
)
else continue;
if(framenumber==1)starttick=timeGetTimeO;
if((framenumber一1)%framespersec==O)
{
static2一>SetWindowText(“当前时间:“
+ConvertTime((timeGetTimeO—starttick)/1 O0O)):
sprintf(s,"当前帧:% ,framenumber一1):
static3一>SetWindowText(s);
}
if(xvid—dec—stats.type>O)∥解出图像
{
memset(buf3,0,54+width height 3):
imgsize=width height 3
filesize=54L+imgsize;
offset=54;
buf3[O]= B ;buf3[1】_ M :
memcpy(buf3+2,&filesize,4):
for(i=1:i<=4:i++)buf3[5+i]=O;
memcpy(buf3+1 0,&offset,4):
buf3[1 4】_0×28:buf3I1 5]=O;buf3[1 6]=O;buf3[1 7】=O:
memcpy(buf3+l 8,&width,4):
memcpy(buf3+22 &height,4):
buf3126]=1;buf3127]=O:
b 3
b
18 ;bu f3 12 9] = O
;
uf3【3O1=0:buf3【311=O:buf3【
.
。
321=0:
.
buf
3【
。
33l
。
=0:
memcpy(buf3+34,& mgsize,4)
for(i:1:i<:16:l+十)buf3137+i]=O:
memcpy(buf3+54,bufl,width height 3):
hbmp=MemoryToBmp(buf3);
hbmpl—Attach(hbmp):
pOIdBitmap=(
hbmp1.
CBi
GetBi
tmap*)
tmap(
dc1一>SeI
&bm);
ectObject(hbmp1):
dc2->StretchBIt(O,0,showwidth,showheight,
dc1,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
dcl一>SelectO bject(&p0ldBitmap):
DeleteObject(hbmp1);
DeI e
Object{hbmp):
、
,
)
}
else SetFiIePointer(hv,一3L.NULL,FILE—CURREN T);
}
else SetFilePointer(hv.一2L,NULL,FILE—CURRENT);
)
else SetFlIePOinter(hv,一1 L,NULL,FILE—CURRENT);
)
if(chl== i )//读到索引段则退出
{
ReadFile(hv,&ch2,1,&ReadCount,NULL);
if(ch2==~d)
{
ReadFile{hv &ch3,1,&ReadCount,NULL);
if(ch3== × )
{
ReadFile(hv,&ch4,1,&ReadCount,NULL);
if(ch4== 1 )break;
else SetF¨ePointer(hv,一3L.NULL,FILE—CURRENT);
)
else Set ePointer(hv,-2L,NULL,FILE—CURRENT);
)
else SetFilePointer(hv,一1 L,NULL,FILE
CURRENT);
}
)
static2一>SetWindowText(”当前时间:”
+ConvertTime((timeGetTimeO—starttick)/1 O00)):
sprintf(s,"当前帧:% framenumber);
static3—.>SetWindowText(s);
free《buf):free《buf1);delete buf3;
xvid—decore (dec—handle,XVlD
—
DEC
—
DESTROY,NULL,
NULL);//结束解码实例
CIoseHand{e(hv)://关闭文件
return O:
)
现在声音
、
图像解码和输出都介绍完了,另外还有一个重
要问题
,
就是影音同步问题。因为AVI文件中不仅包含图像,
同时也包含声音,所以必须考虑图像和声音的同步。
……… ’ ………… … … “…
声音播放时间可以交给声卡控制,只要能在一块声音播放
完成之前解码出下一块声音数据,再迅速切换声音输出即可。
图像播放时间则要利用精确计时函数,计算}fJ当前时间应
该播放的帧号
,
当实际帧号小于应该播放帧号时,则等待,直
到二者相等时进行显示
,
而当实际帧号大于应该播放帧=b at,,
应立即取消该帧的显示并立即进行下一帧的解码。
.
硅{五
D 口I=i
AVI播放器程序开发完成,可以进行AVI多媒体文件的播
放
.
具有一定的实用价值。
(收稿日期
:2011-03-11)


发布评论