使用媒体基础捕捉图像

问题描述 投票:0回答:1

我在使用 Windows API 和 Media Foundation 库时遇到问题。我下面的代码从网络摄像头捕获并保存图像,但生成的图像是黑白的,并且有两个并排的图像。谁能帮我解决这个问题吗?

#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <mfobjects.h>
#include <mferror.h>
#include <stdio.h>

#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mf.lib")

const GUID MFVideoFormat_RGB32 = { 0x00000016, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} };
const GUID MF_MT_MAJOR_TYPE = { 0x48eba18e, 0xf8c9, 0x4687, {0xbf, 0x11, 0x0a, 0x74, 0xc9, 0xf9, 0x6a, 0x8f} };
const GUID MF_MT_SUBTYPE = { 0xf7e34c9a, 0x42e8, 0x4714, {0xb7, 0x83, 0x5e, 0xbd, 0xa4, 0x3a, 0xe5, 0x04} };
const GUID MFMediaType_Video = { 0x73646976, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} };

HRESULT InitializeMediaFoundation() {
    HRESULT hr = MFStartup(MF_VERSION);
    if (FAILED(hr)) {
        printf("MFStartup failed: 0x%lx\n", hr);
    }
    return hr;
}

HRESULT CreateVideoDeviceSource(IMFMediaSource** ppSource) {
    IMFAttributes* pAttributes = NULL;
    IMFActivate** ppDevices = NULL;
    UINT32 count = 0;
    HRESULT hr = MFCreateAttributes(&pAttributes, 1);
    if (FAILED(hr)) {
        printf("MFCreateAttributes failed: 0x%lx\n", hr);
        return hr;
    }

    hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
    if (FAILED(hr)) {
        printf("SetGUID MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE failed: 0x%lx\n", hr);
        pAttributes->Release();
        return hr;
    }

    hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
    if (FAILED(hr)) {
        printf("MFEnumDeviceSources failed: 0x%lx\n", hr);
        pAttributes->Release();
        return hr;
    }

    if (count > 0) {
        hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(ppSource));
        if (FAILED(hr)) {
            printf("ActivateObject failed: 0x%lx\n", hr);
        }
    }
    else {
        printf("No video capture devices found.\n");
        hr = E_FAIL;
    }

    for (UINT32 i = 0; i < count; i++) {
        ppDevices[i]->Release();
    }
    CoTaskMemFree(ppDevices);
    pAttributes->Release();

    return hr;
}
HRESULT CaptureImage() {
    IMFMediaSource* pSource = NULL;
    IMFSourceReader* pReader = NULL;
    IMFMediaType* pType = NULL;
    DWORD streamIndex = MF_SOURCE_READER_FIRST_VIDEO_STREAM;
    HRESULT hr = CreateVideoDeviceSource(&pSource);
    if (FAILED(hr)) {
        return hr;
    }

    hr = MFCreateSourceReaderFromMediaSource(pSource, NULL, &pReader);
    if (FAILED(hr)) {
        printf("MFCreateSourceReaderFromMediaSource failed: 0x%lx\n", hr);
        pSource->Release();
        return hr;
    }

    hr = pReader->GetCurrentMediaType(streamIndex, &pType);
    if (FAILED(hr)) {
        printf("GetCurrentMediaType failed: 0x%lx\n", hr);
        pReader->Release();
        pSource->Release();
        return hr;
    }

    hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
    if (FAILED(hr)) {
        printf("SetGUID MF_MT_SUBTYPE failed: 0x%lx\n", hr);
        pType->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    hr = pReader->SetCurrentMediaType(streamIndex, NULL, pType);
    if (FAILED(hr)) {
        printf("SetCurrentMediaType failed: 0x%lx\n", hr);
        pType->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    pType->Release();

    IMFSample* pSample = NULL;
    DWORD dwFlags = 0;

    for (int i = 0; i < 10; ++i) {
        hr = pReader->ReadSample(streamIndex, 0, NULL, &dwFlags, NULL, &pSample);
        if (SUCCEEDED(hr) && pSample) {
            break;  
        }
        Sleep(100); 
    }

    if (FAILED(hr) || !pSample) {
        printf("ReadSample failed: 0x%lx\n", hr);
        printf("Flags: 0x%lx\n", dwFlags); flags
        pReader->Release();
        pSource->Release();
        return hr;
    }

    printf("Sample read successfully.\n");
    IMFMediaBuffer* pBuffer = NULL;
    hr = pSample->ConvertToContiguousBuffer(&pBuffer);
    if (FAILED(hr)) {
        printf("ConvertToContiguousBuffer failed: 0x%lx\n", hr);
        pSample->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    BYTE* pData = NULL;
    DWORD cbBuffer = 0;
    hr = pBuffer->Lock(&pData, NULL, &cbBuffer);
    if (FAILED(hr)) {
        printf("Lock failed: 0x%lx\n", hr);
        pBuffer->Release();
        pSample->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    const char* filePath = "C:\\capture.bmp";
    FILE* pFile;
    fopen_s(&pFile, filePath, "wb");
    if (pFile) {
        BITMAPFILEHEADER bfHeader;
        BITMAPINFOHEADER biHeader;

        bfHeader.bfType = 'MB';
        bfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + cbBuffer;
        bfHeader.bfReserved1 = 0;
        bfHeader.bfReserved2 = 0;
        bfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

        biHeader.biSize = sizeof(BITMAPINFOHEADER);
        biHeader.biWidth = 640;
        biHeader.biHeight = -480;
        biHeader.biPlanes = 1;
        biHeader.biBitCount = 32;
        biHeader.biCompression = BI_RGB;
        biHeader.biSizeImage = cbBuffer;
        biHeader.biXPelsPerMeter = 0;
        biHeader.biYPelsPerMeter = 0;
        biHeader.biClrUsed = 0;
        biHeader.biClrImportant = 0;

        fwrite(&bfHeader, sizeof(BITMAPFILEHEADER), 1, pFile);
        fwrite(&biHeader, sizeof(BITMAPINFOHEADER), 1, pFile);
        fwrite(pData, cbBuffer, 1, pFile);
        fclose(pFile);

        printf("Image saved to %s\n", filePath);
    }
    else {
        printf("Failed to open file for writing\n");
    }

    hr = pBuffer->Unlock();
    pBuffer->Release();

    if (pSample) {
        pSample->Release();
    }
    if (pReader) {
        pReader->Release();
    }
    if (pSource) {
        pSource->Release();
    }

    return hr;
}


int main() {
    HRESULT hr = InitializeMediaFoundation();
    if (SUCCEEDED(hr)) {
        hr = CaptureImage();
        if (SUCCEEDED(hr)) {
            printf("Image captured successfully.\n");
        }
        else {
            printf("Failed to capture image: 0x%lx\n", hr);
        }
    }
    MFShutdown();
    return 0;
}

这是一张示例图片

enter image description here

我使用的是 Visual Studio 2022。这是一个从网络摄像头捕获图像并将其保存到 C 盘的程序。

c++ winapi video ms-media-foundation windows-api-code-pack
1个回答
0
投票

MFVideoFormat_RGB32无法工作。我只能在 Windows 上使用 MFVideoFormat_YUY2。您可以尝试我的示例代码

我还修改了你的代码:

#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <mfobjects.h>
#include <mferror.h>
#include <stdio.h>

#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")

// const GUID MFVideoFormat_RGB32 = {0x00000016, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
// const GUID MF_MT_MAJOR_TYPE = {0x48eba18e, 0xf8c9, 0x4687, {0xbf, 0x11, 0x0a, 0x74, 0xc9, 0xf9, 0x6a, 0x8f}};
// const GUID MF_MT_SUBTYPE = {0xf7e34c9a, 0x42e8, 0x4714, {0xb7, 0x83, 0x5e, 0xbd, 0xa4, 0x3a, 0xe5, 0x04}};
// const GUID MFMediaType_Video = {0x73646976, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};

unsigned char clamp(double value, double min, double max)
{
    if (value < min)
        return static_cast<unsigned char>(min);
    if (value > max)
        return static_cast<unsigned char>(max);
    return static_cast<unsigned char>(value);
}

void ConvertYUY2ToRGB(const unsigned char *yuy2Data, unsigned char *rgbData, int width, int height)
{
    int rgbIndex = 0;
    for (int i = 0; i < width * height * 2; i += 4)
    {
        unsigned char y1 = yuy2Data[i];
        unsigned char u = yuy2Data[i + 1];
        unsigned char y2 = yuy2Data[i + 2];
        unsigned char v = yuy2Data[i + 3];

        rgbData[rgbIndex++] = clamp(y1 + 1.772 * (u - 128), 0.0, 255.0);
        rgbData[rgbIndex++] = clamp(y1 - 0.344136 * (u - 128) - 0.714136 * (v - 128), 0.0, 255.0);
        rgbData[rgbIndex++] = clamp(y1 + 1.402 * (v - 128), 0.0, 255.0);

        rgbData[rgbIndex++] = clamp(y2 + 1.772 * (u - 128), 0.0, 255.0);
        rgbData[rgbIndex++] = clamp(y2 - 0.344136 * (u - 128) - 0.714136 * (v - 128), 0.0, 255.0);
        rgbData[rgbIndex++] = clamp(y2 + 1.402 * (v - 128), 0.0, 255.0);
    }
}

HRESULT InitializeMediaFoundation()
{
    HRESULT hr = MFStartup(MF_VERSION);
    if (FAILED(hr))
    {
        printf("MFStartup failed: 0x%lx\n", hr);
    }
    return hr;
}

HRESULT CreateVideoDeviceSource(IMFMediaSource **ppSource)
{
    IMFAttributes *pAttributes = NULL;
    IMFActivate **ppDevices = NULL;
    UINT32 count = 0;
    HRESULT hr = MFCreateAttributes(&pAttributes, 1);
    if (FAILED(hr))
    {
        printf("MFCreateAttributes failed: 0x%lx\n", hr);
        return hr;
    }

    hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
    if (FAILED(hr))
    {
        printf("SetGUID MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE failed: 0x%lx\n", hr);
        pAttributes->Release();
        return hr;
    }

    hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
    if (FAILED(hr))
    {
        printf("MFEnumDeviceSources failed: 0x%lx\n", hr);
        pAttributes->Release();
        return hr;
    }

    if (count > 0)
    {
        hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(ppSource));
        if (FAILED(hr))
        {
            printf("ActivateObject failed: 0x%lx\n", hr);
        }
    }
    else
    {
        printf("No video capture devices found.\n");
        hr = E_FAIL;
    }

    for (UINT32 i = 0; i < count; i++)
    {
        ppDevices[i]->Release();
    }
    CoTaskMemFree(ppDevices);
    pAttributes->Release();

    return hr;
}
HRESULT CaptureImage()
{
    int width = 640, height = 480;
    IMFMediaSource *pSource = NULL;
    IMFSourceReader *pReader = NULL;
    IMFMediaType *pType = NULL;
    DWORD streamIndex = MF_SOURCE_READER_FIRST_VIDEO_STREAM;
    HRESULT hr = CreateVideoDeviceSource(&pSource);
    if (FAILED(hr))
    {
        return hr;
    }

    hr = MFCreateSourceReaderFromMediaSource(pSource, NULL, &pReader);
    if (FAILED(hr))
    {
        printf("MFCreateSourceReaderFromMediaSource failed: 0x%lx\n", hr);
        pSource->Release();
        return hr;
    }

    hr = pReader->GetCurrentMediaType(streamIndex, &pType);
    if (FAILED(hr))
    {
        printf("GetCurrentMediaType failed: 0x%lx\n", hr);
        pReader->Release();
        pSource->Release();
        return hr;
    }

    hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2);
    if (FAILED(hr))
    {
        printf("SetGUID MF_MT_SUBTYPE failed: 0x%lx\n", hr);
        pType->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    hr = MFSetAttributeSize(pType, MF_MT_FRAME_SIZE, width, height);
    if (FAILED(hr))
    {
        printf("MFSetAttributeSize failed: 0x%lx\n", hr);
        pType->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    hr = pReader->SetCurrentMediaType(streamIndex, NULL, pType);
    if (FAILED(hr))
    {
        printf("SetCurrentMediaType failed: 0x%lx\n", hr);
        pType->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    pType->Release();

    IMFSample *pSample = NULL;
    DWORD dwFlags = 0;

    for (int i = 0; i < 10; ++i)
    {
        hr = pReader->ReadSample(streamIndex, 0, NULL, &dwFlags, NULL, &pSample);
        if (SUCCEEDED(hr) && pSample)
        {
            break;
        }
        Sleep(100);
    }

    if (FAILED(hr) || !pSample)
    {
        printf("ReadSample failed: 0x%lx\n", hr);
        printf("Flags: 0x%lx\n", dwFlags);
        pReader->Release();
        pSource->Release();
        return hr;
    }

    printf("Sample read successfully.\n");
    IMFMediaBuffer *pBuffer = NULL;
    hr = pSample->ConvertToContiguousBuffer(&pBuffer);
    if (FAILED(hr))
    {
        printf("ConvertToContiguousBuffer failed: 0x%lx\n", hr);
        pSample->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    BYTE *pData = NULL;
    DWORD cbBuffer = 0;
    hr = pBuffer->Lock(&pData, NULL, &cbBuffer);
    if (FAILED(hr))
    {
        printf("Lock failed: 0x%lx\n", hr);
        pBuffer->Release();
        pSample->Release();
        pReader->Release();
        pSource->Release();
        return hr;
    }

    printf("cbBuffer: %lu\n", cbBuffer);
    unsigned char *rgbData = new unsigned char[width * height * 3];

    ConvertYUY2ToRGB(pData, rgbData, width, height);
    const char *filePath = "capture.bmp";
    FILE *pFile;
    fopen_s(&pFile, filePath, "wb");
    if (pFile)
    {
        BITMAPFILEHEADER bfHeader;
        BITMAPINFOHEADER biHeader;

        bfHeader.bfType = 'MB';
        bfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + width * height * 3;
        bfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
        bfHeader.bfReserved1 = 0;
        bfHeader.bfReserved2 = 0;

        biHeader.biSize = sizeof(BITMAPINFOHEADER);
        biHeader.biBitCount = 24;
        biHeader.biClrImportant = 0;
        biHeader.biClrUsed = 0;
        biHeader.biCompression = BI_RGB;
        biHeader.biHeight = height;
        biHeader.biWidth = width;
        biHeader.biPlanes = 1;
        biHeader.biSizeImage = width * height * 3;
        biHeader.biXPelsPerMeter = 0;
        biHeader.biYPelsPerMeter = 0;

        fwrite(&bfHeader, sizeof(BITMAPFILEHEADER), 1, pFile);
        fwrite(&biHeader, sizeof(BITMAPINFOHEADER), 1, pFile);
        fwrite(rgbData, width * height * 3, 1, pFile);
        fclose(pFile);

        printf("Image saved to %s\n", filePath);
    }
    else
    {
        printf("Failed to open file for writing\n");
    }

    hr = pBuffer->Unlock();
    pBuffer->Release();

    if (pSample)
    {
        pSample->Release();
    }
    if (pReader)
    {
        pReader->Release();
    }
    if (pSource)
    {
        pSource->Release();
    }

    delete[] rgbData;

    return hr;
}

int main()
{
    HRESULT hr = InitializeMediaFoundation();
    if (SUCCEEDED(hr))
    {
        hr = CaptureImage();
        if (SUCCEEDED(hr))
        {
            printf("Image captured successfully.\n");
        }
        else
        {
            printf("Failed to capture image: 0x%lx\n", hr);
        }
    }
    MFShutdown();
    return 0;
}

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.