DirectShow中寫push模式的source filter流程 + 原始碼(內附詳細注釋)

來源:互聯網
上載者:User

雖然網上已有很多關於DirectShow寫source filter的資料,不過很多剛開始學的朋友總說講的不是很清楚(可能其中作者省略了許多他認為簡

單的過程),讀者總希望看到象第一步怎麼做,第二步怎麼做....這樣的demo。其實寫你的第一個filter是有一定難度的,只要過了這關以後

就容易多了。
由於最近需要自己寫一個push推模式的source filter,加上剛啟用了Blog,不好意思Blog上沒有一篇文章,所以將寫這個filter的過程寫下來

,為了照顧剛開始學的朋友,我採用第一步第二步....這樣的方式儘可能的講解詳細,相信你按照這個步驟一定沒問題的,對於vc中DirectSho

w開發環境的配置,這裡不做講解。下面開始:

(vc 6.0 + DirectShow 9.0)
我也記得剛學時候的迷茫,所以會盡量詳細每個過程,所以很多是sdk的例子我沒改動它,沒講的是我提供的原始碼裡面我加有比較詳細的注釋

,可以配合我提供的原始碼一起看。

第一步:建立工程

File->New->Project選擇Win32 Dynamic-Link Library,(由於是個demo,名字我用的Push_Test_01)->Next後選擇A simple DLL project(這裡

為了避免自己寫DllMain的麻煩,所以沒選An empty DLL project)->可以Finish了
到這裡工程建立結束。

第二步:相關設定和需要加入的檔案等操作

首先將Debug方式改為Release。接著Project->Seetings->Link裡的Output file

name從Release/Push_Test_01.dll改為Release/Push_Test_01.ax。

在工程目錄下建立一個文字檔,修改名字為Push_Test_01.def。將其加入工程:Project->Add to project->Files 選擇Push_Test_01.def後

加入。
對Push_Test_01.def進行修改,FileView->Source Files 雙擊Push_Test_01.def後輸入:

LIBRARY     Push_Test_01.ax

EXPORTS
            DllMain                 PRIVATE
            DllGetClassObject       PRIVATE
            DllCanUnloadNow         PRIVATE
            DllRegisterServer       PRIVATE
            DllUnregisterServer     PRIVATE

,確定project->Seetings->link下Object/library modules裡面為:

strmbase.lib msvcrt.lib quartz.lib vfw32.lib winmm.lib kernel32.lib advapi32.lib version.lib largeint.lib user32.lib

gdi32.lib comctl32.lib ole32.lib olepro32.lib oleaut32.lib uuid.lib

添加標頭檔:

#include <streams.h>
#include <olectl.h>
#include <initguid.h>

產生全球唯一標識,這裡這樣

DEFINE_GUID(CLSID_PushTest,
  0xfd501041, 0x8ebe, 0x11ce, 0x81, 0x83, 0x00, 0xaa, 0x00, 0x57, 0x7d, 0xa1);

第三步:註冊等函數的添加

首先修改入口函數,並添加註冊和反註冊函數,操作後的內容如下:

//註冊
STDAPI DllRegisterServer()
{
    return AMovieDllRegisterServer2(TRUE);
 
}

//反註冊
STDAPI DllUnregisterServer()
{
    return AMovieDllRegisterServer2(FALSE);
 
}

//filter的入口函數
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD  dwReason,
                      LPVOID lpReserved)
{
 return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}

此時編譯會有class CFactoryTemplate沒實現等錯誤,下面我們來實現它。

添加下面的代碼,每個地方我基本都加了大體意思的注釋:

 

/**************開始填寫註冊資訊***************/

//媒體類型
const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
{
    &MEDIATYPE_Video,       // Major type 主類型
  &MEDIASUBTYPE_NULL      // Minor type sub類型,可以為MEDIASUBTYPE_NULL
};

//pin的資訊
const AMOVIESETUP_PIN sudOpPin =
{
  L"Output",              // Pin string name      pin的名字
  FALSE,                  // Is it rendered       輸入pin有用,輸出pin一般為FALSE
  TRUE,                   // Is it an output      TRUE表示是輸出pin,不然是輸入pin
  FALSE,                  // Can we have none  是否能不執行個體化
  FALSE,                  // Can we have many  是否能建立多個同這樣類型的pin
  &CLSID_NULL,            // Connects to filter 串連的filter類
  NULL,                   // Connects to pin      該pin要串連的pin的類
  1,                      // Number of types  該pin支援的媒體類型
  &sudOpPinTypes          // Pin details   該pin的媒體類型的描述

};
const AMOVIESETUP_FILTER sudBallax =
{
    &CLSID_PushTest,    // Filter CLSID   該filter的類標誌
  L"Push_Test",       // String name   該filter的名字
  MERIT_DO_NOT_USE,       // Filter merit   該filter的Merit值
  1,                      // Number pins   該filter的pin的數目
  &sudOpPin               // Pin details   該filter的pin的描述
};

//建立執行個體時用,有類,名字等需要的資訊
CFactoryTemplate g_Templates[] = {
 {
  L"Push_Test"     //filter的名字
   , &CLSID_PushTest    //對象的類標識  
   , PushTestFilter::CreateInstance //建立一個執行個體用的函數
   , NULL        //
   , &sudBallax      //filter的註冊資訊
 }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

通過上面的注釋,我們看到該filter有一個輸出pin,支援Video類型等等資訊,不多說了。
這裡主要對PushTestFilter::CreateInstance //建立一個執行個體用的函數
說明一下!!PushTestFilter就是我們的filter類!!在下面實現它。

第四步:filter類的實現

添加新類PushTestFilter,使其繼承自CSource。這就是我們的filter類,在這個類裡面沒有過多的操作,就只有2個函數而已:

//filter的主類,繼承自CSource
class PushTestFilter : public CSource
{
public:
 // 唯一能建立該類執行個體的介面
    static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);

private:
 //只能通過CreateInstance()的調用建立執行個體
 PushTestFilter(LPUNKNOWN lpunk, HRESULT *phr);
};

這裡有2點需要注意:

建構函式PushTestFilter()是private的,不是一般的public!!!!!!!!!!!
CreateInstance()函數是static的,因為它不能通過對象來調用!!!!

2個函數的具體實現如下:

//建構函式,注意這裡是private屬性的,不是public,
//所以要建立它的執行個體,只能是通過CreateInstance()函數的方式
PushTestFilter::PushTestFilter(LPUNKNOWN lpunk, HRESULT *phr):
   CSource(NAME("PushTest"), lpunk, CLSID_PushTest)
{
 ASSERT(phr);
 CAutoLock cAutoLock(&m_cStateLock);
 
 //m_paStreams是從CSource基類繼承來的指標數組。由於這個demo我們只
 //有1個pin,所以分配了1個空間
 m_paStreams = (CSourceStream **) new PushTesiPin*[1];
 if(m_paStreams == NULL)
 {
  if(phr)
   *phr = E_OUTOFMEMORY;
  
  return;
 }

 //為剛分配的那個空間付值,這就自動給filter加入了一個pin,析構的
 //時候會自動釋放
 m_paStreams[0] = new PushTesiPin(phr,this,L"Push_Test");
 if(m_paStreams[0] == NULL)
 {
  if(phr)
   *phr = E_OUTOFMEMORY;
  
  return;
 }
}

//CreateInstance()該函數是static屬性的,因為不能通過對象來調用
CUnknown * WINAPI PushTestFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
{
 ASSERT(phr);
 
 //這裡調用了private屬性的建構函式
 CUnknown *punk = new PushTestFilter(lpunk, phr);
 if(punk == NULL)
 {
  if(phr)
   *phr = E_OUTOFMEMORY;
 }
 return punk;   
}

這裡的類PushTesiPin就是我們的pin類,在後面要實現!!其實主要的操作是在pin類PushTesiPin裡面的。

第五步:pin類的實現

添加類PushTesiPin,使其繼承自CSourceStream。這裡需要重載的函數會多一點!不過沒關係!我會一個一
個的進行說明。

主要是這3個:

//由於我們的filter就一種媒體類型,所以重載了GetMediaType(CMediaType *pMediaType)
//如果有多種類型,就應該重載另外2個函數了,具體參考基類CSourceStream
HRESULT GetMediaType(CMediaType *pMediaType);

//這個函數是用來設定Sample大小的,在pin串連成功後會被調用
HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc,ALLOCATOR_PROPERTIES *pProperties);

//對Sample資料的填充
HRESULT FillBuffer(IMediaSample *pms);

我在原始碼裡面都家了比較詳細的注釋,參考原始碼一起看容易明白。

其實這個filter沒做別的,就相當與將sdk下的PushSource例子自己再寫了一遍,主要是為了說明這個過程,
到這裡相信你應該有個大概的概念了,那麼恭喜!

我也寫累了,如果對大家有協助就找個時間再將寫pull拉
模式的過程也寫出來。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.