Media Foundation SourceReader 返回空数据

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

我想创建一个类,负责使用 Media Foundation 的 SourceReader 从 MP4 文件中读取压缩视频数据。我编写了一个读取单个样本的方法,它运行时没有任何错误,但缓冲区中的数据始终为空。我按照以下教程寻求指导:

https://learn.microsoft.com/en-us/windows/win32/medfound/processing-media-data-with-the-source-reader

我已经检查了文件验证,一切看起来都很好。此外,我尝试使用本机 MediaType 和手动配置的 MediaType 来配置 SourceReader。这是我的代码:

HRESULT MfVideoReader::Initialize(std::string filePath) {
    try {
        std::wstring wsFilePath = StringHelper::str2wstr(filePath);
        throw_if_fail(MFCreateSourceReaderFromURL(wsFilePath.c_str(), NULL, &pSourceReader));
        throw_if_fail(pSourceReader->GetNativeMediaType(0, 0, &pOutputMediaType));
        throw_if_fail(pSourceReader->SetCurrentMediaType(0, NULL, pOutputMediaType));
        return S_OK;
    }
    catch (const std::exception& e) {
        Logger::log_error("Fail to initialize the video source reader", e.what());
        return E_FAIL;
    }
}

HRESULT MfVideoReader::ReadFrame(BYTE* frameData, LONGLONG* pSampleTime) {
    try {
        CComPtr<IMFSample> pSample;
        DWORD stream = 0;
        DWORD streamFlags = 0;
        throw_if_fail(pSourceReader->ReadSample(0, 0, &stream, &streamFlags, pSampleTime, &pSample));
        
        CComPtr<IMFMediaBuffer> pMediaBuffer;
        throw_if_fail(pSample->GetBufferByIndex(0, &pMediaBuffer));

        BYTE* pData = nullptr;
        DWORD maxLength = 0;
        DWORD dataSize = 0;
        throw_if_fail(pMediaBuffer->Lock(&pData, &maxLength, &dataSize));
        memcpy(frameData, pData, dataSize);
        throw_if_fail(pMediaBuffer->Unlock());

        return S_OK;
    }
    catch (const std::exception& e) {
        Logger::log_error("Fail to read a sample", e.what());
        return E_FAIL;
    }
}
winapi video ms-media-foundation
1个回答
0
投票

我根据与读取音频流并将其写入文件相关的Microsoft 示例修改了代码。修改后,代码如下:

HRESULT MfVideoReader::Initialize(const std::string& filePath) {
    try {
        std::wstring wsFilePath = StringHelper::str2wstr(filePath);
        throw_if_fail(MFCreateSourceReaderFromURL(wsFilePath.c_str(), NULL, &pSourceReader));
        
        CComPtr<IMFMediaType> pUncompressedVideoType;
        CComPtr<IMFMediaType> pPartialType;

        throw_if_fail(MFCreateMediaType(&pPartialType));
        throw_if_fail(pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
        throw_if_fail(pPartialType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12));

        throw_if_fail(pSourceReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pPartialType));
        throw_if_fail(pSourceReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pUncompressedVideoType));
        throw_if_fail(pSourceReader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE));

        return S_OK;
    }
    catch (const std::exception& e) {
        Logger::log_error("Fail to initialize the video source reader", e.what());
        return E_FAIL;
    }
}

HRESULT MfVideoReader::ReadFrame(BYTE* frameData, LONGLONG* pSampleTime) {
    try {
        CComPtr<IMFSample> pSample;
        DWORD streamFlags = 0;
        throw_if_fail(pSourceReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, &streamFlags, pSampleTime, &pSample));

        CComPtr<IMFMediaBuffer> pMediaBuffer;
        BYTE* pData = NULL;
        DWORD cbBuffer = 0;
        throw_if_fail(pSample->ConvertToContiguousBuffer(&pMediaBuffer));
        throw_if_fail(pMediaBuffer->Lock(&pData, NULL, &cbBuffer));
        memcpy(frameData, pData, cbBuffer);
        throw_if_fail(pMediaBuffer->Unlock());

        return S_OK;
    }
    catch (const std::exception& e) {
        Logger::log_error("Fail to read a sample", e.what());
        return E_FAIL;
    }
}

执行测试后,我注意到这种情况下并非支持所有视频格式。以下是支持的视频格式列表:

  • MFVideoFormat_H264,
  • MFVideoFormat_I420,
  • MFVideoFormat_IYUV,
  • MFVideoFormat_NV12,
  • MFVideoFormat_YUY2,
  • MFVideoFormat_YV12。

对于H264格式,没有设置标志,数据为空。对于 I420、IYUV、NV12、YUY2 和 YV12 格式,设置 MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED 标志并正确返回数据。

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