ScreenRecorder zu wenig fps (und Systemsound?)

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von thefiloe.

    ScreenRecorder zu wenig fps (und Systemsound?)

    Hallo Leute
    ich habe einen Screen-Recorder programmiert und wollte jetzt noch einfügen, dass er mehr fps aufnimmt. Bin leider auf nicht mehr als 15-20 gekommen.
    Wenn jemand ne Idee hätte wie ich das hinbekommen könnte wäre das cool. :D
    Mein Code ist bisher:

    VB.NET-Quellcode

    1. Dim screenShotCount as integer= 0
    2. Sub ScreenshotThread()
    3. While True
    4. screenShotCount += 1
    5. Screenshot()
    6. End While
    7. End Sub
    An Error 404 occurred while loading signature...
    Hallo,

    solange Du so arbeitest kannst Du es leider schon vergessen. Mich wundert, dass Du somit schon so viele FPS schaffst. ;)
    Auf jeden Fall: Das scheint mir nicht all zu performant auszusehen, da Du die Hardware wirklich beanspruchst, vor allem wenn man auch so viele Bilder in den RAM reinholt etc.

    Du könntest höchstens noch mit DirectX arbeiten, aber das erhöht den Aufwand und erfordert mehr Kenntnisse in der Programmierung.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Trade“ ()

    @ThePlexian Der Code von Screenshot ist der hier:

    VB.NET-Quellcode

    1. Dim waW As Integer = My.Computer.Screen.WorkingArea.Width
    2. Dim waH As Integer = My.Computer.Screen.WorkingArea.Height
    3. Dim screenX As Integer = My.Computer.Screen.Bounds.X
    4. Dim screenY As Integer = My.Computer.Screen.Bounds.Y
    5. Private Sub Screenshot()
    6. Dim screenImage = New Bitmap(waW, waH)
    7. Dim g As Graphics = Graphics.FromImage(screenImage)
    8. g.CopyFromScreen(screenX, screenY, 0, 0, New Size(waW, waH))
    9. Cursor.Draw(g, New Rectangle(MousePosition, New Size(32, 32)))
    10. screenImage.Save("C:\rec\" + screenShotCount.ToString + ".jpg", ImageFormat.Jpeg)
    11. g.Dispose()
    12. screenImage.Dispose()
    13. End Sub

    Und Die Methode hat den Suffix Thread weil sie zu einem Thread gehört

    VB.NET-Quellcode

    1. Public tScreenshot As New Thread(AddressOf ScreenshotThread)

    @Trade
    Ich lade sie ja nicht in den RAM sondern speichere sie. DirectX habe ich mal probiert, zwar für 3D aber das ist echt schwer finde ich.
    An Error 404 occurred while loading signature...
    Doch du lädst die Bilder in den RAM. Mit

    VB.NET-Quellcode

    1. Dim screenImage = New Bitmap(waW, waH)
    2. Dim g As Graphics = Graphics.FromImage(screenImage)
    3. g.CopyFromScreen(screenX, screenY, 0, 0, New Size(waW, waH))

    erstellst du die Variable screenImage und füllst Sie mit dem Screenshot. Wenn das ganze nicht im RAM wäre, würde deine Zeile zum speichern nicht funktionieren, weil sie nichts zum speichern hätte. Das Bild wird bis zu screenImage.Dispose() im RAM zwischengespeichert. Das ist der Sinn des Arbeitsspeichers, denn sonst müsstest du das Bild direkt abspeichern, ohne Nutzung des Arbeitsspeichers, was in VB soviel ich weiß nicht möglich ist. (Korrigiert mich bitte, wenn Ich da falsch liege...)

    Um den Screenshot zu machen nutzt du GDI+. Das ist Bullshit :!: , denn GDI+ läuft komplett über den Prozessor. Intelligenter wäre es, die Grafikkarte zu nutzen (bspw. mit DirectX oder OpenGL). Diese hat deutlich mehr Leistung, und wurde extra dafür konzipiert, um mit Grafiken / Medien zu arbeiten.

    LG

    Twometer schrieb:

    Ich lade sie ja nicht in den RAM sondern speichere sie.
    Was die Sache noch viel langsamer macht. In dem RAM müssen die Bilder ja so oder so, da kommt kein Rocording-Programm drum rum, aber was wirklich Zeit kostet ist, die Bilder unkomprimiert zu speichern. Gute Frameraten wirst du nur erhalten, wenn du die Bilder gleich zu einem Video kodierst und dieses speicherst.
    @Artentus Ich hab da jetzt aber was gefunden, was aber leider nicht funktioniert...
    Der code ist nicht von mir, aber da kommt ein Fehler
    AviWriter.vb
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Drawing.Imaging
    2. Imports System.Runtime.InteropServices
    3. Public Class AviWriter
    4. Private aviFile As Integer = 0
    5. Private aviStream As IntPtr = IntPtr.Zero
    6. Private frameRate As UInt32 = 0
    7. Private countFrames As Integer = 0
    8. Private width As Integer = 0
    9. Private height As Integer = 0
    10. Private stride As UInt32 = 0
    11. Private fccType As UInt32 = Avi.StreamtypeVIDEO
    12. Private fccHandler As UInt32 = 1668707181
    13. Private strideInt As Integer
    14. Private strideU As UInteger
    15. Private heightU As UInteger
    16. Private widthU As UInteger
    17. Public Sub OpenAVI(ByVal fileName As String, ByVal frameRate As UInt32)
    18. Me.frameRate = frameRate
    19. Avi.AVIFileInit()
    20. Dim OpeningError As Integer = Avi.AVIFileOpen(aviFile, fileName, 4097, 0)
    21. If OpeningError <> 0 Then
    22. Throw New Exception("Error in AVIFileOpen: " + OpeningError.ToString())
    23. End If
    24. End Sub
    25. Public Sub AddFrame(ByVal bmp As Bitmap)
    26. bmp.RotateFlip(RotateFlipType.RotateNoneFlipY)
    27. Dim bmpData As BitmapData = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.[ReadOnly], PixelFormat.Format24bppRgb)
    28. If countFrames = 0 Then
    29. Dim bmpDatStride As UInteger = bmpData.Stride
    30. Me.stride = DirectCast(bmpDatStride, UInt32)
    31. Me.width = bmp.Width
    32. Me.height = bmp.Height
    33. CreateStream()
    34. End If
    35. strideInt = stride
    36. Dim writeResult As Integer = Avi.AVIStreamWrite(aviStream, countFrames, 1, bmpData.Scan0, DirectCast((strideInt * height), Int32), 0, 0, 0)
    37. If writeResult <> 0 Then
    38. Throw New Exception("Error in AVIStreamWrite: " + writeResult.ToString())
    39. End If
    40. bmp.UnlockBits(bmpData)
    41. System.Math.Max(System.Threading.Interlocked.Increment(countFrames), countFrames - 1)
    42. End Sub
    43. Private Sub CreateStream()
    44. Dim strhdr As New Avi.AVISTREAMINFOstruc()
    45. strhdr.fccType = fccType
    46. strhdr.fccHandler = fccHandler
    47. strhdr.dwScale = 1
    48. strhdr.dwRate = frameRate
    49. strideU = stride
    50. heightU = height
    51. strhdr.dwSuggestedBufferSize = DirectCast((stride * strideU), UInt32)
    52. strhdr.dwQuality = 10000
    53. heightU = height
    54. widthU = width
    55. strhdr.rcFrame.bottom = DirectCast(heightU, UInt32)
    56. strhdr.rcFrame.right = DirectCast(widthU, UInt32)
    57. strhdr.szName = New UInt16(64) {}
    58. Dim createResult As Integer = Avi.AVIFileCreateStream(aviFile, aviStream, strhdr)
    59. If createResult <> 0 Then
    60. Throw New Exception("Error in AVIFileCreateStream: " + createResult.ToString())
    61. End If
    62. Dim bi As New Avi.BITMAPINFOHEADERstruc()
    63. Dim bisize As UInteger = Marshal.SizeOf(bi)
    64. bi.biSize = DirectCast(bisize, UInt32)
    65. bi.biWidth = DirectCast(width, Int32)
    66. bi.biHeight = DirectCast(height, Int32)
    67. bi.biPlanes = 1
    68. bi.biBitCount = 24
    69. strideU = stride
    70. heightU = height
    71. bi.biSizeImage = DirectCast((strideU * heightU), UInt32)
    72. Dim formatResult As Integer = Avi.AVIStreamSetFormat(aviStream, 0, bi, Marshal.SizeOf(bi))
    73. If formatResult <> 0 Then
    74. Throw New Exception("Error in AVIStreamSetFormat: " + formatResult.ToString())
    75. End If
    76. End Sub
    77. Public Sub Close()
    78. If aviStream <> IntPtr.Zero Then
    79. Avi.AVIStreamRelease(aviStream)
    80. aviStream = IntPtr.Zero
    81. End If
    82. If aviFile <> 0 Then
    83. Avi.AVIFileRelease(aviFile)
    84. aviFile = 0
    85. End If
    86. Avi.AVIFileExit()
    87. End Sub
    88. End Class


    Avi.vb
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Drawing.Imaging
    2. Imports System.Runtime.InteropServices
    3. Public Class Avi
    4. Public Const StreamtypeVIDEO As Integer = 1935960438
    5. Public Const OF_SHARE_DENY_WRITE As Integer = 32
    6. Public Const BMP_MAGIC_COOKIE As Integer = 19778
    7. <StructLayout(LayoutKind.Sequential, Pack:=1)> _
    8. Public Structure RECTstruc
    9. Public left As UInt32
    10. Public top As UInt32
    11. Public right As UInt32
    12. Public bottom As UInt32
    13. End Structure
    14. <StructLayout(LayoutKind.Sequential, Pack:=1)> _
    15. Public Structure BITMAPINFOHEADERstruc
    16. Public biSize As UInt32
    17. Public biWidth As Int32
    18. Public biHeight As Int32
    19. Public biPlanes As Int16
    20. Public biBitCount As Int16
    21. Public biCompression As UInt32
    22. Public biSizeImage As UInt32
    23. Public biXPelsPerMeter As Int32
    24. Public biYPelsPerMeter As Int32
    25. Public biClrUsed As UInt32
    26. Public biClrImportant As UInt32
    27. End Structure
    28. <StructLayout(LayoutKind.Sequential, Pack:=1)> _
    29. Public Structure AVISTREAMINFOstruc
    30. Public fccType As UInt32
    31. Public fccHandler As UInt32
    32. Public dwFlags As UInt32
    33. Public dwCaps As UInt32
    34. Public wPriority As UInt16
    35. Public wLanguage As UInt16
    36. Public dwScale As UInt32
    37. Public dwRate As UInt32
    38. Public dwStart As UInt32
    39. Public dwLength As UInt32
    40. Public dwInitialFrames As UInt32
    41. Public dwSuggestedBufferSize As UInt32
    42. Public dwQuality As UInt32
    43. Public dwSampleSize As UInt32
    44. Public rcFrame As RECTstruc
    45. Public dwEditCount As UInt32
    46. Public dwFormatChangeCount As UInt32
    47. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=64)> _
    48. Public szName As UInt16()
    49. End Structure
    50. 'Initialize the AVI library
    51. <DllImport("avifil32.dll")> _
    52. Public Shared Sub AVIFileInit()
    53. End Sub
    54. 'Open an AVI file
    55. <DllImport("avifil32.dll", PreserveSig:=True)> _
    56. Public Shared Function AVIFileOpen(ByRef ppfile As Integer, ByVal szFile As [String], ByVal uMode As Integer, ByVal pclsidHandler As Integer) As Integer
    57. End Function
    58. 'Create a new stream in an open AVI file
    59. <DllImport("avifil32.dll")> _
    60. Public Shared Function AVIFileCreateStream(ByVal pfile As Integer, ByRef ppavi As IntPtr, ByRef ptr_streaminfo As AVISTREAMINFOstruc) As Integer
    61. End Function
    62. 'Set the format for a new stream
    63. <DllImport("avifil32.dll")> _
    64. Public Shared Function AVIStreamSetFormat(ByVal aviStream As IntPtr, ByVal lPos As Int32, ByRef lpFormat As BITMAPINFOHEADERstruc, ByVal cbFormat As Int32) As Integer
    65. End Function
    66. 'Write a sample to a stream
    67. <DllImport("avifil32.dll")> _
    68. Public Shared Function AVIStreamWrite(ByVal aviStream As IntPtr, ByVal lStart As Int32, ByVal lSamples As Int32, ByVal lpBuffer As IntPtr, ByVal cbBuffer As Int32, ByVal dwFlags As Int32, _
    69. ByVal dummy1 As Int32, ByVal dummy2 As Int32) As Integer
    70. End Function
    71. 'Release an open AVI stream
    72. <DllImport("avifil32.dll")> _
    73. Public Shared Function AVIStreamRelease(ByVal aviStream As IntPtr) As Integer
    74. End Function
    75. 'Release an open AVI file
    76. <DllImport("avifil32.dll")> _
    77. Public Shared Function AVIFileRelease(ByVal pfile As Integer) As Integer
    78. End Function
    79. 'Close the AVI library
    80. <DllImport("avifil32.dll")> _
    81. Public Shared Sub AVIFileExit()
    82. End Sub
    83. End Class



    Mein Code
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub Screenshot()
    2. Dim screenImage = New Bitmap(waW, waH)
    3. Dim g As Graphics = Graphics.FromImage(screenImage)
    4. g.CopyFromScreen(screenX, screenY, 0, 0, New Size(waW, waH))
    5. Cursor.Draw(g, New Rectangle(MousePosition, New Size(32, 32)))
    6. w.AddFrame(screenImage) 'w=der AviWriter
    7. g.Dispose()
    8. screenImage.Dispose()
    9. End Sub

    Vorher wird natürlich noch OpenAVI ausgeführt:

    VB.NET-Quellcode

    1. w.OpenAVI("E:\test.avi", 30)



    Fehler siehe Anhang (sorry für den seltsamen dateinamen)
    Bilder
    • Unbenannt.png

      9,66 kB, 559×318, 114 mal angesehen
    An Error 404 occurred while loading signature...
    Mein Tipp: Nimm einen Thread um die Screenshots in den Speicher zu laden und einen anderen der diese abarbeitet, speichert und im RAM löscht. Das einzige Problem dabei kann sein, dass der 2. Thread mit schreiben nicht hinter her kommt und es dir den RAM zuhaut.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „thefiloe“ ()

    Okay ich habe jetzt den einen Fehler wegbekommen - lag daran, dass ich auf Die Systemplatte geschrieben hab. Da hat der natürlich keine Rechte... Jetzt hab ich gedacht es funktioniert, aber meine IDE sieht das wohl anders. Jetzt kommt ein noch mysteriöserer Fehler. Wenn da jemand eine Idee hätte, was das sein könnte und was ich dagegen machen könnte, wäre das wirklich cool.
    EDIT: @thefiloe Gute Idee werd ich mal ausprobieren
    Bilder
    • fehler_accessviolation.png

      11,44 kB, 559×318, 91 mal angesehen
    An Error 404 occurred while loading signature...
    Entschuldige aber was sollen wir mit sowas anfangen können? Hat wahrscheinlich was mit pinvoke, ... irgendwas im nicht verwalteten Speicher zu tun. Kein Stacktrace nichts. Ne Fehlermeldung hinklatschen... naja kannste gern machen, wird nix bringen.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Ich habe das jetzt so gemacht das er nicht immer neu das Bild erzeugen muss und jetzt läufts mit 29fps :D
    Was ich jetzt noch gerne einbauen würde ist, dass er den System-Sound aufnimmt. Geht das, wenn ja wie?
    An Error 404 occurred while loading signature...
    Puh. Das ist schwierig. Frag am besten mal unseren Multimedia-Experten @ErfinderDesRades. Der hat sicherlich eine fantastische Lösung für dich die auch garantiert überall inklusive Rechenschieber läuft :).


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Sorry für die vielleicht blöde Frage, aber ich bin noch relativ neu hier. Wie macht man das (Einzelne Person fragen)?
    An Error 404 occurred while loading signature...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Twometer“ ()