1. CSourceStream类,是CSource类的OutputPin[source.h/source.cpp] 派生自CAMThread和CBaseOutputPin
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 继承的CBasePin的virtual函数: 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 CAMThread的virtual函数 // 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初始化为0,m_paStreams初始化为NULL。
l 继承的CBaseFilter的virtual函数: 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,进行指针比较,返回相同那个Pin的Number,否则返回-1 }
3. DirectShow 中Source Filter的一个例子Ball[fball.h/fball.cpp] Filter Ball是一个能生成跳跃小球的Source Filter。
l Filter类CBouncingBall:
i. 成员函数: // The only allowed way to create Bouncing balls! static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr); {创建(new)了一个新的CBouncingBall的Object。}
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 Pin:m_paStreams[0] = new CBallStream(phr, this, L"A Bouncing Ball!"); }
l Pin 类CBallStream: 派生自CSourceStream。CBall是一个具体实现其功能的类,这里不做分析。
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. 从CBasePin和CBaseOutputPin继承的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) { // 根据位数不同,8,16,32来对成员变量进行不同的设置 } } // 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_rtSampleTime和m_iRepeatTime}
前一篇:(四)部分Helper Classes类源代码分析

|