Reputation: 97
I am trying to return the byte array from my unmanaged c++ dll back to c# unity. Thank you very much in advance for taking the time to help >< I'm really new to DLL in unity so I'm extremely confused how 2 languages are even suppose to work together.
CPP
The problem is in here, I've done my calculations, but I'm struggling to find a way to return it back to c# with an array format.
Currently, the byte array holds color codes e.g RGBA (223,124,23,255,212,143,234,255) and it repeats
#include "WebcamDLL.h"
#include <vector>
extern "C" {
int adjustBrightnesss(unsigned char* bytes, int sizeOfArray)
{
std::vector<int> myvector;
int alphaP = 0;
for (int i = 0; i < sizeOfArray; i++) {
switch (alphaP) {
case 0:
case 1:
case 2:
myvector[i] = bytes[i] / 2;
alphaP++;
break;
case 3:
alphaP = 0;
break;
}
}
return bytes;
}
}
Header file
#ifdef TESTFUNCDLL_EXPORT
#define TESTFUNCDLL_API __declspec(dllexport)
#else
#define TESTFUNCDLL_API __declspec(dllimport)
#endif
extern "C" {
TESTFUNCDLL_API int adjustBrightnesss(unsigned char* bytes, int sizeOfArray);
}
C# File
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices; // Needed for custom DLL
using System;
public class WebcamManager : MonoBehaviour
{
private RawImage ri; // Gets the RawImage component from script parent
private WebCamTexture wct; // Object to hold the WebCamTexture add-on
private AspectRatioFitter arf; // Ensures RawImage object has same scaling as Webcam
private Color32[] pixels; // Keeps the pixels from webcamtexture
Texture2D tex; // A placeholder for the texture2D
[DllImport("WebcamBrightness", EntryPoint = "adjustBrightness")]
public static extern int adjustBrightness(byte bytes, int b);
void Start()
{
newBrightness = 1; // Default 1, if 0 will make image go super bright
arf = GetComponent<AspectRatioFitter>(); // Gets the component AspectRatioFitter in script parent
ri = GetComponent<RawImage>(); // Gets the component RawImage in script parent
wct = new WebCamTexture(Screen.width, Screen.height); // Creates a new WebCamTexture in wct with the width and height of the current screen
wct.Play(); // plays webcam
//adjustBrightness(wct.GetPixels32());
}
// Update is called once per frame
void Update()
{
float videoRatio = (float)wct.width / (float)wct.height; // Ensures that the scaling is the same as the webcam
arf.aspectRatio = videoRatio; // applies webcam scaling to rawimage
tex = new Texture2D(wct.width, wct.height, TextureFormat.ARGB32, false); // pass texture2D tex the information of webcamtexture height, width, ARGB32 (32 bit with alpha) and no mipmaps
pixels = wct.GetPixels32();
// After getting the bytes, I wanna save it back to color32 or atleast an array format.
tex.SetPixels32(pixels);
tex.Apply();
// Sets texture of rawimage from canvas to be web camera view
ri.texture = tex;
}
}
EDITTED CPP FILE
#include "WebcamDLL.h"
#include <vector>
extern "C" {
unsigned char* adjustBrightness(unsigned char* bytes, int sizeOfArray)
{
int alphaP = 0;
for (int i = 0; i < sizeOfArray; i++) {
switch (alphaP) {
case 0:
case 1:
case 2:
bytes[i] = bytes[i] / 2;
alphaP++;
break;
case 3:
alphaP = 0;
break;
}
}
return bytes;
}
int freeMem(unsigned char* arrayPtr) {
delete[] arrayPtr;
return 0;
}
}
EDITTED HEADER FILE
#ifdef TESTFUNCDLL_EXPORT
#define TESTFUNCDLL_API __declspec(dllexport)
#else
#define TESTFUNCDLL_API __declspec(dllimport)
#endif
extern "C" {
TESTFUNCDLL_API unsigned char* adjustBrightness(unsigned char* bytes, int sizeOfArray);
TESTFUNCDLL_API int freeMem(unsigned char* arrayPtr);
}
EDITTED C# FILE
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices; // Needed for custom DLL
using System;
public class WebcamManager : MonoBehaviour
{
private RawImage ri; // Gets the RawImage component from script parent
private WebCamTexture wct; // Object to hold the WebCamTexture add-on
private AspectRatioFitter arf; // Ensures RawImage object has same scaling as Webcam
private Color32[] pixels; // Keeps the pixels from webcamtexture
Texture2D tex; // A placeholder for the texture2D
public RawImage ri2;
float timer;
[DllImport("WebcamBrightness", EntryPoint = "adjustBrightness", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr adjustBrightness(byte[] bytes, int b);
[DllImport("WebcamBrightness", EntryPoint = "freeMem", CallingConvention = CallingConvention.Cdecl)]
public static extern int freeMem(IntPtr ptr);
[SerializeField]
int newBrightness;
void Start()
{
newBrightness = 1; // Default 1, if 0 will make image go super bright
arf = GetComponent<AspectRatioFitter>(); // Gets the component AspectRatioFitter in script parent
ri = GetComponent<RawImage>(); // Gets the component RawImage in script parent
wct = new WebCamTexture(Screen.width, Screen.height); // Creates a new WebCamTexture in wct with the width and height of the current screen
wct.Play(); // plays webcam
float videoRatio = (float)wct.width / (float)wct.height; // Ensures that the scaling is the same as the webcam
arf.aspectRatio = videoRatio; // applies webcam scaling to rawimage
tex = new Texture2D(wct.width, wct.height, TextureFormat.ARGB32, false); // pass texture2D tex the information of webcamtexture height, width, ARGB32 (32 bit with alpha) and no mipmaps
}
// Update is called once per frame
void Update()
{
//timer += Time.deltaTime;
pixels = wct.GetPixels32();
IntPtr returnedPtr = adjustBrightness(Color32ArrayToByteArray(pixels), Color32ArrayToByteArray(pixels).Length);
byte[] returnedResult = new byte[Color32ArrayToByteArray(pixels).Length];
Marshal.Copy(returnedPtr, returnedResult, 0, Color32ArrayToByteArray(pixels).Length);
freeMem(returnedPtr);
Debug.Log(returnedResult[0]);
tex.SetPixels32(pixels);
ri.texture = tex;
tex.Apply();
// Sets texture of rawimage from canvas to be web camera view
}
public void AdjustBrightness(float b)
{
newBrightness = (int)b;
}
private static byte[] Color32ArrayToByteArray(Color32[] colors)
{
if (colors == null || colors.Length == 0)
return null;
int lengthOfColor32 = Marshal.SizeOf(typeof(Color32));
int length = lengthOfColor32 * colors.Length;
byte[] bytes = new byte[length];
GCHandle handle = default(GCHandle);
try
{
handle = GCHandle.Alloc(colors, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
Marshal.Copy(ptr, bytes, 0, length);
}
finally
{
if (handle != default(GCHandle))
handle.Free();
}
return bytes;
}
}
Upvotes: 2
Views: 6489
Reputation: 125455
There are many ways to return byte arrays from C# and below is one of them. The memory allocation and de-allocation are both done in C++. You must call the function to free the memory from C#. I made the example very simple so that you can easily integrate it in your current code.
IntPtr
is the key in this answer.
C++:
char* getByteArray()
{
//Create your array(Allocate memory)
char * arrayTest = new char[2];
//Do something to the Array
arrayTest[0]=3;
arrayTest[1]=5;
//Return it
return arrayTest;
}
int freeMem(char* arrayPtr){
delete[] arrayPtr;
return 0;
}
C#:
[DllImport("Test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr getByteArray();
[DllImport("Test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int freeMem(IntPtr ptr);
//Test
void Start() {
//Call and return the pointer
IntPtr returnedPtr = getIntArray();
//Create new Variable to Store the result
byte[] returnedResult = new byte[2];
//Copy from result pointer to the C# variable
Marshal.Copy(returnedPtr, returnedResult, 0, 2);
//Free native memory
freeMem(returnedPtr);
//The returned value is saved in the returnedResult variable
byte val1 = returnedResult[0];
byte val2 = returnedResult[1];
}
Upvotes: 7
Reputation: 825
You could pass an extra parameter to the function, let's say another byte array, and then in the adjustBrightnesss function replace that myvector with that array. As far as i know you will get the array with the modified values
Upvotes: 0