以上是mpeg4 Encode filter的主要代码框架.
MPEG4 decode filter:
类定义
class CMPEG4Decode
: public CTransformFilter
{
public:
DECLARE_IUNKNOWN;
CMPEG4Decode(LPUNKNOWN pUnk, HRESULT *pHr);
~CMPEG4Decode();
static CUnknown *CreateInstance(LPUNKNOWN punk, HRESULT *pHr);
HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut);
HRESULT CheckInputType(const CMediaType* mtIn) ;
HRESULT CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) ;
HRESULT DecideBufferSize(IMemAllocator *pAlloc,
ALLOCATOR_PROPERTIES *pProperties);
HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin)
{
return S_OK;
}
private:
HRESULT Copy(IMediaSample *pSource, IMediaSample *pDest) ;
BOOL IsRGB24(const CMediaType *pMediaType);
bool m_bInit;
int m_nVideoWidth;
int m_nVideoHeight;
CCritSec m_EncodeLock;
DECODER * m_pDeocder;
BOOL Converse(BYTE * pSource);
};
CheckInputType实现
HRESULT CMPEG4Decode::CheckInputType(const CMediaType *mtIn)
{
if (*mtIn->FormatType() != FORMAT_VideoInfo) {
return E_INVALIDARG;
}
init_codec();
init_decoder(m_nVideoWidth,m_nVideoHeight,&m_pDeocder);
m_bInit = true;
return NOERROR;
} // CheckInputType
Transform实现和Copy函数与Encode filter的一致,知识copy里的处理不同,一个是encode,一个是decode.
DecideBufferSize实现:
HRESULT CMPEG4Decode::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties)
{
if (m_pInput->IsConnected() == FALSE)
{
return E_UNEXPECTED;
}
HRESULT hr = NOERROR;
pProperties->cBuffers = 1;
//注意,由于解压后数据长度增加,所以采用(m_pInput->CurrentMediaType().GetSampleSize())是不够的
pProperties->cbBuffer = m_nVideoWidth * m_nVideoHeight *3;
if (!m_pInput->CurrentMediaType().bFixedSizeSamples) {
if (pProperties->cbBuffer < 100000) {
pProperties->cbBuffer = 100000;
}
}
ALLOCATOR_PROPERTIES Actual;
hr = pAlloc->SetProperties(pProperties,&Actual);
if (FAILED(hr)) {
return hr;
}
if (pProperties->cBuffers > Actual.cBuffers ||
pProperties->cbBuffer > Actual.cbBuffer) {
return E_FAIL;
}
return NOERROR;
} // DecideBufferSize
GetMediaType函数实现
HRESULT CMPEG4Decode::GetMediaType(int iPosition, CMediaType *pMediaType)
{
if (m_pInput->IsConnected() == FALSE) {
return E_UNEXPECTED;
}
if (iPosition < 0) {
return E_INVALIDARG;
}
if (iPosition > 0) {
return VFW_S_NO_MORE_ITEMS;
}
*pMediaType = m_pInput->CurrentMediaType();
return NOERROR;
} // GetMediaType
类工厂:
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
&MEDIATYPE_Video, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
const AMOVIESETUP_PIN psudPins[] =
{ { L"Input" // strName
, FALSE // bRendered
, FALSE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_MPEG4Decode // clsConnectsToFilter
, NULL // strConnectsToPin
, 1 // nTypes
, &sudPinTypes // lpTypes
}
, { L"Output" // strName
, FALSE // bRendered
, TRUE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_MPEG4Decode // clsConnectsToFilter
, NULL // strConnectsToPin
, 1 // nTypes
, &sudPinTypes // lpTypes
}
};
const AMOVIESETUP_FILTER sudMPEG4Decode =
{ &CLSID_MPEG4Decode // clsID
, L"IES MPEG4 Decode" // strName
, MERIT_DO_NOT_USE // dwMerit
, 2 // nPins
, psudPins }; // lpPin
// CreateInstance机制需要,只能放在后面
CFactoryTemplate g_Templates[]=
{ { L"IES MPEG4 Decode"
, &CLSID_MPEG4Decode
, CMPEG4Decode::CreateInstance
, NULL
, &sudMPEG4Decode }
};
int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);
以上摘录了两个filter的主要框架代码.
目前,我这两个filter编译成功,开始测试,下面是测试的一些现象和问题.
测试环境:
Windows XP 简体中文版
DirectX 8.1
测试工具:
GraphEdt
1.压缩解压实验
Graph连接图:
Logitech QuickCam Pro 4000 --> My MPEG4 Encode Filter --> My MPEG4 Decode Filter -->VMR Video Render
注意:实际在连接My MPEG4 Decode Filter和VMR Video Render时,中间还会自动加入一个Color Space Convert
测试结果:图象清晰,剧烈运动时有些许叠影,但几乎可以忽略不计。
图象是倒的!!!
结论和改进措施:
这个实验基本证明我们这两个Filter基本框架无误,工作正常。
图象是倒的,怎么办呢?
由于图象的存储是线形的,一个象素三个字节.后面紧跟下一个象素的三个字节。这样看来,只要简单倒一下就可以了.
BOOL CMPEG4Decode::Converse(BYTE * pSource)
{
const PIX = m_nVideoWidth*m_nVideoHeight;
const PIXS = PIX*3;
BYTE * pTemp;
pTemp = (BYTE *)malloc(PIXS);
for(int i=1;i<=PIX;i++)
{
memcpy(pTemp+(i-1)*3,pSource+PIXS-i*3,3);
}
memcpy(pSource,pTemp,PIXS);
free(pTemp);
return TRUE;
}
用Converse函数对上面描述的decode filter代码里面的Copy函数进行改进,问题解决,一切ok,happy!!!!。
2.录象实验
Graph连接图:
Logitech QuickCam Pro 4000 --> My MPEG4 Encode Filter --> AVI Mux --> FileWrite(Mytest.avi)
测试结果:一切正常,按需要生成了AVI文件.
如果你现在用Media Player播放该AVI文件,屏幕上会出现一片雪花和条纹,最后程序还会崩溃,faint!
不过这样的结果应该在你的意料之中.
3.打开刚才录的AVI,看究竟发生了什么事情!
在GraphEdt里面选择对 Mytest.avi进行Renderfile,会出现以下的Graph:
这个步骤也就是Windows Media Player播放文件的步骤!!!
File Source(Mytest.avi) --> AVI Splitter --> Color Space Convert --> VMR Video Render
前面的 File Source(Mytest.avi) --> AVI Splitter是我们所希望的,AVI Splitter会把我们Encode的视频分离出来,这很好。
但是接下来就不对了.在还没有用My Decode Filter解码之前,系统就直接连接到VMR Video Render了,Color Space Convert 只是中间的一个色彩空间的转换。
那么,究竟如何才能让系统认识我们分离出来的流呢,并为我们正确加上My decode Filter呢?
老实说,我现在还不知道。
我写这篇文章的目的是抛砖引玉,希望各位一起出谋划策,得以共同进步。
4.手工添加My decode Filter.
上面的实验很令我沮丧和迷惑。为此我做了很多工作。
手工建立下面的Graph连接图:
File Source(Mytest.avi) --> AVI Splitter -->My MPEG4 Decode Filter -->Color Space Convert --> VMR Video Render
现在一切又正常了。
现在问题是:如何让系统自动完成这一切。
我要写的就写完了,真切希望看到我这篇文章并对DirectShow有兴趣的高人能够就这些问题给些意见,同时,希望大家:
“知无不言,言无不尽;言者无罪,闻者足戒...”
有一位高人,名唤陆其明,写过很多DirectShow方面的启蒙文章,现在从事这个领域的人大都知道他。该同志现在在写一本书,叫做《DirectShow宝典》,据说已经完成。我曾将这些问题在其个人主页上多次提出,但该位仁兄除了不痛不痒说几句以外,基本上没有作用,可能是我太笨的缘故。