Question

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?

Was it helpful?

Solution

It's not a real solution, but more a hack / workarond.

Anyway I found that the exception is throwed randomly, but not frequently, so the workaround is to decorate the OverlapSkeleton method with

[HandleProcessCorruptedStateExceptions]

and

[SecurityCritical]

Doing this it is possible to catch CSEs using a try/catch. The resulting code is:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
private byte[] OverlapSkeleton(byte[] currentFrame, Skeleton S)
{
    if (S == null)
        return currentFrame;

    try
    {
        //The above code with Marshall.copy and lines drawing
    }
    catch(Exception)
    {
        return currentFrame;
    }

Again, it doesn't solve the problem, but since there's no performance impact and we also runned out of ideas this is the best solution I have to offer. If anyone has a better/working idea is welcomed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top