Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Video 异步MFT未发送MFT输出事件(英特尔硬件MJPEG解码器MFT)_Video_Visual C++_Media_Ms Media Foundation - Fatal编程技术网

Video 异步MFT未发送MFT输出事件(英特尔硬件MJPEG解码器MFT)

Video 异步MFT未发送MFT输出事件(英特尔硬件MJPEG解码器MFT),video,visual-c++,media,ms-media-foundation,Video,Visual C++,Media,Ms Media Foundation,我正在使用MediaFoundation SourceReader技术开发USB摄像头流式桌面应用程序。该相机支持USB3.0,1080p MJPG视频格式分辨率为60fps 我使用软件MJPEG解码器MFT将MJPG转换为YUY2帧,然后转换为RGB32帧在窗口上绘制。当使用这个软件解码器时,我能够在窗口上只渲染30fps,而不是60fps。我在这个网站上发布了一个问题,并得到了一些使用Intel硬件MJPEG解码器MFT解决帧丢失问题的建议 为了使用这个硬件MJPEG解码器,我处理了异步MF

我正在使用MediaFoundation SourceReader技术开发USB摄像头流式桌面应用程序。该相机支持USB3.0,1080p MJPG视频格式分辨率为60fps

我使用软件MJPEG解码器MFT将MJPG转换为YUY2帧,然后转换为RGB32帧在窗口上绘制。当使用这个软件解码器时,我能够在窗口上只渲染30fps,而不是60fps。我在这个网站上发布了一个问题,并得到了一些使用Intel硬件MJPEG解码器MFT解决帧丢失问题的建议

为了使用这个硬件MJPEG解码器,我处理了异步MFT处理模型,并通过IMFTTransform接口为IMFMediaEventGenerator配置了一个异步回调

在使用ProcessMessage方法调用MFT_MESSAGE_NOTIFY_START_OF_STREAM之后,我收到了两次MFTransformNeedInput事件,但没有收到MFT的MFTransformHaveOutput事件

我在这里分享了我的代码供您参考:

IMFTransform* m_pTransform = NULL;

HRESULT EnumDecoderMFT ()
{
    HRESULT hr;
    IMFActivate** ppActivate;   
    UINT32 numDecodersMJPG = 0;
    LPWSTR lpMFTName = 0;

    MFT_REGISTER_TYPE_INFO inputFilter = {MFMediaType_Video,MFVideoFormat_MJPG};
    MFT_REGISTER_TYPE_INFO outputFilter = {MFMediaType_Video,MFVideoFormat_YUY2};

    UINT32 unFlags = MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_LOCALMFT | MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;

    hr = MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER, unFlags, &inputFilter, &outputFilter, &ppActivate, &numDecodersMJPG);
    if (FAILED(hr)) return hr; 

    hr = ppActivate[0]->GetAllocatedString(MFT_FRIENDLY_NAME_Attribute,&lpMFTName,0);
    if (FAILED(hr)) return hr;

    // Activate transform
    hr = ppActivate[0]->ActivateObject(__uuidof(IMFTransform), (void**)&m_pTransform);
    if (FAILED(hr)) return hr;

    hr = hr = m_pTransform->GetAttributes(&pAttributes);
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);           
        if(FAILED(hr)) return hr;

        hr = pAttributes->SetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE,TRUE);        
        if(FAILED(hr)) return hr;

        hr = pAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
        if(FAILED(hr)) return hr;

        hr = m_pTransform->QueryInterface(IID_IMFMediaEventGenerator,(void**)&m_pEventGenerator);           
        if(FAILED(hr)) return hr;

        hr = m_pEventGenerator->BeginGetEvent((IMFAsyncCallback*)this,NULL);
        if(FAILED(hr)) return hr;

        pAttributes->Release();
    }

    SafeRelease(&ppActivate[0]);

    CoTaskMemFree(ppActivate);

    return hr;      
}

HRESULT Invoke(IMFAsyncResult *pResult)
{
    HRESULT hr = S_OK,hrStatus;
    MediaEventType meType = MEUnknown;  // Event type
    IMFMediaEvent *pEvent = NULL;

    // Get the event from the event queue.
    hr = m_pEventGenerator->EndGetEvent(pResult, &pEvent);      //Completes an asynchronous request for the next event in the queue.
    if(FAILED(hr)) return hr;

    // Get the event type. 
    hr = pEvent->GetType(&meType);
    if(FAILED(hr)) return hr;

    hr = pEvent->GetStatus(&hrStatus);
    if(FAILED(hr)) return hr;

    if(SUCCEEDED(hrStatus))
    {
        if(meType == METransformNeedInput)
        {       
            SetEvent(m_hNeedInputEvent);
        }
        else if(meType == METransformHaveOutput)
        {           
            SetEvent(m_hHaveOutputEvent);
        }
        else if(meType == METransformDrainComplete)
        {
            hr = m_pTransform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH,0);
            if(FAILED(hr)) return hr;
        }
        else if(meType == MEError)
        {
            PROPVARIANT pValue;
            hr = pEvent->GetValue(&pValue);         
            if(FAILED(hr)) return hr;   
        }

        hr = m_pEventGenerator->BeginGetEvent((IMFAsyncCallback*)this,NULL);    
        if(FAILED(hr)) return hr;
    }

done:
    SafeRelease(&pEvent);
    return S_OK;
}

HRESULT CMFSourceReader::OnReadSample(
    HRESULT hrStatus,
    DWORD  dwStreamIndex ,
    DWORD  dwStreamFlags ,
    LONGLONG  llTimestamp ,
    IMFSample *pSample      // Can be NULL
    )
{
    HRESULT hr = S_OK;
    IMFMediaBuffer *pBuffer = NULL;
    DWORD dwcbTotLen = 0;           
    IMFSample *mftOutSample = NULL;

    EnterCriticalSection(&m_critsec);

    if (FAILED(hrStatus))
    {
        hr = hrStatus;
    }

    if (SUCCEEDED(hr))
    {
        if (pSample != NULL)
        {
            if(dwStreamIndex == 0)      //VideoStream
            {                   
                if(m_pTransform)
                {   
                    hr = m_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
                    if(FAILED(hr))  return hr;

                    m_dwWaitObj = WaitForSingleObject(m_hNeedInputEvent,INFINITE);
                    if(m_dwWaitObj == WAIT_OBJECT_0)
                    {                           
                        hr = ProcessInputSample(pSample);
                        if(FAILED(hr))  return hr;
                    }

                    m_dwWaitObj = WaitForSingleObject(m_hHaveOutputEvent,INFINITE);
                    if(m_dwWaitObj == WAIT_OBJECT_0)
                    {
                        hr = ProcessOutputSample(&mftOutSample);
                        if(FAILED(hr))  return hr;
                    }
                }
            }
        }
    }

    if(SUCCEEDED(hr))
    {
        if(m_pReader != NULL)
        {
            hr = m_pReader->ReadSample(
                (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                0,
                NULL,   // actual
                NULL,   // flags
                NULL,   // timestamp
                NULL    // sample
                );
            if(FAILED(hr)) return hr;
        }
    }

    SafeRelease(&mftOutSample);

    LeaveCriticalSection(&m_critsec);
    return hr; 
}

HRESULT ProcessOutputSample(IMFSample **pOutSample)
{
    HRESULT hr = S_OK;
    MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
    DWORD processOutputStatus = 0,mftOutFlags = 0;
    MFT_OUTPUT_STREAM_INFO StreamInfo;
    IMFSample *mftOutSample = NULL;
    IMFMediaBuffer *pOutBuffer = NULL;

    if(m_pTransform != NULL)
    {   
        hr = m_pTransform->GetOutputStreamInfo(0, &StreamInfo);
        if(FAILED(hr)) return hr;

        DWORD status = 0;
        hr = m_pTransform->GetOutputStatus(&status);
        if (FAILED(hr)) return hr;

        hr = MFCreateSample(&mftOutSample);
        if(FAILED(hr)) return hr;

        hr = MFCreateMemoryBuffer(StreamInfo.cbSize, &pOutBuffer);
        if(FAILED(hr)) return hr;

        hr = mftOutSample->AddBuffer(pOutBuffer);
        if(FAILED(hr)) return hr;

        outputDataBuffer.dwStreamID = 0;
        outputDataBuffer.dwStatus = 0;
        outputDataBuffer.pEvents = NULL;
        outputDataBuffer.pSample = mftOutSample;

        hr = m_pTransform->ProcessOutput(0, 1, &outputDataBuffer, &processOutputStatus);            
        if(FAILED(hr)) return hr;

        hr = m_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
        if (FAILED(hr))  return hr;

        hr = m_pTransform->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
        if (FAILED(hr))  return hr;

        if(mftOutSample)
        {
            *pOutSample = mftOutSample;
            (*pOutSample)->AddRef();
        }

        ResetEvent(m_hHaveOutputEvent);
    }

    SafeRelease(&mftOutSample);
    SafeRelease(&pOutBuffer);

    return hr;
}

HRESULT ProcessInputSample(IMFSample *pInputSample)
{
    HRESULT hr;

    if(m_pTransform != NULL)
    {               
        hr = m_pTransform->ProcessInput(0, pInputSample, 0);
        if(FAILED(hr)) return hr;

        hr = m_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM,0);
        if(FAILED(hr)) return hr;

        ResetEvent(m_hNeedInputEvent);
    }

    return hr;
}
我在代码中注释了ProcessOutputSample()方法,并检查了MFT send MFTransformNeedInput事件类型。在ProcessInput示例之后,我得到了ProcessOutput方法,但它返回了一个E_意外错误。我在MSDN中读到这个错误,他们提到我不应该在没有接收MFTransformHaveOutput事件的情况下调用IMFTTransform::ProcessOutput方法

我遗漏了什么吗?我可以在MediaFoundation内部使用Intel硬件MJPEG解码器MFT吗?是否有人提供了使用此解码器的示例?在过去的4天里,我一直在努力解决这个问题


提前感谢。

首先,您不必称此为:

hr = pAttributes->SetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE,TRUE);
Mft对此负责,因为它是异步的,所以可以假定它是真的。您只需检查调用GetUINT32是否真实

第二:

hr = pAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
这并不意味着MFT。此属性用于源读取器或接收器写入器:

从您的代码中,我看到的问题是,您总是调用
hr=m\u pTransform->ProcessMessage(MFT\u MESSAGE\u NOTIFY\u START\u OF_STREAM,0)在OnReadSample中,您应该在开始时调用一次

这同样适用于ProcessInputSample和ProcessOutputSample,您可以调用
hr=m\u ptTransform->ProcessMessage(MFT\u MESSAGE\u NOTIFY\u END\u OF_STREAM,0),您告诉MFT流已结束

您的代码应该处理如下事项:

  • 开始解码
  • MFT\u消息\u通知\u启动\u流
  • 根据需要处理输入
  • 根据需要处理输出
  • 根据需要处理输入
  • 根据需要处理输出
  • MFT\u消息\u通知\u结束\u流
  • 结束解码
您从未收到outputsample,因为您告诉MFT流在第一个inputsample进程之后就结束了

请阅读以下内容:

通知第一个样本即将被处理的媒体基础转换(MFT)。

是的,第一个样品,不是所有的样品

编辑

CMFSourceReader::OnReadSample中还有一个问题:

m_dwWaitObj = WaitForSingleObject(m_hNeedInputEvent,INFINITE);

if(m_dwWaitObj == WAIT_OBJECT_0)
{                           
   hr = ProcessInputSample(pSample);
   if(FAILED(hr))  return hr;
}

m_dwWaitObj = WaitForSingleObject(m_hHaveOutputEvent,INFINITE);

if(m_dwWaitObj == WAIT_OBJECT_0)
{
   hr = ProcessOutputSample(&mftOutSample);
   if(FAILED(hr))  return hr;
}
首先等待m_HnedInputEvent,然后等待m_hHaveOutputEvent。但如果在m_hHaveOutputEvent之前两次收到m_hNedInputEvent,会发生什么。此代码不正确。您没有正确处理调用。仅当ProcessInput完成时才应调用OnReadSample。总体设计似乎不正确

更新

当您在CMFSourceReader::OnReadSample中收到一个样本时,您只需要将样本排入一个列表(队列(样本))。 要管理示例列表,可以使用以下类型的代码:

在CMFSourceReader::Invoke中,当您收到METransformNeedInput时,只需将(Sample)出列并调用ProcessInputSample

在CMFSourceReader::Invoke中,当您收到MhHaveOutputEvent时,调用ProcessOutputSample

两件事:

  • 您可以在程序开始时调用m_pReader->ReadSample三次,然后等待列表中有三个样本。当您有三个样本时,您可以开始解码,就像这样,您将确保当METransformNeedInput发生时,您有一个样本可以处理。在ProcessInputSample维护列表中的三个样本后,此时可以调用m_pReader->ReadSample
  • 解码器的处理速度可能比源阅读器读取样本的速度快,或者相反。因此,请检查METransformNeedInput时,列表中始终存在样本。策略是在解码过程中保持一个合理的样本数,比如说三个

在英特尔硬件上输入第一个输入样本后,Transform的事件生成器立即返回了相同的E_意外(“未指定错误”)错误,并且,进一步的调用刚刚返回“Transform需要更多输入”,但没有生成输出。同样的代码在Nvidia机器上运行良好。经过大量的实验和研究,我发现我创建了太多D3D11设备的实例,在我的例子中,我分别创建了2到3个用于捕获、颜色转换和硬件编码器的设备。然而,我可以简单地重用一个D3dDevice实例。不过,创建多个D3D11设备实例可能在高端机器上工作。这在任何地方都没有记录。我甚至找不到“E_意外”错误原因的线索。没有提到过。有许多与此类似的StackOverflow线程没有得到回答,即使是微软的人也无法指出问题所在,因为有完整的源代码


重用D3D11设备实例解决了问题。

那是什么网络摄像头?(只是好奇)我正在使用链接中提到的相机:@Abi,我也面临着同样的问题。你能解决这个问题吗?如果是的话,你能告诉我什么样的样品吗?谢谢你对我的问题的详细回答,Mofo。投寄前