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 …………………………………………………………………… … ……………… ・ 

ve

rsio

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

:电麓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 

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)