c# - Kinect:AccessViolationException

标签 c# .net exception kinect access-violation

我们正在使用 Kinect 流式传输用户的可自定义视频,您可以在不停止流的情况下选择流类型(颜色、深度,都可以选择显示跟踪的骨架)。

如果我们更改流类型,我们的程序运行良好,但在启用框架的几帧(并且仅在某些 PC 上)后,应用程序崩溃显示:

Unhandled Exception: System.AccessViolationException.

这是我们的代码:

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;

在 Marshal.Copy() 行抛出异常。 我们已经在 SO 上看到有人建议不要一次复制整个数据 block ,而是循环复制图像的每一行(参见 OverlapSkeleton 中的 for 循环),但它不起作用。

奇怪的是,在我们的开发机器上(i5-2410m@2.30GHz/4Gb RAM 和 i5-m560@2.67GHz/4Gb RAM)一切正常,但在将托管应用程序的机器上(i3-2377m @1.5GHz/4Gb RAM)它在骨架启用后 2-3 秒后崩溃,抛出该异常。

操作系统为 Win7 SP1,适用于每台机器的 .NET Framework 4.5。

知道什么会导致这个看似随机的异常吗?

最佳答案

这不是一个真正的解决方案,而是一个 hack/workarond。

反正我发现异常是随机抛出的,但并不频繁,所以解决方法是用

装饰OverlapSkeleton方法
[HandleProcessCorruptedStateExceptions]

[SecurityCritical]

这样做可以使用 try/catch 捕获 CSE。生成的代码是:

[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;
    }

同样,它没有解决问题,但由于没有性能影响,而且我们也没有想法,所以这是我必须提供的最佳解决方案。如果有人有更好/可行的想法,我们欢迎。

关于c# - Kinect:AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21379695/

相关文章:

c# - SimpleInjector - 注册对象依赖于另一个注册对象的值

android - 游标索引越界异常: Index -1 requested with size 0

c# - 将 DateTime 与 SqlDateTime.MinValue 进行比较

C# - System.Windows.Forms.Clipboard.GetDataObject() 没有响应

c# - 当 Enumerable 在 Linq 中有超过 X 个元素时提前返回

.NET 国际奥委会 : Preconfiguring library components for easier use

java - 如何解决 honeSTLY 没有意义的 TransientObjectException

c# - 如何清除组合框?

c# - 如果结构具有 ReadOnlySpan 字段,如何将 ref struct 参数传递给 MethodInfo

c# - 不同线程访问 MemoryStream