Search code examples
c#c++opencvdllexport

cv::VideoCapture doesn't open a file or stream when using it from DLL in C# project


I'm using Unity's C# scripts and OpenCV in C++ via DllImports. My goal is to create an video stream inside Unity scene coming from OpenCV . Unity loads the library, which contains OpenCV functions. The problem is that cv::VideoCapture().open("path_to_file_or_stream") always return false when get called from dll (from Unity).

When I build my C++ code as executable everything works just perfect. I am using CMAKE to build my project.

# Build exe
ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS_DIR} ${INCL_DIR})

# Build lib
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS_DIR} ${INCL_DIR})

# OpenCV
FIND_PACKAGE(OpenCV)
IF(OpenCV_FOUND)
  TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC ${OpenCV_LIBS})
    MESSAGE(STATUS "[OpenCV_LIBS] " ${OpenCV_LIBS})
ENDIF()

However, when running from dll, cv::VideoCapture() is not opening.

Here is some code I have so far:

C++ / ImageProviderAPI.h

#define IMAGE_API __declspec(dllexport)
extern "C"
{
    ...
    IMAGE_API ImageProviderAPI* InitProvider(const char* url);
    IMAGE_API void StartProvider(ImageProviderAPI* api);
    ...
}

class ImageProviderAPI {

public:

    ImageProviderAPI(std::string url);
    ~ImageProviderAPI();

    void start();

private:

    std::string m_url;
    cv::VideoCapture* p_videoCapture;
};

C++ / ImageProviderAPI.h

IMAGE_API ImageProviderAPI* InitProvider(const char* url) {
    return new ImageProviderAPI(std::string(url));
}

IMAGE_API void StartProvider(ImageProviderAPI* api) {
    api->start();
}

ImageProviderAPI::ImageProviderAPI(std::string url) : 
m_url(url), p_videoCapture(nullptr) {

}

void ImageProviderAPI::start() {
    p_videoCapture = new cv::VideoCapture();
    bool res = p_videoCapture->open(m_url);     // m_url - path to file or stream url
                                                // Always false if called from dll 
    // or this way

    p_videoCapture = new cv::VideoCapture(m_url);
    bool res = p_videoCapture->isOpened();      // Always false if called from dll
}

C# / MyScript.cs

public class MyScript: MonoBehaviour {
    ...
    [DllImport("ImageProviderAPI.dll", CharSet = CharSet.Unicode)]
    private static extern IntPtr InitProvider(string url);

    [DllImport("ImageProviderAPI.dll", CharSet = CharSet.Unicode)]
    private static extern void StartProvider(IntPtr api);

    private IntPtr API;

    void Start() {
        API = InitProvider("path_to_file_or_stream_url");
        StartProvider(API);
    }

    void Update() {
        // Do stuff
    }
}

For example some other OpenCV functions like cv::imread, cv::resize, cv::cvtColor works when called from dll. I used std::ofstream to log VideoCapture opening result.

I didn't expect that there any difference when running as exe or dll. Maybe I missed something during dll import/export.


Solution

  • The problem is DllImportAttribute, particularly CharSet = CharSet.Unicode.

    To solve it just remove CharSet = CharSet.Unicode

    [DllImport("ImageProviderAPI.dll")]