directshow之filters 例程BALL的详细解析
2015-01-10 20:57
351 查看
directshow之filters 例程BALL的详细解析
BALL是一个推模式的source
filter,其产生一个不断撞击窗口边界的小球。编译BALL
工程,将生成ball.ax文件,用regsvr32注册该文件,打开graphedit.exe插入Bouncing
Ball、Color Space Converter、Video Renderer三个filter,其中Bouncing
Ball即ball.ax。将插入的三个filters连接起来,运行就可以看到下图所示的界面。
BALL工程中有三个类CBall、CBallStream、CBouncingBall,其中CBall封装了小球的行为即产生每个图像时小球应在图像中的位置。CBouncingBall继承自CSource,CSource是一个基类在BaseClasses工程中实现,CSource一般作为source
filters的基类使用,CSource继承于CBaseFilter,旨在简化source
Filters组件的生成,支持连续数据源的生成,因此CBouncingBall为该工程的主filter。CBallStream继承自CSourceStream,而CSourceStream又继承自CAMThread、CBaseOutputPin,其中CAMThread用于工作线程的生成,CBaseOutputPin使CBallStream类具有输出pin的特性。
1、 CBouncingBall
和CBallStream是怎么关联起来的?
在CBouncingBall的构造函数中构造了一个CBallStream实例,并将该实例的指针赋值
给m_paStreams变量,m_paStreams是CBouncingBall的父类CSource的变量,该变量用来保存SourceFilter拥有的pin。代码如下:
CBouncingBall::CBouncingBall(LPUNKNOWN lpunk, HRESULT *phr) :
CSource(NAME("Bouncingball"),
lpunk,
CLSID_BouncingBall)
{
CAutoLock cAutoLock(&m_cStateLock);
m_paStreams
= (CSourceStream **) new CBallStream*[1];
if (m_paStreams == NULL) {
*phr = E_OUTOFMEMORY;
return;
}
m_paStreams[0] = newCBallStream(phr, this, L"A Bouncing Ball!");
if (m_paStreams[0] == NULL) {
*phr = E_OUTOFMEMORY;
return;
}
} // (Constructor
2、原始数据是在什么位置产生的?
该工程的原始数据是CBallStream负责产生的,在该类的FillBuffer方法中,将产生的图像填充到MediaSample中。
HRESULT CBallStream::FillBuffer(IMediaSample *pms)
{
BYTE *pData;
long lDataLen;
pms->GetPointer(&pData);//得到MediaSample中存储数据buffer的地址
lDataLen = pms->GetSize();//得到存储数据buffer的大小
// If true then we clear theoutput buffer and don't attempt to
// erase a previous drawing ofthe ball - this will be the case
// when we start running as thebuffer will be full of rubbish
if( m_bZeroMemory ) {
ZeroMemory( pData, lDataLen);
}
{
CAutoLockcAutoLockShared(&m_cSharedState);
// If we haven't justcleared the buffer delete the old
// ball and move the ball on
if( !m_bZeroMemory ){
BYTE aZeroes[ 4 ] = { 0,0, 0, 0 };
m_Ball->PlotBall(pData, aZeroes, m_iPixelSize);//画球
m_Ball->MoveBall(m_rtSampleTime - (LONG) m_iRepeatTime);//移动球
}
m_Ball->PlotBall(pData,m_BallPixel, m_iPixelSize);//画球
// The current time is thesample's start
CRefTime rtStart =m_rtSampleTime;
// Increment to find thefinish time
m_rtSampleTime+= (LONG)m_iRepeatTime;//增加参考时间
pms->SetTime((REFERENCE_TIME *) &rtStart,(REFERENCE_TIME *)&m_rtSampleTime);
}
m_bZeroMemory = FALSE;
pms->SetSyncPoint(TRUE);
return NOERROR;
} // FillBuffer
3、 产生的数据是怎么源源不断的传输给下游filter的?
在Graph开始运行后会调用SourceFIlterpin的Active函数,CBallStream没有
CSourceStream的Active方法,所以CSourceStream的Active方法会被调用,在Active方法中调用Create函数(CAMThread类的方法)来创建一个工作线程,线程函数为CAMThread::InitialThreadPoc,在InitialThreadPoc函数中调用CAMThread子类(CSourceStream及其子类)的threadpoc方法进行graph需求命令的解析和执行。由于CBallStream没有实现threadpoc方法,所以调用的是CSourceStream的threadpoc方法。
在threadpoc方法中GetRequest,并根据GetRequest的返回值做出相应动作,当返回值为CMD_PAUSE时调用DoBufferProcessingLoop来生成和传输数据。DoBufferProcessingLoop函数中先调用GetDeliveryBuffer生成一个MediaSample,然后调用FillBuffer(CBallStream重载了该函数)填充该MediaSample,最后调用Deliver函数将填充后的MediaSample向下游filter传输。
Deliver函数是CBallStream父类CSourceStream父类CBaseOutputPIn的方法,即调用filter的输出pin的Deliver方法,Deliver方法中调用与该输出pin连接的输入pin的Receive方法将MediaSample传送给下一个Filter。而输出pin是怎么知道和它连接的输入pin的呢?CBaseOutputPin基类中定义了一个m_pInputPin的变量用来保存和它连接的输入pin,在pin连接成功时将与其连接的pin保存到m_pInputPin的变量中,这样在MediaSample传输中直接调用m_pInputPin的接收方法,就可以将数据向下传输了。这也是pin与pin直接沟通的方法,输出pin中有变量来保存与其相连的输入pin,通样的输入pin中也有变量来保存与其相连的输出pin的变量。
CSourceStream的Active函数:
HRESULT CSourceStream::Active(void) {
CAutoLocklock(m_pFilter->pStateLock());
HRESULT hr;
if (m_pFilter->IsActive()) {
return S_FALSE; // succeeded, but did not allocate resources(they already exist...)
}
// do nothing if not connected -its ok not to connect to
// all pins of a source filter
if (!IsConnected()) {
return NOERROR;
}
hr = CBaseOutputPin::Active();
if (FAILED(hr)) {
return hr;
}
ASSERT(!ThreadExists());
// start the thread
// Create()函数来创建工作线程,该函数是CAMThread的方法,由于CAMThread是//CSourceStream的一个父类,用来管理工作线程。
if (!Create()) {
return E_FAIL;
}
// Tell thread to initialize. IfOnThreadCreate Fails, so does this.
hr = Init();
if (FAILED(hr))
return hr;
returnPause();
}
CAMThread的Create()方法:在CreateThread函数中用this作为参数传给线程函数InitialThreadProc,当在CSourceStream调用该函数时,this指向CSourceStream实例。
在InitialThreadProc函数调用了this指向实例的ThreadProc函数,即CSourceStream的ThreadProc函数
BOOL
CAMThread::Create()
{
DWORD threadid;
CAutoLocklock(&m_AccessLock);
if (ThreadExists()) {
return FALSE;
}
//创建线程,并以this作为线程函数的指针。
m_hThread = CreateThread(
NULL,
0,
CAMThread::InitialThreadProc,
this,
0,
&threadid);
if (!m_hThread) {
return FALSE;
}
return TRUE;
}
CSourceStream的ThreadProc函数:
ThreadProc函数有do…while循环来源源不断解析各个命名DWORD
CSourceStream::ThreadProc(void) {
HRESULT hr; // the return code from calls
Command com;
//处理线程线程初始化
do {
com = GetRequest();
if (com != CMD_INIT) {
DbgLog((LOG_ERROR, 1, TEXT("Threadexpected init command")));
Reply((DWORD) E_UNEXPECTED);
}
} while (com != CMD_INIT);
DbgLog((LOG_TRACE, 1,TEXT("CSourceStream worker thread initializing")));
// CSourceStream定义的函数,在该工程中没有做任何动作
hr = OnThreadCreate(); // perform set up tasks
if (FAILED(hr)) {
DbgLog((LOG_ERROR, 1,TEXT("CSourceStream::OnThreadCreate failed. Aborting thread.")));
OnThreadDestroy();
Reply(hr); // send failed return code from OnThreadCreate
return 1;
}
// Initialisation suceeded
Reply(NOERROR);
//处理执行各种命令
Command cmd;
do {
cmd = GetRequest();
switch (cmd) {
case CMD_EXIT:
Reply(NOERROR);
break;
case CMD_RUN:
DbgLog((LOG_ERROR, 1, TEXT("CMD_RUNreceived before a CMD_PAUSE???")));
// !!! fall through???
//在DoBufferProcessingLoop()函数中调用FillBuffer Deliver函数产生传输数据。
case CMD_PAUSE:
Reply(NOERROR);
DoBufferProcessingLoop();
break;
case CMD_STOP:
Reply(NOERROR);
break;
default:
DbgLog((LOG_ERROR, 1, TEXT("Unknowncommand %d received!"), cmd));
Reply((DWORD) E_NOTIMPL);
break;
}
} while (cmd != CMD_EXIT);
hr = OnThreadDestroy(); // tidy up.
if (FAILED(hr)) {
DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroyfailed. Exiting thread.")));
return 1;
}
DbgLog((LOG_TRACE, 1,TEXT("CSourceStream worker thread exiting")));
return 0;
}
CSourceStream的DoBufferProcessingLoop函数:该函数的do…while结构来源源不断的产生、传输数据。在产生数据之前要先分配空间来保存数据,那么要分配多大的空间才算合适呢,这个由CBallStream类的DecideBufferSize(IMemAllocator*pAlloc,ALLOCATOR_PROPERTIES
*pProperties)函数来告知内存分配对象Allocator。
HRESULT CSourceStream::DoBufferProcessingLoop(void) {
Command com;
// CSourceStream定义的函数,在该工程中没有做任何动作
OnThreadStartPlay();
//
do {
//检查com命令码是否有效
while (!CheckRequest(&com)) {
//分配MediaSample空间用于保存产生的样本数据
IMediaSample *pSample;
HRESULT hr =GetDeliveryBuffer(&pSample,NULL,NULL,0);
if (FAILED(hr)) {
Sleep(1);
continue; // go round again. Perhaps the error will goaway
// or the allocator is decommited & wewill be asked to
// exit soon.
}
// Virtual function user will override.
//生成、填充数据
hr = FillBuffer(pSample);
if (hr == S_OK) {
hr = Deliver(pSample);//传输数据
pSample->Release();
// downstream filterreturns S_FALSE if it wants us to
// stop or an errorif it's reporting an error.
if(hr != S_OK)
{
DbgLog((LOG_TRACE,2, TEXT("Deliver() returned %08x; stopping"), hr));
return S_OK;
}
} else if (hr == S_FALSE) {
// derived classwants us to stop pushing data
pSample->Release();
DeliverEndOfStream();
return S_OK;
} else {
// derived classencountered an error
pSample->Release();
DbgLog((LOG_ERROR, 1,TEXT("Error %08lX from FillBuffer!!!"), hr));
DeliverEndOfStream();
m_pFilter->NotifyEvent(EC_ERRORABORT,hr, 0);
return hr;
}
// all paths release thesample
}
// For all commands sent tous there must be a Reply call!
if (com == CMD_RUN || com ==CMD_PAUSE) {
Reply(NOERROR);
} else if (com != CMD_STOP) {
Reply((DWORD) E_UNEXPECTED);
DbgLog((LOG_ERROR, 1, TEXT("Unexpectedcommand!!!")));
}
} while (com != CMD_STOP);
return S_FALSE;
}
4、
CSourceStream类中线程函数中的命令码是怎么传输的?
CSourceStream类中线程函数中的命令码CMD_STOP等,并不是DrectShow通用的,只有CSourceStream类才实现了这样了机制(PULLPIN也实现了类似的机制TM_STOP等)。CMD_INIT这样的命令码定义在CSourceStream的头文件中。在程序指向过程中由CSourceStream发出,有CSourceStream的线程函数进行处理。在Craph开始、暂停、运行、停止时,CSourceStream放出响应的命令码,发送命令码时调用CAMThread的CallWorker传给CAMThread,在CSourceStream的线程函数中通过CAMThread的GetRequest或者CheckRequest函数获得命令码来进行响应的处理。
CSourceStream类中命令码的定义和发送
enum Command {CMD_INIT,CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT};
HRESULT Init(void) { returnCallWorker(CMD_INIT); }
HRESULT Exit(void) { returnCallWorker(CMD_EXIT); }
HRESULT Run(void) { returnCallWorker(CMD_RUN); }
HRESULT Pause(void) { returnCallWorker(CMD_PAUSE); }
HRESULT Stop(void) { returnCallWorker(CMD_STOP); }
5、
pin连接构成中的媒体协商怎么实现的?
所谓的Filter Pin之间的连接,实际上是Pin之间Media Type(媒体类型)的一个协商过程。连接总是从输出Pin指向输入Pin的。要想深入了解具体的连接过程,就必须认真研读
SDK的基类源代码(位DXSDK\samples\Multimedia\DirectShow\BaseClasses\amfilter.cpp,类CBasePin的Connect方法)。连接的大致过程为,枚举欲连接的输入Pin上所有的媒体类型,逐一用这些媒体类型与输出Pin进行连接,如果输出Pin也接受这种媒体类型,则Pin之间的连接宣告成功;如果所有输入Pin上枚举的媒体类型输出Pin都不支持,则枚举输出Pin上的所有媒体类型,并逐一用这些媒体类型与输入Pin进行连接。如果输入Pin接受其中的一种媒体类型,则Pin之间的连接到此也宣告成功;如果输出Pin上的所有媒体类型,输入Pin都不支持,则这两个Pin之间的连接过程宣告失败。
CBallStream类中的GetMediaType()、CheckMediaType()就是在pin媒体协商用用到的关键函数。GetMediaType()用来得到CBallStream(一个输出pin)支持的媒体类型,CheckMediaType()用来接触传入的媒体类型CBallStream(一个输出pin)是否支持。
BALL是一个推模式的source
filter,其产生一个不断撞击窗口边界的小球。编译BALL
工程,将生成ball.ax文件,用regsvr32注册该文件,打开graphedit.exe插入Bouncing
Ball、Color Space Converter、Video Renderer三个filter,其中Bouncing
Ball即ball.ax。将插入的三个filters连接起来,运行就可以看到下图所示的界面。
BALL工程中有三个类CBall、CBallStream、CBouncingBall,其中CBall封装了小球的行为即产生每个图像时小球应在图像中的位置。CBouncingBall继承自CSource,CSource是一个基类在BaseClasses工程中实现,CSource一般作为source
filters的基类使用,CSource继承于CBaseFilter,旨在简化source
Filters组件的生成,支持连续数据源的生成,因此CBouncingBall为该工程的主filter。CBallStream继承自CSourceStream,而CSourceStream又继承自CAMThread、CBaseOutputPin,其中CAMThread用于工作线程的生成,CBaseOutputPin使CBallStream类具有输出pin的特性。
1、 CBouncingBall
和CBallStream是怎么关联起来的?
在CBouncingBall的构造函数中构造了一个CBallStream实例,并将该实例的指针赋值
给m_paStreams变量,m_paStreams是CBouncingBall的父类CSource的变量,该变量用来保存SourceFilter拥有的pin。代码如下:
CBouncingBall::CBouncingBall(LPUNKNOWN lpunk, HRESULT *phr) :
CSource(NAME("Bouncingball"),
lpunk,
CLSID_BouncingBall)
{
CAutoLock cAutoLock(&m_cStateLock);
m_paStreams
= (CSourceStream **) new CBallStream*[1];
if (m_paStreams == NULL) {
*phr = E_OUTOFMEMORY;
return;
}
m_paStreams[0] = newCBallStream(phr, this, L"A Bouncing Ball!");
if (m_paStreams[0] == NULL) {
*phr = E_OUTOFMEMORY;
return;
}
} // (Constructor
2、原始数据是在什么位置产生的?
该工程的原始数据是CBallStream负责产生的,在该类的FillBuffer方法中,将产生的图像填充到MediaSample中。
HRESULT CBallStream::FillBuffer(IMediaSample *pms)
{
BYTE *pData;
long lDataLen;
pms->GetPointer(&pData);//得到MediaSample中存储数据buffer的地址
lDataLen = pms->GetSize();//得到存储数据buffer的大小
// If true then we clear theoutput buffer and don't attempt to
// erase a previous drawing ofthe ball - this will be the case
// when we start running as thebuffer will be full of rubbish
if( m_bZeroMemory ) {
ZeroMemory( pData, lDataLen);
}
{
CAutoLockcAutoLockShared(&m_cSharedState);
// If we haven't justcleared the buffer delete the old
// ball and move the ball on
if( !m_bZeroMemory ){
BYTE aZeroes[ 4 ] = { 0,0, 0, 0 };
m_Ball->PlotBall(pData, aZeroes, m_iPixelSize);//画球
m_Ball->MoveBall(m_rtSampleTime - (LONG) m_iRepeatTime);//移动球
}
m_Ball->PlotBall(pData,m_BallPixel, m_iPixelSize);//画球
// The current time is thesample's start
CRefTime rtStart =m_rtSampleTime;
// Increment to find thefinish time
m_rtSampleTime+= (LONG)m_iRepeatTime;//增加参考时间
pms->SetTime((REFERENCE_TIME *) &rtStart,(REFERENCE_TIME *)&m_rtSampleTime);
}
m_bZeroMemory = FALSE;
pms->SetSyncPoint(TRUE);
return NOERROR;
} // FillBuffer
3、 产生的数据是怎么源源不断的传输给下游filter的?
在Graph开始运行后会调用SourceFIlterpin的Active函数,CBallStream没有
CSourceStream的Active方法,所以CSourceStream的Active方法会被调用,在Active方法中调用Create函数(CAMThread类的方法)来创建一个工作线程,线程函数为CAMThread::InitialThreadPoc,在InitialThreadPoc函数中调用CAMThread子类(CSourceStream及其子类)的threadpoc方法进行graph需求命令的解析和执行。由于CBallStream没有实现threadpoc方法,所以调用的是CSourceStream的threadpoc方法。
在threadpoc方法中GetRequest,并根据GetRequest的返回值做出相应动作,当返回值为CMD_PAUSE时调用DoBufferProcessingLoop来生成和传输数据。DoBufferProcessingLoop函数中先调用GetDeliveryBuffer生成一个MediaSample,然后调用FillBuffer(CBallStream重载了该函数)填充该MediaSample,最后调用Deliver函数将填充后的MediaSample向下游filter传输。
Deliver函数是CBallStream父类CSourceStream父类CBaseOutputPIn的方法,即调用filter的输出pin的Deliver方法,Deliver方法中调用与该输出pin连接的输入pin的Receive方法将MediaSample传送给下一个Filter。而输出pin是怎么知道和它连接的输入pin的呢?CBaseOutputPin基类中定义了一个m_pInputPin的变量用来保存和它连接的输入pin,在pin连接成功时将与其连接的pin保存到m_pInputPin的变量中,这样在MediaSample传输中直接调用m_pInputPin的接收方法,就可以将数据向下传输了。这也是pin与pin直接沟通的方法,输出pin中有变量来保存与其相连的输入pin,通样的输入pin中也有变量来保存与其相连的输出pin的变量。
CSourceStream的Active函数:
HRESULT CSourceStream::Active(void) {
CAutoLocklock(m_pFilter->pStateLock());
HRESULT hr;
if (m_pFilter->IsActive()) {
return S_FALSE; // succeeded, but did not allocate resources(they already exist...)
}
// do nothing if not connected -its ok not to connect to
// all pins of a source filter
if (!IsConnected()) {
return NOERROR;
}
hr = CBaseOutputPin::Active();
if (FAILED(hr)) {
return hr;
}
ASSERT(!ThreadExists());
// start the thread
// Create()函数来创建工作线程,该函数是CAMThread的方法,由于CAMThread是//CSourceStream的一个父类,用来管理工作线程。
if (!Create()) {
return E_FAIL;
}
// Tell thread to initialize. IfOnThreadCreate Fails, so does this.
hr = Init();
if (FAILED(hr))
return hr;
returnPause();
}
CAMThread的Create()方法:在CreateThread函数中用this作为参数传给线程函数InitialThreadProc,当在CSourceStream调用该函数时,this指向CSourceStream实例。
在InitialThreadProc函数调用了this指向实例的ThreadProc函数,即CSourceStream的ThreadProc函数
BOOL
CAMThread::Create()
{
DWORD threadid;
CAutoLocklock(&m_AccessLock);
if (ThreadExists()) {
return FALSE;
}
//创建线程,并以this作为线程函数的指针。
m_hThread = CreateThread(
NULL,
0,
CAMThread::InitialThreadProc,
this,
0,
&threadid);
if (!m_hThread) {
return FALSE;
}
return TRUE;
}
CSourceStream的ThreadProc函数:
ThreadProc函数有do…while循环来源源不断解析各个命名DWORD
CSourceStream::ThreadProc(void) {
HRESULT hr; // the return code from calls
Command com;
//处理线程线程初始化
do {
com = GetRequest();
if (com != CMD_INIT) {
DbgLog((LOG_ERROR, 1, TEXT("Threadexpected init command")));
Reply((DWORD) E_UNEXPECTED);
}
} while (com != CMD_INIT);
DbgLog((LOG_TRACE, 1,TEXT("CSourceStream worker thread initializing")));
// CSourceStream定义的函数,在该工程中没有做任何动作
hr = OnThreadCreate(); // perform set up tasks
if (FAILED(hr)) {
DbgLog((LOG_ERROR, 1,TEXT("CSourceStream::OnThreadCreate failed. Aborting thread.")));
OnThreadDestroy();
Reply(hr); // send failed return code from OnThreadCreate
return 1;
}
// Initialisation suceeded
Reply(NOERROR);
//处理执行各种命令
Command cmd;
do {
cmd = GetRequest();
switch (cmd) {
case CMD_EXIT:
Reply(NOERROR);
break;
case CMD_RUN:
DbgLog((LOG_ERROR, 1, TEXT("CMD_RUNreceived before a CMD_PAUSE???")));
// !!! fall through???
//在DoBufferProcessingLoop()函数中调用FillBuffer Deliver函数产生传输数据。
case CMD_PAUSE:
Reply(NOERROR);
DoBufferProcessingLoop();
break;
case CMD_STOP:
Reply(NOERROR);
break;
default:
DbgLog((LOG_ERROR, 1, TEXT("Unknowncommand %d received!"), cmd));
Reply((DWORD) E_NOTIMPL);
break;
}
} while (cmd != CMD_EXIT);
hr = OnThreadDestroy(); // tidy up.
if (FAILED(hr)) {
DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroyfailed. Exiting thread.")));
return 1;
}
DbgLog((LOG_TRACE, 1,TEXT("CSourceStream worker thread exiting")));
return 0;
}
CSourceStream的DoBufferProcessingLoop函数:该函数的do…while结构来源源不断的产生、传输数据。在产生数据之前要先分配空间来保存数据,那么要分配多大的空间才算合适呢,这个由CBallStream类的DecideBufferSize(IMemAllocator*pAlloc,ALLOCATOR_PROPERTIES
*pProperties)函数来告知内存分配对象Allocator。
HRESULT CSourceStream::DoBufferProcessingLoop(void) {
Command com;
// CSourceStream定义的函数,在该工程中没有做任何动作
OnThreadStartPlay();
//
do {
//检查com命令码是否有效
while (!CheckRequest(&com)) {
//分配MediaSample空间用于保存产生的样本数据
IMediaSample *pSample;
HRESULT hr =GetDeliveryBuffer(&pSample,NULL,NULL,0);
if (FAILED(hr)) {
Sleep(1);
continue; // go round again. Perhaps the error will goaway
// or the allocator is decommited & wewill be asked to
// exit soon.
}
// Virtual function user will override.
//生成、填充数据
hr = FillBuffer(pSample);
if (hr == S_OK) {
hr = Deliver(pSample);//传输数据
pSample->Release();
// downstream filterreturns S_FALSE if it wants us to
// stop or an errorif it's reporting an error.
if(hr != S_OK)
{
DbgLog((LOG_TRACE,2, TEXT("Deliver() returned %08x; stopping"), hr));
return S_OK;
}
} else if (hr == S_FALSE) {
// derived classwants us to stop pushing data
pSample->Release();
DeliverEndOfStream();
return S_OK;
} else {
// derived classencountered an error
pSample->Release();
DbgLog((LOG_ERROR, 1,TEXT("Error %08lX from FillBuffer!!!"), hr));
DeliverEndOfStream();
m_pFilter->NotifyEvent(EC_ERRORABORT,hr, 0);
return hr;
}
// all paths release thesample
}
// For all commands sent tous there must be a Reply call!
if (com == CMD_RUN || com ==CMD_PAUSE) {
Reply(NOERROR);
} else if (com != CMD_STOP) {
Reply((DWORD) E_UNEXPECTED);
DbgLog((LOG_ERROR, 1, TEXT("Unexpectedcommand!!!")));
}
} while (com != CMD_STOP);
return S_FALSE;
}
4、
CSourceStream类中线程函数中的命令码是怎么传输的?
CSourceStream类中线程函数中的命令码CMD_STOP等,并不是DrectShow通用的,只有CSourceStream类才实现了这样了机制(PULLPIN也实现了类似的机制TM_STOP等)。CMD_INIT这样的命令码定义在CSourceStream的头文件中。在程序指向过程中由CSourceStream发出,有CSourceStream的线程函数进行处理。在Craph开始、暂停、运行、停止时,CSourceStream放出响应的命令码,发送命令码时调用CAMThread的CallWorker传给CAMThread,在CSourceStream的线程函数中通过CAMThread的GetRequest或者CheckRequest函数获得命令码来进行响应的处理。
CSourceStream类中命令码的定义和发送
enum Command {CMD_INIT,CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT};
HRESULT Init(void) { returnCallWorker(CMD_INIT); }
HRESULT Exit(void) { returnCallWorker(CMD_EXIT); }
HRESULT Run(void) { returnCallWorker(CMD_RUN); }
HRESULT Pause(void) { returnCallWorker(CMD_PAUSE); }
HRESULT Stop(void) { returnCallWorker(CMD_STOP); }
5、
pin连接构成中的媒体协商怎么实现的?
所谓的Filter Pin之间的连接,实际上是Pin之间Media Type(媒体类型)的一个协商过程。连接总是从输出Pin指向输入Pin的。要想深入了解具体的连接过程,就必须认真研读
SDK的基类源代码(位DXSDK\samples\Multimedia\DirectShow\BaseClasses\amfilter.cpp,类CBasePin的Connect方法)。连接的大致过程为,枚举欲连接的输入Pin上所有的媒体类型,逐一用这些媒体类型与输出Pin进行连接,如果输出Pin也接受这种媒体类型,则Pin之间的连接宣告成功;如果所有输入Pin上枚举的媒体类型输出Pin都不支持,则枚举输出Pin上的所有媒体类型,并逐一用这些媒体类型与输入Pin进行连接。如果输入Pin接受其中的一种媒体类型,则Pin之间的连接到此也宣告成功;如果输出Pin上的所有媒体类型,输入Pin都不支持,则这两个Pin之间的连接过程宣告失败。
CBallStream类中的GetMediaType()、CheckMediaType()就是在pin媒体协商用用到的关键函数。GetMediaType()用来得到CBallStream(一个输出pin)支持的媒体类型,CheckMediaType()用来接触传入的媒体类型CBallStream(一个输出pin)是否支持。
相关文章推荐
- STM32F303X单片机USB例程详细解析1
- STM32F303X单片机USB例程详细解析3
- DirectShow之filters例程详解前言
- STM32F303X单片机USB例程详细解析4
- STM32F303X单片机USB例程详细解析2
- directshow之filter开发---ASYNC例程解析
- JFreeChart初学者入门实例详细解析之二
- 详细解析JSP编程中进度条的设计实例
- 详细解析C++编写的ATM自动取款机模拟程序
- 全新体验 诺基亚S40第3版详细解析介绍(上)
- 经常用的一些开源协议的详细解析
- ping 命令工作原理详细解析
- 全新体验 诺基亚S40第3版详细解析介绍(下)
- BT种子文件 bencoding编码详细解析
- ATi的救赎——X1000系列显卡技术详细解析(zz)
- 详细解析C++编写的ATM自动取款机模拟程序
- DirectShow 学习(六) CTransfromFilter及相关联Pin类的源代码解析
- BT种子文件 bencoding编码详细解析
- 详细解析C++编写的ATM自动取款机模拟程序
- ping 命令工作原理详细解析