注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

gmd20的个人空间

// 编程和生活

 
 
 

日志

 
 

Directshow 中的滤镜概念  

2008-10-11 19:15:37|  分类: 程序设计 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

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

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

Directshow 中的滤镜概念 - widebright - widebright的个人空间

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

Directshow 中的滤镜概念 - widebright - widebright的个人空间

上面这个是加上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是会进行一些智能连接尝试的。

  评论这张
 
阅读(600)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017