You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IMFStreamSink::ProcessSample返回E_NOINTERFACE错误求助

Media Foundation中调用IMFStreamSink::ProcessSample返回E_NOINTERFACE错误

问题描述

我正在做一个快速POC验证,使用无容器的原始H264文件(仅NALU封装的裸H264数据)模拟设备数据源。通过标准fstream以1024字节块读取H264文件模拟流数据,手动创建IMFSample发送给解码器,积累足够数据后解码器能成功解码,但将解码后的样本传入从EVR获取的IMFStreamSink时,调用ProcessSample返回HRESULT错误E_NOINTERFACE No such interface supported。已确认解码后的样本包含有效数据,困惑于无额外信息的情况下出现该错误。

核心循环代码

while (true) {
    // My Loop Stuff

    IMFMediaBuffer* inputBuffer = CreateMediaBuffer(1024);
    IMFSample* compressedSample = CreateMediaSample(inputBuffer);

    if (compressedSample == NULL) {
        return 1;
    }

    BYTE* tempBuff;
    DWORD tempMaxLength = 0;
    DWORD tempCurrentLength = 0;

    hr = inputBuffer->Lock(
        &tempBuff,
        &tempMaxLength,
        &tempCurrentLength
    );

    if (FAILED(hr)) {
        std::cout << "Failed to lock buffer" << std::endl;
        return 1;
    }

    inputTestFile.read((char*)tempBuff, tempMaxLength - tempCurrentLength);

    hr = inputBuffer->SetCurrentLength(tempMaxLength - tempCurrentLength);

    if (FAILED(hr)) {
        std::cout << "Failed to set the lenght of the buffer" << std::endl;
        return 1;
    }

    hr = inputBuffer->Unlock();

    if (FAILED(hr)) {
        std::cout << "FAILED to unlock buffer!" << std::endl;
        return 1;
    }

    hr = pDecoder->ProcessInput(0, compressedSample, 0);

    if (FAILED(hr)) {
        std::cout << "Failed sending compressedSample to decoder" << std::endl;

        IMFMediaBuffer* outputBuffer = CreateMediaBuffer(streamInfo.cbSize);
        IMFSample* decompressedSample = CreateMediaSample(outputBuffer);

        _MFT_OUTPUT_DATA_BUFFER outBuff = {};
        outBuff.dwStreamID = 0;
        outBuff.pSample = decompressedSample;

        _MFT_OUTPUT_DATA_BUFFER outBuffs[] = { outBuff };
        DWORD outStatus = 0;

        hr = pDecoder->ProcessOutput(0, 1, outBuffs, &outStatus);

        if (FAILED(hr)) {
            std::cout << "FAILED TO PROCESS OUTPUT" << std::endl;
            continue;
            //return 1;
        }
        else {
            std::cout << "Successfully decoded data!!!" << std::endl;

            IMFMediaEvent* mediaEvent = NULL;

            ssink->GetEvent(0, &mediaEvent);

            if (mediaEvent == NULL) {
                // Nothing to do.. Wait for a request for more 
                continue;
            }

            hr = ssink->ProcessSample(decompressedSample);

            if (FAILED(hr)) {
                std::cout << "Failed to process sample to sink" << std::endl;
                continue;
            }

        }
    }
    // END My Loop Stuff
}

完整核心逻辑代码

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_H264RENDERINGWINDOW, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_H264RENDERINGWINDOW));

    MSG msg;

    // My Stuff
    HRESULT hr = S_OK;
    UINT32 count = 0;

    hr = MFStartup(MF_VERSION);
    if (FAILED(hr)) {
        return 1;
    }

    IMFActivate** ppActivate = NULL;    
    IMFTransform* pDecoder = NULL;      

    MFT_REGISTER_TYPE_INFO info = { MFMediaType_Video, MFVideoFormat_H264 };

    UINT32 unFlags = MFT_ENUM_FLAG_SYNCMFT |
        MFT_ENUM_FLAG_LOCALMFT |
        MFT_ENUM_FLAG_SORTANDFILTER;

    hr = MFTEnumEx(
        MFT_CATEGORY_VIDEO_DECODER,
        unFlags,
        &info,      
        NULL,       
        &ppActivate,
        &count
    );

    if (SUCCEEDED(hr) && count == 0)
    {
        std::cout << "NOT SUCCESS!!!!" << std::endl;
        return 1;
    }

    if (SUCCEEDED(hr))
    {
        std::cout << "SUCCESS AGAIN!!!" << std::endl;
        hr = ppActivate[0]->ActivateObject(IID_PPV_ARGS(&pDecoder));
    }

    DWORD pcInputStreamsNum = 0;
    DWORD pcOutputStreamsNum = 0;

    hr = pDecoder->GetStreamCount(
        &pcInputStreamsNum,
        &pcOutputStreamsNum
    );
    if (FAILED(hr)) {
        std::cout << "Unable to get stream count" << std::endl;
        return 1;
    }

    std::cout << "Available Input Streams: " << pcInputStreamsNum << " Available Output Streams: " << pcOutputStreamsNum << std::endl;

    IMFMediaType* pInMediaType = NULL;
    hr = MFCreateMediaType(&pInMediaType);
    if (FAILED(hr)) {
        std::cout << "Unable to create Input Media Type" << std::endl;
        return 1;
    }

    hr = pDecoder->GetInputAvailableType(0, 0, &pInMediaType);
    if (FAILED(hr)) {
        std::cout << "Unable to get Input Media Type for Decoder" << std::endl;
        return 1;
    }

    hr = pDecoder->SetInputType(0, pInMediaType, 0);
    if (FAILED(hr)) {
        std::cout << "Unable to set Media Type for Decoder" << std::endl;
        return 1;
    }

    IMFMediaType* pOutMediaType = NULL;
    hr = MFCreateMediaType(&pOutMediaType);
    hr = pDecoder->GetOutputAvailableType(0, 0, &pOutMediaType);
    if (FAILED(hr)) {
        std::cout << "Unable to get output type" << std::endl;
        return 1;
    }

    GUID v;
    hr = pOutMediaType->GetGUID(MF_MT_SUBTYPE, &v);
    if (FAILED(hr)) {
        std::cout << "Unable to get output media sub-type" << std::endl;
        return 1;
    }

    hr = pDecoder->SetOutputType(0, pOutMediaType, 0);
    if (FAILED(hr)) {
        std::cout << "Failed setting output type" << std::endl;
        return 1;
    }

    hr = pDecoder->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
    if (FAILED(hr)) {
        std::cout << "Failed to send begin streaming message" << std::endl;
        return 1;
    }

    std::cout << "Successfully Initialized the Decoder..." << std::endl;

    std::ifstream inputTestFile = std::ifstream("c:\\open\\fbsource\\arvr\\apps\\MagicIsle\\magic-capture.h264", std::ios::binary);
    if (!inputTestFile.is_open()) {
        std::cout << "unable to open test input file, did run with --capture previously?"
            << std::endl;
        return 1;
    }

    MFT_INPUT_STREAM_INFO inStreamInfo{};
    hr = pDecoder->GetInputStreamInfo(0, &inStreamInfo);
    if (FAILED(hr)) {
        std::cout << "Failed to get the stream info" << std::endl;
        return 1;
    }

    std::cout << "Stream Info: ";
    if (inStreamInfo.dwFlags == MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) {
        std::cout << "MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES" << std::endl;
    }
    else if (inStreamInfo.dwFlags == MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) {
        std::cout << "MFT_OUTPUT_STREAM_PROVIDES_SAMPLES" << std::endl;
    }

    MFT_OUTPUT_STREAM_INFO streamInfo{};
    hr = pDecoder->GetOutputStreamInfo(0, &streamInfo);
    if (FAILED(hr)) {
        std::cout << "Failed to get the stream info" << std::endl;
        return 1;
    }

    std::cout << "Stream Info: ";
    if (streamInfo.dwFlags == MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) {
        std::cout << "MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES" << std::endl;
    }
    else if (streamInfo.dwFlags == MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) {
        std::cout << "MFT_OUTPUT_STREAM_PROVIDES_SAMPLES" << std::endl;
    }
    else {
        std::cout << "NEITHER" << std::endl;
    }

    IMFPresentationClock* clock = NULL;
    hr = MFCreatePresentationClock(&clock);
    if (FAILED(hr)) {
       return 1;
    }

    IMFPresentationTimeSource* timeSource = NULL;
    hr = MFCreateSystemTimeSource(&timeSource);
    if (FAILED(hr)) {
        return 1;
    }

    hr = clock->SetTimeSource(timeSource);
    if (FAILED(hr)) {
        return 1;
    }

    hr = clock->Start(0);
    if (FAILED(hr)) {
        return 1;
    }

    hr = pRenderer->SetPresentationClock(clock);
    if (FAILED(hr)) {
        return 1;
    }

    DWORD rendererCharacteristics = 0;
    hr = pRenderer->GetCharacteristics(&rendererCharacteristics);
    if ((rendererCharacteristics & MEDIASINK_CANNOT_MATCH_CLOCK) == MEDIASINK_CANNOT_MATCH_CLOCK) {
        std::cout << "Cannot Match Clock" << std::endl;
    }
    if ((rendererCharacteristics & MEDIASINK_RATELESS) == MEDIASINK_RATELESS) {
        std::cout << "Rateless" << std::endl;
    }
    if (FAILED(hr)) {
        return 1;
    }

    IMFStreamSink* ssink = NULL;
    hr = pRenderer->GetStreamSinkById(0, &ssink);
    if (FAILED(hr)) {
        return 1;
    }

    IMFMediaTypeHandler* ssinkMediaTypeHandler = NULL;
    hr = ssink->GetMediaTypeHandler(&ssinkMediaTypeHandler);
    if (FAILED(hr)) {
        return 1;
    }

    hr = ssinkMediaTypeHandler->SetCurrentMediaType(pOutMediaType);

    // End My Stuff

    auto f = [&] {
        while (true) {
            // My Loop Stuff
            IMFMediaBuffer* inputBuffer = CreateMediaBuffer(1024);
            IMFSample* compressedSample = CreateMediaSample(inputBuffer);

            if (compressedSample == NULL) {
                return 1;
            }

            BYTE* tempBuff;
            DWORD tempMaxLength = 0;
            DWORD tempCurrentLength = 0;

            hr = inputBuffer->Lock(
                &tempBuff,
                &tempMaxLength,
                &tempCurrentLength
            );

            if (FAILED(hr)) {
                std::cout << "Failed to lock buffer" << std::endl;
                return 1;
            }

            inputTestFile.read((char*)tempBuff, tempMaxLength - tempCurrentLength);

            hr = inputBuffer->SetCurrentLength(tempMaxLength - tempCurrentLength);

            if (FAILED(hr)) {
                std::cout << "Failed to set the lenght of the buffer" << std::endl;
                return 1;
            }

            hr = inputBuffer->Unlock();

            if (FAILED(hr)) {
                std::cout << "FAILED to unlock buffer!" << std::endl;
                return 1;
            }

            hr = pDecoder->ProcessInput(0, compressedSample, 0);

            if (FAILED(hr)) {
                std::cout << "Failed sending compressedSample to decoder" << std::endl;

                IMFMediaBuffer* outputBuffer = CreateMediaBuffer(streamInfo.cbSize);
                IMFSample* decompressedSample = CreateMediaSample(outputBuffer);

                _MFT_OUTPUT_DATA_BUFFER outBuff = {};
                outBuff.dwStreamID = 0;
                outBuff.pSample = decompressedSample;

                _MFT_OUTPUT_DATA_BUFFER outBuffs[] = { outBuff };
                DWORD outStatus = 0;

                hr = pDecoder->ProcessOutput(0, 1, outBuffs, &outStatus);

                if (FAILED(hr)) {
                    std::cout << "FAILED TO PROCESS OUTPUT" << std::endl;
                    continue;
                }
                else {
                    std::cout << "Successfully decoded data!!!" << std::endl;

                    IMFMediaEvent* mediaEvent = NULL;
                    ssink->GetEvent(0, &mediaEvent);

                    if (mediaEvent == NULL) {
                        continue;
                    }

                    hr = ssink->ProcessSample(decompressedSample);

                    if (FAILED(hr)) {
                        std::cout << "Failed to process sample to sink" << std::endl;
                        continue;
                    }
                }
            }
            // END My Loop Stuff
        }
    };

    std::thread t(f);

    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    t.join();
    return (int) msg.wParam;
}

解决方案

1. 错误核心原因

EVR的IMFStreamSink要求传入的IMFSample中的媒体缓冲区必须实现**IMF2DBuffer接口**,你手动创建的decompressedSample使用的是普通IMFMediaBuffer,未实现该接口,导致ProcessSample调用时找不到所需接口,返回E_NOINTERFACE。

2. 关键修复步骤

(1)让解码器自动分配输出样本

不要手动创建ProcessOutput的样本,解码器输出的样本默认会实现IMF2DBuffer接口,完全适配EVR的要求:

// 移除手动创建outputBuffer和decompressedSample的代码
_MFT_OUTPUT_DATA_BUFFER outBuff = {};
outBuff.dwStreamID = 0;
outBuff.pSample = NULL; // 让解码器自动分配样本

DWORD outStatus = 0;
hr = pDecoder->ProcessOutput(0, 1, &outBuff, &outStatus);

if (SUCCEEDED(hr)) {
    IMFSample* decompressedSample = outBuff.pSample;
    // 后续操作使用解码器提供的sample
}

(2)正确处理EVR的流事件

当前直接调用ssink->GetEvent(0, &mediaEvent)的方式错误,需要等待MESinkRequestSample事件(EVR主动请求新样本的信号):

IMFMediaEvent* mediaEvent = NULL;
// 使用MF_EVENT_FLAG_WAIT等待事件,而不是立即返回
hr = ssink->GetEvent(MF_EVENT_FLAG_WAIT, &mediaEvent);
if (SUCCEEDED(hr)) {
    MediaEventType eventType = MEUnknown;
    mediaEvent->GetType(&eventType);
    // 仅在EVR请求样本时发送
    if (eventType == MESinkRequestSample) {
        hr = ssink->ProcessSample(decompressedSample);
    }
    mediaEvent->Release();
}

(3)为解码样本设置正确时间戳

EVR依赖时间戳进行渲染同步,必须为样本设置有效时间戳(单位:100纳秒):

// 示例:假设帧率为30fps,逐帧累加时间戳
static LONGLONG currentTimestamp = 0;
const LONGLONG frameDuration = 10000000 / 30; // 30fps单帧时长

decompressedSample->SetSampleTime(currentTimestamp);
decompressedSample->SetSampleDuration(frameDuration);
currentTimestamp += frameDuration;

3. 其他注意事项

  • 确保
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:55:18