none
Kinect wrapper to Unity crashes when built to x64 RRS feed

  • Question

  • Hi,

    We have written a plugin for Kinect, which is used with the Unity3D engine. The plugin works fine when working in the Unity editor (32bit), standalone 32bit builds and standalone 64bit builds where the Kinect is disconnected. However, when building for 64bit and the Kinect connected, then it crashes with an OxC000005 error (access violation). It doesn't always crash, but might require a few runs before happening.

    The plugin was initially built with the Kinect SDK 1.0, but later ported to Kinect SDK 1.5. We have tried to find the cause of this, but haven't been succesful yet.

    Currently we have tried to:

    • Attach Visual Studio to the process for debugging. We do have dmp files if any what to take a look. We might have missed something.
    • Write a new .dll which mimics the Kinect, which didn't give any crashes.
    • Tried the slow and painstakingly way of removing some code to see if it stopped the crashing.
    • Set the build settings for stdcall, instead of cdecl (solution suggested to another troubled soul).

    Many thanks

    #include "stdafx.h"
    #include <NuiApi.h>
    #include <string>
    
    // Console includes
    #include <iostream>
    #include <stdio.h>
    #include <io.h>
    #include <fcntl.h>
    
    typedef unsigned int uint;
    
    #if _MSC_VER // this is defined when compiling with Visual Studio
    #define EXPORT_API __declspec(dllexport) // Visual Studio needs annotating exported functions with this
    #else
    #define EXPORT_API // XCode does not need annotating exported functions, so define is empty
    #endif
    
    extern "C"
    {
    
    INuiSensor* nuiSensor = NULL;
    
    // The functions we will call from extern
    
    // Forward declerations
    void FireUpConsole();
    
    void CALLBACK DeviceStatusCallback(HRESULT hr, const OLECHAR* instanceName, const OLECHAR* uniqueDeviceName, void* pUserData) {
    	// FireUpConsole();
    	std::cout << "Device " << uniqueDeviceName << "'s state changed to " << hr << std::endl;
    }
    
    // Initialize the kinect. Flags is an OR'ed bitmask of available options.
    uint EXPORT_API InitializeKinect(int flags){
    
    	//FireUpConsole();
    
    	//std::cout << "Initialize kinect?" << std::endl;
    
    	NuiSetDeviceStatusCallback(&DeviceStatusCallback, NULL);
    	HRESULT hr = NuiCreateSensorByIndex(0, &nuiSensor);
    	if (hr == S_OK) {
    		//std::cout << "Kinect initialized?" << std::endl;
    		BSTR instanceId = nuiSensor->NuiDeviceConnectionId();
    		//std::cout << "Kinect instance id: " << instanceId << std::endl;
    		hr = nuiSensor->NuiInitialize(flags);
    	}
    
    	//std::cout << "Aaaaaand done!" << std::endl;
    	return hr;
    }
    
    //exposes the kinect cleanup function
    void EXPORT_API StopKinect(){
    	//FireUpConsole();
    	//std::cout << "Stop kinect?" << std::endl;
    
    	if (nuiSensor) {
    		//std::cout << "Stop kinect!" << std::endl;
    
    		//uninitialize the kinect
    		nuiSensor->NuiShutdown();
    		nuiSensor->Release();
    		nuiSensor = NULL;
    	}
    }
    
    uint EXPORT_API GetKinectAngle(int& angle){
    	//std::cout << "GetKinectAngle" << std::endl;
    	if (!nuiSensor) return E_NUI_DEVICE_NOT_READY;
    
    	long val = angle;
    	HRESULT res = nuiSensor->NuiCameraElevationGetAngle(&val);
    	angle = val;
    	//std::cout << "GetKinectAngle res " << res << std::endl;
    	return res;
    }
    
    //exposes kinect-motor control
    uint EXPORT_API SetKinectAngle(int angle){
    	//std::cout << "SetKinectAngle to " << angle << std::endl;
    	if (!nuiSensor) return E_NUI_DEVICE_NOT_READY;
    
    	HRESULT res = nuiSensor->NuiCameraElevationSetAngle(angle);
    
    	//std::cout << "SetKinectAngle res " << res << std::endl;
    	return res;
    }
    
    //******** Exposed image strem methods ************
    
    uint EXPORT_API ImageStreamOpen(int imageType, int resolution, int& streamHandle) {
    	//std::cout << "ImageStreamOpen(" << imageType << ", " << resolution << ")" << std::endl;
    
    	if (!nuiSensor) return E_NUI_DEVICE_NOT_READY;
    
    	//std::cout << "  and we can because the kinect is initialized!" << std::endl;
    
    	HANDLE h;
    	HRESULT res = nuiSensor->NuiImageStreamOpen((NUI_IMAGE_TYPE)imageType, (NUI_IMAGE_RESOLUTION)resolution, 0, 2, NULL, &h);
    	streamHandle = (int)h;
    	//std::cout << "ImageStreamOpen: " << res << std::endl;
    	return res;
    }
    
    uint EXPORT_API ImageStreamGetNextFrame(int streamHandle, int& frameNumber, byte* data) {
    	//std::cout << "ImageStreamGetNextFrame" << std::endl;
    	if (!nuiSensor) return E_NUI_DEVICE_NOT_READY;
    
    	NUI_IMAGE_FRAME frame;
    	HRESULT res = nuiSensor->NuiImageStreamGetNextFrame((void*)streamHandle, 0, &frame);
    	if (res != S_OK) return res;
    		
    	// Copy data to C# land
    	frameNumber = frame.dwFrameNumber;
    	INuiFrameTexture* tex = frame.pFrameTexture;
    	NUI_LOCKED_RECT lockedRect;
    	tex->LockRect(0, &lockedRect, NULL, 0);
    	if(lockedRect.Pitch != 0) {
    		BYTE* pBuffer = (BYTE*) lockedRect.pBits;
    		std::memcpy(data, lockedRect.pBits, tex->BufferLen());
    	}
    	tex->UnlockRect(0);
    
    	// Release frame data again
    	res = nuiSensor->NuiImageStreamReleaseFrame((void*)streamHandle, &frame);
    	//std::cout << "Release image frame data again: " << res << std::endl;
    	return res;
    }
    
    //******** Exposed skeleton tracking methods ************
    
    NUI_SKELETON_FRAME skeletonFrame;
    NUI_TRANSFORM_SMOOTH_PARAMETERS* skeletonSmoothing = NULL;
    
    int EXPORT_API SupportedSkeletonCount() {
    	return NUI_SKELETON_COUNT;
    }
    
    /**
     * Grabs the next available skeleton frame.
     */
    uint EXPORT_API SkeletonGetNextFrame(){
    
    	//FireUpConsole();
    	//std::cout << "Get next skeleton frame." << std::endl;
    
    	if (!nuiSensor) return E_NUI_DEVICE_NOT_READY;
    
    	NUI_SKELETON_FRAME tempFrame; //use temp frame to avoid corrupting latest skeleton frame.
    	HRESULT ret = nuiSensor->NuiSkeletonGetNextFrame(0, &tempFrame);
    	if (ret == S_OK) {
    		//std::cout << "New frame aquired." << std::endl;
    		// Store the new skeleton frame
    		skeletonFrame = tempFrame;
    
    		if (skeletonSmoothing)
    			nuiSensor->NuiTransformSmooth(&skeletonFrame, skeletonSmoothing);
    	}
    
    	//std::cout << "Next skeleton frame result: " << ret << std::endl;
    
    	return ret;
    }
    
    /**
     * Enables skeleton smoothing and sets the smoothing parameters.
     */
    void EXPORT_API SetSkeletonSmoothing(float smoothing, float correction, float prediction, float jitter, float maxDeviation) {
    	if (skeletonSmoothing) delete skeletonSmoothing;
    	
    	skeletonSmoothing = new NUI_TRANSFORM_SMOOTH_PARAMETERS();
    	skeletonSmoothing->fSmoothing = smoothing;
    	skeletonSmoothing->fCorrection = correction;
    	skeletonSmoothing->fPrediction = prediction;
    	skeletonSmoothing->fJitterRadius = jitter;
    	skeletonSmoothing->fMaxDeviationRadius = maxDeviation;
    }
    
    /**
     * Disables skeleton smoothing.
     */
    void EXPORT_API DisableSkeletonSmoothing() {
    	if (skeletonSmoothing) delete skeletonSmoothing;
    	skeletonSmoothing = NULL;
    }
    
    void EXPORT_API UpdateSkeletonData(int index, int& trackingState, int& trackingId, int& userIndex, Vector4& centerOfMass, Vector4* positions, int* jointTrackingState){
    	//FireUpConsole();
    	//std::cout << "Update skeleton data" << std::cout;
    	
    	NUI_SKELETON_DATA* skeleton = skeletonFrame.SkeletonData + index;
    	//std::cout << "Skeleton addr: " << skeleton << std::endl;
    	trackingState = skeleton->eTrackingState;
    	trackingId = skeleton->dwTrackingID;
    	userIndex = skeleton->dwUserIndex;
    	centerOfMass = skeleton->Position;
    
    	//std::cout << "Copy skeleton joints from: " << (unsigned long long)skeleton->SkeletonPositions << std::endl;
    	std::memcpy(positions, skeleton->SkeletonPositions, sizeof(Vector4) * NUI_SKELETON_POSITION_COUNT);
    	//std::cout << "Skeleton joints copied" << std::endl; 
    
    	// tracking state is an enum of unknown size, so it needs to be converted to int before returning to C# (atleast that's easier than handling different enum sizes in C# and C++)
    	//std::cout << "Copy skeleton joints state from: " << (unsigned long long)skeleton->eSkeletonPositionTrackingState << std::endl;
    	for (int i = 0; i < NUI_SKELETON_POSITION_COUNT; ++i)
    		jointTrackingState[i] = skeleton->eSkeletonPositionTrackingState[i];
    	//std::cout << "Skeleton joints state copied" << std::endl;
    }
    
    
    // 
    
    void FireUpConsole() {
    	static bool done = false;
    	if (!done) {
    		AllocConsole();
    
    	    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
    		int hCrt = _open_osfhandle((long) handle_out, _O_TEXT);
    	    FILE* hf_out = _fdopen(hCrt, "w");
    		setvbuf(hf_out, NULL, _IONBF, 1);
    	    *stdout = *hf_out;
    
    		HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
    	    hCrt = _open_osfhandle((long) handle_in, _O_TEXT);
    		FILE* hf_in = _fdopen(hCrt, "r");
    	    setvbuf(hf_in, NULL, _IONBF, 128);
    		*stdin = *hf_in;
    
    		done = true;
    	}
    }
    
    } // end of export C block
    
    
    Friday, June 29, 2012 11:14 AM