媒体基金会捕获反转图像
Media Foundation capture reversed image
这有点奇怪,我正在使用 SourceReader 从我的相机中捕捉样本。我最终得到了一个颠倒的 HBITMAP。
捕获代码如下:
for (;;)
{
DWORD streamIndex = 0, flags = 0;
LONGLONG llTimeStamp = 0;
CComPtr<IMFSample> pSample;
hr = sr->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM,0,&streamIndex,&flags,&llTimeStamp,&pSample);
...
}
我得到一个 IMFSample,我正在尝试绘制它(目前不是使用 Direct3D,而是使用 Direct2D)。捕获的格式是 MFVideoFormat_NV12,我想将它转换为 MFVideoFormat_RGB32,这样我就可以从中创建一个 HBITMAP。因此,我创建了一个 IMFTransform,其源类型设置为从捕获返回的媒体类型,并以 RGB 类型为目标:
if (prvtrs)
{
DWORD is = 0, os = 0;
hr = prvtrs->GetStreamCount(&is, &os);
if (is > 0 && os > 0)
{
hr = prvtrs->SetInputType(iids[0], fmt, 0);
if (SUCCEEDED(hr))
{
PROPVARIANT pv;
InitPropVariantFromCLSID(MFVideoFormat_RGB32, &pv);
hr = prmt->SetItem(MF_MT_SUBTYPE, pv);
if (SUCCEEDED(hr))
{
hr = prvtrs->SetOutputType(oods[0], prmt, 0);
if (SUCCEEDED(hr))
{
// OK
}
}
}
}
}
捕获后,我转换 IMFSample:
CComPtr<IMFSample> pSample2;
MFCreateSample(&pSample2);
if (si.cbSize == 0)
prvtrs->GetOutputStreamInfo(oods[0], &si);
CComPtr<IMFMediaBuffer> bb;
MFCreateMemoryBuffer(si.cbSize, &bb);
pSample2->AddBuffer(bb);
hr = prvtrs->ProcessInput(iids[0], pSample, 0);
MFT_OUTPUT_DATA_BUFFER db = { 0 };
db.dwStreamID = oods[0];
db.pSample = pSample2;
DWORD st;
hr = prvtrs->ProcessOutput(0, 1, &db, &st);
if (db.pEvents)
db.pEvents->Release();
if (SUCCEEDED(hr))
{
// Show it
CComPtr<IMFMediaBuffer> b4;
pSample2->ConvertToContiguousBuffer(&b4);
if (b4)
{
vector<char> o;
auto bi = SaveSample(b4, wi, he);
....
这是我的 SaveSample:
HBITMAP SaveSample(CComPtr<IMFMediaBuffer> mediaBuffer, int width32, int height32)
{
HRESULT hr = 0;
BYTE *pData = NULL;
DWORD le = 0;
mediaBuffer->GetCurrentLength(&le);
hr = mediaBuffer->Lock(&pData, NULL, NULL);
if (!pData)
return 0;
unsigned char* pixels = pData;
// at this point we have some input
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = width32;
bmih.biHeight = height32;
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
BITMAPINFO dbmi = { 0 };
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;
HDC hdc = ::GetDC(NULL);
HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, pixels, &dbmi, DIB_RGB_COLORS);
::ReleaseDC(NULL, hdc);
mediaBuffer->Unlock();
return hbmp;
}
我得到的是倒置的位图。我做错了什么?
您错过了 specification of BMP files 的关键部分:
The pixel array is a block of 32-bit DWORDs, that describes the image pixel by pixel. Usually pixels are stored "bottom-up", starting in the lower left corner, going from left to right, and then row by row from the bottom to the top of the image.[4] Unless BITMAPCOREHEADER is used, uncompressed Windows bitmaps also can be stored from the top to bottom, when the Image Height value is negative.
考虑到这一点,您可以轻松修复错误。
这有点奇怪,我正在使用 SourceReader 从我的相机中捕捉样本。我最终得到了一个颠倒的 HBITMAP。
捕获代码如下:
for (;;)
{
DWORD streamIndex = 0, flags = 0;
LONGLONG llTimeStamp = 0;
CComPtr<IMFSample> pSample;
hr = sr->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM,0,&streamIndex,&flags,&llTimeStamp,&pSample);
...
}
我得到一个 IMFSample,我正在尝试绘制它(目前不是使用 Direct3D,而是使用 Direct2D)。捕获的格式是 MFVideoFormat_NV12,我想将它转换为 MFVideoFormat_RGB32,这样我就可以从中创建一个 HBITMAP。因此,我创建了一个 IMFTransform,其源类型设置为从捕获返回的媒体类型,并以 RGB 类型为目标:
if (prvtrs)
{
DWORD is = 0, os = 0;
hr = prvtrs->GetStreamCount(&is, &os);
if (is > 0 && os > 0)
{
hr = prvtrs->SetInputType(iids[0], fmt, 0);
if (SUCCEEDED(hr))
{
PROPVARIANT pv;
InitPropVariantFromCLSID(MFVideoFormat_RGB32, &pv);
hr = prmt->SetItem(MF_MT_SUBTYPE, pv);
if (SUCCEEDED(hr))
{
hr = prvtrs->SetOutputType(oods[0], prmt, 0);
if (SUCCEEDED(hr))
{
// OK
}
}
}
}
}
捕获后,我转换 IMFSample:
CComPtr<IMFSample> pSample2;
MFCreateSample(&pSample2);
if (si.cbSize == 0)
prvtrs->GetOutputStreamInfo(oods[0], &si);
CComPtr<IMFMediaBuffer> bb;
MFCreateMemoryBuffer(si.cbSize, &bb);
pSample2->AddBuffer(bb);
hr = prvtrs->ProcessInput(iids[0], pSample, 0);
MFT_OUTPUT_DATA_BUFFER db = { 0 };
db.dwStreamID = oods[0];
db.pSample = pSample2;
DWORD st;
hr = prvtrs->ProcessOutput(0, 1, &db, &st);
if (db.pEvents)
db.pEvents->Release();
if (SUCCEEDED(hr))
{
// Show it
CComPtr<IMFMediaBuffer> b4;
pSample2->ConvertToContiguousBuffer(&b4);
if (b4)
{
vector<char> o;
auto bi = SaveSample(b4, wi, he);
....
这是我的 SaveSample:
HBITMAP SaveSample(CComPtr<IMFMediaBuffer> mediaBuffer, int width32, int height32)
{
HRESULT hr = 0;
BYTE *pData = NULL;
DWORD le = 0;
mediaBuffer->GetCurrentLength(&le);
hr = mediaBuffer->Lock(&pData, NULL, NULL);
if (!pData)
return 0;
unsigned char* pixels = pData;
// at this point we have some input
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = width32;
bmih.biHeight = height32;
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
BITMAPINFO dbmi = { 0 };
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;
HDC hdc = ::GetDC(NULL);
HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, pixels, &dbmi, DIB_RGB_COLORS);
::ReleaseDC(NULL, hdc);
mediaBuffer->Unlock();
return hbmp;
}
我得到的是倒置的位图。我做错了什么?
您错过了 specification of BMP files 的关键部分:
The pixel array is a block of 32-bit DWORDs, that describes the image pixel by pixel. Usually pixels are stored "bottom-up", starting in the lower left corner, going from left to right, and then row by row from the bottom to the top of the image.[4] Unless BITMAPCOREHEADER is used, uncompressed Windows bitmaps also can be stored from the top to bottom, when the Image Height value is negative.
考虑到这一点,您可以轻松修复错误。