{ AVIStream.pas : AVI stream class Written by maruguu 2004/08/31 } unit AVIStream; interface uses Windows, SysUtils, Graphics, VfW; type // AVIストリームクラス TAVIStream = class private FReady: Boolean; protected FAVIStream: PAVISTREAM; FAVIStreamInfo: TAVISTREAMINFOW; FGetFrame: PGETFRAME; FFrameCounter: Integer; function GetWidth(): Integer; function GetHeight(): Integer; function GetFPS(): Single; function GetLength(): Integer; procedure SetPosition(pos: Integer); public constructor Create(); destructor Destroy(); override; procedure Open(FileName: String); procedure Close(); procedure GetNextFrame(DIBBitmap: TBitmap); property Width: Integer read GetWidth; property Height: Integer read GetHeight; property FPS: Single read GetFPS; property Length: Integer read GetLength; property Position: Integer read FFrameCounter write SetPosition; property isReady: Boolean read FReady; end; implementation { TAVIStream } // ストリームを閉じる procedure TAVIStream.Close; begin FReady := False; if (Assigned(FGetFrame)) then begin AVIStreamGetFrameClose(FGetFrame); FGetFrame := nil; end; if (Assigned(FAVIStream)) then begin AVIStreamRelease(FAVIStream); FAVIStream := nil; end; end; // コンストラクタ constructor TAVIStream.Create; begin inherited; FAVIStream := nil; FGetFrame := nil; FReady := False; end; // デストラクタ destructor TAVIStream.Destroy; begin Close; inherited; end; // Frame Per Second取得 function TAVIStream.GetFPS: Single; begin Result := FAVIStreamInfo.dwRate / FAVIStreamInfo.dwScale; end; // 高さ取得 function TAVIStream.GetHeight: Integer; begin Result := FAVIStreamInfo.rcFrame.Bottom; end; // ストリーム長を取得 function TAVIStream.GetLength: Integer; begin Result := FAVIStreamInfo.dwLength; end; // 次のフレームを取得 procedure TAVIStream.GetNextFrame(DIBBitmap: TBitmap); var DIB: ^DWORD; BitmapInfoHeader: PBitmapInfoHeader; y, length: Integer; begin if(not isReady)then Raise EInvalidGraphic.Create('ファイルが開かれていません'); // 自動で巻き戻る if (DWORD(FFrameCounter) >= FAVIStreamInfo.dwLength) then FFrameCounter := 0; BitmapInfoHeader := AVIStreamGetFrame(FGetFrame, FFrameCounter); if (not Assigned(BitmapInfoHeader)) then Raise EInvalidGraphic.Create('フレーム取得に失敗'); // データの始まりの位置にセットする DIB := Pointer(Integer(BitmapInfoHeader) + SizeOf(TBITMAPINFOHEADER)); // バッファの1ラインの長さを計算 if (Width mod 4 = 0) then length := Width * 3 else length := Width * 3 + (4 - (Width * 3) mod 4); for y := 0 to Height - 1 do begin CopyMemory(DIBBitmap.ScanLine[Height - y - 1], DIB, length * sizeof(BYTE)); DIB := Pointer(Integer(DIB) + length * sizeof(BYTE)); end; Inc(FFrameCounter); end; // 幅取得 function TAVIStream.GetWidth: Integer; begin Result := FAVIStreamInfo.rcFrame.Right; end; // ファイルを開く procedure TAVIStream.Open(FileName: String); var re: Integer; BitmapInfoHeader: TBITMAPINFOHEADER; begin FReady := False; re := AVIStreamOpenFromFile(FAVIStream, PChar(FileName), streamtypeVIDEO, 0, OF_READ, nil); if re <> 0 then Raise EInvalidGraphic.Create('ファイルオープンに失敗'); re := AVIStreamInfo(FAVIStream, @FAVIStreamInfo, sizeof(TAVISTREAMINFOW)); if re <> AVIERR_OK then Raise EInvalidGraphic.Create('AVIストリームの情報取得に失敗'); ZeroMemory(@BitmapInfoHeader, sizeof(TBITMAPINFOHEADER)); BitmapInfoHeader.biSize := sizeof(TBITMAPINFOHEADER); BitmapInfoHeader.biWidth := Width; BitmapInfoHeader.biHeight := Height; BitmapInfoHeader.biPlanes := 1; BitmapInfoHeader.biBitCount := 24; BitmapInfoHeader.biCompression := BI_RGB; FGetFrame := AVIStreamGetFrameOpen(FAVIStream, @BitmapInfoHeader); if (not Assigned(FGetFrame)) then Raise EInvalidGraphic.Create('ストリームの設定に失敗'); FFrameCounter := 0; FReady := True; end; // ストリーム内での位置を指定 procedure TAVIStream.SetPosition(pos: Integer); begin FFrameCounter := pos; if (FFrameCounter < 0) Or (DWORD(FFrameCounter) >= FAVIStreamInfo.dwLength) then FFrameCounter := 0; end; // AVIFileInit, AVIFileExitは多重に行ってはいけない initialization AVIFileInit; finalization AVIFileExit; end.