views:

1492

answers:

6

Hello,

I am working on a C# application that would display live images from a camera. The problem i am facing with the below code snippet is that, i get AccessViolationException in Marshall.Copy method when running this function executed continuosly in a thread. But, this runs successfuly when run once (i get a single static image). I guess it has to do with some memory corruption issue. Any idea/suggestions on how to deal with this problem ?

    private Image ByteArrayToImage(byte[] myByteArray) 
    {
        if (myByteArray != null)
        {
            MemoryStream ms = new MemoryStream(myByteArray);
            int Height = 504;
            int Width = 664;
            Bitmap bmp = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
            Marshal.Copy(myByteArray, 0, bmpData.Scan0, myByteArray.Length);
            bmp.UnlockBits(bmpData);

            return bmp;
        }
        return null;
    }
+2  A: 

It looks to me like you are always trying to copy the number of bytes myByteArray.Length to the bitmap buffer.

You are not checking that the bitmap buffer is in fact as big as that - so are probably writing off the end of the bitmap buffer.

Try checking if myByteArray.Length is ever greater than bmpData.Stride x bmp.Height

If this is the case you'll need to relook at the assumptions you've made with your hard coded values for width, height and pixel format.

morechilli
+1  A: 

You shouldn't copy the entire image at once. The memory allocation of the bitmap object might not be what you expect. For example the first scan line may be stored last in memory, which would mean that the data for the second scan line would end up outside the allocated memory area for the bitmap object. Also there may be padding between the scan lines to place them on an even address.

Copy one line at a time, using bmpData.Stride to find the next scan line:

int offset = 0;
long ptr = bmpData.Scan0.ToInt64();
for (int i = 0; i < Height; i++) {
   Marshal.Copy(myByteArray, offset, new IntPtr(ptr), Width * 3);
   offset += Width * 3;
   ptr += bmpData.Stride;
}
Guffa
Is this true? See the example code at http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx
morechilli
It's a bit surprising that they would write code like that. That conflicts with the information here: http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.stride.aspx
Guffa
You have a point - more rubbish msdn sample code :)
morechilli
+1. Oh god, thanks for this. I struggled for ages just because of that stupid MSDN example!
Skurmedel
A: 

Hello Guffa,

The piece of code you sent throws 'ArgumentOutOfRangeException' in line Marshall.Copy() ... Any suggestions ??

More evidence that your hardcoded bitmap size does not match the bitmap data.
Hans Passant
How to get the height and width of bitmap array data (w/o harcoding)??
A: 

I tried using 8bpp PixelFormat and 24 bpp PixelFormat ... Nothing worked

I am sure the size of my array data is 334656 (664 * 504) ...

myByteArray.Length is equal to bmpData.Stride x bmp.Height ...

Why does the code not work ?

Can someone guide me how to proceed ?

I'd proceed by copying ony a tiny amount of data, say 30 bytes instead of myByteArray.Length and then you see what happens. No exception= Then study the resulting image and take it from there. What's with the MemoryStream btw? Not used anywere to be seen...
danbystrom
Are you sure because you think so or because you have checked it in the program?
morechilli
A: 

As it works singly, is it being called from a single thread, or multiple different threads ?

and have you tried simply putting a lock around the routine ?

Paul
A: 

Answer for me: forgot to -> // Unlock the bits right after Marshal.Copy bmp.UnlockBits(bmpData);

Has anyone figured this out? This is about the fourth page without an answer. Using the exact code from msdn: http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx which is:

                        Bitmap bmp = new Bitmap("c:\\picture.jpg");

                        // Lock the bitmap's bits.  
                        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                        System.Drawing.Imaging.BitmapData bmpData =
                            bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                            bmp.PixelFormat);

                        // Get the address of the first line.
                        IntPtr ptr = bmpData.Scan0;

                        // Declare an array to hold the bytes of the bitmap.
                        int bytes = bmpData.Stride * bmp.Height;
                        byte[] rgbValues = new byte[bytes];

                        // Copy the RGB values into the array.
                        //This causes read or write protected memory
                        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

This doesn't work in optimize mode and running as exe not in IDE. Any ideas I tried to put this is a new project and if I attached to process when i push a button, and press this button multiple times the error occurs, but in my code I'm only calling once, either way not sure why the error.

jjfait