我的DirectShow在动态格式更改时失败了

时间:2014-12-24 07:59:34

标签: winapi visual-c++ video directshow

最近我正在使用VC和DirectShow,问题是动态格式更改对我没用。

我将CBaseFilter定制为我的SouceFilter。它获取,填充并传递MediaSample(简称Sample)到下游过滤器,这是一个精确的VMR.SourceFilter通过CBaseOutputPin :: GetDeliveryBuffer获取Sample,并通过CBaseOutputPin :: Deliver传递Sample。

由于原因,帧的分辨率可能随时改变。因此,每次分辨率更改时,我都会在其pbFormat bmiHeader中附加一个新的MediaType,其宽度和高度已更改。

根据MSDN Dynamic Format Changes,我编写了如下代码:

// YUV420 frame got
// now try to get Sample buffer
if(pvi.bmiHeader.biWidth != width || pvi.bmiHeader.biHeight != height){ 
    // if resolution changed
    // generate new MediaType with new resolution
    SetMediaType(width, height);
    if(S_OK == pRenderInPin->QueryAccept(&mediaType)){
        // if the input Pin of render accept the new MediaType
        if(pSourceFilter){
            /*
             * In function GetSampleBufferOfMediaType, 
             * I ask for a Sample, attach a MediaType to it,
             * and get its buffer for future use
             */
            while(S_OK != pSourceFilter->GetSampleBufferOfMediaType(&mediaType, &pSampleBuffer)
                    && isActive){
                Sleep(8);
            }
        }
    }else{
        DEBUG_INFO("ERROR - failed on QueryAccept\n");
    }
}else{
    // in function GetSampleBuffer, just ask for a Sample buffer
    while (S_OK != pSourceFilter->GetSampleBuffer(&pSampleBuffer)
            && isActive){
        Sleep(8);
    }
}
// fill buffer and deliver it

我认为一旦RenderFilter获得附加了新MediaType的Sample,它将调用IMediaSample :: GetMediaType,并采用新的MediaType。但是我发现onece分辨率已经改变,GetSampleBufferOfMediaType将会执行,遗憾的是图片没有在屏幕上正确显示。

我想知道为什么它不能像我预期的那样工作,我应该如何修改我的程序。

任何提示都将非常感激。

----- [额外信息] -----

在没有格式更改的情况下,我的MediaType可以很好地使用720P和1080P,但使用CIF(352 * 288)并不幸运。也许这里我的函数SetMediaType()有问题吗?

void CReadBufController::SetMediaType(short _width, short _height){
    mMediaType.subtype = MEDIASUBTYPE_YV12;
    mMediaType.majortype = MEDIATYPE_Video;
    mMediaType.formattype = FORMAT_VideoInfo;
    mMediaType.bFixedSizeSamples = FALSE;
    mMediaType.bTemporalCompression = TRUE;
    mMediaType.lSampleSize = 0;
    mMediaType.pUnk = 0;
    mMediaType.cbFormat = sizeof(VIDEOINFOHEADER);

    pvi.bmiHeader.biBitCount = 12;
    pvi.bmiHeader.biWidth = _width;
    pvi.bmiHeader.biHeight  = _height;
    pvi.bmiHeader.biSizeImage = GetBitmapSize(&pvi.bmiHeader);
    pvi.bmiHeader.biPlanes = 1;
    pvi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pvi.bmiHeader.biCompression = MAKEFOURCC('Y', 'V', '1', '2');

    mMediaType.pbFormat = (BYTE *)(&pvi);
}

- - - - [UPDATE] -----

根据@Roman_R的评论,这是我的GetSampleBufferOfMediaType代码:

// here CReadBufferFilter is the SourceFilter I mentioned
HRESULT CReadBufferFilter::GetSampleBufferOfMediaType(AM_MEDIA_TYPE *_pMediaType, PBYTE *_pBuffer){
    SAFE_RELEASE(mSample);
    // get a Sample from output Pin
    mOutputPin->GetDeliveryBuffer(&mSample, NULL, NULL, 0);
    // attach the new MediaType to the Sample
    if(mSample && (S_OK == mSample->SetMediaType(_pMediaType) )){
        mSample->GetPointer(_pBuffer); // get the Sample buffer
        return S_OK;
    }
    return E_FAIL;
}

'图片没有在屏幕上正确显示'表示它的灰色并与其多个图像副本重叠,就像你为MediaType分配了不正确的宽度和高度一样。

1 个答案:

答案 0 :(得分:0)

您的MSDN部分是QueryAccept (Downstream)。这种类型的格式更改仅在从较高分辨率切换到较低分辨率时才有效,即当连接不需要重新同意内存分配器并且已分配的缓冲区适合新的更新分辨率时。

您应该会在其中一个来电中看到视频渲染器返回的错误或拒绝代码:IPin::QueryAcceptIMediaSample::SetMediaTypeIMemInputPin::Receive

然后添加到此,即使您更改分辨率,视频渲染器可能还需要更改步幅以适应硬件要求。特别是较小分辨率的情况,因为视频渲染器/硬件希望将步幅对齐到16个字节或更多。您设置352x288分辨率的请求可能会立即导致Handling Format Changes from the Video Renderer更改同意相同的分辨率,但步幅增加。不处理这种情况可能会导致图像在视觉上被视为具有偏移线的图像。