+ Reply to Thread
Results 1 to 5 of 5

Thread: How to record your screen and saving it as .AVI

  1. #1
    Join Date
    Apr 2009
    Location
    Uppsala, Sweden
    Posts
    9,547
    Blog Entries
    5
    Rep Power
    98

    How to record your screen and saving it as .AVI

    This tutorial is going to show you how you can record your screen and then save the bitmaps to a .Avi file. It's a little bit complicated but if you only understands how to use the AViWriter class and the AVI class you doesn't necessary need to understand how it works.
    Never mind, let's get started.


    First we need to import a few things:

    Code:
    Imports System.Drawing.Imaging
    Imports System.Runtime.InteropServices

    Then we add the AVI class:


    Code:
        Public Class Avi
    
            Public Const StreamtypeVIDEO As Integer = 1935960438
            Public Const OF_SHARE_DENY_WRITE As Integer = 32
            Public Const BMP_MAGIC_COOKIE As Integer = 19778
    
    
    
            <StructLayout(LayoutKind.Sequential, Pack:=1)> _
            Public Structure RECTstruc
                Public left As UInt32
                Public top As UInt32
                Public right As UInt32
                Public bottom As UInt32
            End Structure
    
            <StructLayout(LayoutKind.Sequential, Pack:=1)> _
            Public Structure BITMAPINFOHEADERstruc
                Public biSize As UInt32
                Public biWidth As Int32
                Public biHeight As Int32
                Public biPlanes As Int16
                Public biBitCount As Int16
                Public biCompression As UInt32
                Public biSizeImage As UInt32
                Public biXPelsPerMeter As Int32
                Public biYPelsPerMeter As Int32
                Public biClrUsed As UInt32
                Public biClrImportant As UInt32
            End Structure
    
            <StructLayout(LayoutKind.Sequential, Pack:=1)> _
            Public Structure AVISTREAMINFOstruc
                Public fccType As UInt32
                Public fccHandler As UInt32
                Public dwFlags As UInt32
                Public dwCaps As UInt32
                Public wPriority As UInt16
                Public wLanguage As UInt16
                Public dwScale As UInt32
                Public dwRate As UInt32
                Public dwStart As UInt32
                Public dwLength As UInt32
                Public dwInitialFrames As UInt32
                Public dwSuggestedBufferSize As UInt32
                Public dwQuality As UInt32
                Public dwSampleSize As UInt32
                Public rcFrame As RECTstruc
                Public dwEditCount As UInt32
                Public dwFormatChangeCount As UInt32
                <MarshalAs(UnmanagedType.ByValArray, SizeConst:=64)> _
                Public szName As UInt16()
            End Structure
    
    
    
            'Initialize the AVI library
            <DllImport("avifil32.dll")> _
            Public Shared Sub AVIFileInit()
            End Sub
    
            'Open an AVI file
            <DllImport("avifil32.dll", PreserveSig:=True)> _
            Public Shared Function AVIFileOpen(ByRef ppfile As Integer, ByVal szFile As [String], ByVal uMode As Integer, ByVal pclsidHandler As Integer) As Integer
            End Function
    
            'Create a new stream in an open AVI file
            <DllImport("avifil32.dll")> _
            Public Shared Function AVIFileCreateStream(ByVal pfile As Integer, ByRef ppavi As IntPtr, ByRef ptr_streaminfo As AVISTREAMINFOstruc) As Integer
            End Function
    
            'Set the format for a new stream
            <DllImport("avifil32.dll")> _
            Public Shared Function AVIStreamSetFormat(ByVal aviStream As IntPtr, ByVal lPos As Int32, ByRef lpFormat As BITMAPINFOHEADERstruc, ByVal cbFormat As Int32) As Integer
            End Function
    
            'Write a sample to a stream
            <DllImport("avifil32.dll")> _
            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, _
             ByVal dummy1 As Int32, ByVal dummy2 As Int32) As Integer
            End Function
    
            'Release an open AVI stream
            <DllImport("avifil32.dll")> _
            Public Shared Function AVIStreamRelease(ByVal aviStream As IntPtr) As Integer
            End Function
    
            'Release an open AVI file
            <DllImport("avifil32.dll")> _
            Public Shared Function AVIFileRelease(ByVal pfile As Integer) As Integer
            End Function
    
            'Close the AVI library
            <DllImport("avifil32.dll")> _
            Public Shared Sub AVIFileExit()
            End Sub
    
    
    
    
    
    
        End Class

    This class contains some dll imports and a few structures. This class is only for the AviWriter so it can write the .avi:s. By reading the comments you will see what the dll imports is for. You don't need to think about what id does now, because we're going to use everything here when we're creating the AviWriter class.



    Now we come to something more interesting, the AviWriter class, we create it and add some variables:


    Code:
        Public Class AviWriter
            Private aviFile As Integer = 0
            Private aviStream As IntPtr = IntPtr.Zero
            Private frameRate As UInt32 = 0
            Private countFrames As Integer = 0
            Private width As Integer = 0
            Private height As Integer = 0
            Private stride As UInt32 = 0
            Private fccType As UInt32 = Avi.StreamtypeVIDEO
            Private fccHandler As UInt32 = 1668707181
    Code:
            Private strideInt As Integer
            Private strideU As UInteger
            Private heightU As UInteger
            Private widthU As UInteger
    The second code box is just because I had some problems converting Uint32 to integer and integer to Uinteger. So then I do like this:

    Code:
    strideU = stride
    Just to show a example.



    But never mind about that, now we're going to create a new class named OpenAVI:


    Code:
            Public Sub OpenAVI(ByVal fileName As String, ByVal frameRate As UInt32)
                Me.frameRate = frameRate
    
                Avi.AVIFileInit()
    
    
                Dim OpeningError As Integer = Avi.AVIFileOpen(aviFile, fileName, 4097, 0)
                If OpeningError <> 0 Then
                    Throw New Exception("Error in AVIFileOpen: " + OpeningError.ToString())
                End If
            End Su

    The variable fileName is where you want to save the .Avi file and frameRate is of course the frame rate of the video.


    Then we set the frame rate of the video to the frameRate's value.

    The next line of code Initialize the avi by using one of the dll imports in the AVI class.

    Then with another dll import we're opening the avi so we later can add bitmaps to it. The opening will return a value which we store in a variable called OpeningError. If OpeningError is not equals to 0 it means we got an error so then an Exception is thrown.


    Then we create a new sub Called AddFrame:

    Code:
            Public Sub AddFrame(ByVal bmp As Bitmap)
    
                bmp.RotateFlip(RotateFlipType.RotateNoneFlipY)
    
                Dim bmpDat As BitmapData = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.[ReadOnly], PixelFormat.Format24bppRgb)

    With this sub we can add bitmaps as frames of the video, the bmp variable is the bitmap we want to add.



    The first thing we are doing in the sub is to flip the bitmap on its Y axis, I don't really know why the picture need to be upside down.



    Then we declares a variable called bmpData and assign it a BitmapData which locks the bitmap to memory.



    Now we'll add:


    Code:
                If countFrames = 0 Then
                    Dim bmpDatStride As UInteger = bmpData.Stride
                    Me.stride = DirectCast(bmpDatStride, UInt32)
                    Me.width = bmp.Width
                    Me.height = bmp.Height
                    CreateStream()
                End If


    The countFrames variable, which we declared in the beginning of the class, keeping track of how many frames we got. And if we have 0 (= this is the first frame) we want to set the Avi's stride to the stride of the bmpData and then set the Avi's size to our bitmap's size. At last we want to create a stream, this is a sub we'll create later.


    Then we add these lines:

    Code:
                strideInt = stride
                Dim writeResult As Integer = Avi.AVIStreamWrite(aviStream, countFrames, 1, bmpData.Scan0, DirectCast((strideInt * height), Int32), 0, _
                 0, 0)
    
                If writeResult <> 0 Then
                    Throw New Exception("Error in AVIStreamWrite: " + writeResult.ToString())
                End If

    Here we add the bitmap with bmpData by a dll import from the AVI class.
    Here we also gets a value, if the value is 0 we know it worked, else we throw an exception.



    Last in this sub we add:

    Code:
                bmp.UnlockBits(bmpData)
                System.Math.Max(System.Threading.Interlocked.Increment(countFrames), countFrames - 1)
            End Sub

    We removes the bitmap from memory and increases the countFrames with one.



    Then that sub was done, now we will create the sub Called CreateStream which will be the sub which creating the stream (as I said before and as you can hear on its name):


    Code:
            Private Sub CreateStream()
                Dim strhdr As New Avi.AVISTREAMINFOstruc()
                strhdr.fccType = fccType
                strhdr.fccHandler = fccHandler
                strhdr.dwScale = 1
                strhdr.dwRate = frameRate
                strideU = stride
                heightU = height
                strhdr.dwSuggestedBufferSize = DirectCast((stride * strideU), UInt32)
                strhdr.dwQuality = 10000
    
                heightU = height
                widthU = width
                strhdr.rcFrame.bottom = DirectCast(heightU, UInt32)
                strhdr.rcFrame.right = DirectCast(widthU, UInt32)
                strhdr.szName = New UInt16(64) {}

    So now we created the sub with some variables. We sets the quality, the size and the type of the stream etc.


    Now we create the stream:

    Code:
                Dim createResult As Integer = Avi.AVIFileCreateStream(aviFile, aviStream, strhdr)
                If createResult <> 0 Then
                    Throw New Exception("Error in AVIFileCreateStream: " + createResult.ToString())
                End If

    And as usual we throw an exception if the value we get isn't 0.


    Then two variables:


    Code:
                Dim bi As New Avi.BITMAPINFOHEADERstruc()
                Dim bisize As UInteger = Marshal.SizeOf(bi)
                bi.biSize = DirectCast(bisize, UInt32)
                bi.biWidth = DirectCast(width, Int32)
                bi.biHeight = DirectCast(height, Int32)
                bi.biPlanes = 1
                bi.biBitCount = 24
    
                strideU = stride
                heightU = height
                bi.biSizeImage = DirectCast((strideU * heightU), UInt32
    )


    These we will used when we sets the image format to the stream. As you can see one of them is one of our structures from the AVI class.


    And we'll set the format of the stream:


    Code:
                Dim formatResult As Integer = Avi.AVIStreamSetFormat(aviStream, 0, bi, Marshal.SizeOf(bi))
                If formatResult <> 0 Then
                    Throw New Exception("Error in AVIStreamSetFormat: " + formatResult.ToString())
                End If
           End Sub

    And as usual...


    Now we only have one sub left in the AviWriter class:

    Code:
            Public Sub Close()
                If aviStream <> IntPtr.Zero Then
                    Avi.AVIStreamRelease(aviStream)
                    aviStream = IntPtr.Zero
                End If
                If aviFile <> 0 Then
                    Avi.AVIFileRelease(aviFile)
                    aviFile = 0
                End If
                Avi.AVIFileExit()
            End Sub
        End Class

    This sub we use for closing the stream and the avi file when we're done with them.

    So if we still have the aviStream left, we will release it.
    And if the aviFile still in unreleased, we'll release it too.

    Then we Exit the avi file because we're now done.


    That was the two avi classes.



    Now I'm going to show how to do a VERY simple screen recorder with these classes.

    First we'll need to add a timer and one button. We call the timer for bmpTimer and the button for StartButton. The button's text should be "Start" and the timer's interval should be 100 (because here I will use 10 frames per seconds).


    Now we can save the bitmaps in two ways, I'm going to save them in a variable but you can also save them as files on your computer:


    Code:
        Private screenBimaps(99) As Bitmap
        Private currentBitmap As Integer = 0
    Observe that I only can store 100 pictures now.



    When the user click on the button:


    Code:
        Private Sub StartButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartButton.Click
            If StartButton.Text = "Start" Then
                currentBitmap = 0
                StartButton.Text = "Stop"
                bmpTimer.Enabled = True
            Else
                CreateFile()
                StartButton.Text = "Start"
                bmpTimer.Enabled = False
            End If
        End Sub

    If we haven't started yet, we reset the currentBitmap variable so it's starting from the beginning, then we starts our timer and changes the text on the button to "Stop".

    If we're already recording we'll create the file with another sub, and then stops the timer and the text changes back to "Start".



    Then we adds a sub which handles bmpTimer.tick:

    Code:
        Private Sub bmpTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bmpTimer.Tick
            If currentBitmap < 100 Then
                Dim w As Integer = Screen.PrimaryScreen.WorkingArea.Width
                Dim h As Integer = Screen.PrimaryScreen.WorkingArea.Height
                Dim bmp As New Bitmap(w, h)
                Using gr As Graphics = Graphics.FromImage(bmp)
                    gr.CopyFromScreen(0, 0, 0, 0, bmp.Size)
                End Using
                screenBimaps(currentBitmap) = bmp
                currentBitmap += 1
            Else
                CreateFile()
                StartButton.Text = "Start"
                bmpTimer.Enabled = False
            End If
        End Sub
    So no when the timer tick a screen shot is taken and stored as the current frame. But if it already has recorded 100 pictures, it saves the avi (since I only added the opportunity for up to 100 images in the screenBitmaps variable).





    And now we're going to create the AVI file with our bitmaps:

    Code:
        Private Sub CreateFile()
            Dim Writer As New AviWriter
    
            Writer.OpenAVI("C:\Test.Avi", 10)
            For Frame As Integer = 0 To currentBitmap - 1
                Writer.AddFrame(screenBimaps(Frame))
            Next
            Writer.Close()
        End Sub
    So here we're creating a AviWriter which Opens a Avi File called Test located in C:\ with 10 frames/second. Then we're adding all the frames and at last we close the writer.



    And now it's done. In this last part you can do many things, give the user the opportunity to choose file path, changing frame rate, pausing, changing recording area and so on.





    This was my tutorial. It was a quite hard to explain some parts so if you doesn't understand, just ask.
    Last edited by Vswe; 05-02-2009 at 08:15 AM. Reason: One code line at the end was wrong

  2. CODECALL Circuit advertisement
    Join Date
    Always
    Location
    Advertising world
    Posts
    Many

     
  3. #2
    Join Date
    Jul 2006
    Posts
    16,466
    Blog Entries
    74
    Rep Power
    143

    Re: How to record your screen and saving it as .AVI

    Awesome! +rep
    Programming is a branch of mathematics.
    My CodeCall Blog | My Personal Blog

  4. #3
    Jordan Guest

    Re: How to record your screen and saving it as .AVI

    Impressive!! I will +rep you when I get to a computer.
    Posted via CodeCall Mobile

  5. #4
    Join Date
    Nov 2008
    Location
    Kosovo.
    Posts
    2,391
    Rep Power
    30

    Re: How to record your screen and saving it as .AVI

    Fantastic .
    +reppppppppppp

  6. #5
    oehoe is offline Newbie
    Join Date
    Dec 2011
    Posts
    1
    Rep Power
    0

    Re: How to record your screen and saving it as .AVI

    Thanks for the great code. I only have a problem with running out of memory. After about 1000 frames of 600x600 pixels I get an out of memory message. When I look at my taskmanager I see the used memory quickly reach my 4GB of RAM. It seems it's not using the virtual memory. Is there a way to write the frames to the disk every x number of frames to prevent this problem?

    Greet Johan

+ Reply to Thread

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. use php to display record!!!
    By noprobz09 in forum PHP Development
    Replies: 0
    Last Post: 10-16-2010, 04:13 PM
  2. How to Record Video using VB
    By ayachub in forum Visual Basic Programming
    Replies: 4
    Last Post: 07-11-2010, 10:32 PM
  3. Screen resolution issue and getting rid of gaps around the edges of the screen...
    By HumansAreFriendsNotFood in forum HTML Programming
    Replies: 10
    Last Post: 06-07-2010, 11:07 AM
  4. Saving Position and Split Screen
    By Crom in forum C# Programming
    Replies: 1
    Last Post: 09-07-2007, 09:14 AM

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts