如何能够获得视频文件的头一帧(或者是第二帧),并且把它保存为图片?(100分)

  • 主题发起人 主题发起人 ArJianzeng
  • 开始时间 开始时间
A

ArJianzeng

Unregistered / Unconfirmed
GUEST, unregistred user!
如何能够获得视频文件的头一帧,并且把它保存为图片(bmp格式或者jpg格式都可以)?
 
觉得应该去看看一些GDI的API函数就能解决问题
 
//从AVi文件中提取任何一帧作为图片

uses
VfW { from download };

function GrabAVIFrame(avifn: string; iFrameNumber: Integer; ToFileName: TFileName): Boolean;
var
Error: Integer;
pFile: PAVIFile;
AVIStream: PAVIStream;
gapgf: PGETFRAME;
lpbi: PBITMAPINFOHEADER;
bits: PChar;
hBmp: HBITMAP;
AviInfo: TAVIFILEINFOW;
sError: string;
TmpBmp: TBitmap;
DC_Handle: HDC;
begin
Result := False;
// Initialize the AVIFile library.
AVIFileInit;

// The AVIFileOpen function opens an AVI file
Error := AVIFileOpen(pFile, PChar(avifn), 0, nil);
if Error <> 0 then
begin
AVIFileExit;
case Error of
AVIERR_BADFORMAT: sError := 'The file couldn''t be read';
AVIERR_MEMORY: sError := 'The file could not be opened because of insufficient memory.';
AVIERR_FILEREAD: sError := 'A disk error occurred while reading the file.';
AVIERR_FILEOPEN: sError := 'A disk error occurred while opening the file.';
end;
ShowMessage(sError);
Exit;
end;

// AVIFileInfo obtains information about an AVI file
if AVIFileInfo(pFile, @AVIINFO, SizeOf(AVIINFO)) <> AVIERR_OK then
begin
// Clean up and exit
AVIFileRelease(pFile);
AVIFileExit;
Exit;
end;

// Show some information about the AVI
Form1.Memo1.Lines.Add('AVI Width : ' + IntToStr(AVIINFO.dwWidth));
Form1.Memo1.Lines.Add('AVI Height : ' + IntToStr(AVIINFO.dwHeight));
Form1.Memo1.Lines.Add('AVI Length : ' + IntToStr(AVIINFO.dwLength));

// Open a Stream from the file
Error := AVIFileGetStream(pFile, AVIStream, streamtypeVIDEO, 0);
if Error <> AVIERR_OK then
begin
// Clean up and exit
AVIFileRelease(pFile);
AVIFileExit;
Exit;
end;

// Prepares to decompress video frames
gapgf := AVIStreamGetFrameOpen(AVIStream, nil);
if gapgf = nil then
begin
AVIStreamRelease(AVIStream);
AVIFileRelease(pFile);
AVIFileExit;
Exit;
end;

// Read current Frame
// AVIStreamGetFrame Returns the address of a decompressed video frame
lpbi := AVIStreamGetFrame(gapgf, iFrameNumber);
if lpbi = nil then
begin
AVIStreamGetFrameClose(gapgf);
AVIStreamRelease(AVIStream);
AVIFileRelease(pFile);
AVIFileExit;
Exit;
end;

// Show number of frames:
Form1.Memo1.Lines.Add(Format('Framstart: %d FrameEnd: %d',
[AVIStreamStart(AVIStream), AVIStreamEnd(AVIStream)]));

TmpBmp := TBitmap.Create;
try
TmpBmp.Height := lpbi.biHeight;
TmpBmp.Width := lpbi.biWidth;
bits := Pointer(Integer(lpbi) + SizeOf(TBITMAPINFOHEADER));

DC_Handle := CreateDC('Display', nil, nil, nil);
try
hBmp := CreateDIBitmap(DC_Handle, // handle of device context
lpbi^, // address of bitmap size and format data
CBM_INIT, // initialization flag
bits, // address of initialization data
PBITMAPINFO(lpbi)^, // address of bitmap color-format data
DIB_RGB_COLORS); // color-data usage
finally
DeleteDC(DC_Handle);
end;

TmpBmp.Handle := hBmp;
AVIStreamGetFrameClose(gapgf);
AVIStreamRelease(AVIStream);
AVIFileRelease(pfile);
AVIFileExit;
try
TmpBmp.SaveToFile(ToFileName);
Result := True;
except
end;
finally
TmpBmp.Free;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
// Extract Frame 3 from AVI file
GrabAVIFrame('C:/Test.avi', 3, 'c:/avifram.bmp');
end;
 
给个DirectShow9的你,Windows Media Player能播放的就能截,自己改一下吧,其实不怎么好用,因为得到的高宽不一定准确,指定的频不能精确到毫秒,只是能截Windows Media Player能播放文件。[:)]
procedure TMainForm.GetBmp02;
var
dsMediaDet: IMediaDet;
dsMediaType: TAMMEDIATYPE;
dsMediaStreams, i, VideoStream: Integer;
p: int64;
begin
if MediaSeeking <> nil then
MediaSeeking.GetCurrentPosition(p)
else
p := 0;
p := Trunc(p / 10000000);
VideoStream := 0;
if FileExists(Media_FileName) = True then
if CoCreateInstance
(CLSID_MediaDet, nil, CLSCTX_INPROC, IID_IMediaDet, dsMediaDet) = S_OK then
if dsMediaDet.put_FileName(Media_FileName) = S_OK then
if dsMediaDet.get_OutputStreams(dsMediaStreams) = S_OK then
if dsMediaStreams > 0 then
begin
for i := 0 to dsMediaStreams - 1 do
if dsMediaDet.put_CurrentStream(i) = S_OK then
if dsMediaDet.get_StreamMediaType(dsMediaType) = S_OK then
if IsEqualGUID(dsMediaType.FormatType, FORMAT_VideoInfo) then
begin
VideoStream := i;
Break;
end;
if dsMediaDet.put_CurrentStream(VideoStream) = S_OK then
if dsMediaDet.get_StreamMediaType(dsMediaType) = S_OK then
begin
if IsEqualGUID(dsMediaType.FormatType, FORMAT_VideoInfo) then
begin
// dsMediaWidth :=
// Abs(TVIDEOINFOHEADER(dsMediaType.pbFormat^).bmiHeader.biWidth);
// dsMediaHeight :=
// Abs(TVIDEOINFOHEADER(dsMediaType.pbFormat^).bmiHeader.biHeight);
if dsMediaDet.WriteBitmapBits(p, Video_Width,
Video_Height, GetF) <> S_OK then
ShowMessage('Failed to Grab Image - Sorry');
end;
FreeMediaType(@dsMediaType);
// Sleep(2000);
end;
end;
dsMediaDet := nil;
end;
 
多人接受答案了。
 
后退
顶部