Media Foundation 捕获的视频是垂直镜像的

Posted

技术标签:

【中文标题】Media Foundation 捕获的视频是垂直镜像的【英文标题】:Video captured by Media Foundation is vertical mirrorred 【发布时间】:2014-11-09 10:53:33 【问题描述】:

我使用 Media Foundation IMFSourceReaderCallback 实现从摄像头抓取视频帧,然后使用 OpenCV imshow 循环呈现帧。 但是,我将框架垂直翻转... 这是一个错误吗?我应该设置一些属性来避免这种情况吗? 这是我的代码:

初始化:

IMFAttributes* pDeviceAttrs, *pReaderAttrs;
        hr = MFCreateAttributes(&pDeviceAttrs, 1);
        if (FAILED(hr)) goto Exit;
        hr = pDeviceAttrs->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
        if (FAILED(hr)) goto Exit;
//...
// Correct source provider is activated through ActivateObject  
//
        hr = MFCreateAttributes(&pReaderAttrs, 2);
        if (FAILED(hr)) goto Exit;

        pReaderAttrs->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK,(IUnknown*)this);
        pReaderAttrs->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE); 

        hr = MFCreateSourceReaderFromMediaSource(pMediaSource, pReaderAttrs, &m_pReader);
        if (FAILED(hr)) goto Exit;
// Correct profile is set

OnReadSample 实现:

HRESULT hr = S_OK;
        LONG defaultStride = 0;
        LONG stride = 0;
        BYTE *pBuffer = NULL;

        EnterCriticalSection(&m_critSec);
        if (NULL != pSample)
        
            IMFMediaBuffer* pMediaBuffer;
            DWORD dataSize = 0;
            // In case of a single buffer, no copy would happen
            hr = pSample->ConvertToContiguousBuffer(&pMediaBuffer);
            if (FAILED(hr)) goto Cleanup;
            pMediaBuffer->GetCurrentLength(&dataSize);

            hr = pMediaBuffer->Lock(&pBuffer, &dataSize, &dataSize);
            if (FAILED(hr)) goto Cleanup;

            // todo: use a backbuffer to avoid sync issues
            if (NULL == m_pLatestFrame) m_pLatestFrame = (BYTE*)malloc(dataSize);
            memcpy(m_pLatestFrame, pBuffer, dataSize);
            ++m_frameNumber;

            pMediaBuffer->Unlock();
            pMediaBuffer->Release();
        
Cleanup:
        LeaveCriticalSection(&m_critSec);

        // Async ReadFrame for the next buffer:
        hr = m_pReader->ReadSample(
            (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
            0,
            NULL,   // actual
            NULL,   // flags
            NULL,   // timestamp
            NULL    // sample
            );
        return hr;

转换为 cv::image:

void SourceReaderImpl::GetLatestFrame(BYTE** ppLatestFrame)
    
        EnterCriticalSection(&m_critSec);
        *ppLatestFrame = m_pLatestFrame;
        LeaveCriticalSection(&m_critSec);
    

void* CameraWrapperImpl::getLatestFrame()

    BYTE* pLatestFrame = NULL;
    m_pMfReader->GetLatestFrame(&pLatestFrame);
    return pLatestFrame;


void Player::Present()

//...
    color = cv::Mat(colorSize,
                CV_8UC3,
                static_cast<unsigned char*>(m_pColorCameraImpl->getLatestFrame()));
cv::imshow(color);

有什么想法吗?

提前致谢!

【问题讨论】:

不,这肯定是你耳朵之间的错误。位图通常是倒置存储的,最后一条扫描线首先在内存中。除非 biHeight 是负数。您没有正确地将其转换为 CV 数组,您没有发布的代码。 @Hans Passant:谢谢,添加了上面的简历代码。 您发布的代码几乎无法完整获取详细信息,但我认为 Hans 的假设是正确的,您将自下而上的 RGB 图像视为自上而下的图像。 @RomanR.媒体基金会有没有办法知道捕获的视频是否被镜像?我知道图像的存储方式是自下而上或自上而下,但是否有可能预先知道(也许通过一些 api 调用?) 【参考方案1】:

位图与最后一个扫描线一起存储,因此图像会上下颠倒。最简单的解决办法是拨打cv::flip

void Player::Present()

    //...
    color = cv::Mat(colorSize,
                CV_8UC3,
                static_cast<unsigned char*>(m_pColorCameraImpl->getLatestFrame()));

    cv::Mat corrected;
    flip(color, corrected, 0);
    imshow(corrected);

【讨论】:

谢谢,这就是我目前所做的。我只是想知道是否可以在不进行额外翻转的情况下更改配置中的某些内容。

以上是关于Media Foundation 捕获的视频是垂直镜像的的主要内容,如果未能解决你的问题,请参考以下文章

与 Media Foundation 一起制作视频

Windows Media Foundation 音视频采集 小记

UWP 硬件视频解码 - DirectX12 与 Media Foundation

使用 Microsoft Media Foundation 从文件播放视频

Media Foundation 将音频流添加到视频文件

使用 Media Foundation 源阅读器阅读 3D(左右)视频