如何从 SoftwareBitmap (UWP) 正确释放 BitmapBuffer?
Posted
技术标签:
【中文标题】如何从 SoftwareBitmap (UWP) 正确释放 BitmapBuffer?【英文标题】:How to properly Release BitmapBuffer from SoftwareBitmap (UWP)? 【发布时间】:2018-08-21 09:15:32 【问题描述】:我很难在 UWP 上的 C++/CX 代码中正确释放使用 SoftwareBitmap.LockBuffer()
方法锁定的 BitmapBuffer
。
基本代码如下所示(它是来自 Microsoft 的 OpenCV 桥接示例,可用 here。
bool OpenCVHelper::GetPointerToPixelData(SoftwareBitmap^ bitmap, unsigned char** pPixelData, unsigned int* capacity)
BitmapBuffer^ bmpBuffer = bitmap->LockBuffer(BitmapBufferAccessMode::ReadWrite);
IMemoryBufferReference^ reference = bmpBuffer->CreateReference();
ComPtr<IMemoryBufferByteAccess> pBufferByteAccess;
if ((reinterpret_cast<IInspectable*>(reference)->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess))) != S_OK)
return false;
if (pBufferByteAccess->GetBuffer(pPixelData, capacity) != S_OK)
return false;
return true;
然后使用此缓冲区 (pPixelData
) 来初始化 cv:Mat
对象(浅拷贝)。并且永远不会被释放。
在同一个SoftwareBitmap
对象上连续调用LockBuffer()
引发异常:
Platform::AccessDeniedException ^ 在内存位置 0x00000002CEEFDCC0。 HRESULT:0x80070005 访问被拒绝。 WinRT 信息:位图共享锁被占用
如何正确释放这个缓冲区?尤其是在 C++/CX 中?
我试图保留引用以在不再需要时释放它。在 C++/CX 中,Dispose() 或 Close() 方法不可访问,编译器建议改为调用析构函数:
BitmapBuffer^ bmpBuffer = nullptr;
// ... get the buffer, use it
//((IDisposable^)bmpBuffer)->Dispose();
bmpBuffer->~BitmapBuffer();
但它不起作用(什么都不做)。正在调用析构函数,但对 LockBuffer() 的另一个调用引发了与以前相同的错误。
【问题讨论】:
我不确定你为什么需要明确释放pPixelData
缓冲区。但是如果你想这样做,你可以在它创建的地方释放它,并在这个函数OpenCVHelper::TryConvert
在这一行创建它:unsigned char* pPixels = nullptr;
。你可以像这样在pPixels = nullptr;
之前释放它return true;
。其实它是一个局部变量,在函数结束后会自动释放。
不是pPixelData,而是bmpBuffer(BitmapBuffer)。原因是要释放通过 LockBuffer() 方法获取的锁。否则它只能工作一次(我在文档中没有找到任何信息,一旦你使用 LockBuffer() 就无法释放它)。
【参考方案1】:
如何从 SoftwareBitmap (UWP) 中正确释放 BitmapBuffer?
在BitmapBuffer
和IMemoryBufferReference
完成工作后,可以通过调用delete
表达式来关闭这些对象。更多详情请查看Destructors。例如:
SoftwareBitmap^ bitmap = ref new SoftwareBitmap(
BitmapPixelFormat::Bgra8,
100,
200,
BitmapAlphaMode::Premultiplied);
BitmapBuffer^ bmpBuffer = bitmap->LockBuffer(BitmapBufferAccessMode::ReadWrite);
IMemoryBufferReference^ reference = bmpBuffer->CreateReference();
delete reference;
delete bmpBuffer;
BitmapBuffer^ bmpBuffer2 = bitmap->LockBuffer(BitmapBufferAccessMode::ReadWrite);
如上代码sn-p所示,删除BitmapBuffer
对象后,可以再次成功锁定缓冲区。
【讨论】:
在您的示例中,两个 LockBuffers 恰好位于同一范围内。通常,在 Pawels 的情况下,不需要手动删除对象。 BitmapBuffer^ 引用一旦超出范围就会自动释放,当没有更多引用时,对象本身就会被删除。 Pawel 的代码必须在某处保留引用。考虑一下,一旦底层对象被强行销毁,这些会发生什么。以上是关于如何从 SoftwareBitmap (UWP) 正确释放 BitmapBuffer?的主要内容,如果未能解决你的问题,请参考以下文章
如何设置 UWP C# StorageFile 以将 SoftwareBitmap 存储到特定路径