如何将位图转换为视频? [英] How to convert bitmaps to video?

查看:762
本文介绍了如何将位图转换为视频?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序从分形创建图像,我喜欢分形的飞行感觉。我曾经将约2000个位图保存到文件中,并使用Premiere创建了一个AVI。虽然我成功地创作了一部电影,但这种经历非常令人沮丧。那是壮观的。当然,我想从我的应用程序创建一个视频。实际上我并不关心编解码器,压缩或其他任何东西的漂亮。我只是想有一个视频,我可以在大多数系统上重播。



在过去我已经尝试过,但从未成功。我被问题触发最近,唉,不能让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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆