I am using VFW unit from JEDI wrapper on WinAPI.
The code I am writing is intended to search user drives and detect warez. We do MP3, WMA and some graphic file search. Now we want to detect illegal movies. I want to open AVI file, read some details from it and close it. I have the following code:
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;
There are two problems:
- The lLenMinutes is something equal to 98 while the movie is about two hours. dwRate is 1 million and dwScale is 40k, so the FPS is perfectly 25. MSDN says: “The units are defined by dwRate and dwScale”.
- The code crashes on FreeAndNil line. Why? I assume I am responsible for freeing lFile (and at least I feel supposed to release file). Without line with FreeAndNil, I have Acces Violation on exit from a procedure.
So, do you have any clue how to correctly obtain movie duration from AVI file? And why the crash?
Edit
The movie is 2hours one minute, so the result should be really close to 120.The lFile is declared in Jedi as:
IAVIFile = interface(IUnknown)
the AVIFileOpen is declared in JEDI as:
function AVIFileOpen(var ppfile: IAVIFILE; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall; external AVIFILDLL name 'AVIFileOpenW';
and in MSDN:
STDAPI AVIFileOpen( PAVIFILE *ppfile, LPCTSTR szFile, UINT mode, CLSID pclsidHandler );
MSDN says:
开发者_如何学C"The AVIFileOpen function opens an AVI file and returns the address of a file interface used to access it."
so I assume object is created by this function.
Edit 2
The avi file length has been move to new question, since mghie answered this question.
The functions are paired, AVIFileOpen()
and AVIFileRelease()
belong together. Before AVIFileOpen()
is called the lFile
variable is nil
, afterwards (if all went well) it contains an interface pointer. It has the reference count 1. After calling AVIFileRelease()
the variable should again contain nil
, but it doesn't. Now when your method exits the compiler-provided code to release interface pointers will try to decrement the reference count of the already released interface.
You have basically two ways to fix this:
Increment the reference count of the interface pointer after
AVIFileOpen()
.Reset the variable without trying to decrement the reference count. Use a typecast to a pointer:
pointer(lFile) := nil;
Also, add a call to AVIFileExit()
to match your call to AVIFileInit()
.
98 minutes is an hour and 38 minutes. What is "about two hours"?
As for the crash on FreeAndNil(), it's designed to free a TObject descendant and set the variable containing it to nil. Where do you create a TObject descendant in your code? It appears that lFile
is an interface, so simply setting the variable to nil should be enough to decrement the reference count:
lFile := nil;
The call to Free inside FreeAndNil() is probably what's causing the crash.
EDIT: Based on the edits to the original question, obviously the above isn't correct. However, I'd suspect that the call to AVIFileRelease()
has already freed the interface, and therefore there's nothing left for you to do. lFile
is going out of scope anyway, and the reference count will be decremented automatically.
As far as the MSDN quote on AVIFileOpen()
, note that it says that it "returns the address of a file interface". This is a COM interface, which in no way, shape or form is a Delphi TObject
descendant. The snippet from the JEDI code says so as well, as it says that IAviFile
is an interface(IUnknown)
精彩评论