Directshow 中的滤镜概念

Directshow的中filter (滤镜) 其实可以看作是一个功能模块,它规定了标准的接口,用于不同的滤镜直接传递媒体数据。各个滤镜也不用知道其他滤镜具体是怎么样工作的,他只要知道传过来的 是什么样格式的媒体数据就行了,然后他自己又由什么样的格式传出去给下个滤镜。

一个典型的在播放器中播放mp3文件的filter出来大概是这样子到;

文件源滤镜(File source filter)-》 mp3 解码filter -》音频渲染filter

 

上面这个是加上dsp 音效处理的。

最开始的叫做 “源滤镜” ,最后的叫做“renderer filter” ,每个播放流程,这两种类型的滤镜都是一定存在的,中间 到按照功能等分类,还可以分为“transfer filter”(变换滤镜)、“分离滤镜(把音视频数据分离)”等等各种类型。有的还能够一个接受接口,输出多个接口。

滤镜和滤镜的连接还可以分为推模式(push filter)和拉模式(pull filter)两种。

推模式的特点就是数据由上游的滤镜决定,就是上游的滤镜一有数据了可以推给下游的去处理。

拉模式的呢就是下游什么时候处理数据完了,才通过接口像上游滤镜要数据。

两种的不同就是数据的传递方法不同,所以中间的缓存数据策略也不一样,具体可以去查看msdn。

总的来说拉模式的适合用来播放文件,而推模式适合用来网络传输实时媒体。因为对实时性要求比较高的,我在自己的源滤镜中收到数据,就马上要求播放这 个数据了呀,推模式呢就可以马上在这个源滤镜中把数据传给下游滤镜,要求播放。如果是拉模式就不一样咯,下游滤镜决定了播放的话语权,我什么时候播放完 了,我再什么时候找你源滤镜要数据,这样有可能慢吞吞的在放,而源滤镜那有可能已经累积了很多数据在那了来不及播放,这样实时性就不好。

我在写语音聊天的时候,也是试了这两种滤镜的,采用push filter到时候,实时性确实要好些的。

关于学习,可以参考directshow sdk自带的两个例子

memfile(pull filter到)

ball (push filter的)

仔细看一些,稍稍修改就可以工作了。

=================

pull filter的

下游需要数据时会调用这个函数向上游filter要数据

HRESULT Read(PBYTE pbBuffer,
                 DWORD dwBytesToRead,
                 BOOL bAlign,                  LPDWORD pdwBytesRead)    

 

 

在这个函数可以设置我们推荐的缓存的大小,可以在这里改一下把数据大小改一下,缓存越小延时就,不过这里是有要求的,不能乱改,乱改了,决定权在下 游filter,他就会拒接连接,网上那些人说是要是32768 乘以6的大小,我测试的时候,播放mp3文件时这里最小可以调到4096 *48 。
// we need to return an addrefed allocator, even if it is the preferred
// one, since he doesn't know whether it is the preferred one or not.
STDMETHODIMP
CAsyncOutputPin::RequestAllocator(
    IMemAllocator* pPreferred,
    ALLOCATOR_PROPERTIES* pProps,
    IMemAllocator ** ppActual)
{
    CheckPointer(pPreferred,E_POINTER);
    CheckPointer(pProps,E_POINTER);
    CheckPointer(ppActual,E_POINTER);
    ASSERT(m_pIo);

    // we care about alignment but nothing else
    if(!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign))
    {
        m_pIo->Alignment(&pProps->cbAlign);
    }

    ALLOCATOR_PROPERTIES Actual;
    HRESULT hr;
/// 设置IMediaSample的长度更小一点,可以使语音的延时小一点?
///默认值为 32768 ,可能延时太大了
    pProps->cbBuffer = 4096 ; /4096 *48 可以成功  
    pProps->cBuffers = 48;    
    if(pPreferred)
    {
        hr = pPreferred->SetProperties(pProps, &Actual);

        if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
        {
            pPreferred->AddRef();
            *ppActual = pPreferred;
            return S_OK;
        }
    }

    // create our own allocator
    IMemAllocator* pAlloc;
    hr = InitAllocator(&pAlloc);
    if(FAILED(hr))
    {
        return hr;
    }

    //...and see if we can make it suitable
    hr = pAlloc->SetProperties(pProps, &Actual);
    if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
    {
        // we need to release our refcount on pAlloc, and addref
        // it to pass a refcount to the caller - this is a net nothing.
        *ppActual = pAlloc;
        return S_OK;
    }

    // failed to find a suitable allocator
    pAlloc->Release();

    // if we failed because of the IsAligned test, the error code will
    // not be failure
    if(SUCCEEDED(hr))
    {
        hr = VFW_E_BADALIGN;
    }
    return hr;
}

--------------

push模式时,

他会在后台启动一个进程不停调用FillBuffer函数,我们只要在源滤镜中有数据来时,把数据传下去就可以了。在这个函数里面我们可以用锁来等 待数据的到来,一来了马上push就行了。

 

 

===================

写filter的时候,还需要注意设置filter的可以接受的和输出的 媒体类型,CMediaType 这个类的设置很关键 。设置好了,各个filter才能连的起来,虽然directshow是会进行一些智能连接尝试的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值