Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Video captured by Media Foundation is vertical mirrorred

I'm using Media Foundation IMFSourceReaderCallback implementation for grabbing video frames from the camera, and then OpenCV imshow to present the frames in a loop.
However I get the frames vertically flipped...
Is this a bug? Should I set some attribute to avoid this?
Here is my code:

Initialization:

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 implementation:

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;

Conversion to 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);
}

Any idea?

Thanks in advance!

like image 858
rkellerm Avatar asked Nov 09 '14 10:11

rkellerm


1 Answers

A bitmap is stored with the last scan line first, so the image will appear upside down. The easiest solution is to call 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);
}
like image 59
cdmh Avatar answered Oct 21 '22 11:10

cdmh