2024年3月12日发(作者:)

AVI录像机开发

江洪

摘要:使用微软的

进行视频捕获,使用

进行音频捕获,使用

XVID

编解码

进行视频编码,结合

AVI

文件的结构,开发了可以实现录像功能的实用程序,录像

存储在

AVI

文件中。

关键词:

AVI

;录像机;

XVID

;视频;音频

1

引言

AVI

文件是微软公司开发的一种多媒体文件格式。视频和

音频数据交错存储在文件中,其中的图像和声音数据大都经过

编码后进行存放。

AVI

文件的使用非常广泛,大多数媒体播放

器都支持此类文件。下面将开发一个

AVI

录像机程序,可实现

AVI

文件的录像功能。

视频部分,宽度为

640

,高度为

480

,每秒帧数为

20

,编

码采用

XVID

音频部分,声道数为

1

,采样位数为

8

,采样频率为

8000

,编码采用

PCM

使用

进行视频捕获。该库是

VC

中自带的库,提

供了对

AVI

视频进行处理的功能。

使用

进行音频捕获。该库也是

VC

中自带的库,

提供了对声音进行处理的功能。

进行图像编码,需用到

动态链接库。这是一个

开源的

XVID

编码解码库,可以从

下载该库的源

代码。

2AVI

文件结构

要开发

AVI

录像机程序,需要对

AVI

文件格式有比较清

楚的了解。

AVI

文件是微软公司推出的一种多媒体文件格式。

该文件通常包括一个视频流和一个音频流。

AVI

文件由一个

RIFF

头,两个列表

hdrl

(用于描述媒体

流格式)和

movi

列表(用于保存媒体流数据),以及一个可选

的索引块组成。

整个

AVI

文件结构如表

1

所示。

1

段名字段名长度说明

ChunkId4

值为’

RIFF

’表示这是一个

RIFF

文件

RIFF

Size4

整个

AVI

文件大小

-8

Flag4

值为’

AVI

‘表示这是一个

AVI

文件

Chunkid4

值为’

LIST

’,表示这是一个列表

hdrl

列表

Size4

该列表长度,不包括’

LIST

’和列表长度字

段,设为

294

段名字段名长度说明

hdrl

列表

Flag4

值为’

hdrl

’,表示这是一个

AVI

头段,设

294

Fcc4

值为’

avih

’,表示这是

AVI

主信息头

Cb4

主信息头大小,不包括

fcc

cb

两个字

段,设为

56

dwMicroSecPerFrame4

视频帧间隔时间(以微秒为单位),设

50000

dwMaxBytesPerSec4AVI

文件的最大数据率,可设

0

dwPaddingGranularity4

数据填充的粒度,可设

0

dwFlags4AVI

全局标记,设为

0x0110

主信息头

dwTotalFrames4

总帧数

dwInitialFrames4

为交互格式指定初始帧数(非交互格式为

0

dwStreams4

AVI

文件包含的流的个数(通常为

2

,即

1

个视频流,

1

个音频流)

dwSuggestedBufferSize4

建议读取本文件的缓存大小,可设

0

dwWidth4

视频图像的宽(以像素为单位),设

640

dwHeight4

视频图像的高(以像素为单位),设

480

dwReserved16

保留,设

0

ChunkId4

值为’

LIST

’,这是一个子列表

视频流子

4

该列表长度,不包括’

LIST

’和列表长度

列表

Size

字段,设

116

Flag4

值为’

strl

’,表示这是

AVI

流列表

fcc4

值为’

strh

’,表示这是

AVI

流头

cb4

流头大小,不包括

fcc

cb

两字段,设

56

fccType4

流类型,视频流为’

vids

fccHandler4

流的处理者,视频流设为’

XVID

dwFlags4

标记,设

0

wPriority2

流的优先级,设

0

wLanguage2

流的语言,设

0

dwInitialFrames4

初始帧数,设

0

dwScale4

时间尺度,设

1

视频流头

dwRate4

流速率,视频流设为每秒帧数

dwStart4

流的开始时间,设

0

dwLength4

流的长度,视频流设为总帧数

dwSuggestedBufferSize4

读取这个流数据建议使用的缓存大小,可

0

dwQuality4

流数据的质量指标,可设

0

dwSampleSize4

采样大小,设

0

left2

视频流左坐标,设

0

top2

视频流上坐标,设

0

right2

视频流右坐标,设图像宽,

640

bottom2

视频流下坐标,设图像高,

480

2011.01

69

段名字段名长度说明

视频流描述

Chunkid4

值为’

strf

’,表示这是流的具体格式

列表

Size4

流描述头大小,设

40

biSize4

本结构大小,设

40

biWidth4

图像宽,设

640

biHeight4

图像高,设

480

biPlanes2

位平面数,设

1

视频流描述

biBitCount2

颜色位数,设

24

biCompression4

压缩方式,设’

XVID

biSizeImage4

图像大小,可设

0

biXPelsPerMeter4

横向分辨率,设

0

biYPelsPerMeter4

纵向分辨率,设

0

biClrImportant4

重要颜色数,设

0

biClrUsed4

使用颜色数,设

0

ChunkId4

值为’

LIST

’,这是一个子列表

音频流子列

Size4

该列表长度,不包括’

LIST

’和列表长度

字段,设

94

Flag4

值为’

strl

’,表示这是

AVI

流列表

Fcc4

值为’

strh

’,表示这是

AVI

流头

Cb4

流头大小,不包括

fcc

cb

两字段,设

56

fccType4

流类型,音频流为’

auds

fccHandler4

流的处理者,音频流设

0

dwFlags4

标记,设

0

wPriority2

流的优先级,设

0

wLanguage2

流的语言,设

0

dwInitialFrames4

初始帧数,设

0

dwScale4

时间尺度,设

1

音频流头

dwRate4

流速率,音频流设为每秒字节数

dwStart4

流的开始时间,设

0

dwLength4

流的长度,音频流设为总音频数据大小

dwSuggestedBuffer-

Size

4

读取这个流数据建议使用的缓存大小,可设

0

dwQuality4

流数据的质量指标,可设

0

dwSampleSize4

采样大小,设

1

left2

保留,设

0

top

2

保留,设

0

right2

保留,设

0

bottom2

保留,设

0

音频流描述

Chunkid4

值为’

strf

’,表示这是流的具体格式

列表

Size4

流描述头大小,设

18

wFormatTag2

编码格式,设为

1

,即

PCM

nChannels2

声道数,设

1

音频流描述

nSamplesPerSec4

采样频率,设

8000

nAvgBytesPerSec4

每秒字节数,设

8000

nBlockAlign2

每个采样占字节数,设

1

wBitsPerSample2

采样位数,设

8

cbSize2

附加字节数,设

0

ChunkId4

值为’

LIST

’,这是一个列表

movi

列表

Size4

该列表长度,不包括’

LIST

’和列表长度字段

Flag4

值为’

movi

’,此列表保存视频和音频数据

Chunkid4

值为’

01wb

’表示音频数据

,

值为’

00dc

视频

/

音频

表示视频数据

数据

(

若干

)

Size4

本数据块大小

Data

实际的视频或音频数据,如数据块大小为

奇数,需在数据块末尾补

1

字节

0

70

2011.01

段名字段名长度说明

Fcc4

值为’

idx1

’,表示这是索引列表

索引列表

Cb4

该列表长度,不包括’

idx1

’和列表长度

字段

dwChunkId4

值为’

01wb

’表示音频数据

,

值为’

00dc

表示视频数据

索引(若干)

dwFlags4

块标志

(0x10

为关键帧

,0x00

为非关键帧

)

dwOffset4

相对于

movi

列表的偏移量

dwSize4

本数据块的大小

视频流和音频流子列表中包括一些基本的视频和音频参

数,如编码格式、声道数、采样频率等。

movi

列表中保存实际的视频和音频数据。其中视频和音

频数据都是交错存放的。视频数据以

00dc

开头,其后

4

个字

节是该块数据长度,然后是实际的视频数据。音频数据以

01wb

开头,其后

4

个字节是该块数据长度,然后是实际的音

频数据。

索引段以

idx1

开头,用于保存

movi

列表中各块的索引信息。

微软提供了

库,头文件名为

vfw.h

。该库提供了

对视频处理的支持,可以利用该库进行视频捕获。

4

微软多媒体开发库

微软提供了

,头文件名为

mmsystem.h

。该库提

供了对声音处理的支持。其中

waveIn

系列函数用于声音输入。

可以利用该库进行音频捕获。

5XVID

编码解码库

XVID

库中提供了

XVID

数据的编码操作。

编码前首先调用

xvid_global(NULL,XVID_GBL_INIT,

&xvid_gbl_init,NULL);

进行初始化。其中

XVID_GBL_INIT

表示

进行初始化。

xvid_gbl_init

是一个

xvid_gbl_init_t

类型的变量,

该类型用于

XVID

初始化。

然后调用

xvid_encore(NULL,XVID_ENC_CREATE,

&xvid_enc_create,NULL)

;创建一个编码实例。其中

XVID_ENC_CREATE

表示创建编码实例。

xvid_enc_create

是一

xvid_enc_create_t

类型的变量,该类型用于建立编码实例。

如果

xvid_encore

返回

0

,则可从

xvid_enc_create

中取得编码实

例的句柄。

xvid_enc_create_t

结构定义如下:

typedefstruct{

intversion;//

版本号

intprofile;//XVID

级别

intwidth;//

图像宽度

intheight;//

图像高度

intnum_zones;

xvid_enc_zone_t*zones;

intnum_plugins;

xvid_enc_plugin_t*plugins;

intnum_threads;

intmax_bframes;

intglobal;

intfincr;//

帧率增量

intfbase;//

帧间隔时间

intmax_key_interval;

intframe_drop_ratio;

intbquant_ratio;

intbquant_offset;

intmin_quant[3];

intmax_quant[3];

void*handle;

}xvid_enc_create_t;

调用

xvid_encore(enc_handle,XVID_ENC_ENCODE,

&xvid_enc_frame,&xvid_enc_stats);

进行

XVID

编码。

其中

XVID_ENC_ENCODE

表示进行

XVID

编码。

xvid_enc_frame

是一个

xvid_enc_frame_t

类型的变量,该类

型用于描述要进行编码的帧。

xvid_enc_frame_t

定义如下:

typedefstruct{

intversion;//

版本号

intvol_flags;

unsignedchar*quant_intra_matrix;

unsignedchar*quant_inter_matrix;

intpar;

intpar_width;

intpar_height;

intfincr;

intvop_flags;

intmotion;

xvid_image_tinput;//

输入图像

inttype;//

编码类型,一般设

XVID_TYPE_AUTO

intquant;//

帧量化器

intbframe_threshold;

void*bitstream;//

输出缓冲区

intlength;//

输出缓冲区长度

intout_flags;

}xvid_enc_frame_t;

其中

xvid_image_t

是另一个结构,用于表示输入图像,其

定义如下:

typedefstruct{

intcsp;//

使用的色场空间

void*plane[4];//

图像平面,最多

4

个,一般只使用

plane[0]

intstride[4];//

表示每行像素占用字节数

}xvid_image_t;

xvid_enc_stats

是一个

xvid_enc_stats_t

类型的变量,该类型

用于表示编码帧的状态。

xvid_enc_stats_t

定义如下:

typedefstruct{

intversion;//

版本号

inttype;

intquant;

intvol_flags;

intvop_flags;

intlength;

inthlength;

intkblks;

intmblks;

intublks;

intsse_y;

intsse_u;

intsse_v;

}xvid_enc_stats_t;

调用

xvid_encore(enc_handle,XVID_ENC_DESTROY,NULL,

NULL);

结束一个编码实例。其中

enc_handle

是先前得到的编

码实例句柄,

XVID_ENC_DESTROY

表示撤销编码实例。

6

代码解析

使用如下代码段进行录像预览:

//

显示捕获窗口

mywnd=newCWnd;

mywnd->Create(NULL,"",WS_CHILD|WS_VISIBLE,

CRect(0,0,videowidth,videoheight),this,1234);

mywnd->ShowWindow(SW_SHOW);

mywnd->GetWindowRect(rect);

ghCapWnd=capCreateCaptureWindow("MyOwnCapture

Window",

WS_CHILD|WS_VISIBLE,0,0,

(),(),

mywnd->GetSafeHwnd(),1235);

capDriverConnect(ghCapWnd,0);

capCaptureGetSetup(ghCapWnd,&CapParms,sizeof(CAP-

TUREPARMS));

estMicroSecPerFrame=1000000L/vide-

oframes;

Enabled=FALSE;

ntrol=FALSE;

=TRUE;

ort=VK_ESCAPE;

LeftMouse=FALSE;

RightMouse=FALSE;

capCaptureSetSetup(ghCapWnd,&CapParms,sizeof(CAP-

TUREPARMS));

capPreviewRate(ghCapWnd,videoframes/2);

capPreviewScale(ghCapWnd,TRUE);

capPreview(ghCapWnd,TRUE);

使用如下代码将捕获到图像转换为

HBITMAP

HBITMAPCopyWindowToBitmap(void)//

复制捕获窗口图像

2011.01

71

//

HBITMAP

{

HDChScrDC,hMemDC;

intnX,nY,nX2,nY2;

intnWidth,nHeight;

intxScrn,yScrn;

RECTrect1;

::GetWindowRect(ghCapWnd,&Rect);

::GetWindowRect(AfxGetMainWnd()->m_hWnd,&rect1);

if(IsRectEmpty(&Rect))returnNULL;

hScrDC=CreateDC("DISPLAY",NULL,NULL,NULL);

hMemDC=CreateCompatibleDC(hScrDC);

nX=+3;

nY=+31;

nX2=;

nY2=;

xScrn=GetDeviceCaps(hScrDC,HORZRES);

yScrn=GetDeviceCaps(hScrDC,VERTRES);

if(nX<0)nX=0;

if(nY<0)nY=0;

if(nX2>xScrn)nX2=xScrn;

if(nY2>yScrn)nY2=yScrn;

nWidth=nX2-nX;

nHeight=nY2-nY;

if(hBitmap==NULL)

hBitmap=CreateCompatibleBitmap(hScrDC,nWidth,

nHeight);

hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);

BitBlt(hMemDC,0,0,nWidth,nHeight,hScrDC,nX,nY,SRC-

COPY);

hBitmap=(HBITMAP)SelectObject(hMemDC,hOldBitmap);

DeleteDC(hScrDC);

DeleteDC(hMemDC);

returnhBitmap;

}

使用如下代码将

HBITMAP

转换到内存:

//HBITMAP

复制到

buf

内存

BOOLCopyBmpToMemory(HBITMAPhBitmap,LPSTRbuf)

{

HDChDC;

intiBits;

WORDwBitCount;

DWORDdwPaletteSize=0,dwBmBitsSize=0,dwDIBSize=0,

dwWritten=0;

BITMAPBitmap;

BITMAPFILEHEADERbmfHdr;

BITMAPINFOHEADERbi;

LPBITMAPINFOHEADERlpbi;

HANDLEhDib,hPal,hOldPal=NULL;

hDC=CreateDC("DISPLAY",NULL,NULL,NULL);

iBits=GetDeviceCaps(hDC,BITSPIXEL)*GetDeviceCaps

72

2011.01

(hDC,PLANES);

DeleteDC(hDC);

if(iBits<=1)

wBitCount=1;

elseif(iBits<=4)

wBitCount=4;

elseif(iBits<=8)

wBitCount=8;

else

wBitCount=24;

GetObject(hBitmap,sizeof(Bitmap),(LPSTR)&Bitmap);

=sizeof(BITMAPINFOHEADER);

h=h;

ht=ht;

es=1;

ount=wBitCount;

ression=BI_RGB;

Image=0;

sPerMeter=0;

sPerMeter=0;

mportant=0;

sed=0;

dwBmBitsSize=((h*wBitCount+31)/32)

*4*ht;

hDib=GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+

sizeof(BITMAPINFOHEADER));

lpbi=(LPBITMAPINFOHEADER)GlobalLock(hDib);

*lpbi=bi;

hPal=GetStockObject(DEFAULT_PALETTE);

if(hPal)

{

hDC=::GetDC(NULL);

hOldPal=::SelectPalette(hDC,(HPALETTE)hPal,FALSE);

RealizePalette(hDC);

}

GetDIBits(hDC,hBitmap,0,(UINT)ht,

(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dw-

PaletteSize,

(BITMAPINFO*)lpbi,DIB_RGB_COLORS);

if(hOldPal)

{

::SelectPalette(hDC,(HPALETTE)hOldPal,TRUE);

RealizePalette(hDC);

::ReleaseDC(NULL,hDC);

}

=0x4D42;

dwDIBSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAP-

INFOHEADER)+

dwPaletteSize+dwBmBitsSize;

=dwDIBSize;

rved1=0;

rved2=0;

its=(DWORD)sizeof(BITMAPFILEHEADER)+

(DWORD)sizeof(BITMAPINFOHEADER)+dw-

PaletteSize;

memcpy(buf,(LPSTR)&bmfHdr,14);

memcpy(buf+14,(LPSTR)lpbi,dwDIBSize);

GlobalUnlock(hDib);

GlobalFree(hDib);

returnTRUE;

}

使用如下代码写

AVI

头:

voidWriteAviHeader(void)//

AVI

文件头

{

charbuf[1000];

structAVIMAINHEADERah;

structAVISTREAMHEADERash;

BITMAPINFOHEADERbih;

unsignedlonglen;

WAVEFORMATEXwf;

fseek(avifp,0,SEEK_SET);

buf[0]='R';buf[1]='I';buf[2]='F';buf[3]='F';

fwrite(buf,1,4,avifp);//

写入

RIFF

标记

buf[0]=0;buf[1]=0;buf[2]=0;buf[3]=0;

fwrite(buf,1,4,avifp);//

写入文件总长度

buf[0]='A';buf[1]='V';buf[2]='I';buf[3]='';fwrite(buf,1,4,

avifp);

buf[0]='L';buf[1]='I';buf[2]='S';buf[3]='T';fwrite(buf,1,4,

avifp);

len=294;fwrite(&len,1,4,avifp);

buf[0]='h';buf[1]='d';buf[2]='r';buf[3]='l';fwrite(buf,1,4,avifp);

memset(&ah,0,sizeof(ah));

[0]='a';[1]='v';[2]='i';[3]='h';

=sizeof(ah)-8;

oSecPerFrame=1000000L/videoframes;

s=0x110;

ams=2;

h=videowidth;

ht=videoheight;

fwrite(&ah,1,sizeof(ah),avifp);//

写入主信息头

buf[0]='L';buf[1]='I';buf[2]='S';buf[3]='T';fwrite(buf,1,4,

avifp);

buf[0]=0x74;buf[1]=0;buf[2]=0;buf[3]=0;fwrite(buf,1,4,avifp);

buf[0]='s';buf[1]='t';buf[2]='r';buf[3]='l';fwrite(buf,1,4,avifp);

memset(&ash,0,sizeof(ash));

[0]='s';[1]='t';[2]='r';[3]='h';

=sizeof(ash)-8;

e[0]='v';e[1]='i';

e[2]='d';e[3]='s';

dler[0]='X';dler[1]='V';

dler[2]='I';dler[3]='D';

e=1;

=videoframes;

th=0;

=0;=0;

=videowidth;=video-

height;

fwrite(&ash,1,sizeof(ash),avifp);//

写入视频流头

buf[0]='s';buf[1]='t';buf[2]='r';buf[3]='f';fwrite(buf,1,4,avifp);

buf[0]=0x28;buf[1]=0;buf[2]=0;buf[3]=0;fwrite(buf,1,4,avifp);

memset(&bih,0,sizeof(bih));

=0x28;

h=videowidth;

ht=videoheight;

es=1;

ount=0x18;

ression=1145656920L;

fwrite(&bih,1,sizeof(bih),avifp);//

写入视频流信息头

buf[0]='L';buf[1]='I';buf[2]='S';buf[3]='T';fwrite(buf,1,4,

avifp);

buf[0]=0x5e;buf[1]=0;buf[2]=0;buf[3]=0;fwrite(buf,1,4,avifp);

buf[0]='s';buf[1]='t';buf[2]='r';buf[3]='l';fwrite(buf,1,4,avifp);

memset(&ash,0,sizeof(ash));

[0]='s';[1]='t';[2]='r';[3]='h';

=sizeof(ash)-8;

e[0]='a';e[1]='u';

e[2]='d';e[3]='s';

dler[0]=0;dler[1]=0;

dler[2]=0;dler[3]=0;

e=1;

=audiochannels*audiobits/8*audiorate;

leSize=1;

fwrite(&ash,1,sizeof(ash),avifp);//

写入音频流头

buf[0]='s';buf[1]='t';buf[2]='r';buf[3]='f';fwrite(buf,1,4,avifp);

buf[0]=0x12;buf[1]=0;buf[2]=0;buf[3]=0;fwrite(buf,1,4,avifp);

memset(&wf,0,sizeof(wf));

tTag=1;

els=audiochannels;

esPerSec=audiorate;

tesPerSec=audiochannels*audiobits/8*audiorate;

Align=audiochannels*audiobits/8;

erSample=audiobits;

=0;

fwrite(&wf,1,sizeof(wf),avifp);//

写入音频流信息头

//

写入

movi

列表

buf[0]='L';buf[1]='I';buf[2]='S';buf[3]='T';fwrite(buf,1,4,

avifp);

buf[0]=0;buf[1]=0;buf[2]=0;buf[3]=0;fwrite(buf,1,4,avifp);

buf[0]='m';buf[1]='o';buf[2]='v';buf[3]='i';fwrite(buf,1,4,

avifp);

}

使用如下代码写

AVI

索引,使用一个链表存储索引信息。

voidWriteAviIndex(void)//

AVI

文件索引

{

2011.01

73

charbuf[1000];

unsignedlongindexsize;

AVIINDEX*p;

fseek(avifp,0,SEEK_END);

buf[0]='i';buf[1]='d';buf[2]='x';buf[3]='1';

fwrite(buf,1,4,avifp);//

写入索引标记

indexsize=16*indexcount;

fwrite(&indexsize,1,4,avifp);//

写入索引段长度

if(aviindexlist->next!=NULL)

{

p=aviindexlist->next;

while(1)//

将链表中记录写入索引

{

fwrite(&p->dwChunkId,1,4,avifp);

fwrite(&p->dwFlags,1,4,avifp);

fwrite(&p->dwOffset,1,4,avifp);

fwrite(&p->dwSize,1,4,avifp);

if(p->next==NULL)break;

p=p->next;

}

}

}

使用如下代码更新

AVI

头:

voidUpdateAviHeader(void)//

更新

AVI

文件头

{

longlength;

length=326+movisize+16*indexcount;

fseek(avifp,4,SEEK_SET);

fwrite(&length,1,4,avifp);//

更新文件总长度

fseek(avifp,48,SEEK_SET);

fwrite(&totalframes,1,4,avifp);//

更新主信息头帧数

fseek(avifp,140,SEEK_SET);

fwrite(&totalframes,1,4,avifp);//

更新视频流头帧数

fseek(avifp,264,SEEK_SET);

fwrite(&audiosize,1,4,avifp);//

更新声音数据长度

fseek(avifp,318,SEEK_SET);

length=movisize+4;

fwrite(&length,1,4,avifp);//

更新

movi

列表长度

}

使用如下代码写

AVI

流:

UINTWriteAviStream(LPVOIDpParam)//

AVI

文件流

{

HINSTANCEhHandle;

typedefint(*Txvid_global)(void*handle,intopt,void

*param1,void*param2);

Txvid_globalxvid_global;

typedefint(*Txvid_encore)(void*handle,intopt,void

*param1,void*param2);

Txvid_encorexvid_encore;

74

2011.01

xvid_gbl_init_txvid_gbl_init;

void*enc_handle=NULL;

xvid_enc_create_txvid_enc_create;

xvid_enc_frame_txvid_enc_frame;

xvid_enc_stats_txvid_enc_stats;

unsignedchar*buf1=NULL,*buf2=NULL;

unsignedcharbuf[1000];

LPSTRbuf3;

DWORDlen,len1;

AVIINDEX*newlist,*thelist;

unsignedlongstartindex;

unsignedlongtick1,tick2;

unsignedinti;

WAVEFORMATEXwaveformat;

buf3=newchar[60000000];

tTag=1;

els=audiochannels;

esPerSec=audiorate;

tesPerSec=audiochannels*audiobits/

8*audiorate;

Align=audiochannels*audiobits/8;

erSample=audiobits;

=0;

waveInOpen(&wavein_handle,WAVE_MAPPER,&wavefor-

mat,NULL,

0L,CALLBACK_WINDOW);

=(char*)GlobalLock(GlobalAlloc

(GMEM_MOVEABLE|

GMEM_SHARE,60000000L));

memset(,0,60000000L);

erLength=60000000L;

sRecorded=0;

=0;

s=0;

s=0;

waveInPrepareHeader(wavein_handle,&waveinhdr,sizeof

(WAVEHDR));

waveInAddBuffer(wavein_handle,&waveinhdr,sizeof(WAVE-

HDR));

waveInStart(wavein_handle);//

开始录音

startindex=4;

hHandle=LoadLibrary("");//

加载

xvid_global=(Txvid_global)GetProcAddress(hHandle,"

xvid_global");

xvid_encore=(Txvid_encore)GetProcAddress(hHandle,"

xvid_encore");

memset(&xvid_gbl_init,0,sizeof(xvid_gbl_init_t));

xvid_gbl_n=XVID_VERSION;

xvid_gbl__flags=0;

xvid_gbl_=0;

xvid_global(NULL,XVID_GBL_INIT,&xvid_gbl_init,NULL);

//

全局初始化

memset(&xvid_enc_create,0,sizeof(xvid_enc_create_t));

xvid_enc_n=XVID_VERSION;

xvid_enc_=videowidth;

xvid_enc_=videoheight;

xvid_enc_e=XVID_PROFILE_S_L0;

xvid_enc_=1;

xvid_enc_=3;

if(xvid_encore(NULL,XVID_ENC_CREATE,&xvid_enc_create,

NULL)==0)

//

创建编码实例

{

enc_handle=xvid_enc_;

buf1=(unsignedchar*)malloc(5000000);

buf2=(unsignedchar*)malloc(5000000);

tick1=GetTickCount();

while(1)

{

tick2=GetTickCount();

if(indexcount%(videoframes+1)==0)//

写入音频流

{

waveInReset(wavein_handle);

buf[0]='0';buf[1]='1';buf[2]='w';buf[3]='b';

fwrite(buf,1,4,avifp);

len=sRecorded;

if(len%2!=0)len++;

fwrite(&len,1,4,avifp);

for(i=1;i<=sRecorded;i++)

buf3[i-1]=[i-1];

waveInUnprepareHeader(wavein_handle,&waveinhdr,

sizeof(WAVEHDR));

GlobalFree(GlobalHandle());

waveInClose(wavein_handle);

tTag=1;

els=audiochannels;

esPerSec=audiorate;

tesPerSec=audiochannels*audio-

bits/8*audiorate;

Align=audiochannels*audiobits/8;

erSample=audiobits;

=0;

waveInOpen(&wavein_handle,WAVE_MAPPER,

&waveformat,NULL,

0L,CALLBACK_WINDOW);

=(char*)GlobalLock(GlobalAlloc

(GMEM_MOVEABLE|

GMEM_SHARE,60000000L));

memset(,0,60000000L);

erLength=60000000L;

sRecorded=0;

=0;

s=0;

s=0;

waveInPrepareHeader(wavein_handle,&waveinhdr,

sizeof(WAVEHDR));

waveInAddBuffer(wavein_handle,&waveinhdr,

sizeof(WAVEHDR));

waveInStart(wavein_handle);

fwrite(buf3,1,len,avifp);

indexcount++;

movisize=movisize+len+8;

audiosize=audiosize+len;

newlist=newAVIINDEX;//

更新索引链表

newlist->dwChunkId=1651978544L;

newlist->dwFlags=0x10;

newlist->dwOffset=startindex;

newlist->dwSize=len;

newlist->next=NULL;

startindex=startindex+len+8;

thelist=aviindexlist;

while(1)

{

if(thelist->next==NULL)break;

thelist=thelist->next;

}

thelist->next=newlist;

}

if(tick2-tick1>=(1000/videoframes)||

totalframes/videoframes+1

(audiochannels*audiobits/8*audiorate)+1)

//

写入视频流

{

CopyBmpToMemory(CopyWindowToBitmap(),(char*)

buf2);

memset(&xvid_enc_frame,0,sizeof(xvid_enc_frame_t));

xvid_enc_n=XVID_VERSION;

xvid_enc_eam=buf1;

xvid_enc_=-1;

xvid_enc_[0]=buf2+54;

xvid_enc_=XVID_CSP_BGR|

XVID_CSP_VFLIP;

xvid_enc_[0]=videowidth*3;

xvid_enc_=6;

xvid_enc_=XVID_TYPE_AUTO;

memset(&xvid_enc_stats,0,sizeof(xvid_enc_stats_t));

xvid_enc_n=XVID_VERSION;

len=xvid_encore(enc_handle,XVID_ENC_ENCODE,

&xvid_enc_frame,

&xvid_enc_stats);//XVID

编码

if(len>0)

{

buf[0]='0';buf[1]='0';buf[2]='d';buf[3]='c';fwrite(buf,

1,4,avifp);

(下转第

83

页)

2011.01

75

w(lv);

//

将组织好的对话框布局添加到历史记录选择对话框中

tentView(ll);

}

从上述代码中可以看出,列表(

ListView

)中选项的内容

都是由其适配器(

Adapter

)提供的,本应用中适配器的实现采

用的是继承

BaseAdapter

的方式。当

ListView

需要选项时,首

先会调用其对应

Adapter

getCount

方法获取选项的个数,然

后依次调用

getView

方法获取各个选项对象。本应用程序中,

每个选项都是由

TextView

实现的。

完成了上述代码的开发后,所有的代码开发工作就都完成了。

2

、图

3

所示的界面。

6bin

子目录下的

apk

7

结语

通过开发旅游景点位置查询的应用程序,读者可以基本掌

6

应用程序的打包发布

由于

Android

平台下的应用程序一般都是使用

Eclipse

开发

Android

平台下

Google

地图应用的开发,了解如何向地图中

添加自定义的内容。

本应用的功能还不够完善,读者可以自行进一步扩展。例

如结合

GPS

定位,开发出从当前位置到查询的旅游景点自动

路线导航的功能等。

(收稿日期:

2010-10-17

的,因此打包与发布的工作非常简单。只要在开发完成后在

Eclipse

中运行一下项目,然后就可以在项目文件夹下的

bin

文件夹下找到可以用于安装发布的

APK

包,如图

6

所示。

将此

APK

包安装到基于

Android

平台的手机中即可运行,

在联网正确的状态下可以成功获取景点经纬度并显示如图

1

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

(上接第

75

页)

len1=len;

if(len%2!=0)len1++;

fwrite(&len1,1,4,avifp);

fwrite(buf1,1,len1,avifp);

indexcount++;

totalframes++;

movisize=movisize+len1+8;

newlist=newAVIINDEX;//

更新索引链表

newlist->dwChunkId=1667510320L;

if(xvid_enc_==XVID_TYPE_IVOP)

newlist->dwFlags=0x10;

else

newlist->dwFlags=0x00;

newlist->dwOffset=startindex;

newlist->dwSize=len;

newlist->next=NULL;

startindex=startindex+len1+8;

thelist=aviindexlist;

while(1)

{

if(thelist->next==NULL)break;

thelist=thelist->next;

}

thelist->next=newlist;

}

tick1=tick2;

}

if(recording==0)break;

Sleep(1);

}

free(buf1);

free(buf2);

xvid_encore(enc_handle,XVID_ENC_DESTROY,NULL,

NULL);//

撤消编码实例

}

FreeLibrary(hHandle);

WriteAviIndex();

UpdateAviHeader();

fclose(avifp);

waveInReset(wavein_handle);

waveInUnprepareHeader(wavein_handle,&waveinhdr,sizeof

(WAVEHDR));

GlobalFree(GlobalHandle());

waveInClose(wavein_handle);//

关闭声音输入

deletebuf3;

return0;

}

7

结语

AVI

录像机程序开发完成,对

AVI

多媒体文件的录制,具

有一定的实用价值。

(收稿日期:

2010-11-03

2011.01

83