AVI Reader Object + Audio !!!

User projects written in or related to FreeBASIC.
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

AVI Reader Object + Audio !!!

Postby vdecampo » Nov 28, 2008 0:40

This is a new project I've been working on to read and display frames from an AVI file. This new version also includes facilities to read, decompress, and play the audio track as well. I consider this a BETA version so expect some issues. The download includes a sample AVI that is used by the test program which is also the only documentation for using the AVI object.

Using it is as simple as..
Dim AVIR As _AVI_READER = _AVI_READER("myavifile.avi")


You can get the project source from here...
AVI Reader (Win 8.7Mb)

Cheers!
-Vince
Last edited by vdecampo on Dec 22, 2010 17:32, edited 3 times in total.
SSC
Posts: 319
Joined: May 29, 2005 4:47
Location: Around
Contact:

Postby SSC » Nov 28, 2008 7:39

Sounds like a useful tool, will you eventually add support for mpeg or other formats?
Leonheart
Posts: 82
Joined: Nov 20, 2007 9:08
Contact:

Postby Leonheart » Nov 28, 2008 8:24

There is also MCL winapi that you can use for next developing to add support for mpeg and other video/sound/midi support from codec installed on win, but tht can't do cross-platform. Doh! xD
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Nov 28, 2008 9:00

Leonheart wrote:There is also MCL winapi that you can use for next developing to add support for mpeg and other video/sound/midi support from codec installed on win, but tht can't do cross-platform. Doh! xD


This should decompress any AVI as long as the proper codec is installed in Windows, MPEG,DIVX,etx....
sgaba
Posts: 31
Joined: Aug 15, 2005 19:18
Location: Czech Republic

Vista

Postby sgaba » Dec 04, 2008 18:29

Not run on my Windows vista :(:(
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Re: Vista

Postby vdecampo » Dec 04, 2008 19:26

sgaba wrote:Not run on my Windows vista :(:(


Any error messages? Can you play the AVI file in media player? Do you have the correct codec installed?

-Vince
sgaba
Posts: 31
Joined: Aug 15, 2005 19:18
Location: Czech Republic

Postby sgaba » Dec 06, 2008 20:04

Any error messages?
No
Can you play the AVI file in media player?
Yes
Do you have the correct codec installed?
Yes

In AVIRtest is var hDIB for all frames zero...
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Dec 06, 2008 20:12

sgaba wrote:Any error messages?
No
Can you play the AVI file in media player?
Yes
Do you have the correct codec installed?
Yes

In AVIRtest is var hDIB for all frames zero...


No, if hDIB is zero that means the AVI library could not decompress the image stored in the AVI file.

Do you have SP1 for VISTA? I know there was a bug in the original distribution of VISTA concerning the AVI library.

-Vince
rolliebollocks
Posts: 2655
Joined: Aug 28, 2008 10:54
Location: new york

Postby rolliebollocks » Dec 07, 2008 13:57

Vince,

I'm running Vista and I didn't have a problem with it. Awesome!

rb
CommanderRaven
Posts: 86
Joined: Jan 22, 2009 18:52
Location: Houston, tx

Re: AVI Reader Object (Win32)

Postby CommanderRaven » Mar 14, 2009 20:54

Thanks dude, your code is a life saver. However just so you know your code has a design flaw on AVITEST. Your sleep command Sleep AVIR.tpf 'Sleep Tick-Per-Frame. Does not take into consideration that your other code requires a small amount of processing time, which will vary between PC to PC. This small amount of processing time will slow down your video. Even if you get the audio to play, your video won't be in sync.

This code should play the video properly. However it does not take check to see if too much time has based, and frames need to be skipped.

I suppose if one took the (Maxframes/FPS)*60 you would get the time in seconds. Setup a second eggtimer2 = timer at the start of video playing. Then do a frame display count=Int((Timer-eggtimer2)/playtime)*maxframenumbers). If they match, then you are in sync, if not, either skip to the correct frame, or slow down.

Just my 2cents...

Sorry I can't help with the audio stream. I used your code to display a AVI intro and credits in my game that I'm working on. I using FMOD to play the extracted auto track as back ground music.

Thank you thank you. I was using jpg, and displaying the frames. It worked... But then I found your code, which low and behold extracts each frame from a AVI... Reduced my program size from 170 meg to 65 meg....

One more thing, I noticed if you add a END or STOP to the end of the program player AVI Reader Test, it closes, but does not close. It stays open as a task in task manager. Strange one? Leave it off, no problem....

Code: Select all

/'--------------------------------------------------------------------
                AVI Reader Object Test Application             
                  Copyright Vincent DeCampo 2008     

   This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Last Updated: 11/27/2008
--------------------------------------------------------------------'/

#Include "AVIReader.bas"

Dim AVIR As _AVI_READER = _AVI_READER("Voyager Finale.avi") '<- Fill in name of AVI to play
Dim BIH  As BITMAPINFOHEADER
Dim As HANDLE hDIB,pDIB
dim eggtimer As Double

   ScreenRes AVIR.SizeX,AVIR.SizeY,32 'Set Screen to Size of AVI

   Var GDIimg1 = ImageCreateGDI (AVIR.SizeX,AVIR.SizeY) 'Create FB_GDI Image
   Var GDIimg2 = ImageCreateGDI (AVIR.SizeX,AVIR.SizeY) 'Create FB_GDI Image
   eggtimer=0


videoloop:

If Timer-eggtimer>= AVIR.tpf Then
      eggtimer=timer
      hDIB = AVIR.GetNextFrame()
      If hDIB Then
         
         pDIB=GlobalLock(hDIB) 'Get pointer to DIB
            memcpy @BIH,pDIB,SizeOf(BITMAPINFOHEADER)'Get BITMAPINFOHEADER
            AVIR.RGB_RGBA (pDIB+BIH.biSize,GDIimg1.pBits,BIH.biSizeImage/3)'RGB->RGBA
         GlobalUnlock hDIB     'Releas DIB pointer
         
         GDIimg1.BltStretch (GDIimg2.DC,0,AVIR.SizeY,AVIR.SizeX,-AVIR.SizeY)'Flip image
         GDIimg2.UpdateFBImage 'Update GDI surface to FB
         
         Put (0,0),GDIImg2.GetFBImage,PSet
                 
'         Sleep AVIR.tpf 'Sleep Tick-Per-Frame
         
         If InKey=Chr(27) Then GoTo programexit
           
      EndIf
     
EndIf

If AVIR.currentframe >= AVIR.numframes-1 Then GoTo programexit

GoTo videoloop

programexit:




vdecampo wrote:This is a new project I've been working on to read and display frames from an AVI file. It does video only for now but I am planning to add sound support in the future.

Using it is as simple as..
Dim AVIR As _AVI_READER = _AVI_READER("myavifile.avi")


You can get the project source from here...
http://www.imakegames.com/?q=node/25

Cheers!
-Vince
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Mar 14, 2009 21:03

@CommanderRaven

I'm glad you found it useful. You are correct about the audio timing. I was just creating a small demo program so I kept it simple. ;)

I will be playing around with extracting and playing the audio data. I don't think it should be too difficult but I have not played with the ACM functions. I love a challenge!

-Vince
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Mar 14, 2009 21:07

@CommandRaven

BTW, Why not compress your AVI using XVID? You should be able to get your video below 6Mb. Its free and widely available.

-Vince
Sisophon2001
Posts: 1704
Joined: May 27, 2005 6:34
Location: Cambodia, Thailand, Lao, Ireland etc.
Contact:

Re: AVI Reader Object (Win32)

Postby Sisophon2001 » Mar 15, 2009 1:27

CommanderRaven wrote:One more thing, I noticed if you add a END or STOP to the end of the program player AVI Reader Test, it closes, but does not close. It stays open as a task in task manager. Strange one? Leave it off, no problem....


The END command is intended for abnormal termination of a program. All clean-up code is skipped. In this case the destructor would never be called, so it is not surprising that it cause strange effects. See the help file for details.

I never even realised there was a STOP command, but obviously it woks the same way.

Garvan
squall4226
Posts: 284
Joined: Dec 21, 2008 15:08
Contact:

Postby squall4226 » Dec 10, 2010 3:37

Sorry to necropost, but as my question pertains specifically to this code I think it is the best place to post. I am hoping that Vdecampo will notice it and have the answer.

I am using this code with good success. In case it might be useful to anyone else: if the avi you are using contains audio supported by FMOD(e.g MP3, OGG, WAV), you can pass the avi file to FMOD just like an audio file and it will play it. So if you open the AVI with Vdecampo's code for video and then FMOD for audio, voila! For some reason it opens on channel 71 on my PC regardless of where I tell it to though. So I think it is sort of hackish that it works.

Code: Select all

dim as integer ptr trackhandle

FSOUND_Init(44100, 8, 0)

'then open a file
trackHandle = FSOUND_Stream_Open("somefile.avi", FSOUND_NORMAL, 0, 0 )

'then tell FMOD to play it in channel 1
FSOUND_Stream_Play(1, trackHandle)

'IT STILL PLAYS ON CHANNEL 71.
'I found this out by calling FSOUND_SetPaused in a FOR...NEXT loop
'and seeing which one actually paused it lol


So it may just be dumb luck that it works. But it does, and I can modify the volume or position of the AVI audio with normal FSOUND calls if I specify channel 71.

Code: Select all

FSOUND_SetPaused(71,TRUE)
'will pause the AVI audio HOWEVER
FSOUND_SetPaused(FSOUND_ALL,TRUE)
'will not pause the AVI audio!


Anyway so I don't think it is actually SUPPOSED to work, but the point is it does! I have not experienced any negative effects from doing this, although I admit it is a short term solution. I have tried it with 5 or 6 different AVI files so far, all with MP4/ASP Video (xvid encoded) and MP3 audio. It worked every time and always opened to channel 71.

Also of note, I have had no luck playing AVI that contain AVC/H264 video. Possibly because getting AVC into an AVI is kind of hackish anyway. Well who are we kidding, the AVI format has been hacked to death in order to keep it alive. A true Frankenstein of file formats! Anyway on to the real question.

In using this code in my media player I obviously want to be able to close one AVI and open another without restarting the program. But I can't get it to work. Here is what I have tried and how it fails:

Code: Select all

'Attempt 1:
Dim Shared AVIR As _AVI_READER ' to try to load the file later
'compiler fails with:
'TYPE or CLASS has no default constructor

'Attempt 2:
Dim Shared AVIR As _AVI_READER = _AVI_READER(NULL)
'other code
'later:
AVIR = _AVI_READER("test.avi")
'application crashes silenty as soon as AVIR is referenced after this point

'Attempt 3:
Dim Shared AVIR As _AVI_READER = _AVI_READER("test.avi")
'Plays fine but then if you want to change files:
AVIR = _AVI_READER("test2.avi")
'It will silently crash on the next reference to AVIR


Other important things to note are that I am trying to DIM SHARED AVIR etc etc. It needs to be visible in quite a few different subroutines. Anyway it works fine as long as we don't try to load a second AVI. Also note it isn't related to using FMOD for audio because I disabled that to make sure.

What I need to be able to do is open an AVI, play it, close it, open a new AVI, play it, close it, etc. Without restarting my program. If I hardcode the name of the file into the code it will play almost any AVI I throw at it. But if I try to open a specific one through an interface or a directory listing or something it just ain't happening. In case it is useful this is the meat of the code that I am using to play AVI. Note that I am not hunting down all the shared vars it references in order to copy in their DIM statements lol:

Code: Select all

#include once "inc/avireader.bas"


'In the top of my app, with the other shared vars:
Dim Shared AVIR As _AVI_READER = _AVI_READER("atest3.avi")


'This is in the main loop to keep things synchronized:
audiopos = fsound_stream_getTime(trackhandle)/1000
videopos = avir.currentframe/avir.fps
If videopos > audiopos Then
   Sleep (videopos*1000) - (audiopos*1000)
elseIf audiopos - videopos > .15 And audiopos > 3 And manskip = 0 Then
   fskip-=1
   If fskip = 1 then
      skipnum+=1
      fskip = 2
   EndIf
FSOUND_Stream_SetTime(trackHandle,((avir.currentframe/avir.fps)*1000))
EndIf
   

'In the subroutine that handles loading/changing files:
If UCase(Right(cursong.filename,4)) = ".AVI" Then
   mode = "Video"
   channel = 71
        'note that this is NOT to set the channel it loads to
        'but rather to compensate for it loading to 71
        'this way I can FSOUND_SetPaused(channel, TRUE)
        'instead of needing an if statement to compensate for it
   cursong.title = cursong.filename
   viz_mode = 11
   loadsubtitle 'Load subtitles from external file.
Else
   mode = "Audio"
   channel = 1
EndIf


'This is the main bit, it is in my visualization subroutine. That is where
'the music effects are rendered, and I figured it to be a good place to
'plop the video rendering as well. Most of this is Vdecampo's code
'from the demo in his download. I removed his comments to make it
'fit in this post better.
Select Case Viz_mode
'etc
'etc

Case Is = 11 'Video
        'This bit is for frameskipping, in order to keep the video
        'synced with audio even if the PC can't render the video
        'at full speed.
   If fskip < 10 And avir.currentframe Mod fskip = 0 Then
      avir.currentframe+=skipnum
      frames_skipped+=skipnum
   End if
        'Here the actual AVI stuff begins
   Var GDIimg1 = ImageCreateGDI (AVIR.SizeX,AVIR.SizeY)
   Var GDIimg2 = ImageCreateGDI (AVIR.SizeX,AVIR.SizeY)
   hDIB = AVIR.GetNextFrame()
   If hDIB Then
      frames_rendered+=1
      pDIB=GlobalLock(hDIB)
      memcpy @BIH,pDIB,SizeOf(BITMAPINFOHEADER)
      AVIR.RGB_RGBA(pDIB+BIH.biSize,GDIimg1.pBits,BIH.biSizeImage/3)
      GlobalUnlock hDIB
          GDIimg1.BltStretch(GDIimg2.DC,0,AVIR.SizeY,AVIR.SizeX,-AVIR.SizeY)
      GDIimg2.UpdateFBImage
      
'This is my stuff for scaling the resultant image. First it is
'scaled to as big as will fit in the player. Then the
'zoom_mult is applied in order to let the user zoom
'in or out. Also there are two variables to control the x/y
'offset which the user can change on the fly in order to pan.   
      Dim As Single scalex = screenx/avir.sizeX
      Dim As Single scaley = screeny/avir.sizeY
      Dim As Single perc = 1
   If scaley < scalex Then perc = scaley Else perc = scalex
      perc*=zoom_mult
multiput(,screenx/2+vid_x_offset,screeny/2+vid_y_offset,GDIImg2.GetFBImage,perc,perc)
   EndIf

End Select

I could not for the life of me get that multiput statement to fit on one line in the code block so here:
multiput
(,screenx/2+vid_x_offset,screeny/2+vid_y_offset,GDIImg2.GetFBImage,perc,perc)


Anyway that is pretty much the most important chunks of code that I am using in this endeavor. So I want to know how I can load additional AVI files. I don't want to just have to have a different variable for each file since obviously I don't know how many AVI a user might want to open in a particular session. There has to be someway to reinitialize the thing without closing the program. And I also pretty much HAVE to hardcode in the AVI name at this point since the loading happens in a subroutine and I need the AVIR to be shared. Since I can't dim it shared with no value and then later read in a value(see my examples of stuff I tried above), I'm stuck.

So hopefully Vdecampo will see this and have an answer. Or maybe someone else might have an answer. Anyway, this is still a very cool bit of code. In the future I thought about maybe translating the headers for libvlc but for now this is the code powering the video part of my media player. Anyway thanks for the AVI reader Vdecampo! Hopefully I can get this figured out. I am sure there is a way that I am either missing completely or just don't know about.

~Blyss
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Dec 10, 2010 17:40

@squall4226

Here is a small snippet from the new example I included with the AVI Reader download.

Code: Select all

/'
   BEGIN MAIN PROGRAM
'/

Dim AVIR As _AVI_READER Ptr

   AVIR = new _AVI_READER("trek.avi") '<- Fill in name of AVI to play
   ScreenRes AVIR->SizeX,AVIR->SizeY,32 'Set Screen to Size of AVI
   
   DisplayVideo(AVIR)
               
   Delete AVIR 'Call destructor on AVI Reader
   
   AVIR = new _AVI_READER("test.avi") '<- Fill in name of AVI to play
   ScreenRes AVIR->SizeX,AVIR->SizeY,32 'Set Screen to Size of AVI
 
   DisplayVideo(AVIR)
 
   Delete AVIR 'Call destructor on AVI Reader


This shows how to open and close multiple AVIs. I also updated the AVI Reader with a new utility function to flip the image buffer. Download the new version from the link in the first post.

Hope this helps.

-Vince

Return to “Projects”

Who is online

Users browsing this forum: No registered users and 7 guests