directshow方法关键帧java,如何实现DirectShow source filter

实现DirectShow source filter有两大类方法

先研究第一种实现方法。从DirectShow SDK push source的例子来看,CSource派生类的实现都非常简单,无非在构造函数中生成一个CSourceStream派生的pin对象,在析构函数中将pin删除。主要的代码实现都在CSourceStream的派生类。而CSourceStream要重载的主要方法包括

HRESULT GetMediaType(CMediaType *pMediaType);

HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);

HRESULT FillBuffer(IMediaSample *pSample);

GetMediaType接口用于返回pin接受的媒体格式。GetMediaType有两种形式的接口,一种是一个参数的,另外一种是两个参数的

HRESULT GetMediaType(CMediaType *pMediaType);

HRESULT GetMediaType(int iPosition, CMediaType *pmt);

一个参数的版本适用于pin只提供一种输出格式的情况。如果pin支持多种格式的输出,需要使用第二种接口,同时重载CSourceStream::CheckMediaType接口。

CMediaType类是对AM_MEDIA_TYPE结构体的封装。这个结构体要赋值的成员还是挺多的,如何设置可以参考例子当中的GetMediaType函数

http://blog.csdn.net/zhengxinwcking/article/details/30475869

DecideBufferSize接口用于设置需要多大的buffer。CSourceStream类的父类CBasePin中有个m_mt的成员保存了GetMediaType设置的媒体格式。一份buffer的大小通常就是GetMediaType中设置的pmt->lSampleSize。一般用一份buffer也够了。

FillBuffer接口用于填写每一帧的音视频数据。这个接口一般先调用IMediaSample::GetPointer获得新一帧数据的缓冲,然后把数据写入这个缓冲。接着调用IMediaSample::SetTime设置帧的时间戳。最后调用IMediaSample::SetSyncPoint设置该帧是否为关键帧。对于提供非压缩数据的source filter,每一帧都应该设置为TRUE。

如果source filter的下游是vmr7(vmr9测试没有这个问题),还需要多实现两个接口

HRESULT CheckMediaType(const CMediaType *pMediaType)

STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)

vmr7要自己实现CheckMediaType的原因是,如果不重载CheckMediaType,DecideBufferSize函数中调用IMemAllocator::SetProperties会报错,返回E_FAIL,从而导致FillBuffer不会被调用(更正,如果IMemAllocator::SetProperties,则DecideBufferSize也应该报错,这样仍可以运行)。stackoverflow上面有一个类似的问题

https://stackoverflow.com/questions/7928828/negotiating-an-allocator-between-directshow-filters-fails

上面的解释是,VMR/EVR filter所需要的buffer stride会跟source filter GetMediaType设置的图像宽度不一致(显存需要字节对齐),导致格式发生改变。当VMR/EVR改变格式数据的时候,它会调用IPin::QueryAccept询问上游filter是否接受这个格式。CSourceStream实现的CheckMediaType是这样的

HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType)

{

CAutoLock lock(m_pFilter->pStateLock());

CMediaType mt;

GetMediaType(&mt);

if (mt == *pMediaType) {

return NOERROR;

}

return E_FAIL;

}

它会调用我们派生类实现的GetMediaType获得一个CMediaType,然后将这个CMediaType和下游传过来的CMediaType作比较。如果不一致,就返回E_FAIL。而CMediaType的==运算符是这样定义的

BOOL

CMediaType::operator == (const CMediaType& rt) const

{

// I don't believe we need to check sample size or

// temporal compression flags, since I think these must

// be represented in the type, subtype and format somehow. They

// are pulled out as separate flags so that people who don't understand

// the particular format representation can still see them, but

// they should duplicate information in the format block.

return ((IsEqualGUID(majortype,rt.majortype) == TRUE) &&

(IsEqualGUID(subtype,rt.subtype) == TRUE) &&

(IsEqualGUID(formattype,rt.formattype) == TRUE) &&

(cbFormat == rt.cbFormat) &&

( (cbFormat == 0) ||

pbFormat != NULL && rt.pbFormat != NULL &&

(memcmp(pbFormat, rt.pbFormat, cbFormat) == 0)));

}

通过调试,发现上游传过来的格式是用VIDEOINFO结构体的,而且biHeight是负数,因此会被误判为格式不相同。因此需要我们自己重载实现CheckMediaType

Notify虽然没什么鸟用,但是必须实现。否则CBasePin::Notify会抛出断言错误

CBasePin::Notify(IBaseFilter * pSender, Quality q)

{

UNREFERENCED_PARAMETER(q);

UNREFERENCED_PARAMETER(pSender);

DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)");

return E_NOTIMPL;

} //Notify

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值