|
論壇說明 |
歡迎您來到『史萊姆論壇』 ^___^ 您目前正以訪客的身份瀏覽本論壇,訪客所擁有的權限將受到限制,您可以瀏覽本論壇大部份的版區與文章,但您將無法參與任何討論或是使用私人訊息與其他會員交流。若您希望擁有完整的使用權限,請註冊成為我們的一份子,註冊的程序十分簡單、快速,而且最重要的是--註冊是完全免費的! 請點擊這裡:『註冊成為我們的一份子!』 |
|
主題工具 | 顯示模式 |
2004-02-23, 10:04 PM | #1 |
榮譽會員
|
如何讓Windows Media Player播放你的自訂媒體檔案類型
正文
有時候,我們會產生自訂的媒體文件(不同於標準的AVI、MPEG等文件格式)。為了回放這些特殊格式的文件,於是,我們不得不再寫一個播放器。那麼,有沒有一種辦法,讓Windows Media Player能夠認識我們的文件,進而讓它像播放其他標準文件一樣播放我們的文件呢?答案是肯定的。 Windows Media Player是關於DirectShow架構來播放媒體文件的。我們只要從DirectShow方面入手,就一定能夠解決問題。首先,我們來看看一般的播放文件的處理程序。大家知道,使用DirectShow播放媒體文件,肯定要新增一個Filter Graph。給定了一個文件路徑,首先是要找到一個合適的Source Filter,即得到它的CLSID。一般只需使用IGraphBuilder::RenderFile或者IGraphBuilder::AddSourceFilter就能做到。那麼,Filter Graph Manager(以下簡稱為FGM)的實現細節是怎麼樣的呢?瞭解這些,對我們解決問題有著決定性的作用。 首先要分析一下文件路徑,因為它可能包含有傳輸協定(譬如http、htp等)。FGM認為冒號前面的即為傳輸協定名。例如文件路徑為「 myprotocol://myfile.ext」,則myprotocol即為傳輸協定名。於是,FGM到註冊表的如下位置去找這個傳輸協定: HKEY_CLASSES_ROOT <protocol> Source Filter = <Source filter CLSID> Extensions <.ext1> = <Source filter CLSID> <.ext2> = <Source filter CLSID> 如果找到了這個傳輸協定,並且存在Extensions子鍵,FGM再到Extensions子鍵中進行文件副檔名的匹配。如果匹配成功,FGM就用這個找到的GUID字串串作為Source Filter的CLSID;如果不成功,FGM就使用該傳輸協定子鍵下的Source Filter的值。如果myprotocol這個傳輸協定並沒有在註冊表中註冊,FGM就預設使用一個叫File Source (URL)的Filter。另外,有兩點注意:(1)為了區別傳輸協定和驅動器磁碟代號(如C:\myfile.ext),FGM不承認單字串的傳輸協定;(2)字串串「file:」或「 file://」不認為是傳輸協定。 如果文件路徑中不包含傳輸協定呢?FGM就分析文件的副檔名,即到註冊表的HKEY_CLASSES_ROOT\Media Type\Extensions下去匹配。相應的副檔名子鍵下指定了Source Filter的CLSID字串串,有的還有Media Type和Subtype指定Source Filter輸出Pin上使用的Media Type。但是,如果這種文件的副檔名在這裡也沒有註冊呢?FGM還有最後一招,就是通過文件的校驗字元(Check Bytes)去判斷。這些校驗字元在如下位置定義: HKEY_CLASSES_ROOT\MediaType\{major type}\{subtype} 典型的如下: {e436eb83-524f-11ce-9f53-0020af0ba770} {7364696D-0000-0010-8000-00AA00389B71} 0 "0,4,,52494646,8,4,,524D4944" 1 "0,4,,4D546864" Source Filter "{E436EBB5-524F-11CE-9F53-0020AF0BA770}" 開啟註冊表,我們可以看到MediaType有一個{e436eb83-524f-11ce-9f53-0020af0ba770}子鍵,即為MEDIATYPE_Stream,它下面又定義了一系列的Subtype,有{e436eb88-524f-11ce-9f53-0020af0ba770}(MEDIASUBTYPE_Avi)、{e436eb84-524f-11ce-9f53-0020af0ba770}(MEDIASUBTYPE_MPEG1System)等。在Subtype子鍵下,我們還可以看到一些子鍵,其中編號為0,1,2…的即是定義的校驗字元,Source Filter即為定義的相應的CLSID。校驗字元定義塊一般的格式為:offset,cb,mask,val,意思為在文件頭偏移offset字元處讀取cb個字元的資料,將其與mask做位與操作,結果等於val即表示匹配。如果定義的mask為空,可以不做位與操作;如果offset為負數,表示從文件尾開始計算偏移;如果一個子鍵有多個定義塊,則所有的定義塊都匹配才能算這個子鍵匹配;如果有多個子鍵用於校驗字元的定義,那麼任何一個匹配就表示Source Filter的匹配。如果註冊表中定義的所有校驗字元都不能匹配,FGM最後就只能預設新增一個叫File Source (Async.)的Filter,Media Type使用{MEDIATYPE_Stream, MEDIASUBTYPE_None}。 找好Source Filter之後,FGM在這個Filter上得到IFileSourceFilter接頭,通過其接頭方法IFileSourceFilter::Load載入將要播放的這個媒體文件(或者URL)。然後Render這個Source Filter的所有Output pin,完成Filter Graph的構造。 知道了以上原理後,我們就可以採取原則了。針對我們自訂的媒體文件,我們可以開發一個Pull模式的「Parser Filter」。這個Filter必須實現一個Pull模式的Input pin,Filter完成的主要功能還有:從File Source中讀取資料;分析資料,如果是音視瀕交互格式的,則要把它們分離,然後從不同的Output pin輸出;實現IMediaSeeking接頭;回應Quality Control消息等。另外,我們還要保證「Parser Filter」輸出的資料,系統中有相應的Decoder進行解碼(如果沒有,我們要寫自己的Decoder)。注意,註冊這個「Parser Filter」(以及相應的Decoder)時,要讓它(們)的Merit值大於MERIT_DO_NOT_USE。這種處理方法,我們不在註冊表中寫額外的信息。在文件回放時,FGM使用預設的File Source (Async.) Filter作為Source Filter,而後面接上我們的「Parser Filter」(以及相應的Decoder)。 另外一種解決方法,我們可以寫一個Push模式的Source Filter。這個Filter類可以從CSource類中繼承;Filter完成的功能包括:讀取文件內容,如果是音視瀕交互格式,則將它們分離後從不同的Output pin輸出,實現IFileSourceFilter接頭,實現IMediaSeeking接頭,回應Quality Control消息等。(如果我們的Source Filter輸出的資料不是裸資料,而系統中沒有對應的Decoder,那我們也必須自己寫相應的Decoder,類似於第一種處理方法。)這種情況下,要讓FGM自動找到我們的Source Filter,我們就必須在Filter註冊的時候向註冊表中寫入一些額外的信息:可以是註冊文件副檔名,也可以註冊這種文件的校驗字元。下面,筆者給出一種註冊文件副檔名的方法,程式碼參考如下(假設我們的自訂文件副檔名為「.avx」,Source Filter的CLSID為CLSID_MySourceFiler): STDAPI DllRegisterServer() { // Register the ".avx" file extension DWORD dwDisposition; DWORD dwReserved = 0; HKEY hTempKey = (HKEY)0; TCHAR szKey[] = "Media Type\\Extensions\\.avx"; TCHAR sz類型[] = "Source Filter"; TCHAR szData[100]; WCHAR * pClsid = NULL; StringFromCLSID(CLSID_MySourceFiler, &pClsid); WideCharToMultiByte(CP_ACP, 0, pClsid, -1, szData, 100, NULL, NULL); CoTaskMemFree(pClsid); DWORD dwBufferLength = lstrlen(szData) * sizeof(TCHAR); if (ERROR_SUCCESS == ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, dwReserved, (太太TSTR)0, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, 0, &hTempKey, &dwDisposition)) { // dwBufferLength must include size of terminating nul // character when using REG_SZ with RegSet類型Ex function dwBufferLength += sizeof(TCHAR); ::RegSet類型Ex(hTempKey, (太太TSTR)sz類型, dwReserved, REG_SZ, (太太BYTE)szData, dwBufferLength); ::RegCloseKey(hTempKey); } return AMovieDllRegisterServer2( TRUE ); } STDAPI DllUnregisterServer() { // Remove ".avx" file extension registry HKEY hKey = NULL; DWORD dw = 0; TCHAR szKey[] = "Media Type\\Extensions"; if (ERROR_SUCCESS == ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0L, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dw)) { EliminateSubKey(hKey, ".avx"); ::RegCloseKey(hKey); } return AMovieDllRegisterServer2( FALSE ); } 正文完 |
送花文章: 3,
|
|
|
相似的主題 | ||||
主題 | 主題作者 | 討論區 | 回覆 | 最後發表 |
DRM數字版權管Windows Media Rights Manager 1 簡介 | psac | 作業系統操作技術文件 | 0 | 2004-02-20 11:02 AM |