We are using the Kinect to stream a customizable video of a user that lets you choose, without stopping the stream, the stream type (color, depth, both with the option to show the tracked skeleton).
Our program runs fine if we change the stream type, but after a few frames (and only on some PCs) of skeleton enabled, the application crashes showing:
Unhandled Exception: System.AccessViolationException.
Here is our code:
private void KinectAllFramesReady(object sender, AllFramesReadyEventArgs e)
{
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
currentSkeleton = GetSkeletonFromSkeletonFrame(skeletonFrame);
if (this.frameMode == Constants.VIDEO_DEPTH_MODE)
currentFrame = GetByteArrayFromDepthFrame(e);
else if (this.frameMode == Constants.VIDEO_COLOR_MODE)
currentFrame = GetByteArrayFromColorFrame(e);
else if (this.frameMode == Constants.VIDEO_NONE_MODE)
currentFrame = GetByteFromBlankFrame();
if (isSkeleton)
{
currentFrame = OverlapSkeleton(currentFrame, this.currentSkeleton);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private byte[] OverlapSkeleton(byte[] currentFrame, Skeleton S)
{
Bitmap tempBitmap = new Bitmap(Constants.KINECT_DEFAULT_CAPTURE_WIDTH, Constants.KINECT_DEFAULT_CAPTURE_HEIGHT, PixelFormat.Format32bppArgb);
BitmapData tempBmapData = tempBitmap.LockBits(new Rectangle(0, 0, Constants.KINECT_DEFAULT_CAPTURE_WIDTH, Constants.KINECT_DEFAULT_CAPTURE_HEIGHT), ImageLockMode.ReadWrite, tempBitmap.PixelFormat);
IntPtr ptr = tempBmapData.Scan0;
for (int i = 0, offset = 0; i < Constants.KINECT_DEFAULT_CAPTURE_HEIGHT; i++)
{
Marshal.Copy(currentFrame, offset, ptr, Constants.KINECT_DEFAULT_CAPTURE_WIDTH << 2);
offset += Constants.KINECT_DEFAULT_CAPTURE_WIDTH << 2;
ptr += tempBmapData.Stride;
}
tempBitmap.UnlockBits(tempBmapData);
Graphics g = Graphics.FromImage(tempBitmap);
// Upper Body
DrawBone(JointType.Head, JointType.ShoulderCenter, S, g);
DrawBone(JointType.ShoulderCenter, JointType.Spine, S, g);
DrawBone(JointType.Spine, JointType.HipCenter, S, g);
// Left Arm
DrawBone(JointType.ShoulderCenter, JointType.ShoulderLeft, S, g);
DrawBone(JointType.ShoulderLeft, JointType.ElbowLeft, S, g);
DrawBone(JointType.ElbowLeft, JointType.WristLeft, S, g);
DrawBone(JointType.WristLeft, JointType.HandLeft, S, g);
// Right Arm
DrawBone(JointType.ShoulderCenter, JointType.ShoulderRight, S, g);
DrawBone(JointType.ShoulderRight, JointType.ElbowRight, S, g);
DrawBone(JointType.ElbowRight, JointType.WristRight, S, g);
DrawBone(JointType.WristRight, JointType.HandRight, S, g);
// Left leg
DrawBone(JointType.HipCenter, JointType.HipLeft, S, g);
DrawBone(JointType.HipLeft, JointType.KneeLeft, S, g);
DrawBone(JointType.KneeLeft, JointType.AnkleLeft, S, g);
DrawBone(JointType.AnkleLeft, JointType.FootLeft, S, g);
// Right Leg
DrawBone(JointType.HipCenter, JointType.HipRight, S, g);
DrawBone(JointType.HipRight, JointType.KneeRight, S, g);
DrawBone(JointType.KneeRight, JointType.AnkleRight, S, g);
DrawBone(JointType.AnkleRight, JointType.FootRight, S, g);
byte[] bytes = new byte[Constants.KINECT_COLOR_FRAME_SIZE];
Marshal.Copy(tempBmapData.Scan0, bytes, 0, Constants.KINECT_COLOR_FRAME_SIZE);
return bytes;
}
Constants.KINECT_COLOR_FRAME_SIZE = 1228800;
Constants.KINECT_DEFAULT_CAPTURE_WIDTH = 640;
Constants.KINECT_DEFAULT_CAPTURE_HEIGHT = 480;
The exception is thrown at the line of Marshal.Copy().
We already seen here on SO that somebody suggests not to copy the whole block of data at once, but instead loop and copy every single row of the image (see for loop in OverlapSkeleton), but it doesn't work.
What's weird is that on our developing machines (i5-2410m@2.30GHz/4Gb RAM and i5-m560@2.67GHz/4Gb RAM) it's all working fine, but on the machines which will host the application (i3-2377m@1.5GHz/4Gb RAM) it crashes after 2-3 secs after the skeleton is enabled, throwing that exception.
OS is Win7 SP1, .NET Framework 4.5 for every machine.
Any idea about what would cause this appearently random exception?