PDA

View Full Version : [want help]read the size of a frame in avi


MeteorRain
22nd June 2005, 05:17
i want to write a program which need to read thougthout an avi file and get the size of every frame. what apis should i use?
i have search the msdn and found those apis below:
AVIBuildFilter
AVIClearClipboard
AVIFileAddRef
AVIFileCreateStream
AVIFileEndRecord
AVIFileExit
AVIFileGetStream
AVIFileInfo
AVIFileInit
AVIFileOpen
AVIFileReadData
AVIFileRelease
AVIFileWriteData
AVIGetFromClipboard
AVIMakeCompressedStream
AVIMakeFileFromStreams
AVIMakeStreamFromClipboard
AVIPutFileOnClipboard
AVISave
AVISaveOptions
AVISaveOptionsFree
AVISaveV
AVIStreamAddRef
AVIStreamBeginStreaming
AVIStreamCreate
AVIStreamEndStreaming
AVIStreamFindSample
AVIStreamGetFrame
AVIStreamGetFrameClose
AVIStreamGetFrameOpen
AVIStreamInfo
AVIStreamLength
AVIStreamOpenFromFile
AVIStreamRead
AVIStreamReadData
AVIStreamReadFormat
AVIStreamRelease
AVIStreamSampleToTime
AVIStreamSetFormat
AVIStreamStart
AVIStreamTimeToSample
AVIStreamWrite
AVIStreamWriteData

i would like to write the program in purebasic so a C-style guide is ok
plz give me some hint, appriciate!

regards,
MeteorRain

Inc
22nd June 2005, 23:59
Here a "logic" of catching Video data in Purebasic using the "avifil32.dll" in your System.

OpenLibrary ( #Lib , "AVIFIL32.DLL")
CallFunction ( #Lib, "AVIFileInit" )
avifile.s = OpenFileRequester ( "Select Video File", "", "Video|*.avi; *.avs; *.*", 0 )

res = CallFunction( Lib, "AVIFileOpen", @pAVIFile, @avifile.s, #OF_SHARE_DENY_WRITE, 0 )

If res = 0; #AVI_ERR_OK
res = CallFunction( Lib, "AVIFileGetStream", pAVIFile, @pAVIStream, $73646976, 0 )
If res = 0; #AVI_ERR_OK
firstFrame = CallFunction( Lib, "AVIStreamStart", pAVIStream )
pGetFrameObj = CallFunction( Lib, "AVIStreamGetFrameOpen", pAVIStream, 1 )
*bih.BITMAPINFOHEADER = CallFunction( Lib.l, "AVIStreamGetFrame", pGetFrameObj, firstFrame )
Width= *bih\biWidth
Height= *bih\biHeight
MessageRequester( "Width & Height", Str(Width) + " x " + Str(Height), 0 )
CallFunction( Lib, "AVIStreamGetFrameClose", pGetFrameObj )
EndIf
CallFunction( Lib, "AVIFileRelease", pAVIFile )
EndIf

As you can see above the structure of the BITMAPINFOHEADER has been catched and stored to the pointer *bih\xxxxx

And here is the rest of that structure you can readout using the example above

typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_1rw2.asp

MeteorRain
23rd June 2005, 04:21
well the program you give runs perfact but it seems that it can't obtain what i need.
i need to know the size of a frame, but the one above can only get a number like 614400 or so, is 640*480*2.
what i need is like this:
6574
0
4046
0
8
0
6878
0
7306
0
7848
0
8771
0
9139
0
10017
0
10220
0
10505
0
10258
......many lines

more ideas?
appriciate!
MeteorRain

Inc
23rd June 2005, 13:09
What do you need?

Size seen in amount of bits or ..
Size seen as image proportion?

MeteorRain
24th June 2005, 04:48
What do you need?
Size seen in amount of bits or ..
Size seen as image proportion?
well, my program aim to find out all NULL(dropped) frame in a 120fps japanese anime. so get the actually size of a frame and see if it's zero is it's work.
(what? you have misunderstood? Oooops!)

vhelp
25th June 2005, 04:18
@ meteorRain

What about comparing frames (BITMAP) instead ??

Correct me if I'm wrong, but from my experience, isn't a dropped
frame represented as a duplicate frame of previous frame ??

Example:

if frame_no = frame_no+1 then dup_found=true

If so, then the above would probably be the best method, perhaps.
Or, would it be too slow. I don't know. Just thinking..

-vhelp

MeteorRain
25th June 2005, 04:24
well, it seems to be *too* slow...
if you just compare 1000 frame it doesn't matter. but when you are dealing with 300000 frames, the computer will be exhasted...

in fact, the software 'DivX DRF Analyzer' have the same function as mine.
my program *now* can be feed *.drf and workout the message about 120fps VFR information.
but i want to make it eat avi so that we don't need *another program* any longer.....

vhelp
25th June 2005, 04:34
hmm.. now you got me interestested in the timing of bitmap comparisons.
I never really did do any *real test* of comparing two bitmaps. I must
try this.., I'm really curious now. Anyways.., I hope you figure it out :)

-vhelp

vhelp
25th June 2005, 04:46
I remember something about a "dropped frame" flag. So, I did a little
research, and came up with this below (orig. url link 'html' ver is below,
or you can D/L the .pdf file) ...

Dropped Frames

When frames are dropped by the driver, AVICap32 detects that a frame has
been dropped and inserts a dropped frame placeholder. During playback,
when one or more dropped frame placeholders are encountered the last captured
frame is edisplayed until the next captured frame is reached. Codecs also reuse
the last captured frame in this instance.

Original URL:
* Multimedia (http://64.233.161.104/search?q=cache:uuKsNYJPHF8J:www.nomadelectronics.com/VidCap/Capture%2520using%2520VFW/CAPTURE.DOC+avi+flag+%22dropped+frame%22&hl=en)

If this works or you find the solution, do post back :)

-vhelp

MeteorRain
25th June 2005, 09:35
your link doesn't work for me, but i google it!

seems that only these are related
When frames are dropped by the driver, AVICap32 detects that a frame has been dropped and inserts a “dropped frame” placeholder. During playback, when one or more dropped frame placeholders are encountered the last captured frame is redisplayed until the next captured frame is reached. Codecs also reuse the last captured frame in this instance.
Each dropped frame placeholder occupies only 8 bytes in the capture file; if there are two or more consecutive dropped frames they are stored in the same sector. (Each captured frame, or block of dropped frames, starts on a new sector). The draw devices and codecs will not see the dropped frames unless you parse the AVI file manually.
but nothing useful.
does he want me to parse the avi file manually? Oooop!

well, maybe some dynamic link library can be used to do these things. let's find them...
===============================
well, i think i should have a read about the VDM source code ^_^|||
and as well as AVI-Mux GUI

vhelp
25th June 2005, 17:42
regarding link..

Strange, it works for me. Just tired it, works :)

>> does he want me to parse the avi file manually? Oooop!

If everything else points to that, then I would say, yes.
(Actually, that was my first suggest, though I did not make it)
.
When it comes to parsing AVI's manually, w/out the help of all those
API 's, yeah.., I'm slow at understanding a few things. But then, I
have a tone of things on my plate.

What I'd like to do, (has been my goal for a long time now) is open an
AVI manually, and parse through it, to extract each frame (BITMAP) w/out
any API's or AVIcap32 or whatever helper, and do any necessary work on it.
That is something I have not found easy to figure out - yet.

w/out going OT here..

About the most I've done so far in AVI retreaving and things, is
something like this:

http://www.westnet.com/~vhelp/im/avic.jpg

There are other things I wont to do (including extract frames, find
out total dropped frames, etc etc etc, and put inside this apps window
as information to the user. this was done w/out any avi library's..
all done manually.

-vhelp

MeteorRain
25th June 2005, 18:30
all done manually is cool, but warp the functions into a dll is far more cool:p
good job you have done. may be we should turn to the author of avimux gui and ask for help:)

vhelp
25th June 2005, 18:56
Yes. I would prefer to do it manually myself too :)
This way, I have complete control, and knowledge (of avi)
(regarding the pic above.. I 'cut' out a section of my tool and
posted it here, but the .jpg came out louzy)

yeah, that sounds great, about contacting the author for info,
(knowledge) -- (but, fwiw.. I'm pretty bad at writing formal requests)

I was thinking about the avi parse though.
.
Assuming the AVI is DV ...
.
Say we open and find the area that holds the bitmap data, (and forgetting
about the audio for this scenario) after retreaving the data section,
(ie, say it was a 720 x 480 area of pixels, in this case, YUV pixels)
and because we know that it is DV format, then the next thing would be to
somehow call up a DV codec (link it into the routine) to decompress that
area (any area we define) and then push the now decompressed image onto
an image control.


Assuming we have an textbox; button; and an image control; on our form..

1 - open avi
2 - parse it and find image area (x,y) or something like that
3 - call codec
4 - w/ codec, decompress image area (push image are into a grid array
that codec would understand and ustilize in its method to process
5 - with codec pointing to our image control, finally display the image



This rough analigy could be fine-tuned of course, once the principle of
retrieving the image is understood.
.
I know there is a lot more to it, but this just a basic practice run
to retreave an image area and display it. Later, one could build on
this, by adding more user functions, making the process more meaningful
and worth-while.

I'd like to figure this out.

-vhelp

vhelp
25th June 2005, 19:57
Yes, I missed that part about making it into a DLL for other
languages to use. It would be a great excercise though. I love it.

Just to see it work cmd-line wise, would be nice.

psuedo-code wise, I have the following invisioned in my head:

We could create a basic libriary of calling subroutines, that
other languages could use through the DLL pathway:
(I can't help but feel that something is missing here, (this is
just off the top of my head) but please feel free to make any
comments/revise/correct/add ect)

* Procedure openAVI(f: TFileStruct; fname: String)
* Function getFRAMECount(f: TFileStruct): Longint;
* Function getFRAME(f: TFileStruct; frameNo: Longint): TBitmap;
* Function findDroppedFrameNo(f: TFileStruct): Longint;
* Function getTotalDroppedFrames(f: TFileStruct): Longint;

.
.

To display in an image control:
* image1 := getFRAME(f, frameNo);

To display total frame count in a textbox:
* totalFrameCount.text := intTostr( getFRAMECount(f) );

To display total dropped frames in a textbox:
* totalDroppedFrames.text := intTostr( findDroppedFrameNo(f) );


How does the above sound for starts ?

I would be happy if we could just be able to at least first
fill an image control on a given form. Lets learn how to do
this first.. and then build afterwards.

Remember, this is a bruet-force, direct approach. No AVI library's
(as in your list in your first post) are involved here.., with the
exception of having to call a codec DLL only to decompress an area
in memory.

I'm a Delphi/Pascal developer. If you are a C/C++ developer, then we could
test each other's DLL across these platforms to see if the new subroutines
work. Interesting ??

So, if you think its worth further investigating, great. Otherwise,
it was fun idea :)

-vhelp

MeteorRain
26th June 2005, 04:09
well, very good idea!
but it seems that when you decoding the avi, you need a VFW codec?

and I have already send an e-mail to the author of avimux gui, and just received the reply. i post them here:

>Hello, noe.
> I am a Chinese user of AVI-Mux GUI. Now I am considering to write
> a software which can parse and scan an AVI file and see if a frame is
> null (dropped) frame or an ordinary frame.
> I am interested about your project and thinking of taking advantage
> of your source code. But I have no idea when seeing a lot of .h and .cpp
> files. So, would you like to point me which files are related so i can
> read them and study.
>
The files you need are AVIFile.h and AVIFile.cpp

> Or, would you please give me some idea about how to
> do such work like finding null frames.
>
>
Just look for frames with size 0 in the index (in the sourcecode, look
for "idx1" and "indx",
that should point you to the relevant pieces of code)

regards,
Alex

maybe a study on the avifile.* is a good idea.

==edit==
I'm a Delphi/Pascal developer. If you are a C/C++ developer, then we could test each other's DLL across these platforms to see if the new subroutines work. Interesting ??
Oh, i learn the pascal in my junior middle school, and now i often use PHP and "E language" (i know you must say you haven't hear it, because it's a programming language in Chinese), now i am trying PureBasic.
==/edit==

regards,
MeteorRain ^_^

Inc
26th June 2005, 06:17
Sorry to interrupt you, but did I understand right, you will avoid API calls?
Why? Even latest developements do use API calls on the avifil32.dll in the system. Thats also how Qenc is able to catch frames from avisynth sources. So it the quite sexiest way to get frames for comparing purposes.

I wrote a collection of frame procedures via vfw in purebasic, they are maybe still buggy as I just copy/pasted them into one project file out of some program code of mine for a procedure collection purpose, so watch the variables!

; --------------------------------- Catching Single Frame --------------------------------

Procedure GetAviVideoFrame (Lib.l, avifile.s, frame.l, ImageGadgetNo.l)
res = CallFunction( Lib, "AVIFileOpen", @pAVIFile, @avifile.s, #OF_SHARE_DENY_WRITE, 0 )

If res = 0; #AVI_ERR_OK
res = CallFunction( Lib, "AVIFileGetStream", pAVIFile, @pAVIStream, $73646976, 0 )
If res = 0; #AVI_ERR_OK
firstFrame = CallFunction( Lib, "AVIStreamStart", pAVIStream )
numFrames = CallFunction( Lib, "AVIStreamLength", pAVIStream )
If frame < firstFrame Or frame > firstFrame
MessageRequester( "Error!:The requested Frame does do not exist", "Only Frame "+Str(firstFrame)+" to "+Str(numFrames)+" available!", 0 )
CallFunction( Lib, "AVIFileRelease", pAVIFile )
EndProcedure
EndIf
pGetFrameObj = CallFunction( Lib, "AVIStreamGetFrameOpen", pAVIStream, 1 )
*bih.BITMAPINFOHEADER = CallFunction( Lib, "AVIStreamGetFrame", pGetFrameObj, firstFrame )
ImgID = CreateImage ( #PB_Any, *bih\biWidth, *bih\biHeight )
hBmp = UseImage(ImgID)
*bih.BITMAPINFOHEADER = CallFunction( Lib, "AVIStreamGetFrame", pGetFrameObj, frame )
WindowEvent()
If *bih
hdc = GetDC_(#Null)
hCDC = CreateCompatibleDC_(hdc)
If hCDC
SelectObject_( hCDC, hBmp )
SetDIBits_( hCDC, hBmp, 0, *bih\biHeight, *bih + SizeOf(BITMAPINFOHEADER), *bih, #DIB_RGB_COLORS)
DeleteDC_(hCDC)
EndIf
ReleaseDC_(#Null, hdc)
EndIf
SetGadgetState(GadgetNo, hBmp)
CallFunction( Lib, "AVIStreamGetFrameClose", pGetFrameObj )
EndIf
CallFunction( Lib, "AVIFileRelease", pAVIFile )
EndIf

EndProcedure

; --------------------------------- Play Sequence --------------------------------

Procedure PlayAviVideoSequence (Lib.l, avifile.s, fromFrame.l, toFrame.l, fps.l, ImageGadgetNo.l, StopGadgetNo.l)

Global framenumber
msdelay = Int(1000/fps)

res = CallFunction( Lib, "AVIFileOpen", @pAVIFile, @avifile.s, #OF_SHARE_DENY_WRITE, 0 )

If res = 0; #AVI_ERR_OK
res = CallFunction( Lib, "AVIFileGetStream", pAVIFile, @pAVIStream, $73646976, 0 )
If res = 0; #AVI_ERR_OK
firstFrame = CallFunction( Lib, "AVIStreamStart", pAVIStream )
numFrames = CallFunction( Lib, "AVIStreamLength", pAVIStream )
If fromFrame < firstFrame Or toFrame > firstFrame
MessageRequester( "Error!:The requested Frames do not exist", "Only Frame "+Str(firstFrame)+" to "+Str(numFrames)+" available!", 0 )
CallFunction( Lib, "AVIFileRelease", pAVIFile )
EndProcedure
EndIf

pGetFrameObj = CallFunction( Lib, "AVIStreamGetFrameOpen", pAVIStream, 1 )
*bih.BITMAPINFOHEADER = CallFunction( Lib.l, "AVIStreamGetFrame", pGetFrameObj, firstFrame )
ImgID = CreateImage ( #PB_Any, *bih\biWidth, *bih\biHeight )
hBmp = UseImage(ImgID)
; ------------------- Starting getting frames -----------------


For framenumber = fromFrame To ( toFrame - 1 ) ; - fromFrame
tempstart= ElapsedMilliseconds()
*bih.BITMAPINFOHEADER = CallFunction( Lib, "AVIStreamGetFrame", pGetFrameObj, framenumber )
WindowEvent()

If *bih
hdc = GetDC_(#Null)
hCDC = CreateCompatibleDC_(hdc)
If hCDC
SelectObject_( hCDC, hBmp )
SetDIBits_( hCDC, hBmp, 0, *bih\biHeight, *bih + SizeOf(BITMAPINFOHEADER), *bih, #DIB_RGB_COLORS)
DeleteDC_(hCDC)
EndIf
ReleaseDC_(#Null, hdc)
EndIf

SetGadgetState(ImageGadgetNo, hBmp); Displaying the Framecontent on the Imagewindow

Repeat
While Abs(tempstart-ElapsedMilliseconds()) < msdelay
;40ms = 25 FPS maximal
Delay(0)
Wend
Break
ForEver
If EventGadgetID() = StopGadgetNo
CallFunction( Lib, "AVIStreamGetFrameClose", pGetFrameObj )
CallFunction( Lib, "AVIFileRelease", pAVIFile )
ProcedureReturn framenumber
EndProcedure
EndIf
Next framenumber
CallFunction( Lib, "AVIStreamGetFrameClose", pGetFrameObj )
EndIf
CallFunction( Lib, "AVIFileRelease", pAVIFile )
EndIf
; ProcedureReturn framenumber
EndProcedure

; --------------------------------- Init AVI --------------------------------

Procedure AviVideoInit(Lib.l)
CallFunction ( Lib, "AVIFileInit" )
EndProcedure

; --------------------------------- Exit AVI --------------------------------

Procedure AviVideoExit(Lib.l)
CallFunction( Lib, "AVIFileExit" )
EndProcedure

; --------------------------------- Parse AVI --------------------------------


Procedure AviInfo (Lib.l, avifile.s)

Global AviWidth
Global AviHeigth
Global AviFrameRate
Global AviLength

Structure AVIFILEINFO
dwMaxBytesPerSec.l
dwFlags.l
dwCaps.l
dwStreams.l
dwSuggestedBufferSize.l
dwWidth.l
dwHeight.l
dwScale.l
dwRate.l
dwLength.l
dwEditCount.l
szFileType.b[64]
EndStructure

res = CallFunction( Lib, "AVIFileOpen", @pAVIFile, @avifile.s, #OF_SHARE_DENY_WRITE, 0 )
If res = 0;#AVI_ERR_OK
res = CallFunction( Lib, "AVIFileGetStream", pAVIFile, @pAVIStream, $73646976, 0 )
Result=CallFunction( Lib, "AVIFileInfo", pAVIFile, @AVIFILEINFO1.AVIFILEINFO, SizeOf(AVIFILEINFO))
EndIf
CallFunction( Lib, "AVIFileRelease", pAVIFile )

AviWidth.l = AVIFILEINFO1\dwWidth
AviHeight.l = AVIFILEINFO1\dwHeight
AviFramerate.f = (AVIFILEINFO1\dwRate)/(AVIFILEINFO1\dwScale)
Avilength.l = AVIFILEINFO1\dwLength


EndProcedure


I love purebasic! :cool:

vhelp
26th June 2005, 15:30
>> maybe a study on the avifile.* is a good idea.

Do you mean the AVI RIFF ??
Answer: Yes. I'm doing that now, actually.

Oh. Ok MeteorRain, I get it now. I thought you wanted to learn how to do
all this manually from scratch. I thought it was a great then. Oh well. Anyways.

I don't have C/C++ and it's difficult for me too, to follow all those source code
lines of spagetti-C stuff :lol:

I'll look into what you response suggests. I'm busy at the moment, but I'm
sure its already been done, you (we) just have to find it, via search.
.
I think I might look into it anyways, for manual sake, and try and make a DLL
out of it. It should prove a good learning opportunity. Thank you all.

-vhelp
ps: -- (@ inc) I lost my password ;)

aquaplaning
26th June 2005, 22:32
i made (a long time ago ;-) a delphi source code that parses through an avi file to find the best keyframe to split an avi file into equally big (in size [not in frames]) sub-avi-files. everything done by hand, no dll or vfw calls used.

it is included in the GordianKnot project and therefore widely used and tested.

check it out at:
http://cvs.sourceforge.net/viewcvs.py/gordianknot/gknot/Source/AviSplit.pas?rev=1.6&view=markup

you need to create a TAVISplitSearch object.
call Analyse(filename).
then you will find the private index array filled with the avis index.

if flags is flFRAME or flKEY (=keyFrame) the data chunck holds video information.
length holds the length ;-)
and offset gives you the position in the avi file to look for the data.

you should also be able to get video info (like with, hight,...) from the info variable.

if you want to try it, good luck!

MeteorRain
27th June 2005, 05:59
so cool. i will spend time converting it into basic.
@vhelp
you can use the codes directly, hoho lucky ^ ^
and much thanks to aquaplaning!!