如何将位图转换为视频? [英] How to convert bitmaps to video?
问题描述
在过去我已经尝试过,但从未成功。我被问题触发最近,唉,不能让FFMpeg运行。
更新
我决定稍微调整这个问题,并为它。我已经看到几个解决方案,但最有吸引力(因为它很简单)似乎在我的TAviWrite。我试过TAviWriter但没有成功。在程序TAviWriter.Write;第370行的函数调用
AVIERR:= AVISaveV(s,
// pchar(FileName),
nil,//文件处理程序
无,//回调
nStreams,//流数
流,
CompOptions); // VideoStream的压缩选项
不返回AVIERR_OK。
更新2
上述错误的原因是错误的声明AVISaveV,它应该被声明为AVISaveVW,如TLama指出的。用于创建形成BMP文件的AVI filo的正确代码如下。以下原始代码以示例单元从efg 下载。
在Windows 7上使用Delphi XE。
unit AviWriter;
//////////////////////////////////////// ///////////////////
// //
// AviWriter - 由Elliott Shevin创建初级AVI文件的一个组件//
// // // //
// // //
// // //
//版本1.0。请发送评论,建议和建议//
//给shevine@aol.com。 //
////////////////////////////////////////// ///////////////////
界面
使用
Windows,消息,SysUtils,类,图形,控件,表单,对话框,
StdCtrls,ole2;
//////////////////////////////////////// //////////////////////
// //
// Video for Windows //
// //
//////////////////////////// /////////////////////////////////////////////// b $ b // //
//改编自Thomas Schimming的VFW.PAS //
//(c)1996 Thomas Schimming,schimmin@iee1.et.tu-dresden.de //
//(c)1998,99 Anders Melander //
// //
////////////////////// ////////////////////////////////////////////// //////
// //
//翻转所有COM / ActiveX东西,并添加了一些AVI流功能。 //
// //
////////////////////////////////// ////////////////////////////
//由Arnold和TLama(2012)创建的Unicode版本//
//////////////////////////////// //////////////////////////////
type
LONG = Longint;
PVOID =指针;
const
// TAVIFileInfo dwFlag值
AVIF_HASINDEX = $ 00000010;
AVIF_MUSTUSEINDEX = $ 00000020;
AVIF_ISINTERLEAVED = $ 00000100; $
AVIF_WASCAPTUREFILE = $ 00010000;
AVIF_COPYRIGHTED = $ 00020000;
AVIF_KNOWN_FLAGS = $ 00030130;
AVIERR_UNSUPPORTED = $ 80044065; // MAKE_AVIERR(101)
AVIERR_BADFORMAT = $ 80044066; // MAKE_AVIERR(102)
AVIERR_MEMORY = $ 80044067; // MAKE_AVIERR(103)
AVIERR_INTERNAL = $ 80044068; // MAKE_AVIERR(104)
AVIERR_BADFLAGS = $ 80044069; // MAKE_AVIERR(105)
AVIERR_BADPARAM = $ 8004406A; // MAKE_AVIERR(106)
AVIERR_BADSIZE = $ 8004406B; // MAKE_AVIERR(107)
AVIERR_BADHANDLE = $ 8004406C; // MAKE_AVIERR(108)
AVIERR_FILEREAD = $ 8004406D; // MAKE_AVIERR(109)
AVIERR_FILEWRITE = $ 8004406E; // MAKE_AVIERR(110)
AVIERR_FILEOPEN = $ 8004406F; // MAKE_AVIERR(111)
AVIERR_COMPRESSOR = $ 80044070; // MAKE_AVIERR(112)
AVIERR_NOCOMPRESSOR = $ 80044071; // MAKE_AVIERR(113)
AVIERR_READONLY = $ 80044072; // MAKE_AVIERR(114)
AVIERR_NODATA = $ 80044073; // MAKE_AVIERR(115)
AVIERR_BUFFERTOOSMALL = $ 80044074; // MAKE_AVIERR(116)
AVIERR_CANTCOMPRESS = $ 80044075; // MAKE_AVIERR(117)
AVIERR_USERABORT = $ 800440C6; // MAKE_AVIERR(198)
AVIERR_ERROR = $ 800440C7; // MAKE_AVIERR(199)
// TAVIStreamInfo dwFlag values
AVISF_DISABLED = $ 00000001;
AVISF_VIDEO_PALCHANGES = $ 00010000;
AVISF_KNOWN_FLAGS = $ 00010001;
type
TAVIFileInfoW = record
dwMaxBytesPerSec,// max。传输率
dwFlags,//永久标记
dwCaps,
dwStreams,
dwSuggestedBufferSize,
dwWidth,
dwHeight,
dwScale,
dwRate,// dwRate / dwScale == samples / second
dwLength,
dwEditCount:DWORD; WideBar的
szFileType:array [0..63]; //文件类型的描述性字符串?
结束
PAVIFileInfoW = ^ TAVIFileInfoW;
TAVIStreamInfoW = record
fccType,
fccHandler,
dwFlags,//包含AVITF_ * flags
dwCaps:DWORD;
wPriority,
wLanguage:WORD;
dwScale,
dwRate,// dwRate / dwScale == samples / second
dwStart,
dwLength,//以上单位
dwInitialFrames,
dwSuggestedBufferSize,
dwQuality,
dwSampleSize:DWORD;
rcFrame:TRect;
dwEditCount
dwFormatChangeCount:DWORD;
szName:WideChar的数组[0..63];
结束
TAVIStreamInfo = TAVIStreamInfoW;
PAVIStreamInfo = ^ TAVIStreamInfo;
PAVIStream = pointer;
PAVIFile =指针;
TAVIStreamList =数组[0..0]的PAVIStream;
PAVIStreamList = ^ TAVIStreamList;
TAVISaveCallback = function(nPercent:integer):LONG;标准
TAVICompressOptions =打包记录
fccType:DWORD;
fccHandler:DWORD;
dwKeyFrameEvery:DWORD;
dwQuality:DWORD;
dwBytesPerSecond:DWORD;
dwFlags:DWORD;
lpFormat:pointer;
cb格式:DWORD;
lpParms:pointer;
cbParms:DWORD;
dwInterleaveEvery:DWORD;
结束
PAVICompressOptions = ^ TAVICompressOptions;
//调色板更改数据记录
const
RIFF_PaletteChange:DWORD = 1668293411;
type
TAVIPalChange =打包记录
bFirstEntry:byte;
bNumEntries:byte;
wFlags:WORD;
peNew:TPaletteEntry的数组[byte];
结束
PAVIPalChange = ^ TAVIPalChange;
PAVISTREAM = PAVISTREAM的数组[0..1];
APAVICompressOptions = PAVICompressOptions的数组[0..1];
程序AVIFileInit;标准
程序AVIFileExit;标准
函数AVIFileOpen(var ppfile:PAVIFile; szFile:PChar; uMode:UINT; lpHandler:pointer):HResult;标准
函数AVIFileCreateStream(pfile:PAVIFile; var ppavi:PAVISTREAM; var psi:TAVIStreamInfo):HResult;标准
函数AVIStreamSetFormat(pavi:PAVIStream; lPos:LONG; lpFormat:pointer; cbFormat:LONG):HResult;标准
函数AVIStreamReadFormat(pavi:PAVIStream; lPos:LONG; lpFormat:pointer; var cbFormat:LONG):HResult;标准
函数AVIStreamWrite(pavi:PAVIStream; lStart,lSamples:LONG; lpBuffer:pointer; cbBuffer:LONG; dwFlags:DWORD; var plSampWritten:LONG; var plBytesWritten:LONG):HResult;标准
函数AVIStreamRelease(pavi:PAVISTREAM):ULONG;标准
函数AVIFileRelease(pfile:PAVIFile):ULONG;标准
函数AVIFileGetStream(pfile:PAVIFile; var ppavi:PAVISTREAM; fccType:DWORD; lParam:LONG):HResult;标准
函数CreateEditableStream(var ppsEditable:PAVISTREAM; psSource:PAVISTREAM):HResult;标准
函数AVISaveV(szFile:PChar; pclsidHandler:PCLSID; lpfnCallback:TAVISaveCallback;
nStreams:integer; pavi:APAVISTREAM; lpOptions:APAVICompressOptions):HResult;标准
const
AVIERR_OK = 0;
AVIIF_LIST = $ 01;
AVIIF_TWOCC = $ 02;
AVIIF_KEYFRAME = $ 10;
streamtypeVIDEO = $ 73646976; // DWORD('v','i','d','s')
streamtypeAUDIO = $ 73647561; // DWORD('a','u','d','s')
type
TPixelFormat =(pfDevice,pf1bit,pf4bit,pf8bit,pf15bit, pf16bit,pf24bit,pf32bit,pfCustom);
type
TAviWriter = class(TComponent)
private
TempFileName:string;
pFile:PAVIFile;
fHeight:integer;
fWidth:integer;
fStretch:boolean;
fFrameTime:integer;
fFileName:string;
fWavFileName:string;
VideoStream:PAVISTREAM;
AudioStream:PAVISTREAM;
程序AddVideo;
procedure AddAudio;
procedure InternalGetDIBSizes(Bitmap:HBITMAP; var InfoHeaderSize:Integer;
var ImageSize:longInt; PixelFormat:TPixelFormat);
函数InternalGetDIB(位图:HBITMAP;调色板:HPALETTE;
var BitmapInfo; var Bits; PixelFormat:TPixelFormat):Boolean;
procedure InitializeBitmapInfoHeader(Bitmap:HBITMAP; var Info:TBitmapInfoHeader;
PixelFormat:TPixelFormat);
程序SetWavFileName(value:string);
public
位图:TList;
构造函数Create(AOwner:TComponent);覆盖
析构函数覆盖
程序写;
发布
属性高度:整数读取fHeight写入fHeight;
属性宽度:整数读取fWidth写入fWidth;
属性FrameTime:整数读取fFrameTime写入fFrameTime;
属性Stretch:boolean读取fStretch写入fStretch;
属性FileName:字符串读取fFileName写入fFileName;
属性WavFileName:string读取fWavFileName写入SetWavFileName;
结束
程序注册;
实现
程序AVIFileInit;标准外部'avifil32.dll'的名称'AVIFileInit';
程序AVIFileExit;标准外部'avifil32.dll'的名称'AVIFileExit';
功能AVIFileOpen;外部'avifil32.dll'的名称'AVIFileOpenW';
函数AVIFileCreateStream;外部'avifil32.dll'的名称'AVIFileCreateStreamW';
函数AVIStreamSetFormat;外部'avifil32.dll'的名称'AVIStreamSetFormat';
函数AVIStreamReadFormat;外部'avifil32.dll'的名称'AVIStreamReadFormat';
功能AVIStreamWrite;外部'avifil32.dll'的名称'AVIStreamWrite';
函数AVIStreamRelease;外部'avifil32.dll'的名称'AVIStreamRelease';
函数AVIFileRelease;外部'avifil32.dll'的名称'AVIFileRelease';
函数AVIFileGetStream;外部'avifil32.dll'的名称'AVIFileGetStream';
函数CreateEditableStream;外部'avifil32.dll'名称'CreateEditableStream';
函数AVISaveV;外部'avifil32.dll'的名称'AVISaveVW';
构造函数TAviWriter.Create(AOwner:TComponent);
begin
继承Create(AOwner);
fHeight:= screen.height div 10;
fWidth:= screen.width div 10;
fFrameTime:= 1000;
fStretch:= true;
fFileName:='';
位图:= TList.create;
AVIFileInit;
TempFileName:= {tempdir +}'temp.avi';
结束
析构函数TAviWriter.Destroy;
begin
Bitmaps.free;
AviFileExit;
继承;
结束
程序TAviWriter.Write;
var
ExtBitmap:TBitmap;
nstreams:integer;
i:integer;
流:APAVISTREAM;
CompOptions:APAVICompressOptions;
AVIERR:integer;
refcount:integer;
begin
AudioStream:= nil;
VideoStream:= nil;
//如果列表中没有位图,则会引发错误。
如果Bitmaps.count< 1
然后引发Exception.Create(位图列表中没有位图);
//如果Bitmaps TList上的任何内容不是位图,则会引发
//一个错误。
for i:= 0 to Bitmaps.count - 1 do
begin
ExtBitmap:= Bitmaps [i];
如果没有(ExtBitmap是TBitmap)
然后引发Exception.Create('Bitmaps ['+ inttostr(i)
+']不是TBitmap');
结束// for
try
AddVideo;
如果WavFileName<> ''
then AddAudio;
//创建输出文件。
如果WavFileName<> ''
then nstreams:= 2
else nstreams:= 1;
Streams [0]:= VideoStream;
Streams [1]:= AudioStream;
CompOptions [0]:= nil;
CompOptions [1]:= nil;
AVIERR:= AVISaveV(
pchar(FileName),
nil,//文件处理程序
无,//回调
nStreams,// Number的流
Streams,
CompOptions); //压缩VideoStream的选项
如果AVIERR<> AVIERR_OK then
raise Exception.Create('Unable to write output file');
终于
如果分配(VideoStream)
然后AviStreamRelease(VideoStream);
如果分配(AudioStream)
然后AviStreamRelease(AudioStream);
尝试
重复
refcount:= AviFileRelease(pFile);
until refcount <= 0;
除了
//忽略异常
end; // try..except
DeleteFile(TempFileName);
结束// try..finally
end;
程序TAviWriter.AddVideo;
var
Pstream:PAVISTREAM;
StreamInfo:TAVIStreamInfo;
BitmapInfo:PBitmapInfoHeader;
BitmapInfoSize:整数;
BitmapSize:longInt;
BitmapBits:指针;
位图:TBitmap;
ExtBitmap:TBitmap;
Samples_Written:LONG;
Bytes_Written:LONG;
AVIERR:integer;
i:integer;
ok:Int64;
mode:uInt32;
fn:pChar;
err:string;
begin
//打开AVI文件写
pfile:= nil;
mode:= OF_CREATE或OF_WRITE或OF_SHARE_EXCLUSIVE;
fn:= pchar(TempFileName);
ok:= AVIFileOpen(pFile,fn,mode,nil);
如果ok = AVIERR_BADFORMAT然后err:='该文件无法读取,指示损坏的文件或无法识别的格式。
if ok = AVIERR_MEMORY then err:='由于内存不足,无法打开该文件。
如果ok = AVIERR_FILEREAD then err:='读取文件时发生磁盘错误。
如果ok = AVIERR_FILEOPEN然后err:='打开文件时发生磁盘错误'。
如果ok = REGDB_E_CLASSNOTREG then err:='根据注册表,AVIFileOpen中指定的文件类型没有处理程序。
如果err<> 然后提高Exception.Create(err);
//分配BitTaps中的位图
//将被复制到的位图。
位图:= TBitmap.create;
Bitmap.Height:= self.Height;
Bitmap.Width:= self.Width;
//编写流标题。
try
FillChar(StreamInfo,sizeof(StreamInfo),0);
//设置帧速率和缩放
StreamInfo.dwRate:= 1000;
StreamInfo.dwScale:= fFrameTime;
StreamInfo.fccType:= streamtypeVIDEO;
StreamInfo.fccHandler:= 0;
StreamInfo.dwFlags:= 0;
StreamInfo.dwSuggestedBufferSize:= 0;
StreamInfo.rcFrame.Right:= self.width;
StreamInfo.rcFrame.Bottom:= self.height;
//打开AVI数据流
if(AVIFileCreateStream(pFile,pStream,StreamInfo)<> AVIERR_OK)然后
raise Exception.Create('无法创建AVI视频流');
try
//将位图写入流。
for i:= 0 to Bitmaps.count - 1 do
begin
BitmapInfo:= nil;
BitmapBits:= nil;
try
//将列表中的位图复制到AVI位图
//如果需要伸展。如果调用者选择不
//拉伸,则使用位图中的第一个像素作为
//背景颜色,以防止源的高度或
//宽度小于输出。
//如果Draw失败,请执行StretchDraw。
ExtBitmap:= Bitmaps [i];
如果fStretch
然后Bitmap.Canvas.StretchDraw
(Rect(0,0,self.width,self.height),ExtBitmap)
else尝试
与位图.Canvas do begin
Brush.Color:= ExtBitmap.Canvas.Pixels [0,0];
Brush.Style:= bsSolid;
FillRect(Rect(0,0,Bitmap.Width,Bitmap.Height));
Draw(0,0,ExtBitmap);
结束
除了
Bitmap.Canvas.StretchDraw
(Rect(0,0,self.width,self.height),ExtBitmap);
结束
//确定DIB的大小
InternalGetDIBSizes(Bitmap.Handle,BitmapInfoSize,BitmapSize,pf8bit);
if(BitmapInfoSize = 0)then
raise Exception.Create('Failed to retrieve bitmap info');
//获取DIB标题和像素缓冲区
GetMem(BitmapInfo,BitmapInfoSize);
GetMem(BitmapBits,BitmapSize);
InternalGetDIB
(Bitmap.Handle,0,BitmapInfo ^,BitmapBits ^,pf8bit);
//首次通过时,设置流格式。
如果i = 0然后
if(AVIStreamSetFormat(pStream,0,BitmapInfo,BitmapInfoSize)<> AVIERR_OK)然后
raise Exception.Create('无法设置AVI流格式') ;
//将帧写入视频流
AVIERR:=
AVIStreamWrite(pStream,i,1,BitmapBits,BitmapSize,AVIIF_KEYFRAME,
Samples_Written,Bytes_Written);
如果AVIERR<> AVIERR_OK然后
raise Exception.Create
('无法将帧添加到AVI。Err ='
+ inttohex(AVIERR,8));
finally
if(BitmapInfo<> nil)then
FreeMem(BitmapInfo);
if(BitmapBits<> nil)then
FreeMem(BitmapBits);
结束
结束
//从pStream创建可编辑的VideoStream。
如果CreateEditableStream(VideoStream,pStream)<> AVIERR_OK然后
raise Exception.Create
('无法创建视频流');
终于
AviStreamRelease(pStream);
结束
finally
Bitmap.free;
结束
结束
程序TAviWriter.AddAudio;
var
InputFile:PAVIFILE;
InputStream:PAVIStream;
err:string;
ok:Int64;
begin
//打开音频文件。
ok:= AVIFileOpen(InputFile,pchar(WavFileName),OF_READ,nil);
如果ok = AVIERR_BADFORMAT然后err:='该文件无法读取,指示损坏的文件或无法识别的格式。
if ok = AVIERR_MEMORY then err:='由于内存不足,无法打开该文件。
如果ok = AVIERR_FILEREAD then err:='读取文件时发生磁盘错误。
如果ok = AVIERR_FILEOPEN然后err:='打开文件时发生磁盘错误'。
如果ok = REGDB_E_CLASSNOTREG then err:='根据注册表,AVIFileOpen中指定的文件类型没有处理程序。
如果err<> 然后提高Exception.Create(err);
//打开音频流。
try
if(AVIFileGetStream(InputFile,InputStream,0,0)<> AVIERR_OK)then
raise Exception.Create('Unable to get audio stream');
try
//创建AudioStream作为InputStream的副本
if(CreateEditableStream(AudioStream,InputStream)<> AVIERR_OK)then
raise Exception.Create 无法创建可编辑的AVI音频流);
终于
AviStreamRelease(InputStream);
结束
finally
AviFileRelease(InputFile);
结束
结束
// --------------
// InternalGetDIB
// ------------- -
//将位图转换为指定的PixelFormat的DIB。
//
//注意:InternalGetDIBSizes函数可用于计算BitmapInfo和Bits缓冲区的
// nescessary大小。
//
//从graphics.pas,优化为我们使用
函数TAviWriter.InternalGetDIB
(
位图:HBITMAP; //源位图的处理
调色板:HPALETTE; //源调色板的句柄
var BitmapInfo; //将接收DIB的TBitmapInfo结构的缓冲区
//缓冲区必须在
之前分配足够的大小//调用此函数
var Bits; //将接收DIB的像素数据的缓冲区
PixelFormat:TPixelFormat //目标的像素格式DIB
):Boolean; // True on success,False on failure
var
OldPal:HPALETTE;
DC:HDC;
begin
InitializeBitmapInfoHeader(Bitmap,TBitmapInfoHeader(BitmapInfo),PixelFormat);
OldPal:= 0;
DC:= CreateCompatibleDC(0);
尝试
如果(Palette<> 0)then
begin
OldPal:= SelectPalette(DC,Palette,False);
RealizePalette(DC);
结束
结果:=(GetDIBits(DC,Bitmap,0,abs(TBitmapInfoHeader(BitmapInfo).biHeight),
@Bits,TBitmapInfo(BitmapInfo),DIB_RGB_COLORS)<> 0);
finally
if(OldPal<> 0)then
SelectPalette(DC,OldPal,False);
DeleteDC(DC);
结束
结束
// -------------------
// InternalGetDIBSizes
// ---- ---------------
//计算缓冲区大小,用于将位图转换为指定的PixelFormat的DIB
//。
//有关更多信息,请参阅GetDIBSizes API函数。
//从graphics.pas,优化为我们使用
程序TAviWriter.InternalGetDIBSizes
(
位图:HBITMAP; //源位图的句柄
var InfoHeaderSize:Integer; //将接收
的缓冲区的返回大小// DIB的TBitmapInfo结构
var ImageSize:longInt; //将接收的缓冲区的返回大小DIB的像素数据
PixelFormat:TPixelFormat //目标的像素格式DIB
);
var
信息:TBitmapInfoHeader;
begin
InitializeBitmapInfoHeader(Bitmap,Info,PixelFormat);
//检查调色板设备格式
如果(Info.biBitCount> 8)然后
开始
//标题但不调色板
InfoHeaderSize:= SizeOf(TBitmapInfoHeader );
if((Info.biCompression和BI_BITFIELDS)0)then
Inc(InfoHeaderSize,12);
end else
//标题和调色板
InfoHeaderSize:= SizeOf(TBitmapInfoHeader)+ SizeOf(TRGBQuad)*(1 shl Info.biBitCount);
ImageSize:= Info.biSizeImage;
结束
// --------------------------
// InitializeBitmapInfoHeader
// - -------------------------
//将TBitmapInfoHeader与位图的值一起转换为
//指定的PixelFormat的DIB。
//从graphics.pas,优化为我们使用
程序TAviWriter.InitializeBitmapInfoHeader
(
位图:HBITMAP; //源位图的句柄
var Info:TBitmapInfoHeader; //接收值的bbitmapInfoHeader缓冲区
PixelFormat:TPixelFormat //目标DIB
的像素格式;
var
DIB:TDIBSection;
字节:整数;
函数AlignBit(Bits,BitsPerPixel,Alignment:Cardinal):Cardinal;
begin
Dec(Alignment);
结果:=((Bits * BitsPerPixel)+对齐),而不是对齐;
结果:=结果SHR 3;
结束
begin
DIB.dsbmih.biSize:= 0;
Bytes:= GetObject(Bitmap,SizeOf(DIB),@DIB);
if(Bytes = 0)then
raise Exception.Create('Invalid bitmap');
// Error(sInvalidBitmap);
if(Bytes> =(sizeof(DIB.dsbm)+ sizeof(DIB.dsbmih)))和
(DIB.dsbmih.biSize> = sizeof(DIB.dsbmih) )然后
信息:= DIB.dsbmih
else
begin
FillChar(Info,sizeof(Info),0);
with Info,DIB.dsbm do
begin
biSize:= SizeOf(Info);
biWidth:= bmWidth;
biHeight:= bmHeight;
结束
结束
case PixelFormat of
pf1bit:Info.biBitCount:= 1;
pf4bit:Info.biBitCount:= 4;
pf8bit:Info.biBitCount:= 8;
pf24bit:Info.biBitCount:= 24;
else
//错误(sInvalidPixelFormat);
raise Exception.Create('Invalid pixel format');
// Info.biBitCount:= DIB.dsbm.bmBitsPixel * DIB.dsbm.bmPlanes;
结束
Info.biPlanes:= 1;
Info.biCompression:= BI_RGB; //始终以RGB格式返回数据
Info.biSizeImage:= AlignBit(Info.biWidth,Info.biBitCount,32)* Cardinal(abs(Info.biHeight));
结束
程序TAviWriter.SetWavFileName(value:string);
begin
如果为小写(fWavFileName)<>小写(值)
然后如果小写(ExtractFileExt(value))<> '.wav'
然后引发Exception.Create('WavFileName必须使用.wav扩展名命名一个文件'
+')
else fWavFileName:= value;
结束
程序注册;
begin
RegisterComponents('Samples',[TAviWriter]);
结束
结束。
更改导入部分 AVISaveV
功能到它的Unicode版本。当Windows API引用中的函数具有注释 Unicode和ANSI名称
时,这意味着您在Delphi中,您必须从Unicode版本的函数或从ANSI一个取决于您将使用什么编译器。
您正在尝试调用 AVISaveV
不存在在 avifil32.dll
中只有 AVISaveVA
和 AVISaveVW
因为您要将此代码转换为Unicode,请尝试以这种方式更改函数导入:
函数AVISaveV;外部'avifil32.dll'的名称'AVISaveVW';
这只是第一个想法,即使在非Unicode版本的Delphi中,具有定义的代码也无法正常工作,因为它称为不存在的功能。
My application creates images from fractals and I love the feeling of 'flying' around a fractal. I once saved about 2000 bitmaps to file and created an AVI from it using Premiere. That experience is rather frustrating though I succeeded in creating a movie. That was spectacular. Of course I want to create a video from my application. I actually don't care about the niftyness of the codec, compression or whatever. I just want to have a video that I can replay on most systems.
In the past I have tried this but never succeeded. I was triggered by a question recently but alas could not get FFMpeg running.
Update
I decided to adapt the question slightly and put a bounty for it. I have seen several solutions but the most attractive (because it's simple) seems to me TAviWrite. I tried TAviWriter but did not succeed. In procedure TAviWriter.Write; the function call around line 370
AVIERR := AVISaveV(s,
// pchar(FileName),
nil, // File handler
nil, // Callback
nStreams, // Number of streams
Streams,
CompOptions); // Compress options for VideoStream
does not return AVIERR_OK.
Update 2
The reason for above mentioned error is a wrong declaration of AVISaveV, it should be declared as AVISaveVW as TLama pointed out. The correct code for creating AVI filoes form BMP files is posted below. The original code below was downloaded from efg with an example unit.
Using Delphi XE on Windows 7.
unit AviWriter;
/////////////////////////////////////////////////////////////////////////////
// //
// AviWriter -- a component to create rudimentary AVI files //
// by Elliott Shevin, with large pieces of code //
// stolen from Anders Melander //
// version 1.0. Please send comments, suggestions, and advice //
// to shevine@aol.com. //
/////////////////////////////////////////////////////////////////////////////
interface
uses
Windows,Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ole2;
////////////////////////////////////////////////////////////////////////////////
// //
// Video for Windows //
// //
////////////////////////////////////////////////////////////////////////////////
// //
// Adapted from Thomas Schimming's VFW.PAS //
// (c) 1996 Thomas Schimming, schimmin@iee1.et.tu-dresden.de //
// (c) 1998,99 Anders Melander //
// //
////////////////////////////////////////////////////////////////////////////////
// //
// Ripped all COM/ActiveX stuff and added some AVI stream functions. //
// //
////////////////////////////////////////////////////////////////////////////////
// Unicode version created by Arnold and TLama (2012) //
////////////////////////////////////////////////////////////////////////////////
type
LONG = Longint;
PVOID = Pointer;
const
// TAVIFileInfo dwFlag values
AVIF_HASINDEX = $00000010;
AVIF_MUSTUSEINDEX = $00000020;
AVIF_ISINTERLEAVED = $00000100;
AVIF_WASCAPTUREFILE = $00010000;
AVIF_COPYRIGHTED = $00020000;
AVIF_KNOWN_FLAGS = $00030130;
AVIERR_UNSUPPORTED = $80044065; // MAKE_AVIERR(101)
AVIERR_BADFORMAT = $80044066; // MAKE_AVIERR(102)
AVIERR_MEMORY = $80044067; // MAKE_AVIERR(103)
AVIERR_INTERNAL = $80044068; // MAKE_AVIERR(104)
AVIERR_BADFLAGS = $80044069; // MAKE_AVIERR(105)
AVIERR_BADPARAM = $8004406A; // MAKE_AVIERR(106)
AVIERR_BADSIZE = $8004406B; // MAKE_AVIERR(107)
AVIERR_BADHANDLE = $8004406C; // MAKE_AVIERR(108)
AVIERR_FILEREAD = $8004406D; // MAKE_AVIERR(109)
AVIERR_FILEWRITE = $8004406E; // MAKE_AVIERR(110)
AVIERR_FILEOPEN = $8004406F; // MAKE_AVIERR(111)
AVIERR_COMPRESSOR = $80044070; // MAKE_AVIERR(112)
AVIERR_NOCOMPRESSOR = $80044071; // MAKE_AVIERR(113)
AVIERR_READONLY = $80044072; // MAKE_AVIERR(114)
AVIERR_NODATA = $80044073; // MAKE_AVIERR(115)
AVIERR_BUFFERTOOSMALL = $80044074; // MAKE_AVIERR(116)
AVIERR_CANTCOMPRESS = $80044075; // MAKE_AVIERR(117)
AVIERR_USERABORT = $800440C6; // MAKE_AVIERR(198)
AVIERR_ERROR = $800440C7; // MAKE_AVIERR(199)
// TAVIStreamInfo dwFlag values
AVISF_DISABLED = $00000001;
AVISF_VIDEO_PALCHANGES = $00010000;
AVISF_KNOWN_FLAGS = $00010001;
type
TAVIFileInfoW = record
dwMaxBytesPerSec,// max. transfer rate
dwFlags, // the ever-present flags
dwCaps,
dwStreams,
dwSuggestedBufferSize,
dwWidth,
dwHeight,
dwScale,
dwRate, // dwRate / dwScale == samples/second
dwLength,
dwEditCount: DWORD;
szFileType: array[0..63] of WideChar; // descriptive string for file type?
end;
PAVIFileInfoW = ^TAVIFileInfoW;
TAVIStreamInfoW = record
fccType,
fccHandler,
dwFlags, // Contains AVITF_* flags
dwCaps: DWORD;
wPriority,
wLanguage: WORD;
dwScale,
dwRate, // dwRate / dwScale == samples/second
dwStart,
dwLength, // In units above...
dwInitialFrames,
dwSuggestedBufferSize,
dwQuality,
dwSampleSize: DWORD;
rcFrame: TRect;
dwEditCount,
dwFormatChangeCount: DWORD;
szName: array[0..63] of WideChar;
end;
TAVIStreamInfo = TAVIStreamInfoW;
PAVIStreamInfo = ^TAVIStreamInfo;
PAVIStream = pointer;
PAVIFile = pointer;
TAVIStreamList = array[0..0] of PAVIStream;
PAVIStreamList = ^TAVIStreamList;
TAVISaveCallback = function (nPercent: integer): LONG; stdcall;
TAVICompressOptions = packed record
fccType : DWORD;
fccHandler : DWORD;
dwKeyFrameEvery : DWORD;
dwQuality : DWORD;
dwBytesPerSecond : DWORD;
dwFlags : DWORD;
lpFormat : pointer;
cbFormat : DWORD;
lpParms : pointer;
cbParms : DWORD;
dwInterleaveEvery : DWORD;
end;
PAVICompressOptions = ^TAVICompressOptions;
// Palette change data record
const
RIFF_PaletteChange: DWORD = 1668293411;
type
TAVIPalChange = packed record
bFirstEntry : byte;
bNumEntries : byte;
wFlags : WORD;
peNew : array[byte] of TPaletteEntry;
end;
PAVIPalChange = ^TAVIPalChange;
APAVISTREAM = array[0..1] of PAVISTREAM;
APAVICompressOptions = array[0..1] of PAVICompressOptions;
procedure AVIFileInit; stdcall;
procedure AVIFileExit; stdcall;
function AVIFileOpen(var ppfile: PAVIFile; szFile: PChar; uMode: UINT; lpHandler: pointer): HResult; stdcall;
function AVIFileCreateStream(pfile: PAVIFile; var ppavi: PAVISTREAM; var psi: TAVIStreamInfo): HResult; stdcall;
function AVIStreamSetFormat(pavi: PAVIStream; lPos: LONG; lpFormat: pointer; cbFormat: LONG): HResult; stdcall;
function AVIStreamReadFormat(pavi: PAVIStream; lPos: LONG; lpFormat: pointer; var cbFormat: LONG): HResult; stdcall;
function AVIStreamWrite(pavi: PAVIStream; lStart, lSamples: LONG; lpBuffer: pointer; cbBuffer: LONG; dwFlags: DWORD; var plSampWritten: LONG; var plBytesWritten: LONG): HResult; stdcall;
function AVIStreamRelease(pavi: PAVISTREAM): ULONG; stdcall;
function AVIFileRelease(pfile: PAVIFile): ULONG; stdcall;
function AVIFileGetStream(pfile: PAVIFile; var ppavi: PAVISTREAM; fccType: DWORD; lParam: LONG): HResult; stdcall;
function CreateEditableStream(var ppsEditable: PAVISTREAM; psSource: PAVISTREAM): HResult; stdcall;
function AVISaveV(szFile: PChar; pclsidHandler: PCLSID; lpfnCallback: TAVISaveCallback;
nStreams: integer; pavi: APAVISTREAM; lpOptions: APAVICompressOptions): HResult; stdcall;
const
AVIERR_OK = 0;
AVIIF_LIST = $01;
AVIIF_TWOCC = $02;
AVIIF_KEYFRAME = $10;
streamtypeVIDEO = $73646976; // DWORD( 'v', 'i', 'd', 's' )
streamtypeAUDIO = $73647561; // DWORD( 'a', 'u', 'd', 's' )
type
TPixelFormat = (pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom);
type
TAviWriter = class (TComponent)
private
TempFileName : string;
pFile : PAVIFile;
fHeight : integer;
fWidth : integer;
fStretch : boolean;
fFrameTime : integer;
fFileName : string;
fWavFileName : string;
VideoStream : PAVISTREAM;
AudioStream : PAVISTREAM;
procedure AddVideo;
procedure AddAudio;
procedure InternalGetDIBSizes(Bitmap: HBITMAP; var InfoHeaderSize: Integer;
var ImageSize: longInt; PixelFormat: TPixelFormat);
function InternalGetDIB(Bitmap: HBITMAP; Palette: HPALETTE;
var BitmapInfo; var Bits; PixelFormat: TPixelFormat): Boolean;
procedure InitializeBitmapInfoHeader(Bitmap: HBITMAP; var Info: TBitmapInfoHeader;
PixelFormat: TPixelFormat);
procedure SetWavFileName(value : string);
public
Bitmaps : TList;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure Write;
published
property Height : integer read fHeight write fHeight;
property Width : integer read fWidth write fWidth;
property FrameTime: integer read fFrameTime write fFrameTime;
property Stretch : boolean read fStretch write fStretch;
property FileName : string read fFileName write fFileName;
property WavFileName : string read fWavFileName write SetWavFileName;
end;
procedure Register;
implementation
procedure AVIFileInit; stdcall; external 'avifil32.dll' name 'AVIFileInit';
procedure AVIFileExit; stdcall; external 'avifil32.dll' name 'AVIFileExit';
function AVIFileOpen; external 'avifil32.dll' name 'AVIFileOpenW';
function AVIFileCreateStream; external 'avifil32.dll' name 'AVIFileCreateStreamW';
function AVIStreamSetFormat; external 'avifil32.dll' name 'AVIStreamSetFormat';
function AVIStreamReadFormat; external 'avifil32.dll' name 'AVIStreamReadFormat';
function AVIStreamWrite; external 'avifil32.dll' name 'AVIStreamWrite';
function AVIStreamRelease; external 'avifil32.dll' name 'AVIStreamRelease';
function AVIFileRelease; external 'avifil32.dll' name 'AVIFileRelease';
function AVIFileGetStream; external 'avifil32.dll' name 'AVIFileGetStream';
function CreateEditableStream; external 'avifil32.dll' name 'CreateEditableStream';
function AVISaveV; external 'avifil32.dll' name 'AVISaveVW';
constructor TAviWriter.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
fHeight := screen.height div 10;
fWidth := screen.width div 10;
fFrameTime := 1000;
fStretch := true;
fFileName := '';
Bitmaps := TList.create;
AVIFileInit;
TempFileName := {tempdir +} 'temp.avi';
end;
destructor TAviWriter.Destroy;
begin
Bitmaps.free;
AviFileExit;
inherited;
end;
procedure TAviWriter.Write;
var
ExtBitmap : TBitmap;
nstreams : integer;
i : integer;
Streams : APAVISTREAM;
CompOptions : APAVICompressOptions;
AVIERR : integer;
refcount : integer;
begin
AudioStream := nil;
VideoStream := nil;
// If no bitmaps are on the list, raise an error.
if Bitmaps.count < 1
then raise Exception.Create('No bitmaps on the Bitmaps list');
// If anything on the Bitmaps TList is not a bitmap, raise
// an error.
for i := 0 to Bitmaps.count - 1 do
begin
ExtBitmap := Bitmaps[i];
if not(ExtBitmap is TBitmap)
then raise Exception.Create('Bitmaps[' + inttostr(i)
+ '] is not a TBitmap');
end; // for
try
AddVideo;
if WavFileName <> ''
then AddAudio;
// Create the output file.
if WavFileName <> ''
then nstreams := 2
else nstreams := 1;
Streams[0] := VideoStream;
Streams[1] := AudioStream;
CompOptions[0] := nil;
CompOptions[1] := nil;
AVIERR := AVISaveV(
pchar(FileName),
nil, // File handler
nil, // Callback
nStreams, // Number of streams
Streams,
CompOptions); // Compress options for VideoStream
if AVIERR <> AVIERR_OK then
raise Exception.Create('Unable to write output file');
finally
if assigned(VideoStream)
then AviStreamRelease(VideoStream);
if assigned(AudioStream)
then AviStreamRelease(AudioStream);
try
repeat
refcount := AviFileRelease(pFile);
until refcount <= 0;
except
// ignore exception
end; // try..except
DeleteFile(TempFileName);
end; // try..finally
end;
procedure TAviWriter.AddVideo;
var
Pstream: PAVISTREAM;
StreamInfo: TAVIStreamInfo;
BitmapInfo: PBitmapInfoHeader;
BitmapInfoSize: Integer;
BitmapSize: longInt;
BitmapBits: pointer;
Bitmap: TBitmap;
ExtBitmap: TBitmap;
Samples_Written: LONG;
Bytes_Written: LONG;
AVIERR: integer;
i: integer;
ok: Int64;
mode: uInt32;
fn: pChar;
err: string;
begin
// Open AVI file for write
pfile := nil;
mode := OF_CREATE or OF_WRITE or OF_SHARE_EXCLUSIVE;
fn := pchar (TempFileName);
ok := AVIFileOpen (pFile, fn, mode, nil);
if ok = AVIERR_BADFORMAT then err := 'The file could not be read, indicating a corrupt file or an unrecognized format.';
if ok = AVIERR_MEMORY then err := 'The file could not be opened because of insufficient memory.';
if ok = AVIERR_FILEREAD then err := 'A disk error occurred while reading the file.';
if ok = AVIERR_FILEOPEN then err := 'A disk error occurred while opening the file.';
if ok = REGDB_E_CLASSNOTREG then err := 'According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it.';
if err <> '' then raise Exception.Create (err);
// Allocate the bitmap to which the bitmaps on the Bitmaps Tlist
// will be copied.
Bitmap := TBitmap.create;
Bitmap.Height := self.Height;
Bitmap.Width := self.Width;
// Write the stream header.
try
FillChar (StreamInfo, sizeof (StreamInfo), 0);
// Set frame rate and scale
StreamInfo.dwRate := 1000;
StreamInfo.dwScale := fFrameTime;
StreamInfo.fccType := streamtypeVIDEO;
StreamInfo.fccHandler := 0;
StreamInfo.dwFlags := 0;
StreamInfo.dwSuggestedBufferSize := 0;
StreamInfo.rcFrame.Right := self.width;
StreamInfo.rcFrame.Bottom := self.height;
// Open AVI data stream
if (AVIFileCreateStream(pFile, pStream, StreamInfo) <> AVIERR_OK) then
raise Exception.Create('Failed to create AVI video stream');
try
// Write the bitmaps to the stream.
for i := 0 to Bitmaps.count - 1 do
begin
BitmapInfo := nil;
BitmapBits := nil;
try
// Copy the bitmap from the list to the AVI bitmap,
// stretching if desired. If the caller elects not to
// stretch, use the first pixel in the bitmap as a
// background color in case either the height or
// width of the source is smaller than the output.
// If Draw fails, do a StretchDraw.
ExtBitmap := Bitmaps[i];
if fStretch
then Bitmap.Canvas.StretchDraw
(Rect(0,0,self.width,self.height),ExtBitmap)
else try
with Bitmap.Canvas do begin
Brush.Color := ExtBitmap.Canvas.Pixels[0,0];
Brush.Style := bsSolid;
FillRect(Rect(0,0,Bitmap.Width,Bitmap.Height));
Draw(0,0,ExtBitmap);
end;
except
Bitmap.Canvas.StretchDraw
(Rect(0,0,self.width,self.height),ExtBitmap);
end;
// Determine size of DIB
InternalGetDIBSizes(Bitmap.Handle, BitmapInfoSize, BitmapSize, pf8bit);
if (BitmapInfoSize = 0) then
raise Exception.Create('Failed to retrieve bitmap info');
// Get DIB header and pixel buffers
GetMem(BitmapInfo, BitmapInfoSize);
GetMem(BitmapBits, BitmapSize);
InternalGetDIB
(Bitmap.Handle, 0, BitmapInfo^, BitmapBits^, pf8bit);
// On the first time through, set the stream format.
if i = 0 then
if (AVIStreamSetFormat(pStream, 0, BitmapInfo, BitmapInfoSize) <> AVIERR_OK) then
raise Exception.Create('Failed to set AVI stream format');
// Write frame to the video stream
AVIERR :=
AVIStreamWrite(pStream, i, 1, BitmapBits, BitmapSize, AVIIF_KEYFRAME,
Samples_Written, Bytes_Written);
if AVIERR <> AVIERR_OK then
raise Exception.Create
('Failed to add frame to AVI. Err='
+ inttohex(AVIERR,8));
finally
if (BitmapInfo <> nil) then
FreeMem(BitmapInfo);
if (BitmapBits <> nil) then
FreeMem(BitmapBits);
end;
end;
// Create the editable VideoStream from pStream.
if CreateEditableStream(VideoStream,pStream) <> AVIERR_OK then
raise Exception.Create
('Could not create Video Stream');
finally
AviStreamRelease(pStream);
end;
finally
Bitmap.free;
end;
end;
procedure TAviWriter.AddAudio;
var
InputFile : PAVIFILE;
InputStream : PAVIStream;
err: string;
ok: Int64;
begin
// Open the audio file.
ok := AVIFileOpen(InputFile, pchar(WavFileName),OF_READ, nil);
if ok = AVIERR_BADFORMAT then err := 'The file could not be read, indicating a corrupt file or an unrecognized format.';
if ok = AVIERR_MEMORY then err := 'The file could not be opened because of insufficient memory.';
if ok = AVIERR_FILEREAD then err := 'A disk error occurred while reading the file.';
if ok = AVIERR_FILEOPEN then err := 'A disk error occurred while opening the file.';
if ok = REGDB_E_CLASSNOTREG then err := 'According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it.';
if err <> '' then raise Exception.Create (err);
// Open the audio stream.
try
if (AVIFileGetStream(InputFile, InputStream, 0, 0) <> AVIERR_OK) then
raise Exception.Create('Unable to get audio stream');
try
// Create AudioStream as a copy of InputStream
if (CreateEditableStream(AudioStream,InputStream) <> AVIERR_OK) then
raise Exception.Create('Failed to create editable AVI audio stream');
finally
AviStreamRelease(InputStream);
end;
finally
AviFileRelease(InputFile);
end;
end;
// --------------
// InternalGetDIB
// --------------
// Converts a bitmap to a DIB of a specified PixelFormat.
//
// Note: The InternalGetDIBSizes function can be used to calculate the
// nescessary sizes of the BitmapInfo and Bits buffers.
//
// From graphics.pas, "optimized" for our use
function TAviWriter.InternalGetDIB
(
Bitmap: HBITMAP; // The handle of the source bitmap
Palette: HPALETTE; // The handle of the source palette
var BitmapInfo; // The buffer that will receive the DIB's TBitmapInfo structure.
// A buffer of sufficient size must have been allocated prior to
// calling this function
var Bits; // The buffer that will receive the DIB's pixel data
PixelFormat: TPixelFormat // The pixel format of the destination DIB
): Boolean; // True on success, False on failure
var
OldPal : HPALETTE;
DC : HDC;
begin
InitializeBitmapInfoHeader(Bitmap, TBitmapInfoHeader(BitmapInfo), PixelFormat);
OldPal := 0;
DC := CreateCompatibleDC(0);
try
if (Palette <> 0) then
begin
OldPal := SelectPalette(DC, Palette, False);
RealizePalette(DC);
end;
Result := (GetDIBits(DC, Bitmap, 0, abs(TBitmapInfoHeader(BitmapInfo).biHeight),
@Bits, TBitmapInfo(BitmapInfo), DIB_RGB_COLORS) <> 0);
finally
if (OldPal <> 0) then
SelectPalette(DC, OldPal, False);
DeleteDC(DC);
end;
end;
// -------------------
// InternalGetDIBSizes
// -------------------
// Calculates the buffer sizes nescessary for convertion of a bitmap to a DIB
// of a specified PixelFormat.
// See the GetDIBSizes API function for more info.
// From graphics.pas, "optimized" for our use
procedure TAviWriter.InternalGetDIBSizes
(
Bitmap: HBITMAP; // The handle of the source bitmap
var InfoHeaderSize: Integer; // The returned size of a buffer that will receive
// the DIB's TBitmapInfo structure
var ImageSize: longInt; // The returned size of a buffer that will receive the DIB's pixel data
PixelFormat: TPixelFormat // The pixel format of the destination DIB
);
var
Info: TBitmapInfoHeader;
begin
InitializeBitmapInfoHeader(Bitmap, Info, PixelFormat);
// Check for palette device format
if (Info.biBitCount > 8) then
begin
// Header but no palette
InfoHeaderSize := SizeOf(TBitmapInfoHeader);
if ((Info.biCompression and BI_BITFIELDS) <> 0) then
Inc(InfoHeaderSize, 12);
end else
// Header and palette
InfoHeaderSize := SizeOf(TBitmapInfoHeader) + SizeOf(TRGBQuad) * (1 shl Info.biBitCount);
ImageSize := Info.biSizeImage;
end;
// --------------------------
// InitializeBitmapInfoHeader
// --------------------------
// Fills a TBitmapInfoHeader with the values of a bitmap when converted to a
// DIB of a specified PixelFormat.
// From graphics.pas, "optimized" for our use
procedure TAviWriter.InitializeBitmapInfoHeader
(
Bitmap: HBITMAP; // The handle of the source bitmap
var Info: TBitmapInfoHeader; // The TBitmapInfoHeader buffer that will receive the values
PixelFormat: TPixelFormat // The pixel format of the destination DIB
);
var
DIB : TDIBSection;
Bytes : Integer;
function AlignBit(Bits, BitsPerPixel, Alignment: Cardinal): Cardinal;
begin
Dec(Alignment);
Result := ((Bits * BitsPerPixel) + Alignment) and not Alignment;
Result := Result SHR 3;
end;
begin
DIB.dsbmih.biSize := 0;
Bytes := GetObject(Bitmap, SizeOf(DIB), @DIB);
if (Bytes = 0) then
raise Exception.Create('Invalid bitmap');
// Error(sInvalidBitmap);
if (Bytes >= (sizeof(DIB.dsbm) + sizeof(DIB.dsbmih))) and
(DIB.dsbmih.biSize >= sizeof(DIB.dsbmih)) then
Info := DIB.dsbmih
else
begin
FillChar(Info, sizeof(Info), 0);
with Info, DIB.dsbm do
begin
biSize := SizeOf(Info);
biWidth := bmWidth;
biHeight := bmHeight;
end;
end;
case PixelFormat of
pf1bit: Info.biBitCount := 1;
pf4bit: Info.biBitCount := 4;
pf8bit: Info.biBitCount := 8;
pf24bit: Info.biBitCount := 24;
else
// Error(sInvalidPixelFormat);
raise Exception.Create('Invalid pixel format');
// Info.biBitCount := DIB.dsbm.bmBitsPixel * DIB.dsbm.bmPlanes;
end;
Info.biPlanes := 1;
Info.biCompression := BI_RGB; // Always return data in RGB format
Info.biSizeImage := AlignBit(Info.biWidth, Info.biBitCount, 32) * Cardinal(abs(Info.biHeight));
end;
procedure TAviWriter.SetWavFileName(value : string);
begin
if lowercase(fWavFileName) <> lowercase(value)
then if lowercase(ExtractFileExt(value)) <> '.wav'
then raise Exception.Create('WavFileName must name a file '
+ 'with the .wav extension')
else fWavFileName := value;
end;
procedure Register;
begin
RegisterComponents('Samples', [TAviWriter]);
end;
end.
Change the import part of the AVISaveV
function to the Unicode version of it. When the function in the Windows API reference has the note Unicode and ANSI names
it means for you, in Delphi, you have to choose either from the Unicode version of the function or from the ANSI one depending on what compiler will you use.
You're trying to call the AVISaveV
, which physically doesn't exists. There's only AVISaveVA
and the AVISaveVW
in avifil32.dll
and since you want to convert this code to Unicode, try to change the function import this way:
function AVISaveV; external 'avifil32.dll' name 'AVISaveVW';
This is just a first thought, the code with the definition like was cannot work even in non Unicode versions of Delphi, because it called the not existing function.
这篇关于如何将位图转换为视频?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!