欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

(DirectX系列06)DirectShow 字符疊加Filter編

系統 1944 0

DirectX 系列 06 DirectShow 字符疊加 Filter 編碼分析

在很多視頻播放的軟件當中,字幕的處理是免不了的,有些可能本身已經加載到圖像當中未做處理,但大部分都是通過字符疊加來進行處理的。 DirectShow 的字符疊加 Filter 在這些軟件中都扮演這絕佳的作用。這一節來介紹 DirectShow 字符疊加 Filter 編碼的實現,如下詳細介紹;

這個 Filter 的大概作用是在視頻流指定的一段時間內進行字符疊加,字符字體、大小、顏色都進行控制,普遍支持 RGB 的各種編碼格式,同時實現字符的其他效果例如滾動的。如下來看看具體的編碼實現;

注冊表配置

注冊表的配置對于 Filter 的開發者來說都大同小異,主要對 g_Templates 進行配置,如下代碼;

// {E3FB4BFE-8E5C-4aec-8162-7DA55BE486A1}

DEFINE_GUID ( CLSID_HQTitleOverlay ,

0xe3fb4bfe, 0x8e5c, 0x4aec, 0x81, 0x62, 0x7d, 0xa5, 0x5b, 0xe4, 0x86, 0xa1);

// {E70FE57A-19AA-4a4c-B39A-408D49D73851}

DEFINE_GUID ( CLSID_HQTitleOverlayProp ,

0xe70fe57a, 0x19aa, 0x4a4c, 0xb3, 0x9a, 0x40, 0x8d, 0x49, 0xd7, 0x38, 0x51);

……

// List of class IDs and creator functions for the class factory. This

// provides the link between the OLE entry point in the DLL and an object

// being created. The class factory will call the static CreateInstance

CFactoryTemplate g_Templates [] =

{

{

L "HQ Title Overlay Std." ,

& CLSID_HQTitleOverlay ,

CFilterTitleOverlay :: CreateInstance ,

NULL ,

& sudFilter

},

{

L "HQ Title Overlay Property Page" ,

& CLSID_HQTitleOverlayProp ,

CTitleOverlayProp :: CreateInstance

}

};

CFilterTitleOverlay 類的實現

CFilterTitleOverlay 類設計是整個 Filter 的關鍵所在,其中最重要的是父類的選擇。如下代碼;

class CFilterTitleOverlay : public CTransInPlaceFilter

, public ISpecifyPropertyPages

, public ITitleOverlay

CTransInPlaceFilter 類是 CFilterTitleOverlay 功能實現的關鍵只關鍵,該類可以提供在視頻傳輸的過程中截獲數據流,方便于字符疊加;

ISpecifyPropertyPages 類是 CFilterTitleOverlay 提供屬性頁面支持功能, ITitleOverlay 是一個 Interface 接口的純虛類,也就是所謂的接口,如下來看看這個接口是如何實現;

// ITitleOverlay

// 原型如下

// interface __declspec(novtable) ITitleOverlay : public IUnknown

DECLARE_INTERFACE_ ( ITitleOverlay , IUnknown )

{

// 設置 Filter 進行疊加的類型,如果需要改變類型,這個函數必須第一個設置,

// 調用這個函數成功后,才能調用其他的函數進行參數設置。

// 可以設置的疊加類型參見枚舉類型 OVERLAY_TYPE 的定義。

// 如下原型

// virtual HRESULT _stcall put_TitleOverlayType(long inOverlayType) = 0

STDMETHOD ( put_TitleOverlayType ) ( THIS_

long inOverlayType

) PURE ;

……

};

* 構造函數

先從 CFilterTitleOverlay 類的構造函數說起,在 CFilterTitleOverlay 構造函數中有一個對象是必須創建的,這個對象就是 COverlayController COverlayController 是用來控制疊加效果的通用類,如下代碼;

CFilterTitleOverlay :: CFilterTitleOverlay ( TCHAR * tszName , LPUNKNOWN punk , HRESULT * phr ) :

CTransInPlaceFilter ( tszName , punk , CLSID_HQTitleOverlay , phr )

{

mOverlayType = OT_STATIC ;

mOverlayController = new COverlayController ();

mNeedEstimateFrameRate = FALSE ;

char szTitle [] = "Hello, DirectShow!" ;

put_Title ( szTitle , sizeof ( szTitle ));

}

* CreateInstance 函數

這個函數不用多說了,是 CUnknown 中的一個虛函數,其中這個函數主要用來創建 CFilterTitleOverlay 對象,是 COM 組件必須具備的函數,否則就失去 COM 組件的意義,如下代碼詳解;

CUnknown * WINAPI CFilterTitleOverlay :: CreateInstance ( LPUNKNOWN punk , HRESULT * phr )

{

#if 1

// 做指定應用程序驗證

char szCreatorPath [256], szCreatorName [256];

:: strcpy ( szCreatorPath , "" );

:: strcpy ( szCreatorName , "" );

HMODULE hModule = :: GetModuleHandle ( NULL );

:: GetModuleFileName ( hModule , szCreatorPath , 256);

char * backSlash = :: strrchr ( szCreatorPath , '//' );

if ( backSlash )

{

strcpy ( szCreatorName , backSlash );

}

:: _strlwr ( szCreatorName );

// Please specify your app name with lowercase

if (:: strstr ( szCreatorName , "graphedt" ) == NULL &&

:: strstr ( szCreatorName , "ourapp" ) == NULL )

{

* phr = E_FAIL ;

return NULL ;

}

#endif

// 創建 CFilterTitleOverlay 對象

CFilterTitleOverlay * pNewObject = new CFilterTitleOverlay ( NAME ( "TitleOverlay" ), punk , phr );

return pNewObject ;

}

* Transform 函數

Transform 函數是整個字符疊加處理的關鍵,再這個函數中可以捕獲需要處理的數據( RGB 格式)如下來看看具體的實現;

HRESULT CFilterTitleOverlay :: Transform ( IMediaSample * pSample )

{

// If we cann't read frame rate info from input pin's connection media type,

// We estimate it from the first sample's time stamp!

……

if ( mOverlayType != OT_NONE )

{

PBYTE pData = NULL ;

pSample -> GetPointer (& pData );

mOverlayController -> DoTitleOverlay ( pData );

}

return NOERROR ;

}

代碼中最為關鍵的 DoTitleOverlay 函數就是實現字符疊加的函數,這個函數是 COverlayController 類中的一個成員函數,如下來看看它是如何實現的;

if ( mImageHeight > mTitleSize . cy && mTitleSize . cx > 0 && mTitleSize . cy > 0)

{

……

PBYTE pStartPos = pTopLine + mStartPos . y * strideInBytes + mStartPos . x * mImageBitCount / 8;

for ( DWORD dwY = 0; dwY < ( DWORD ) mTitleSize . cy ; dwY ++)

{

PBYTE pbTitle = mTitleDIBBits + mDIBWidthInBytes * (( DWORD ) mTitleSize . cy - dwY - 1);

// Point to the valid start position of title DIB

pbTitle += ( mValidTitleRect . left >> 3);

long startLeft = mValidTitleRect . left % 8;

long endRight = startLeft + mValidTitleRect . right - mValidTitleRect . left ;

for ( long dwX = startLeft ; dwX < endRight ; dwX ++)

{

if ( !((0x80 >> ( dwX & 7)) & pbTitle [ dwX >> 3]) )

{

PBYTE pbPixel = mPixelConverter -> NextNPixel ( pStartPos , dwX - startLeft );

if ( mIsOverlayByCover )

{

// 進行 RGB 數據復值, 24 三占用三字節

mPixelConverter -> ConvertByCover ( pbPixel );

}

else

{

mPixelConverter -> ConvertByReverse ( pbPixel );

}

}

}

pStartPos += strideInBytes ;

}

}

* ActualCreateTitleDIB 函數

這個函數用于創建字符位圖,創建一個 DIB 位圖的虛擬內存空間,保存 RGB 數據格式,再通過 GetDIBits 函數獲取數據緩沖區用于字符疊加之用,如下代碼;

HBITMAP COverlayController :: ActualCreateTitleDIB ( HDC inDC )

{

// DIB info we used to create title pixel-mapping.

// The system default color policy is:

// Initial Whole Black, while output area White-background and Black-text.

struct {

BITMAPINFOHEADER bmiHeader ;

DWORD rgbEntries [2];

} bmi =

{

{

sizeof ( BITMAPINFOHEADER ),

0,

0,

1,

1,

BI_RGB ,

0,

0,

0

},

{

0x00000000,

0xFFFFFFFF

}

};

……

// Set proper DIB size here! Important!

bmi . bmiHeader . biHeight = mTitleSize . cy ;

bmi . bmiHeader . biWidth = mTitleSize . cx ;

HBITMAP hbm = CreateDIBitmap ( inDC , & bmi . bmiHeader , 0, NULL , NULL , 0);

BOOL pass = ( hbm != NULL );

// Draw title after selecting DIB into the DC

if ( pass )

{

HGDIOBJ hobj = SelectObject ( inDC , hbm );

pass = ExtTextOut ( inDC , 0, 0, ETO_OPAQUE | ETO_CLIPPED , NULL ,

mTitle , lstrlen ( mTitle ), NULL );

SelectObject ( inDC , hobj );

}

// Get the title-drew DIB bits

if ( pass )

{

ReleaseTitleDIB ();

// Attention: To get bitmap data from the DIB object,

// the scan line must be a multiple of 4 (DWORD)!

// If the actual bitmap data is not exactly fit for DWORD,

// The rest of DWORD bits will be filled automatically.

// So we should expand to bytes and round up to a multiple of 4.

mDIBWidthInBytes = (( mTitleSize . cx + 31) >> 3) & ~3;

mTitleDIBBits = new BYTE [ mDIBWidthInBytes * mTitleSize . cy ];

memset ( mTitleDIBBits , 0, mDIBWidthInBytes * mTitleSize . cy );

LONG lLines = GetDIBits ( inDC , hbm , 0, mTitleSize . cy , ( PVOID ) mTitleDIBBits ,

( BITMAPINFO *)& bmi , DIB_RGB_COLORS );

pass = ( lLines != 0);

}

……

return hbm ;

}

* CompleteConnect 函數

CompleteConnect 函數是用來完成 output pin 與 下一個 input pin 連接只用,也是構建 Fiters 鏈的必備函數,如下代碼;

HRESULT CFilterTitleOverlay :: CompleteConnect ( PIN_DIRECTION direction , IPin * pReceivePin )

{

HRESULT hr = CTransInPlaceFilter :: CompleteConnect ( direction , pReceivePin );

if ( SUCCEEDED ( hr ) && direction == PINDIR_INPUT )

{

hr = SetInputVideoInfoToController ();

}

return hr ;

}

屬性頁設置( CTitleOverlayProp

這個類從 CBasePropertyPage 直接繼承的,用于配置和觀察這個 Filters 屬性之用。 CTitleOverlayProp 其實是一個窗體,類似一個應用程序,不過我們可以直接對其進行消息捕捉,如下代碼;

BOOL CTitleOverlayProp :: OnReceiveMessage ( HWND hwnd ,

UINT uMsg ,

WPARAM wParam ,

LPARAM lParam )

{

switch ( uMsg )

{

case WM_INITDIALOG :

{

// Get windows' handles

m_hOverlayType = GetDlgItem ( hwnd , IDC_COMBO_OVERLAY_TYPE );

m_hEditTilte = GetDlgItem ( hwnd , IDC_EDIT_TITLE );

m_hEditStartX = GetDlgItem ( hwnd , IDC_EDIT_STARTX );

m_hEditStartY = GetDlgItem ( hwnd , IDC_EDIT_STARTY );

m_hEditStartTime = GetDlgItem ( hwnd , IDC_EDIT_STARTTIME );

m_hEditEndTime = GetDlgItem ( hwnd , IDC_EDIT_ENDTIME );

m_hEditColorR = GetDlgItem ( hwnd , IDC_EDIT_COLORR );

m_hEditColorG = GetDlgItem ( hwnd , IDC_EDIT_COLORG );

m_hEditColorB = GetDlgItem ( hwnd , IDC_EDIT_COLORB );

break ;

}

case WM_COMMAND :

{

if ( HIWORD ( wParam ) == BN_CLICKED )

{

switch ( LOWORD ( wParam ))

{

case IDC_BUTTON_CHANGE_FONT :

OnButtonChangeFont ();

break ;

}

}

SetDirty ();

break ;

}

}

return CBasePropertyPage :: OnReceiveMessage ( hwnd , uMsg , wParam , lParam );

} // OnReceiveMessage

有了這個消息捕捉函數當然就可以直接對所需要配置的參數進行配置了。同時在繼承 CBasePropertyPage 的時候為了方便 CBasePropertyPage 還提供了其他幾個接口如 CreateInstance OnConnect OnActivate 等。

整個字符疊加的 Fiters 編碼就基本上完成了,其中幾個地方還是需要在次提醒,第一、對基類的選擇,一定要選擇正確的基類,這樣才能達到事半工倍。第二、處理字符疊加時一定要注意幀頻率,否則會產生錯位。第三、字符需要繪制到一段虛擬的內存當中,不能直接繪制。字符疊加的應用非常廣泛,估計暴風影音的字符疊加功能就是這樣做的!

(DirectX系列06)DirectShow 字符疊加Filter編碼分析


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 日本老熟妇毛茸茸 | 久久草视频这里只精品 | 久久精品小视频 | 欧美一级毛片在线播放 | 亚洲综合精品香蕉久久网97 | 亚洲国内精品 | 国产欧美日韩不卡一区二区三区 | 久久99久久99精品免观看不卡 | 黄色影片在线免费观看 | 国产精选91热在线观看 | 91在线视频 | 小明www永久免费播放平台 | 久久一二区 | 999热精品 | 久久精品久 | 激情五月综合婷婷 | 国产成人精品久久二区二区91 | 色情女教师3波多野结衣 | 久久精品人人做人人 | 性色av免费在线观看 | 日韩一级一欧美一级国产 | 国产精品精品视频一区二区三区 | 殴美一区| 亚洲电影一区二区 | 亚洲国产视频网站 | 欧美一区二区三区久久精品 | 日本在线观看视频网站 | 亚洲精品乱码久久久久久蜜桃91 | 日韩欧美综合在线二区三区 | 夫妻性生活交换 | 久久噜噜噜精品国产亚洲综合 | 久久久一区二区 | 天天舔 | 亚洲一区国产二区 | 精品无人乱码一区二区三区 | 欧美一区精品 | 国产日韩一区二区三区 | 久久精彩免费视频 | 色爱区综合| 亚洲第一第二区 | 久久国产热视频 |