2010-03-17 52 views
0

下面是从我的解码器转换过滤器的代码提取,它从我的源过滤器获取数据,该过滤器从IP摄像机获取RTP网络数据。源滤镜,解码滤镜可以动态响应相机图像尺寸的变化,因为我需要处理解码库中的分辨率变化。让DirectShow VideoRender过滤器响应其输入引脚上的MediaType更改?

我已经使用了DirectShow帮助中描述的'ReceiveConnection'方法,在下一个示例中传递新的MediaType数据。但是,即使渲染器在停止并重新启动图形时呈现不同的分辨率,我也无法使视频混合渲染器动态接受分辨率更改。

任何人都可以指出我需要做什么才能让渲染器处理动态分辨率更改?

HRESULT CDecoder::Receive(IMediaSample* pIn) 
{ 
    //Input data does not necessarily correspond one-to-one 
    //with output frames, so we must override Receive instead 
    //of Transform. 
    HRESULT hr = S_OK; 

    //Deliver input to library 
    long cBytes = pIn->GetActualDataLength(); 
    BYTE* pSrc; 
    pIn->GetPointer(&pSrc); 

    try 
    { 
     hr = m_codec.Decode(pSrc, cBytes, (hr == S_OK)?&tStart : NULL); 
    } 
    catch (...) 
    { 
     hr = E_UNEXPECTED; 
    } 
    if (FAILED(hr)) 
    { 
     if (theLog.enabled()){theLog.strm() << "Decoder Error " << hex << hr << dec << "  - resetting input"; theLog.write();} 
     //Force reset of decoder 
     m_bReset = true; 
     m_codec.ResetInput(); 

     //We have handled the error -- don't pass upstream or the source may stop. 
     return S_OK; 
    } 

    //Extract and deliver any decoded frames 
    hr = DeliverDecodedFrames(); 

    return hr; 
} 

HRESULT CDecoder::DeliverDecodedFrames() 
{ 
    HRESULT hr = S_OK; 

    for (;;) 
    { 
     DecodedFrame frame; 
     bool bFrame = m_codec.GetDecodedFrame(frame); 
     if (!bFrame) 
     { 
     break; 
     } 

     CMediaType mtIn; 
     CMediaType mtOut; 
     GetMediaType(PINDIR_INPUT, &mtIn); 
     GetMediaType(PINDIR_OUTPUT, &mtOut); 

     //Get the output pin's current image resolution 
     VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)mtOut.Format(); 

     if(pvi->bmiHeader.biWidth != m_cxInput || 
      pvi->bmiHeader.biHeight != m_cyInput) 
     { 
     HRESULT hr = GetPin(PINDIR_OUTPUT)->GetConnected()->ReceiveConnection(GetPin(PINDIR_OUTPUT), &mtIn); 

     if(SUCCEEDED(hr)) 
     { 
      SetMediaType(PINDIR_OUTPUT, &mtIn); 
     } 
     } 

     IMediaSamplePtr pOut; 
     hr = m_pOutput->GetDeliveryBuffer(&pOut, 0, 0, NULL); 

     if (FAILED(hr)) 
     { 
     break; 
     } 

     AM_MEDIA_TYPE* pmt; 
     if (pOut->GetMediaType(&pmt) == S_OK) 
     { 
     CMediaType mt(*pmt); 
     DeleteMediaType(pmt); 
     SetMediaType(PINDIR_OUTPUT, &mt); 

     pOut->SetMediaType(&mt); 
     } 

     // crop, tramslate and deliver 
    BYTE* pDest; 
    pOut->GetPointer(&pDest); 
    m_pConverter->Convert(frame.Width(), frame.Height(), frame.GetY(), frame.GetU(), frame.GetV(), pDest); 
    pOut->SetActualDataLength(m_pOutput->CurrentMediaType().GetSampleSize()); 
    pOut->SetSyncPoint(true); 

    if (frame.HasTimestamp()) 
    { 
     REFERENCE_TIME tStart = frame.Timestamp(); 
     REFERENCE_TIME tStop = tStart+1; 
     pOut->SetTime(&tStart, &tStop); 
    } 

    m_pOutput->Deliver(pOut); 
    } 
    return hr; 
} 

回答

0

你什么错误,当它失败?可能您需要确保没有未完成的缓冲区 - 所有样本需要在返回成功之前返回给分配器。您是否将您的代码与www.gdcl.co.uk/gmfbridge中的版本进行了比较?

+0

返回的错误是0x8004022A - VFW_E_TYPE_NOT_ACCEPTED,但我现在已经发现它是为什么。看起来引脚的MediaType中的VIDEOINFOHEADER数据已损坏。宽度总是返回为零,并且高度似乎设置为宽度(就好像数据略微与结构不一致)。在转换过滤器的'ReceiveConnection'方法中检查数据时,数据似乎设置正确,但是在收到一个样本时已经损坏。 – 2010-03-17 14:19:23

+0

对不起,上面的代码确实有效。覆盖实现'GetMediaType'导致的混乱,该GetMediaType能够以VIDEOINFOHEADER和VIDEOINFOHEADER2格式返回格式数据,我没有检查这一点。 现在我已经删除了大小检查,而是在传入示例附加了MediaType时调用过滤器中Receive方法的ReceiveConnection。但是,从ReceiveConnection返回的值仍然是VFW_E_TYPE_NOT_ACCEPTED。 – 2010-03-17 15:33:40

+0

解码器滤波器来自CTransformFilter,输出引脚是标准的CTransformOutputPin。目前我没有做任何特殊的处理来分配缓冲区。是否只是在VideoRenderer输入引脚上调用BeginFlush和EndFlush?对不起,发现它有点棘手,以确切地遵循GMFBridge滤波器在这个领域做的事情。 – 2010-03-17 16:44:50