2012-03-08 188 views
14

我的應用程序創建分形的圖像,我喜歡分形的'飛行'的感覺。我曾經使用Premiere保存了大約2000個位圖文件並創建了AVI文件。儘管我成功地創作了一部電影,但這種經歷令人沮喪。那很壯觀。當然,我想從我的應用程序創建一個視頻。我其實並不在乎編解碼器的簡潔,壓縮或其他。我只想拍一部可以在大多數系統上播放的視頻。如何將位圖轉換爲視頻?

在過去,我試過這個,但從來沒有成功。最近我被question觸發了,但唉,無法運行FFMpeg。

更新

我決定稍微適應的問題,並把賞金吧。我已經看到了幾個解決方案,但最吸引人的(因爲它很簡單)在我看來TAviWrite。我嘗試了TAviWriter,但沒有成功。在程序TAviWriter.Write;圍繞線370的函數調用

AVIERR := AVISaveV(s, 
//     pchar(FileName), 
       nil,     // File handler 
       nil,     // Callback 
       nStreams,    // Number of streams 
       Streams, 
       CompOptions);   // Compress options for VideoStream 

不返回AVIERR_OK。

更新2

原因上述錯誤是AVISaveV的一個錯誤的聲明,應該被聲明爲AVISaveVW作爲TLama指出。下面列出了用於創建AVI filoes表單BMP文件的正確代碼。下面的原始代碼是downloaded from efg與一個示例單位。

在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 [email protected]            // 
///////////////////////////////////////////////////////////////////////////// 

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, [email protected]     // 
// (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. 
+0

他們來自AviFil32,我將代碼添加到代碼示例中。由於代碼相當老,我認爲他們不提及unicode。我應該更換'程序AVIFileInit; STDCALL;外部'avifil32.dll'名稱'AVIFileInit''通過'procedure AVIFileInit; STDCALL;外部'avifil32.dll'名'AVIFileInitW''? – Arnold 2012-03-08 19:42:25

+0

做了你的建議和AddVideo的作品!現在試圖理解AVIsaveV中會發生什麼。同樣的建議是否適用於該功能? – Arnold 2012-03-08 19:45:32

+0

不,只有那些以'A'結尾的字符,但是你應該根據MSDN參考來驗證它。例如,如果你看[[AVIFileOpen]](http://msdn.microsoft.com/en-us/library/windows/desktop/dd756800%28v=vs.85%29.aspx),那麼你可以看到頁面底部是「Unicode和ANSI名稱」部分,本部分僅適用於具有ANSI和Unicode版本的函數。 – TLama 2012-03-08 19:47:36

回答

4

AVISaveV函數的導入部分更改爲它的Unicode版本。當Windows API參考中的函數具有註釋Unicode and ANSI names時,它對於您來說意味着,在Delphi中,您必須根據您使用的編譯器從Unicode版本的函數或ANSI函數中選擇。

您正在嘗試撥打AVISaveV,這在物理上不存在。這裏只有AVISaveVAavifil32.dllAVISaveVW既然你想這段代碼轉換爲Unicode,嘗試改變函數導入是這樣的:

function AVISaveV; external 'avifil32.dll' name 'AVISaveVW'; 

enter image description here

這僅僅是第一的思想,用代碼即使在Delphi的非Unicode版本中,像這樣的定義也不能工作,因爲它稱爲不存在的函數。

2

我用Mitov的視頻庫,像你描述的一個任務取得巨大成功用Delphi XE。它是免費的非商業用途,你可以下載一個副本玩。而且,它非常快。如果您使用的是英特爾芯片,那麼它會使用英特爾IPP庫來充分利用您的CPU架構。 http://software.intel.com/en-us/articles/intel-ipp/#support

我不斷被這個多任務圖書館的力量所打動。我以前發佈過關於它的內容,可能看起來我是他們的付費員工,但我不是。我只是驚訝於有多幸運(是的,幸運的),我是爲一個重大項目選擇這個圖書館。它永遠不會讓我失望。 有些東西值得付出,Mitov庫就是其中之一。良好的代碼,頻繁的更新,以及在必要時從開發人員獲得快速支持。

一定要查看Mitov的示例程序,同時會告訴您它是如何工作的。

這裏的網站:www.mitov.com

對不起,我沒有我可以分享任何來源。

+0

這看起來很有趣,我會檢查一下。謝謝。 – Arnold 2012-03-09 16:50:41

10

實際上有一個非常簡單的方法可以在不使用任何代碼的情況下使用ffmpeg來執行此操作。簡單地命名您的所有圖像文件是這樣的:

image-0001.png 

然後使用的ffmpeg將其打包成視頻:

ffmpeg -i 'img-%04d.png' -r 10 out.avi 

-r是輸出的幀速率。)

+0

這可能是一種可能性,但要求我從我的程序運行額外的程序,這不是我想要的。 – Arnold 2012-03-09 16:50:02

+0

如果你不想運行它(這可能是你的問題的一個快速解決方案),那麼你可以考慮找到一個ffmpeg DLL並通過庫調用調用它。 – 2012-03-12 15:59:52

+0

我的問題中的鏈接指向Delphi中FFMpeg的解決方案。我無法得到這個工作,這就是我轉向現在可以工作的AviWriter的原因(見代碼)。 – Arnold 2012-03-13 15:57:52