0

我在 WinAPI 上使用 JEDI 包装器中的 VFW 单元。

我正在编写的代码旨在搜索用户驱动器并检测warez。我们进行 MP3、WMA 和一些图形文件搜索。现在我们要检测非法电影。我想打开 AVI 文件,从中读取一些详细信息并关闭它。我有以下代码:

uses WFV; //from JEDI api wrappers

procedure TForm1.Button1Click(Sender: TObject);
var
  lInfo : TAVIFILEINFO      lFile : IAVIFILE;
  lFileType : string;
  lLenMinutes : integer;
  lFPS : integer;
begin
  {init file}
  AVIFileInit;
  {Open file - note: since we search for warez this is perfely "warezy" file}
  AVIFileOpen(lFile, 'e:\Sideways KLAXXON\Sideways KLAXXON.avi', OF_READ, nil);
  {Get file info}
  AVIFileInfoW(lFile, lInfo, sizeof(lInfo));
  lFPS:=Round(lInfo.dwRate /lInfo.dwScale);
  lLenMinutes := Round(lInfo.dwLength  / lFPS / 60);
  lFileType := lInfo.szFileType;
  {just for show: prepare some memo to see what we get}
  memo1.Lines.Clear;

  memo1.Lines.Add('File lenght [min]: ' + IntToStr(lLenMinutes));
  memo1.Lines.Add('Width: ' + IntToStr(lInfo.dwWidth));
  memo1.Lines.Add('Height: ' + IntToStr(lInfo.dwHeight));
  memo1.Lines.Add('File type: ' + lFileType);

  {Closing the file}
  AVIFileRelease (lFile);
  {and here goes the crash}
  FreeAndNil(lFile);

end;

有两个问题:

  1. lLenMinutes 等于 98,而电影大约是两个小时。dwRate 是 100 万,dwScale 是 40k,所以 FPS 是完美的 25。MSDN:“单位由 dwRate 和 dwScale 定义”。
  2. 代码在 FreeAndNil 行崩溃。为什么?我假设我负责释放 lFile(至少我觉得应该释放文件)。如果不符合 FreeAndNil,我在退出程序时会出现访问违规。

那么,您知道如何从 AVI 文件中正确获取电影时长吗?为什么会崩溃?

编辑

电影是 2 小时一分钟,所以结果应该非常接近 120。lFile 在 Jedi 中声明为:

IAVIFile = interface(IUnknown)

AVIFileOpen 在 JEDI 中声明为:

函数 AVIFileOpen(var ppfile: IAVIFILE; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; 标准调用;外部 AVIFILDLL 名称 'AVIFileOpenW';

在 MSDN 中:

STDAPI AVIFileOpen( PAVIFILE *ppfile, LPCTSTR szFile, UINT 模式, CLSID pclsidHandler );

MSDN 说:

“AVIFileOpen 函数打开一个 AVI 文件并返回用于访问它的文件接口的地址。”

所以我假设对象是由这个函数创建的。

编辑 2

avi 文件长度已移至新问题,因为 mghie 回答了这个问题。

4

2 回答 2

3

这些功能是成对的,AVIFileOpen()并且AVIFileRelease()属于一起。在AVIFileOpen()调用lFile变量之前是nil,之后(如果一切顺利)它包含一个接口指针。它的引用计数为 1。调用AVIFileRelease()变量后应该再次包含nil,但它没有。现在,当您的方法退出编译器提供的代码以释放接口指针时,将尝试减少已释放接口的引用计数。

你基本上有两种方法来解决这个问题:

  • 之后增加接口指针的引用计数AVIFileOpen()

  • 在不尝试减少引用计数的情况下重置变量。对指针使用类型转换:

    指针(lFile):=零;

此外,添加一个呼叫AVIFileExit()以匹配您对 的呼叫AVIFileInit()

于 2009-11-19T20:31:51.673 回答
1

98分钟是一个小时38分钟。什么是“大约两个小时”?

至于 FreeAndNil() 上的崩溃,它旨在释放 TObject 后代并将包含它的变量设置为 nil。您在代码中的何处创建 TObject 后代?这似乎lFile是一个接口,因此只需将变量设置为 nil 就足以减少引用计数:

lFile := nil;

FreeAndNil() 中对 Free 的调用可能是导致崩溃的原因。

编辑:根据对原始问题的编辑,显然上述不正确。但是,我怀疑对 的调用AVIFileRelease()已经释放了接口,因此您无事可做。lFile无论如何都会超出范围,并且引用计数将自动减少。

至于 MSDN 上的引用AVIFileOpen(),请注意它说它“返回文件接口的地址”。这是一个 COM 接口,它绝不是 Delphi 的TObject后代。JEDI 代码的片段也这么说,因为它说这IAviFile是一个interface(IUnknown)

于 2009-11-19T19:40:35.380 回答