DirectShow 学习(五) CSource类和其一个具体实现例子的源代码分析

时间:2021-10-09 20:40:34

1.       CSourceStream类,是CSource类的OutputPin[source.h/source.cpp]
派生自CAMThreadCBaseOutputPin<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

l         成员变量:
CSource
*m_pFilter;    // The parent of this stream

l         新增加的virtual函数:
// Override this to provide the worker thread a means of processing a buffer
virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE;
// Called as the thread is created/destroyed - use to perform
// jobs such as start/stop streaming mode
// If OnThreadCreate returns an error the thread will exit.
virtual HRESULT OnThreadCreate(void) {return NOERROR;};
virtual HRESULT OnThreadDestroy(void) {return NOERROR;};
virtual HRESULT OnThreadStartPlay(void) {return NOERROR;};
virtual HRESULT DoBufferProcessingLoop(void);    // the loop executed whilst running
{
    
Command com;
    
OnThreadStartPlay();
    
do
     {
         
while (!CheckRequest(&com))
         {
               IMediaSample *pSample;
               HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0);
          
    if (FAILED(hr)) { Sleep(1); continue;}
               
// Virtual function user will override.
               
hr = FillBuffer(pSample);
               
if (hr == S_OK)
               { hr = Deliver(pSample); pSample->Release();if(hr != S_OK) return S_OK;}
               
else if (hr == S_FALSE)
               { pSample->Release();DeliverEndOfStream();return S_OK;}
               
else
               {
                    pSample
->Release();DeliverEndOfStream();
                    
m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
                    return
hr;
               }
         }
        
if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); }
         else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED);}
    }
   
while (com != CMD_STOP);
   
return S_FALSE;
}

virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;}

l         继承的CBasePinvirtual函数:
HRESULT Active(void);    // Starts up the worker thread
{
    
CAutoLock lock(m_pFilter->pStateLock());
    
if (m_pFilter->IsActive()) {return S_FALSE;}
    
if (!IsConnected()) {return NOERROR;}
    
hr = CBaseOutputPin::Active();
    
if (FAILED(hr)) {return hr;}
    
ASSERT(!ThreadExists());
    
// start the thread
    
if (!Create()) {return E_FAIL;}
    
// Tell thread to initialize. If OnThreadCreate Fails, so does this.
    
hr = Init();
    
if (FAILED(hr)) return hr;
    
return Pause();
}

HRESULT Inactive(void);  // Exits the worker thread.
{
    
CAutoLock lock(m_pFilter->pStateLock());
    
if (!IsConnected()) {return NOERROR;}
    
// !!! need to do this before trying to stop the thread, because
     // we may be stuck waiting for our own allocator!!!
    
hr = CBaseOutputPin::Inactive();  // call this first to Decommit the allocator
    
if (FAILED(hr)) {return hr;}
    
if (ThreadExists())
     {
          
hr = Stop();if (FAILED(hr)) {return hr;}
          
hr = Exit();if (FAILED(hr)) {return hr;}
          
Close(); // Wait for the thread to exit, then tidy up.
    
}
    
return NOERROR;
}

virtual HRESULT CheckMediaType(const CMediaType *pMediaType);
{

//
默认只支持一种格式,即只调用新增加的GetMediaType函数得到MediaType
//
与输入的Type进行比较
}
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);  // List pos. 0-n
{
//
判断iPosition必须为0,返回新增加的GetMediaType函数
}

l         操作函数:
HRESULT Init(void) { return CallWorker(CMD_INIT); }
HRESULT Exit(void) { return CallWorker(CMD_EXIT); }
HRESULT Run(void) { return CallWorker(CMD_RUN); }
HRESULT Pause(void) { return CallWorker(CMD_PAUSE); }
HRESULT Stop(void) { return CallWorker(CMD_STOP); }

l         CAMThreadvirtual函数
// override these if you want to add thread commands
// Return codes > 0 indicate an error occured
virtual DWORD ThreadProc(void);         // the thread function
{
    
//
整个函数实现了一个同步的通讯Thread
    
Command com;
    
do { com = GetRequest();if (com != CMD_INIT) { Reply((DWORD) E_UNEXPECTED);} }
    
while (com != CMD_INIT);
    
hr = OnThreadCreate(); // perform set up tasks
    
if (FAILED(hr))
     {
         
OnThreadDestroy();
         
Reply(hr);   // send failed return code from OnThreadCreate
         
return 1;
     }
    
Reply(NOERROR);
    
Command cmd;
   
do
    {
        
cmd = GetRequest();
        
switch (cmd) {
        
case CMD_EXIT: Reply(NOERROR); break;
        
case CMD_RUN:
        
case CMD_PAUSE:Reply(NOERROR); DoBufferProcessingLoop();break;
        
case CMD_STOP: Reply(NOERROR); break;
        
default: Reply((DWORD) E_NOTIMPL); break;}
     }

     while (cmd != CMD_EXIT);
    
hr = OnThreadDestroy();  // tidy up.
    
if (FAILED(hr)) { return 1;}
    
return 0;
}

l         Constructor
// increments the number of pins present on the filter
CSourceStream(TCHAR *pObjectName, HRESULT *phr, CSource *ps, LPCWSTR pPinName)
:
CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
m_pFilter(ps) {*phr = m_pFilter->AddPin(this);}

l         Deconstructor
~CSourceStream(void) {m_pFilter->RemovePin(this);}

2.       CSource[source.h/source.cpp]
派生自CBaseFilter

l         成员变量:
int             m_iPins;       // The number of pins on this filter. Updated by CSourceStream constructors & destructors.
CSourceStream **m_paStreams;   // the pins on this filter.
CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state
其中m_iPins初始化为0m_paStreams初始化为NULL

l         继承的CBaseFiltervirtual函数:
int       GetPinCount(void);
CBasePin *GetPin(int n);

l         新增加的函数:
CCritSec* pStateLock(void) { return &m_cStateLock; }   // provide our critical section
HRESULT     AddPin(CSourceStream *);
{
    
CAutoLock lock(&m_cStateLock);
    
/*  Allocate space for this pin and the old ones */
    
CSourceStream **paStreams = new CSourceStream *[m_iPins + 1];
    
if (paStreams == NULL) { return E_OUTOFMEMORY;}
    
//
如果m_paStreams已经存在,则将其复制到paStreams,略去该步代码
    
if (m_paStreams != NULL)
     {
         CopyMemory
((PVOID)paStreams, (PVOID)m_paStreams,
               m_iPins
* sizeof(m_paStreams[0]));
  
      //
其实下面的这行实现复制功能的代码可有可无
         
paStreams[m_iPins] = pStream;
         delete
[] m_paStreams;
     }
    
m_paStreams = paStreams;
    
m_paStreams[m_iPins] = pStream;
    
m_iPins++;
}
HRESULT     RemovePin(CSourceStream *);
{
//
遍历所有的Pin,如果与输入的指针相同,则删除该Pin,如果只有一个Pin存在,释放m_paStreams
//
否则将其后的Pin全部前移一位。
}
STDMETHODIMP FindPin(LPCWSTR Id, IPin ** ppPin );
{
//
输入的Id其实是一个数字字符串,用WstrToInt(Id) -1的结果调用GetPin
//
输出Pin必须调用AddRef
}
int FindPinNumber(IPin *iPin);
{
//
遍历所有Pin,进行指针比较,返回相同那个PinNumber,否则返回-1
}

3.       DirectShow Source Filter的一个例子Ball[fball.h/fball.cpp]
Filter Ball
是一个能生成跳跃小球的Source Filter

l         FilterCBouncingBall

                      i.              成员函数:
// The only allowed way to create Bouncing balls!
static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);
{
创建(new)了一个新的CBouncingBallObject}

                   ii.              Constructor(private)
CBouncingBall::CBouncingBall(LPUNKNOWN lpunk, HRESULT *phr) :
CSource(NAME("Bouncing ball"), lpunk, CLSID_BouncingBall)
{
//
创建Output Pin,首先创建数组指针m_paStreams = (CSourceStream **) new CBallStream*[1];
//
创建真正的Output Pinm_paStreams[0] = new CBallStream(phr, this, L"A Bouncing Ball!");
}

l         Pin CBallStream
派生自CSourceStreamCBall是一个具体实现其功能的类,这里不做分析。

                      i.              成员变量:
int m_iImageHeight;                 // The current image height
int m_iImageWidth;                  // And current image width
int m_iRepeatTime;                  // Time in msec between frames
const int m_iDefaultRepeatTime;     // Initial m_iRepeatTime
BYTE m_BallPixel[4];                // Represents one coloured ball
int m_iPixelSize;                   // The pixel size in bytes
PALETTEENTRY m_Palette[256];        // The optimal palette for the image
CCritSec m_cSharedState;            // Lock on m_rtSampleTime and m_Ball
CRefTime m_rtSampleTime;            // The time stamp for each sample
CBall *m_Ball;                      // The current ball object

                   ii.              CBasePinCBaseOutputPin继承的virtual函数:
// Ask for buffers of the size appropriate to the agreed media type
HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties);
{
    
CAutoLock cAutoLock(m_pFilter->pStateLock());
    
VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();
    
pProperties->cBuffers = 1;
    
pProperties->cbBuffer = pvi->bmiHeader.biSizeImage;
    
ALLOCATOR_PROPERTIES Actual;
    
hr = pAlloc->SetProperties(pProperties,&Actual);
    
if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL;
}
// Set the agreed media type, and set up the necessary ball parameters
HRESULT SetMediaType(const CMediaType *pMediaType);
{
    
HRESULT hr = CSourceStream::SetMediaType(pMediaType);
    
VIDEOINFO * pvi = (VIDEOINFO *) m_mt.Format();
    
switch(pvi->bmiHeader.biBitCount)
     {
    
//
根据位数不同,81632来对成员变量进行不同的设置
     }
}
// We will accept 8, 16, 24 or 32 bit video formats, in any
HRESULT CheckMediaType(const CMediaType *pMediaType);
{
    
if((*(pMediaType->Type()) != MEDIATYPE_Video) ||   // we only output video
    
   !(pMediaType->IsFixedSize()))                   // in fixed size samples
       
return E_INVALIDARG;
    
// Check for the subtypes we support
    
const GUID *SubType = pMediaType->Subtype();
    
if((*SubType != MEDIASUBTYPE_RGB8)
    
    && (*SubType != MEDIASUBTYPE_RGB565)
    
    && (*SubType != MEDIASUBTYPE_RGB555)
    
    && (*SubType != MEDIASUBTYPE_RGB24)
    
    && (*SubType != MEDIASUBTYPE_RGB32))
        
return E_INVALIDARG;
    
// Get the format area of the media type
    
VIDEOINFO *pvi = (VIDEOINFO *) pMediaType->Format();
    
if((pvi->bmiHeader.biWidth < 20) || ( abs(pvi->bmiHeader.biHeight) < 20))
    
    return E_INVALIDARG;
    
//
别的校验
}
HRESULT GetMediaType(int iPosition, CMediaType *pmt);
{
    
CAutoLock cAutoLock(m_pFilter->pStateLock());
    
if((iPosition < 0) || (if(iPosition < 0)))
错误。
     VIDEOINFO
*pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof(VIDEOINFO));
    
ZeroMemory(pvi, sizeof(VIDEOINFO));
    
switch(iPosition)
     {
    
case 0: // Return our highest quality 32bit format
    
case 1: // Return our 24bit format
    
case 2: // 16 bit per pixel RGB565
    
case 3: // 16 bits per pixel RGB555
    
case 4: // 8 bit palettised
     }
    
//
填充pmt的另外一些值
}
// Quality control notifications sent to us
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
{

// Notify
主要设置了一些成员变量以调节速度
}

                iii.              CSourceStream继承的virtual 函数:
// plots a ball into the supplied video frame
HRESULT FillBuffer(IMediaSample *pms);
{
//
得到Sample的数据指针:pms->GetPointer(&pData);
// 调用m_Ball的成员函数填充该数据领域
//
设置时间pms
->SetTime((REFERENCE_TIME *) &rtStart,(REFERENCE_TIME *) &m_rtSampleTime);
// pms
->SetSyncPoint(TRUE);
}
// Resets the stream time to zero
HRESULT OnThreadCreate(void);{
初始化了变量m_rtSampleTimem_iRepeatTime}


前一篇: (四)部分Helper Classes类源代码分析