c # — IMFMediaBuffer из PhotoCaptureFrame

У меня есть плагин для компьютерного зрения, использующий локализованную камеру Hololens на Unity 5.2. Я использую класс UnityEngine.XR.WSA.WebCam.PhotoCaptureFrame с включенным режимом фото при максимальном разрешении, которое составляет 2048×1156, в цветном формате NV12, который является собственным форматом камеры.

Класс PhotoCaptureFrame: https://docs.unity3d.com/2017.2/Documentation/ScriptReference/XR.WSA.WebCam.PhotoCaptureFrame.html

На данный момент я делаю это для того, чтобы мой плагин обрабатывал любую отдельную фотографию:

PhotoCaptureFrame photo; // created correctly through Unity API

List<byte> photoBuffer = new List<byte>();
photo.CopyRawImageDataIntoBuffer(photoBuffer);

// marshal photoBuffer to plugin (and it works fine for the computer vision part)

Однако он копирует необработанный буфер каждый раз. Я хочу использовать необработанный буфер прямо из моего плагина. Итак, я попробовал это:

IntPtr rawBufferPtr = photo.GetUnsafePointerToBuffer(); // COM pointer to IMFMediaBuffer is incremented
// send rawBufferPtr to plugin (native function described below)
Marshal.Release(rawBufferPtr);

Интерфейс IMFMediaBuffer: https://msdn.microsoft.com/en-us/library/windows/desktop/ms696261(v=vs.85).aspx

И в моем плагине C ++:

#include <Mfidl.h> // for IMFMediaBuffer support

void process_photo(void *photo_buffer_wrapper, int photo_width, int photo_height)
{
// photo_buffer_wrapper = rawBufferPtr in managed environment

IMFMediaBuffer *media_buffer = reinterpret_cast<IMFMediaBuffer *>(photo_buffer_wrapper);
BYTE *photo_buffer = NULL;
HRESULT result = media_buffer->Lock(&photo_buffer, NULL, NULL);
if (SUCCEEDED(result))
{
// do image processing stuff here (with OpenCV) using photo_buffer
media_buffer->Unlock;
}
}

Мне кажется, это нормально. Это тоже хорошо компилируется. Но во время выполнения я получаю нарушение прав доступа и приложения вылетают на Hololens.

Код исключения: 0xC0000005

Информация об исключении: Поток попытался прочитать или записать виртуальный адрес, для которого у него нет соответствующего доступа.

Кто-нибудь видит проблему? Что-то связанное с тем, как я передаю объект IMFMediaBuffer из управляемой в неуправляемую среду?

Большое спасибо!

3

Решение

Я отвечу на свой вопрос.

photo_buffer_wrapper не указатель на IMFMediaBuffer как я и думал, но указатель на IUnknown, Вот модифицированная нативная функция, которая работает как задумано:

// UNMANAGED ENVIRONMENT
#include <Mfidl.h> // for IMFMediaBuffer support + other COM stuff

void process_photo(void *photo_buffer_unknown, int photo_width, int photo_height)
{
// photo_buffer_unknown = photoCaptureFrame.GetUnsafePointerToBuffer() in managed environment which is an IntPtr

IMFMediaBuffer *media_buffer;
if (SUCCEEDED(reinterpret_cast<IUnknown *>(photo_buffer_unknown)->QueryInterface<IMFMediaBuffer>(&media_buffer)))
{
BYTE* photo_buffer = NULL;
if (SUCCEEDED(media_buffer->Lock(&photo_buffer, NULL, NULL)))
{
// process photo_buffer with OpenCV (wrapped in a cv::Mat)

media_buffer->Unlock();
media_buffer->Release(); // QueryInterface on IUnknown has incremented reference count by one
}
}
}

NB: указатель возвращается из photoCaptureFrame.GetUnsafePointerToBuffer() все еще должен быть выпущен в управляемой среде, как в моем вопросе:

// MANAGED ENVIRONMENT
IntPtr mediaBufferUnknownPtr = photoCaptureFrame.GetUnsafePointerToBuffer();
// send mediaBufferUnknownPtr to native function through extern DLL call
Marshal.Release(mediaBufferUnknownPtr)
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]