Mega Code Archive

 
Categories / Delphi / Graphic
 

BMPs to AVI file for TAnimate

Title: BMP's to AVI file for TAnimate Question: TAnimate is a rather nice component. However if you don't want to use the built in AVI files and want to create your own AVI files from BMP files, then you may have a problem as there is no tool in Delphi to do this. While browsing the web for information on AVI file formats I came upon a site www.shrinkwrapvb.com/avihelp/avihelp.htm that is maintained by Ray Mercer. In this tutorial he explains how to manipulate,read and write AVI files. I was particularly interested in "Step 5" in which he shows a utility that takes a list of BMP files that creates an AVI file which can be used by the TAnimate component. The only problem was that the examples are in Visual Basic, thus a conversion to Delphi was required. I have posted the procedure CreateAVI(const FileName : string; BMPFileList : TStrings; FramesPerSec : integer = 10); To keep the text of the example simple and readable I have left out most to the error checking (try except etc.). You can also play with the AVISaveOptions dialog box, but I can only seem to get it to work with "Full Frames Uncompressed" with BMP files. Can anyone shed some light on this ? Errors you should check for are .. All files are valid BMP files and are of the same size. All Blockreads are valid with no read errors. Ray has a downloadable EXE that works quite nicely, however I am about to write my own utility that incorporates the following ... Multiline file selection. Listbox line reordering (drag/drop). Sort File list Layout Save and Load . AVI Preview. (I have beta version 1.0.0.0 ready, if anyone wants a copy of exe or source code, drop me a mail at mheydon@eoh.co.za) For further info on AVI files I recommend you vist Ray's site at www.shrinkwrapvb.com/avihelp/avihelp.htm it really is a well written tutorial (even if it is in Visual Basic) Answer: const // AVISaveOptions Dialog box flags ICMF_CHOOSE_KEYFRAME = 1; // show KeyFrame Every box ICMF_CHOOSE_DATARATE = 2; // show DataRate box ICMF_CHOOSE_PREVIEW = 4; // allow expanded preview dialog ICMF_CHOOSE_ALLCOMPRESSORS = 8; // don't only show those that // can handle the input format // or input data AVIIF_KEYFRAME = 10; type AVI_COMPRESS_OPTIONS = packed record fccType : DWORD; // stream type, for consistency fccHandler : DWORD; // compressor dwKeyFrameEvery : DWORD; // keyframe rate dwQuality : DWORD; // compress quality 0-10,000 dwBytesPerSecond : DWORD; // bytes per second dwFlags : DWORD; // flags... see below lpFormat : DWORD; // save format cbFormat : DWORD; lpParms : DWORD; // compressor options cbParms : DWORD; dwInterleaveEvery : DWORD; // for non-video streams only end; AVI_STREAM_INFO = packed record fccType : DWORD; fccHandler : DWORD; dwFlags : DWORD; dwCaps : DWORD; wPriority : word; wLanguage : word; dwScale : DWORD; dwRate : DWORD; dwStart : DWORD; dwLength : DWORD; dwInitialFrames : DWORD; dwSuggestedBufferSize : DWORD; dwQuality : DWORD; dwSampleSize : DWORD; rcFrame : TRect; dwEditCount : DWORD; dwFormatChangeCount : DWORD; szName : array [0..63] of char; end; BITMAPINFOHEADER = packed record biSize : DWORD; biWidth : DWORD; biHeight : DWORD; biPlanes : word; biBitCount : word; biCompression : DWORD; biSizeImage : DWORD; biXPelsPerMeter : DWORD; biYPelsPerMeter : DWORD; biClrUsed : DWORD; biClrImportant : DWORD; end; BITMAPFILEHEADER = packed record bfType : word; //"magic cookie" - must be "BM" bfSize : integer; bfReserved1 : word; bfReserved2 : word; bfOffBits : integer; end; // DLL External declarations function AVISaveOptions(Hwnd : DWORD; uiFlags : DWORD; nStreams : DWORD; pPavi : Pointer; plpOptions : Pointer) : boolean; stdcall; external 'avifil32.dll'; function AVIFileCreateStream(pFile : DWORD; pPavi : Pointer; pSi : Pointer) : integer; stdcall; external 'avifil32.dll'; function AVIFileOpen(pPfile : Pointer; szFile : PChar; uMode : DWORD; clSid : DWORD) : integer; stdCall; external 'avifil32.dll'; function AVIMakeCompressedStream(psCompressed : Pointer; psSource : DWORD; lpOptions : Pointer; pclsidHandler : DWORD) : integer; stdcall; external 'avifil32.dll'; function AVIStreamSetFormat(pAvi : DWORD; lPos : DWORD; lpGormat : Pointer; cbFormat : DWORD) : integer; stdcall; external 'avifil32.dll'; function AVIStreamWrite(pAvi : DWORD; lStart : DWORD; lSamples : DWORD; lBuffer : Pointer; cBuffer : DWORD; dwFlags : DWORD; plSampWritten : DWORD; plBytesWritten : DWORD) : integer; stdcall; external 'avifil32.dll'; function AVISaveOptionsFree(nStreams : DWORD; ppOptions : Pointer) : integer; stdcall; external 'avifil32.dll'; function AVIFileRelease(pFile : DWORD) : integer; stdcall; external 'avifil32.dll'; procedure AVIFileInit; stdcall; external 'avifil32.dll'; procedure AVIFileExit; stdcall; external 'avifil32.dll'; function AVIStreamRelease(pAvi : DWORD) : integer; stdcall; external 'avifil32.dll'; function mmioStringToFOURCCA(sz : PChar; uFlags : DWORD) : integer; stdcall; external 'winmm.dll'; // ============================================================================ // Main Function to Create AVI file from BMP file listing // ============================================================================ procedure CreateAVI(const FileName : string; IList : TStrings; FramesPerSec : integer = 10); var Opts : AVI_COMPRESS_OPTIONS; pOpts : Pointer; pFile,ps,psCompressed : DWORD; strhdr : AVI_STREAM_INFO; i : integer; BFile : file; m_Bih : BITMAPINFOHEADER; m_Bfh : BITMAPFILEHEADER; m_MemBits : packed array of byte; m_MemBitMapInfo : packed array of byte; begin DeleteFile(FileName); Fillchar(Opts,SizeOf(Opts),0); FillChar(strhdr,SizeOf(strhdr),0); Opts.fccHandler := 541215044; // Full frames Uncompressed AVIFileInit; pfile := 0; pOpts := @Opts; if AVIFileOpen(@pFile,PChar(FileName),OF_WRITE or OF_CREATE,0) = 0 then begin // Determine Bitmap Properties from file item[0] in list AssignFile(BFile,IList[0]); Reset(BFile,1); BlockRead(BFile,m_Bfh,SizeOf(m_Bfh)); BlockRead(BFile,m_Bih,SizeOf(m_Bih)); SetLength(m_MemBitMapInfo,m_bfh.bfOffBits - 14); SetLength(m_MemBits,m_Bih.biSizeImage); Seek(BFile,SizeOf(m_Bfh)); BlockRead(BFile,m_MemBitMapInfo[0],length(m_MemBitMapInfo)); CloseFile(BFile); strhdr.fccType := mmioStringToFOURCCA('vids', 0); // stream type video strhdr.fccHandler := 0; // def AVI handler strhdr.dwScale := 1; strhdr.dwRate := FramesPerSec; // fps 1 to 30 strhdr.dwSuggestedBufferSize := m_Bih.biSizeImage; // size of 1 frame SetRect(strhdr.rcFrame,0,0,m_Bih.biWidth,m_Bih.biHeight); if AVIFileCreateStream(pFile,@ps,@strhdr) = 0 then begin // if you want user selection options then call following line // (but seems to only like "Full frames Uncompressed option) // AVISaveOptions(Application.Handle, // ICMF_CHOOSE_KEYFRAME or ICMF_CHOOSE_DATARATE, // 1,@ps,@pOpts); // AVISaveOptionsFree(1,@pOpts); if AVIMakeCompressedStream(@psCompressed,ps,@opts,0) = 0 then begin if AVIStreamSetFormat(psCompressed,0,@m_memBitmapInfo[0], length(m_MemBitMapInfo)) = 0 then begin for i := 0 to IList.Count - 1 do begin AssignFile(BFile,IList[i]); Reset(BFile,1); Seek(BFile,m_bfh.bfOffBits); BlockRead(BFile,m_MemBits[0],m_Bih.biSizeImage); Seek(BFile,SizeOf(m_Bfh)); BlockRead(BFile,m_MemBitMapInfo[0],length(m_MemBitMapInfo)); CloseFile(BFile); if AVIStreamWrite(psCompressed,i,1,@m_MemBits[0], m_Bih.biSizeImage,AVIIF_KEYFRAME,0,0) 0 then begin ShowMessage('Error during Write AVI File'); break; end; end; end; end; end; AVIStreamRelease(ps); AVIStreamRelease(psCompressed); AVIFileRelease(pFile); end; AVIFileExit; m_MemBitMapInfo := nil; m_memBits := nil; end;