2

I am trying to write some video stitching software that emulates the functionality of a car dashboard that has an all around camera system. The program uses HD video capture cards to stream from 5 GoPro cameras and detects movement using PIR sensors with the movement detection data sent down a serial connection.

I am getting a problem with memory leaks, specifically it is using large amounts of "modified" ram, which first fills up the hardware ram then the virtual ram then the program crashes.

I am very new to video processing and openGL and have little experience with memory management and unmanned code.

I have included the entirety of my code at the bottom as I may be looking in the wrong place but I believe the issues are arising around these tow key sections:

The event that takes the image from the aForge webcam driver:

  videoSource1.NewFrame += (Object sender, NewFrameEventArgs eventArgs) =>
        {
            System.Threading.Thread.Sleep(10);
            if (videoFrame1 != null)
                lock (videoFrame1)
                {

                    videoFrame1 = new Bitmap(eventArgs.Frame);


                }
            else
            {
                videoFrame1 = new Bitmap(eventArgs.Frame);
            }

        };

And the section that passes the bitmap to the openGl stuff and displays it:

  if (videoFrame1 != null)

                lock (videoFrame1)
                {
                    glControl1.MakeCurrent();

                    if (videoTexture1 != -1)
                        GL.DeleteTextures(1, ref videoTexture1);

                    videoTexture1 = TexUtil.CreateTextureFromBitmap(videoFrame1);

                    GL.BindTexture(TextureTarget.Texture2D, videoTexture1);

                    //  videoFrame1 = null;
                    fullscreenQuad.Draw(1);
                    if (selectedCam == 1) 
                    {
                        drawSide(videoFrame1);
                    glControl1.MakeCurrent();

                }
                    videoFrame1.Dispose();


                    GC.Collect();

                }

I was under the impression if I dispose of the bitmap and then call GC.collect this should free up the space?

Should I be calling something else to make it get rid of the allocated RAM in a different fashion?

Is there a way to force c# to free up the ram as "zeroed" opposed to marking it as "modified"

If I use the sysinternals RAMMap utility I can shift the modified ram to "standby" and can then wipe the standby freeing up the space. Is there a way to do this programmatically in c#?

Sorry if this is a bit jumbled, as I said I'm very new to this

Many thanks,

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AForge.Video;
using AForge.Video.DirectShow;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using TexLib;

namespace GLembedded
{

public partial class Form1 : Form
{

    bool loaded = false;
    Bitmap videoFrame1 = null;
    Bitmap videoFrame2 = null;
    Bitmap videoFrame3 = null;
    Bitmap videoFrame4 = null;

    VideoCaptureDevice videoSource1;
    VideoCaptureDevice videoSource2;
    VideoCaptureDevice videoSource3;
    VideoCaptureDevice videoSource4;
    FilterInfoCollection videoDevices;
    int videoTexture1 = -1;
    int videoTexture2 = -1;
    int videoTexture3 = -1;
    int videoTexture4 = -1;
    int videoTexture5 = -1;

    int videoTexture6 = -1;

    int selectedCam = 1;
    int countdown = 0;
    int bytein = 0;

    Quad fullscreenQuad = new Quad();

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        timer1.Start();
        this.DoubleBuffered = true;
        serialPort1.Open();
    }
    private void SetupViewport()
    {

        int w = glControl1.Width;
        int h = glControl1.Height;
      //  GL.MatrixMode(MatrixMode.Projection);

      //  GL.Ortho(0, w, 0, h, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
    //    GL.Viewport(0, 0, w, h); // Use all of the glControl painting area

    }
    private void glControl1_Load(object sender, EventArgs e)
    {

        glControl1.MakeCurrent();

        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadIdentity();
        GL.Enable(EnableCap.DepthTest);
        TexUtil.InitTexturing();
        videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

        GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);

        GL.DepthFunc(DepthFunction.Lequal);

        GL.ColorMaterial(MaterialFace.FrontAndBack, ColorMaterialParameter.AmbientAndDiffuse);
        GL.Enable(EnableCap.ColorMaterial);

        GL.Clear(ClearBufferMask.None);
        GL.Enable(EnableCap.Blend);
        GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

        GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0); // render per default onto screen, not some FBO
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); // use the visible framebuffer
        GL.ClearColor(Color.Black);




        GL.Viewport(glControl1.Location.X - 317, glControl1.Location.Y - 67, glControl1.Width, glControl1.Height);

        Matrix4 modelview = Matrix4.LookAt(Vector3.Zero, -1 * Vector3.UnitZ, Vector3.UnitY);
        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadMatrix(ref modelview);

        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        GL.Ortho(-1, 1, -1, 1, -1, 1.1);

        OpenVideoStream();
        loaded = true;
    }


    private void glControl1_Resize(object sender, EventArgs e)
    {
        if (!loaded)
            return;

    }

    private void glControl1_Paint(object sender, PaintEventArgs e)
    {
        glControl1.MakeCurrent();



        if (!loaded) // Play nice
            return;


        //if(videoFrame1!=null & videoFrame2!=null & videoFrame3!=null & videoFrame4!=null )
        {


            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.Enable(EnableCap.Texture2D);
            if (videoFrame1 != null)

                lock (videoFrame1)
                {
                    glControl1.MakeCurrent();

                    if (videoTexture1 != -1)
                        GL.DeleteTextures(1, ref videoTexture1);

                    videoTexture1 = TexUtil.CreateTextureFromBitmap(videoFrame1);

                    GL.BindTexture(TextureTarget.Texture2D, videoTexture1);

                    //  videoFrame1 = null;
                    fullscreenQuad.Draw(1);
                    if (selectedCam == 1) 
                    {
                        drawSide(videoFrame1);
                    glControl1.MakeCurrent();

                }
                    videoFrame1.Dispose();


                    GC.Collect();

                }

            if (videoFrame2 != null)

                lock (videoFrame2)
                {
                    glControl1.MakeCurrent();
                    if (videoTexture2 != -1)
                        GL.DeleteTextures(1, ref videoTexture2);
                    videoTexture2 = TexUtil.CreateTextureFromBitmap(videoFrame2);

                    GL.BindTexture(TextureTarget.Texture2D, videoTexture2);
                    if (selectedCam == 2)
                    {
                        drawSide(videoFrame2);
                        glControl1.MakeCurrent();

                    }
                      videoFrame2.Dispose();
                    // videoFrame2 = null;
                    GC.Collect();
                    fullscreenQuad.Draw(2);


                }


            if (videoFrame3 != null)

                lock (videoFrame3)
                {
                    glControl1.MakeCurrent();
                    if (videoTexture3 != -1)
                        GL.DeleteTextures(1, ref videoTexture3);
                    videoTexture3 = TexUtil.CreateTextureFromBitmap(videoFrame3);

                    GL.BindTexture(TextureTarget.Texture2D, videoTexture3);
                    if (selectedCam == 3)
                    {
                        drawSide(videoFrame3);
                        glControl1.MakeCurrent();

                    }
                    videoFrame3.Dispose();
                      //  videoFrame3 = null;

                    GC.Collect();
                  fullscreenQuad.Draw(3);
                }


            if (videoFrame4 != null)

                lock (videoFrame4)
                {
                    if (videoTexture4 != -1)
                        GL.DeleteTextures(1, ref videoTexture4);
                    videoTexture4 = TexUtil.CreateTextureFromBitmap(videoFrame4);

                    GL.BindTexture(TextureTarget.Texture2D, videoTexture4);
                    if (selectedCam == 4)
                    {
                        drawSide(videoFrame4);
                        glControl1.MakeCurrent();

                    }
                       videoFrame4.Dispose();
                  //   videoFrame4 = null;
                    GC.Collect();
                  fullscreenQuad.Draw(4);

                }

        }
        glControl2.SwapBuffers();
       // GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        GL.Disable(EnableCap.Texture2D);
        GL.Begin(BeginMode.Quads);
        GL.Color4(0f, 0f, 0f,1f);

         GL.Vertex2(1, .98);
         GL.Vertex2(.98, 1);
         GL.Vertex2(0, 0.02);
         GL.Vertex2(0, -0.02);

         GL.Vertex2(-.98, 1);
         GL.Vertex2(-1, .98);
         GL.Vertex2(0, -0.02);
         GL.Vertex2(0, 0.02);

         GL.Vertex2(-1, -.98);
         GL.Vertex2(-.98, -1);
         GL.Vertex2(0, -0.02);
         GL.Vertex2(0, 0.02);

         GL.Vertex2(1, -.98);
         GL.Vertex2(.98, -1);
         GL.Vertex2(0, -0.02);
         GL.Vertex2(0, 0.02);


         GL.Vertex2(-1, 1);
         GL.Vertex2(-0.98, 1);
         GL.Vertex2(-0.98, 0.98);
         GL.Vertex2(-1, 0.98);

         GL.Vertex2(1, 1);
         GL.Vertex2(0.98, 1);
         GL.Vertex2(0.98, 0.98);
         GL.Vertex2(1, 0.98);

         GL.Vertex2(-1, -1);
         GL.Vertex2(-0.98, -1);
         GL.Vertex2(-0.98, -0.98);
         GL.Vertex2(-1, -0.98);

         GL.Vertex2(1, -1);
         GL.Vertex2(0.98, -1);
         GL.Vertex2(0.98, -0.98);
         GL.Vertex2(1, -0.98);


        GL.End();
        GL.Color4(1f, 1f, 1f, 1f);
        glControl1.SwapBuffers();




    }

    private void OpenVideoStream()
    {


        //     Console.WriteLine("Connecting to {0}", url);
        videoSource1 = new VideoCaptureDevice(videoDevices[0].MonikerString);
        videoSource2 = new VideoCaptureDevice(videoDevices[1].MonikerString);
        videoSource3 = new VideoCaptureDevice(videoDevices[2].MonikerString);
        videoSource4 = new VideoCaptureDevice(videoDevices[3].MonikerString);


        videoSource1.NewFrame += (Object sender, NewFrameEventArgs eventArgs) =>
        {
            System.Threading.Thread.Sleep(10);
            if (videoFrame1 != null)
                lock (videoFrame1)
                {

                    videoFrame1 = new Bitmap(eventArgs.Frame);


                }
            else
            {
                videoFrame1 = new Bitmap(eventArgs.Frame);
            }




        };

        videoSource2.NewFrame += (Object sender, NewFrameEventArgs eventArgs) =>
        {
            System.Threading.Thread.Sleep(10);
            if (videoFrame2 != null)
                lock (videoFrame2)
                {
                    videoFrame2 =  new Bitmap(eventArgs.Frame);

                }
            else
            {
                videoFrame2 = new Bitmap(eventArgs.Frame);
            }
        };

        videoSource3.NewFrame += (Object sender, NewFrameEventArgs eventArgs) =>
        {
            System.Threading.Thread.Sleep(10);
            if (videoFrame3 != null)
                lock (videoFrame3)
                {

                    videoFrame3 =  new Bitmap(eventArgs.Frame);

                }
            else
            {
                videoFrame3 = new Bitmap(eventArgs.Frame);
            }
        };

        videoSource4.NewFrame += (Object sender, NewFrameEventArgs eventArgs) =>
        {
            System.Threading.Thread.Sleep(10);
            if (videoFrame4 != null)
                lock (videoFrame4)
                {
                    videoFrame4 = new Bitmap(eventArgs.Frame);

                }
            else
            {

                videoFrame4 = new Bitmap(eventArgs.Frame);
            }
        };

        videoSource1.Start();
        videoSource2.Start();
        videoSource3.Start();
        videoSource4.Start();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        glControl1.Refresh();

        pictureBox2.Visible = (selectedCam == 1) ? true : false;
        pictureBox3.Visible = (selectedCam == 2) ? true : false;
        pictureBox4.Visible = (selectedCam == 3) ? true : false;
        pictureBox5.Visible = (selectedCam == 4) ? true : false;

    }

    private void glControl2_Paint(object sender, PaintEventArgs e)
    {



    //   glControl2.SwapBuffers();

    }

    private void glControl2_Load(object sender, EventArgs e)
    {
        glControl2.MakeCurrent();

        int w = glControl2.Width;
        int h = glControl2.Height;
        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadIdentity();
        GL.Ortho(-1, 1, -1, 1, -1, 1.1);
        GL.Viewport(0,0, glControl2.Width, glControl2.Height);
        GL.MatrixMode(MatrixMode.Modelview);
        TexUtil.InitTexturing();
        GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
        GL.ColorMaterial(MaterialFace.FrontAndBack, ColorMaterialParameter.AmbientAndDiffuse);
        GL.Enable(EnableCap.ColorMaterial);
        GL.Clear(ClearBufferMask.None);
       GL.Enable(EnableCap.Blend);
        GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

        GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0); // render per default onto screen, not some FBO
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); // use the visible framebuffer
        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        GL.Ortho(-1, 1, -1, 1, -1, 1.1);

    }

    private void drawSide(Bitmap cam)
    {

            glControl2.MakeCurrent();

            GL.MatrixMode(MatrixMode.Modelview);
            GL.Color3(1f, 1f, 1f);
            GL.PushMatrix();
            GL.Enable(EnableCap.Texture2D);
            videoTexture5 = TexUtil.CreateTextureFromBitmap(cam);
            GL.BindTexture(TextureTarget.Texture2D, videoTexture5);
            GL.Begin(BeginMode.Quads);

            GL.TexCoord2(0, 0);
            GL.Vertex2(-1, 1);

            GL.TexCoord2(1f, 0);
            GL.Vertex2(1f, 1f);

            GL.TexCoord2(1f, 1f);
            GL.Vertex2(1f, -1f);

            GL.TexCoord2(0, 1f);
            GL.Vertex2(-1f, -1f);

            GL.End();

            GL.Disable(EnableCap.Texture2D);

            GL.Begin(BeginMode.Quads);
            GL.Color4(1f, 0f, 0.0f, 1f);


        //red
            GL.Vertex2(-0.8f, -0.6f);
            GL.Vertex2(-0.7f, -0.4f);
            GL.Vertex2(-0.68f, -0.4f);
            GL.Vertex2(-0.78f,- 0.6f);

            GL.Vertex2(-0.75f, -0.49f);
            GL.Vertex2(-0.65f, -0.49f);
            GL.Vertex2(-0.65f, -0.51f);
            GL.Vertex2(-0.75f, -0.51f);

            GL.Vertex2(0.8f, -0.6f);
            GL.Vertex2(0.7f, -0.4f);
            GL.Vertex2(0.68f, -0.4f);
            GL.Vertex2(0.78f, -0.6f);

            GL.Vertex2(0.75f, -0.49f);
            GL.Vertex2(0.65f, -0.49f);
            GL.Vertex2(0.65f, -0.51f);
            GL.Vertex2(0.75f, -0.51f);


            GL.Vertex2(-0.69f, -0.38f);
            GL.Vertex2(-0.64f, -0.28f);
            GL.Vertex2(-0.62f, -0.28f);
            GL.Vertex2(-0.67f, -0.38f);

            GL.Vertex2(0.69f, -0.38f);
            GL.Vertex2(0.64f, -0.28f);
            GL.Vertex2(0.62f, -0.28f);
            GL.Vertex2(0.67f, -0.38f);
        //end red

        //yellow
            GL.Color4(1f, 1f, 0.0f, 1f);

            GL.Vertex2(-0.63f, -0.25f);
            GL.Vertex2(-0.53f, -0.05f);
            GL.Vertex2(-0.51f, -0.05f);
            GL.Vertex2(-0.61f, -0.25f);

            GL.Vertex2(-0.58f, -0.14f);
            GL.Vertex2(-0.48f, -0.14f);
            GL.Vertex2(-0.48f, -0.16f);
            GL.Vertex2(-0.58f, -0.16f);


            GL.Vertex2(0.63f, -0.25f);
            GL.Vertex2(0.53f, -0.05f);
            GL.Vertex2(0.51f, -0.05f);
            GL.Vertex2(0.61f, -0.25f);


            GL.Vertex2(0.58f, -0.14f);
            GL.Vertex2(0.48f, -0.14f);
            GL.Vertex2(0.48f, -0.16f);
            GL.Vertex2(0.58f, -0.16f);


            GL.End();

            GL.PopMatrix();

            glControl2.Refresh();






    }



    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {




        bytein = serialPort1.ReadByte();
        if(countdown==0){


            if ((bytein & 1) == 1)
            {
                selectedCam = 1;
            }
            else if ((bytein & 2) == 2)
            {
                selectedCam = 2;

            }
            else if ((bytein & 8) == 8)
            {
                selectedCam = 4;

            }
            else if ((bytein & 4) == 4)
            {
                selectedCam = 3;

            }

            countdown = 20;

        }
        countdown--;

    }



    private void Form1_FormClosing_1(object sender, FormClosingEventArgs e)
    {
        videoSource1.Stop();
        videoSource2.Stop();
        videoSource3.Stop();
        videoSource4.Stop();
    }





    }
}
gmaann
  • 39
  • 3
  • 3
    The first *issue* I see is that for `videoFrame1` though 4, you are overwriting the value without disposing of the previous value first. – Matthew Mar 30 '15 at 13:29
  • you pretty much posted the entire code for your application.. which I am wondering if you have even set up break points and stepped thru the code to identify which line(s) may be causing the error and or issue.. I suspect that you are having an issue in your threading portion of the code / locking – MethodMan Mar 30 '15 at 13:30
  • @Matthew, will this not just overwrite the current bitmap held in that location? – gmaann Mar 30 '15 at 13:32
  • @MethodMan There isn't an error as such being called up, it just fills up the ram until it cant fill it up anymore, the issue I'm having is why it is not clearing out the memory as it goes along or asking what I can do to force it to clear out the memory it has allocated as "modified" – gmaann Mar 30 '15 at 13:33
  • @gmaann Assigning to `null` or overwriting the value will not call `Dispose` on the previous object. It *may* end up being called if the object implements a finalizer which calls `Dispose`, but this is out of your control and is non-deterministic for when this happens (if ever). – Matthew Mar 30 '15 at 13:35
  • @Matthew The way I believe the code works is that when the NewFrame event is called it overwrite whatever bitmap data is in the videoframe, then when the paint event is called (second block of code in post) the image is displayed, and then I call videoframe1.Dispose and GC.collect to get rid of it. C# then shunts this to "modified" ram but does then get rid of it. Is this not what is actually going on? – gmaann Mar 30 '15 at 13:38

1 Answers1

1

For Future reference, the issue was here:

        GL.Enable(EnableCap.Texture2D);
        videoTexture5 = TexUtil.CreateTextureFromBitmap(cam);
        GL.BindTexture(TextureTarget.Texture2D, videoTexture5);
        GL.Begin(BeginMode.Quads);

I was not deleting the textures from the video memory. This then caused the video memory to fill up with the video textures, which then spilled out into the main system memory.

gmaann
  • 39
  • 3