2012-03-08 33 views
14

Ứng dụng của tôi tạo ra hình ảnh từ những khúc xương và tôi thích cảm giác 'bay' xung quanh một khúc xương. Tôi đã từng lưu khoảng 2000 bitmap để tạo và tạo một AVI từ nó bằng Premiere. Trải nghiệm đó khá thất vọng mặc dù tôi đã thành công trong việc tạo ra một bộ phim. Điều đó thật ngoạn mục. Tất nhiên tôi muốn tạo video từ ứng dụng của mình. Tôi thực sự không quan tâm đến sự tiện lợi của codec, nén hay bất cứ thứ gì. Tôi chỉ muốn có một video mà tôi có thể phát lại trên hầu hết các hệ thống.Làm cách nào để chuyển đổi bitmap thành video?

Trước đây tôi đã thử cách này nhưng chưa bao giờ thành công. Tôi đã được kích hoạt bởi một question gần đây nhưng than ôi không thể chạy FFMpeg.

Cập nhật

tôi quyết định để thích ứng với câu hỏi hơi và đặt một bounty cho nó. Tôi đã thấy một số giải pháp nhưng hấp dẫn nhất (vì nó đơn giản) dường như với tôi TAviWrite. Tôi đã thử TAviWriter nhưng không thành công. Trong thủ tục TAviWriter.Write; gọi hàm quanh dòng 370

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

không trả về AVIERR_OK.

Cập nhật 2

Lý do cho lỗi nêu trên là một lời tuyên bố sai AVISaveV, cần được khai báo là AVISaveVW như TLama chỉ ra. Mã đúng cho việc tạo các tập tin AVI dạng tập tin BMP được đăng dưới đây. Mã ban đầu bên dưới là downloaded from efg với một đơn vị mẫu.

Sử dụng Delphi XE trên 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

Họ đến từ AviFil32, tôi đã thêm tiêu đề vào ví dụ mã. Vì mã này khá cũ nên tôi cho rằng chúng không liên quan đến unicode. Tôi có nên thay thế 'thủ tục AVIFileInit; stdcall; bên ngoài 'avifil32.dll' tên 'AVIFileInit'' bởi' thủ tục AVIFileInit; stdcall; tên 'avifil32.dll' bên ngoài 'AVIFileInitW''? – Arnold

+0

Bạn đã làm gì và AddVideo hoạt động !. Hiện đang cố gắng hiểu những gì xảy ra trong AVIsaveV. Liệu cùng một loại lời khuyên áp dụng cho chức năng đó? – Arnold

+0

Không, chỉ những cái kết thúc bằng 'A' char, nhưng bạn nên xác minh nó theo tham chiếu MSDN. Ví dụ: nếu bạn nhìn vào ['AVIFileOpen'] (http://msdn.microsoft.com/en-us/library/windows/desktop/dd756800%28v=vs.85%29.aspx) thì bạn có thể thấy phần dưới cùng của trang là phần 'Unicode và ANSI' và phần này chỉ có sẵn cho các chức năng có phiên bản ANSI và Unicode. – TLama

Trả lời

4

Thay đổi phần nhập của hàm AVISaveV thành phiên bản Unicode của nó. Khi hàm trong tham chiếu API của Windows có ghi chú Unicode and ANSI names nó có nghĩa là cho bạn, trong Delphi, bạn phải chọn từ phiên bản Unicode của hàm hoặc từ ANSI tùy thuộc vào trình biên dịch bạn sẽ sử dụng.

Bạn đang cố gọi số AVISaveV, vật lý không tồn tại. Chỉ có AVISaveVAAVISaveVW trong avifil32.dll và kể từ khi bạn muốn chuyển đổi mã này vào Unicode, cố gắng thay đổi khẩu chức năng theo cách này:

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

enter image description here

Đây chỉ là một ý nghĩ đầu tiên, mã với định nghĩa như đã không thể làm việc ngay cả trong các phiên bản Unicode không của Delphi, bởi vì nó được gọi là hàm không tồn tại.

2

Tôi đã sử dụng thư viện video Mitov với thành công rực rỡ về nhiệm vụ giống như bạn mô tả. Nó hoàn toàn miễn phí cho mục đích phi thương mại và bạn có thể tải xuống bản sao để chơi. Và, nó rất nhanh. Nếu bạn đang sử dụng chip Intel, nó sử dụng thư viện Intel IPP để tận dụng tối đa kiến ​​trúc CPU của bạn. http://software.intel.com/en-us/articles/intel-ipp/#support

Tôi liên tục bị thổi bay bởi sức mạnh của thư viện đa tác vụ này. Tôi đã đăng về nó trước đây, và nó có vẻ như tôi là một nhân viên trả tiền cho họ, nhưng tôi thì không. Tôi chỉ ngạc nhiên về cách may mắn (có, may mắn) Tôi đã chọn thư viện này cho một dự án lớn. Nó không bao giờ làm tôi thất vọng. Một số điều đáng để trả tiền, và các thư viện Mitov là một trong số đó. Mã tốt, cập nhật thường xuyên và hỗ trợ nhanh chóng ngay từ các nhà phát triển khi cần thiết.

Hãy chắc chắn kiểm tra các chương trình mẫu của Mitov, trong khi sẽ cung cấp cho bạn ý tưởng tốt về cách hoạt động của chương trình.

Dưới đây là trang web: www.mitov.com

Xin lỗi tôi không có bất kỳ nguồn tôi có thể chia sẻ.

+0

Điều này có vẻ thú vị, tôi sẽ kiểm tra điều này. Cảm ơn. – Arnold

10

Có một cách thực sự dễ dàng để thực hiện việc này bằng cách sử dụng ffmpeg mà không cần bất kỳ mã nào. Đơn giản chỉ cần đặt tên cho tất cả các file hình ảnh của bạn một cái gì đó như:

image-0001.png 

Sau đó sử dụng ffmpeg để bó chúng lại thành một đoạn video:

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

(-r là tỷ lệ khung hình đầu ra.)

+0

Điều này có thể là một khả năng, nhưng yêu cầu tôi chạy một chương trình bổ sung từ chương trình của tôi mà không phải là những gì tôi muốn. – Arnold

+0

Nếu bạn không muốn chạy nó (mà có lẽ sẽ là một giải pháp nhanh cho vấn đề của bạn) thì bạn có thể xem xét để tìm một ffmpeg dll và gọi nó thông qua một cuộc gọi thư viện. –

+0

Liên kết trong câu hỏi của tôi chỉ ra một giải pháp cho FFMpeg ở Delphi.Tôi không thể có được rằng làm việc, đó là lý do tôi chuyển đến AviWriter mà bây giờ hoạt động (xem mã). – Arnold

Các vấn đề liên quan