gmaann
gmaann

Reputation: 39

Memory Leak in C# Video processing

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();
    }





    }
}

Upvotes: 2

Views: 817

Answers (1)

gmaann
gmaann

Reputation: 39

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.

Upvotes: 1

Related Questions