Delay() bei abspielen von einzelnen Frames mit richtiger FPS

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
inc.
Beiträge: 348
Registriert: 27.10.2004 12:25

Delay() bei abspielen von einzelnen Frames mit richtiger FPS

Beitrag von inc. »

Hi,

bin gerade einen Avi Player am erstellen, der mittels der avifil32.dll und deren Funktion "AVIStreamGetFrame" die einzelnen Frames rausholt und sie als PB Imagefolge im Imagegadget ablaufen lässt.

Jetzt kommts aber auf die Geschwindigkeit an.
Lasse ich normal die Frames hintereinander mittels For I =x to y Next Schleife aus dem Avi rausholen und die Framefolge im Imagegadget anzeigen habe ich niemals die richtigen FPS, mit welchen der Stream abgespielt werden sollte.

Lasse ich in der Schleife einen Delay(x) werkeln, müsste man doch den Wert x irgendwie herausbekommen. So wie ich es verstanden habe ist der Delay in milisekunden angegeben. bei 25 FPS (pal) wären das doch .... hmmm

1000/25 = 40

und bei 29.97 fps (ntsc)

1000/29.97 = 33,367

klappt aber nicht, so würden die Filme viel zu langsam abfahren.

Delay(25) bei 25fps PAL wäre (bei meinem Rechner) perfekt. Delay(29.97) würde einen 29,97fps NTSC Film jedoch nicht richtig sondern im Gegenteil noch weit langsamer ablaufen lassen (ist ja logisch), daher ist das Nonsense.

Entweder ich sollte mal die 3te Klasse wiederholen oder hier habe ich was simples vergessen, was z.B. noch den Wert im Delay beeinflusst - z.B. die Zeit, welche die CPU für dein eigentlichen Prozess braucht!?.

Jemand ne Idee?

Vielen Dank
Inc.
Benutzeravatar
redacid
Beiträge: 581
Registriert: 29.08.2004 17:06

Beitrag von redacid »

so mal ganz spontan würde ich behaupten, die Anzeige des Frames benötigt ja auch eine gewisse Zeit - so ist es dein Delay + die Zeit, die die Anzeige des Frames benötigt. Also kannst du dich nicht wundern, wenn die Datei in der falschen Geschwindigkeit angezeigt wird.
Benutzeravatar
inc.
Beiträge: 348
Registriert: 27.10.2004 12:25

Beitrag von inc. »

Ich nehme aber nicht an, dass das Decoding/displaying die Rate von Delay(40) auf Delay(25) runterholt?
Beim Decoden habe ich eine CPU Usage von 10-15%, daher meine Vermutung.


Hier mal der Code (habs versucht übersichtlich zu halten).

Ab "----- Starting getting frames ----" geht die Schleife zum Auslesen und Darstellen los.

Habe was mit

- Starttime=Elapsedmiliseconds()
- Schleife startet
- Hier die Frames die geholt und dargestellt werden
- repeat
- WindowEvent()
- delay(1)
- until (starttime-Elapsedmiliseconds()) > 39
- Zurück zur Schleife

Wird aber alles SEHR langsam und das CPU Meter knallt hoch (wegen Repeat/Until nehme ich an)

Code: Alles auswählen

;Main Soucreparts taken from didges AVI2BMP Procedure
;http://forums.purebasic.com/english/viewtopic.php?t=7648

Enumeration
  #Window_0
   #Source
  #Image_0
EndEnumeration


Procedure Open_Window()
  If OpenWindow(#Window_0, 224, 9, 980, 708,  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar , "Test FPS Playback via avifil32.dll")
    If CreateGadgetList(WindowID())
      ButtonGadget(#Source, 20, 20, 160, 20, "Load Source")
      ImageGadget(#Image_0, 230, 40, 704, 576, 0, #PB_Image_Border); The Image Display Window
      
    EndIf
  EndIf
EndProcedure

; -------------------------------- Procedure GETFRAMES --------------------------------
 
Procedure GETFRAMES ( avifile.s )
 #streamtypeVIDEO = $73646976
 #AVIGETFRAMEF_BESTDISPLAYFMT = 1
 #AVI_ERR_OK = 0
 #Lib = 0

 
 res = CallFunction( #Lib, "AVIFileOpen", @pAVIFile, @avifile.s, #OF_SHARE_DENY_WRITE, 0 )
 
  If res = #AVI_ERR_OK
    res = CallFunction( #Lib, "AVIFileGetStream", pAVIFile, @pAVIStream, #streamtypeVIDEO, 0 )
      
      If res = #AVI_ERR_OK
        firstFrame = CallFunction( #Lib, "AVIStreamStart", pAVIStream )
        numFrames  = CallFunction( #Lib, "AVIStreamLength", pAVIStream )

        pGetFrameObj = CallFunction( #Lib, "AVIStreamGetFrameOpen", pAVIStream, #AVIGETFRAMEF_BESTDISPLAYFMT )

        ImgID = CreateImage ( #PB_Any, 704, 576 ) 
        hBmp  = UseImage(ImgID)
  
        start = ElapsedMilliseconds()
        
        
;             ------------------- Starting getting frames -----------------
  
  
        For a = firstFrame To ( numFrames - 1 ) - firstFrame
          *bih.BITMAPINFOHEADER = CallFunction( AviDll, "AVIStreamGetFrame", pGetFrameObj, a )

          tempstart= ElapsedMilliseconds()
          WindowEvent()
          ;Delay(25)
                    
             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(#Image_0, hBmp); Displaying the Framecontent on the Imagewindow
        Next a
        
        
;              --------------------- End getting frames -----------------
        
        
        
        CallFunction( #Lib, "AVIStreamGetFrameClose", pGetFrameObj )
    EndIf
    CallFunction( #Lib, "AVIFileRelease", pAVIFile )
  EndIf
  
 stop=ElapsedMilliseconds()
 total = stop-start
 MessageRequester( "Time needed to playback", Str(total/1000) + " ms",  0 )
 
EndProcedure

; -------------------------------- Appl.Window --------------------------------

Open_Window()

Repeat
  
  Event = WaitWindowEvent()
  
    If Event = #PB_EventGadget
      GadgetID = EventGadgetID()
    
        If GadgetID = #Source
          OpenLibrary  ( #Lib , "AVIFIL32.DLL")
          CallFunction ( #Lib,  "AVIFileInit" )
          avifile.s = OpenFileRequester ( "Select AVI File", "", "Video|*.avi", 0 )
              If avifile : GETFRAMES( avifile ) : EndIf
                CallFunction( #Lib, "AVIFileExit" )
                CloseLibrary( #Lib )
        EndIf
    EndIf
  
Until Event = #PB_EventCloseWindow

End
Benutzeravatar
inc.
Beiträge: 348
Registriert: 27.10.2004 12:25

Beitrag von inc. »

Habe mich mal hier umgesehen und was mit Repead gefunden und eingebaut:

Code: Alles auswählen

  
  
        For a = firstFrame To ( numFrames - 1 ) - firstFrame
        tempstart= ElapsedMilliseconds()
          *bih.BITMAPINFOHEADER = CallFunction( AviDll, "AVIStreamGetFrame", pGetFrameObj, a )          
          WindowEvent()
          ;Delay(25)
                    
             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(#Image_0, hBmp); Displaying the Framecontent on the Imagewindow
          
          Repeat 
          While abs(tempstart-ElapsedMilliseconds())<39
          ;40ms = 25 FPS maximal
          Wend 
          Break
          ForEver 
        Next a
        
        
;     
Scheint sehr gut zu klappen, jedoch geht die CPU Anzeige eben wegen des Repeats auf 100.

Hmmmm ...
Benutzeravatar
bluejoke
Beiträge: 1244
Registriert: 08.09.2004 16:33
Kontaktdaten:

Beitrag von bluejoke »

Wenn du ein Delay(0) einfügst bleibt zwar die hohe Prozessorauslastung, die anderen Programme kriegen jedoch auf Anfrage was davon ab. Bei delay(1) sollte die Auslastung runtergehen, aber ich weiß nicht ob du das bei dir verwenden kannst.
Ich bin Ausländer - fast überall
Windows XP Pro SP2 - PB 4.00
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

@BJ

hey, klasse tip mit dem Delay(0), wußte ich noch net, danke :allright:
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Andre
PureBasic Team
Beiträge: 1765
Registriert: 11.09.2004 16:35
Computerausstattung: MacBook Core2Duo mit MacOS 10.6.8
Lenovo Y50 i7 mit Windows 10
Wohnort: Saxony / Deutscheinsiedel
Kontaktdaten:

Beitrag von Andre »

Dazu gibts im engl. Forum eine ausführliche Beschreibung:
Tips & Tricks: Delay(0)
Bye,
...André
(PureBasicTeam::Docs - PureArea.net | Bestellen:: PureBasic | PureVisionXP)
Antworten