首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

DirectShow Filter 開發全攻略:從環境配置到 COM 類別工廠、Pin 連接與資料流實作

     編輯:關於VC++

前言

DirectShow 架構核心是 Filter (篩選器) 組件化處理多媒體串流。每個 Filter 是一個 COM 物件,透過 Pin (腳位) 連接形成 Filter Graph。本文完整記錄:VC 環境配置、DLL 專案建立、COM 入口函式、類別工廠模板、Filter 基類選擇、Pin 實作、媒體類型協商、資料處理流程、註冊與除錯。

1. VC 環境配置 (DirectX SDK 9.0 範例)

Include 目錄設定

Library 目錄設定

  • Include:$(DXSDK_DIR)\Include, $(DXSDK_DIR)\Samples\C++\DirectShow\BaseClasses
  • Lib:$(DXSDK_DIR)\Lib\x86, $(DXSDK_DIR)\Samples\C++\DirectShow\BaseClasses\Debug (strmbasd.lib)
  • 專案 → 設定 → Link → Object/Library modules 加入:strmbasd.lib msvcrtd.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
  • 輸出檔名建議改為 .ax (Filter 慣例)

2. Filter 專案骨架:Win32 DLL + .def 匯出

// MyFilter.def
LIBRARY MyFilter.ax
EXPORTS
    DllMain PRIVATE
    DllGetClassObject PRIVATE
    DllCanUnloadNow PRIVATE
    DllRegisterServer PRIVATE
    DllUnregisterServer PRIVATE

COM 入口函式實作 (BaseClasses 已提供)

#include 
#include 

// DllMain → BaseClasses dllentry.cpp
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
    return DllEntryPoint((HINSTANCE)hModule, dwReason, lpReserved);
}

// 註冊/解除註冊 → BaseClasses dllsetup.cpp
STDAPI DllRegisterServer()   { return AMovieDllRegisterServer2(TRUE); }
STDAPI DllUnregisterServer() { return AMovieDllRegisterServer2(FALSE); }

3. 類別工廠模板陣列:Filter 建立入口

// 單例建立函式
CUnknown* WINAPI CMyFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT* phr)
{
    CMyFilter* p = new CMyFilter(NAME("My Filter"), pUnk, phr);
    if (!p) *phr = E_OUTOFMEMORY;
    return p;
}

// 全域模板陣列
CFactoryTemplate g_Templates[] = {
    {
        L"My Filter",              // 名稱
        &CLSID_MyFilter,          // CLSID
        CMyFilter::CreateInstance, // 建立函式
        NULL,                      // 初始化函式 (可選)
        &sudMyFilter               // 註冊資訊 (AMOVIESETUP_FILTER)
    }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

CLSID 定義

// {1915C5C7-02AA-415F-890F-76D94C85AAF1}
DEFINE_GUID(CLSID_MyFilter,
0x1915c5c7, 0x02aa, 0x415f, 0x89, 0x0f, 0x76, 0xd9, 0x4c, 0x85, 0xaa, 0xf1);

4. 選擇正確的 Filter 基類

基類適用場景Pin 配置
CSource源頭 Filter (檔案讀取、攝影機捕獲)僅輸出 Pin
CTransformFilter一對一轉換,輸入/輸出媒體類型可能不同1 輸入 + 1 輸出
CTransInPlaceFilter就地轉換,輸入/輸出媒體類型相同 (如亮度調整)1 輸入 + 1 輸出
CBaseRenderer / CBaseVideoRenderer渲染器 (聲音/視訊輸出)僅輸入 Pin
CBaseFilter完全自訂 Pin 數量/拓撲任意

選擇原則:先定義功能 → 確定 Pin 數量/媒體類型關係 → 選最貼合基類。本文以 CTransformFilter 為例。

5. Filter 類別實作骨架

class CMyFilter : public CTransformFilter
{
public:
    CMyFilter(TCHAR* pName, LPUNKNOWN pUnk, HRESULT* phr);
    ~CMyFilter();

    // 覆寫純虛函式
    HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); // 核心資料處理
    HRESULT CheckInputType(const CMediaType* mtIn);           // 輸入類型檢查
    HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); // 轉換可行性
    HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProp); // 輸出緩衝區大小
    HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); // 支援的輸出類型列舉

    // 非必要但常用
    HRESULT StartStreaming(); // 開始串流前初始化
    HRESULT StopStreaming();  // 停止串流清理
};

關鍵虛函式說明

  • Transform:核心。從 pIn->GetPointer() 取得輸入資料指標,處理後寫入 pOut->GetPointer(),設定 pOut->SetActualDataLength()、SetSyncPoint() 等。
  • CheckInputType:驗證輸入 CMediaType (major/subtype/format) 是否支援。
  • CheckTransform:確認輸入→輸出轉換是否支援。
  • DecideBufferSize:告知下游分配器每個 Sample 需多大緩衝區。
  • GetMediaType:列舉支援的輸出類型,索引 iPosition 從 0 開始,無更多類型時回傳 VFW_S_NO_MORE_ITEMS。

6. 註冊資訊結構 AMOVIESETUP_FILTER

// 媒體類型陣列
AMOVIESETUP_MEDIATYPE sudMediaTypes[] = {
    { &MEDIATYPE_Video, &MEDIASUBTYPE_RGB24 },
    { &MEDIATYPE_Video, &MEDIASUBTYPE_RGB32 },
};

// 輸出 Pin 定義
AMOVIESETUP_PIN sudOutputPin = {
    L"", FALSE, TRUE, FALSE, FALSE, &GUID_NULL, NULL,
    2, sudMediaTypes
};

// Filter 定義
AMOVIESETUP_FILTER sudMyFilter = {
    &CLSID_MyFilter,
    L"My Filter",
    MERIT_NORMAL,      // 優先權
    1, &sudOutputPin   // 1 個 Pin 類型
};

7. 除錯與驗證工具

  • GraphEdit (qedit.dll):圖形化建構 Filter Graph,測試 Filter 連接、媒體類型協商、資料流向。
  • 注冊:regsvr32 MyFilter.ax (需管理員權限)。
  • 日誌:BaseClasses DbgLog 機制,DEBUGMSG 區域輸出至 DebugView。

8. 進階主題

主題關鍵點
自訂介面繼承 IUnknown,在 NonDelegatingQueryInterface 公開,應用層 QueryInterface 呼叫
品質控制實作 IQualityControl 回報上游丟幀/延遲
動態重新連接IPin::QueryAccept + ReconnectPin 支援格式切換
參考時鐘繼承 CBaseReferenceClock 提供同步時鐘
無 Pin Filter繼承 CBaseFilter,實作 IFileSourceFilter 等

結語

DirectShow Filter 開發核心在於:正確選擇基類 → 實作媒體類型協商 → 在 Transform 專注資料處理 → 註冊資訊完整描述 Pin/類型。BaseClasses 庫吸收了 80% 的 COM/連接/分配器樣板代碼,開發者可聚焦於多媒體演算法本身。建議配合 GraphEdit 反覆驗證,並參考 SDK 範例 (EzRGB24, Transform) 深化理解。

本文配套原始碼可供下載。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved