免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

Windows Embedded Compact 7中的多媒體編程(上)

 BeautymengRoom 2013-10-25

  隨著計(jì)算機(jī)技術(shù)、網(wǎng)絡(luò)技術(shù)迅猛發(fā)展,在嵌入式電腦上,多媒體功能變得越來(lái)越普及。倒如現(xiàn)在很多智能手機(jī)、PDA以及嵌入式電腦部具有聽(tīng)MP3、觀看VIDEO視頻以及使用攝像頭拍照、錄像等功能,這些功能極大地增強(qiáng)了用戶(hù)體驗(yàn)。微軟提供Direct Show技術(shù)標(biāo)準(zhǔn),使得可以非常方便地開(kāi)發(fā)多媒體應(yīng)用程序。本章就來(lái)重點(diǎn)介紹Direct Show技術(shù),并以實(shí)例來(lái)展現(xiàn)Direct Show技術(shù)應(yīng)用。

本章主要介紹DirectShow的相關(guān)知識(shí),以及如何利用DirectShow來(lái)進(jìn)行多媒體編程。本章還提供了在Windows Embedded Compact 7環(huán)境下使用DirectShow編程的兩個(gè)實(shí)例。

10.1   Direct Show介紹

DirectShow有時(shí)簡(jiǎn)稱(chēng)為DS或DShow,它是微軟公司對(duì)之前Windows視頻技術(shù)的一次更新,是微軟公司在ActiveMovie和Video for Windows的基礎(chǔ)上推出的新一代基于組建對(duì)象模型(Component Object Model,COM)的流媒體處理開(kāi)發(fā)包。作為DirectX大家族中的一員,DirectShow為Windows平臺(tái)上處理各種格式的媒體文件播放、音頻和視頻采集等高性能的多媒體應(yīng)用提供了完整的解決方案。DirectShow 9.0之前的版本與DirectX開(kāi)發(fā)包一起發(fā)布,之后成為Windows SDK的一部分。

DirectShow為大部分微軟公司程序設(shè)計(jì)語(yǔ)言提供了一個(gè)媒體的通用接口,而且是一個(gè)基于Filter并能在用戶(hù)或開(kāi)發(fā)者的命令下播放或記錄媒體文件的可擴(kuò)展框架。DirectShow的應(yīng)用很廣泛。通過(guò)DirectShow,軟件開(kāi)發(fā)者能夠?qū)SF、MPEG、DV、MP3、WAVE等格式的媒體文件執(zhí)行各種不同的處理。例如,對(duì)于本地應(yīng)用,開(kāi)發(fā)者可以利用DirectShow實(shí)現(xiàn)不同格式媒體文件的解碼播放以及不同媒體格式間的相互轉(zhuǎn)換,可以從本地機(jī)器的采集設(shè)備捕獲音視頻數(shù)據(jù)并保存為文件,可以接受并觀看模擬電視等。此外,DirectShow可用于視頻點(diǎn)播、視頻監(jiān)控以及視頻會(huì)議等網(wǎng)絡(luò)應(yīng)用。廣而言之,DirectShow還可以用于除了音視頻等多媒體數(shù)據(jù)以外的其他流式數(shù)據(jù)的處理。

在Windows Embedded Compact 7中,我們同樣可以使用DirectShow來(lái)捕獲、回放和轉(zhuǎn)換多媒體流數(shù)據(jù)。接下來(lái)我們將分別介紹DirectShow技術(shù)框架、過(guò)濾器(Filter)、過(guò)濾器圖表管理器(Filter Graph Manager)、PIN以及DirectShow接口定義。

介紹下DirectX家族。DirectX是一個(gè)多煤休API,它提供標(biāo)準(zhǔn)接口來(lái)與圖形卡、聲卡、輸入設(shè)備等進(jìn)行交互。如果沒(méi)有這組標(biāo)準(zhǔn)API,用戶(hù)就需要為圖形卡和聲卡的每個(gè)組臺(tái)和每種類(lèi)型的鍵盤(pán)、鼠標(biāo)和游戲桿編寫(xiě)不同的代碼。DirectX從具體的硬件中抽象出來(lái),并且將一組通用指令轉(zhuǎn)換成硬件的具體命令。

DirectX的家族成員很多,而且各有各的本領(lǐng),類(lèi)似于DirectDrawDirect3D負(fù)責(zé)二維圖形圖像,三維動(dòng)面加速、DirectMusicDirectSound負(fù)責(zé)交互式音樂(lè),環(huán)境音效處理一樣,

DirectShowWindows平臺(tái)上處理各種格式的媒體文件播放,音視頻采集等高性能要求的多媒體應(yīng)用,提供了完整的解決方案。

DirectShow是微軟公司提供的一套在Windows平臺(tái)上進(jìn)行流媒體處理的開(kāi)發(fā)包,與

DirectX開(kāi)發(fā)包一起發(fā)布。DirectShowWindows平臺(tái)上的流媒體框架,提供了高質(zhì)量的多媒體流采集和回放功能。它支持多種多樣的媒體文件格式,包括ASF、MPEO、AVI. MP3WAV文件,目時(shí)支持使用WDM驅(qū)動(dòng)或早期的VFW驅(qū)動(dòng)來(lái)進(jìn)行多媒體流的采集。DirectShow整合了其他的DirectX技術(shù),能自動(dòng)偵測(cè)井使用可利用的音視頻硬件加速,也能支持沒(méi)有硬件加速的系統(tǒng)。

Microsoft通過(guò)DirectShow為多媒體程序開(kāi)發(fā)員提供了標(biāo)準(zhǔn)的、統(tǒng)一的、高效的API接口。

DirectShow技術(shù)是建立在DirectXDirectDrawDirectSound的基礎(chǔ)之上的,它通過(guò)

DirectShow對(duì)顯卡進(jìn)行控制以顯示視師,通過(guò)DirectSound對(duì)聲卡進(jìn)行控制以播放聲音。

DirectX為了最大限度提高效率而允許用戶(hù)直接訪問(wèn)硬件,如允許用戶(hù)直接讀寫(xiě)顯存,因此,DirectShow也同樣具有快速的優(yōu)勢(shì)。

下面就對(duì)DirectShow的關(guān)鍵技術(shù)點(diǎn)做簡(jiǎn)要介紹,以便讀者對(duì)DirectShow技術(shù)有了初步了解,也便于理解后面講述的媒體播放器、攝像頭捕捉示例代碼。DirectShow是一門(mén)非常系統(tǒng)的技術(shù),關(guān)于更為詳細(xì)的技術(shù)細(xì)節(jié),請(qǐng)讀者參考相關(guān)專(zhuān)業(yè)DirectShow書(shū)籍或者MSDN

10.1.1  DirectShow技術(shù)框架

  DirectShow的技術(shù)框架如圖10-1所示。看了此框架圖就會(huì)發(fā)現(xiàn)DirectShow的工作原理也非常簡(jiǎn)單、清晰。此圖可以簡(jiǎn)單理解成3部分,輸入→邏輯處理→輸出,這是一個(gè)典型的計(jì)算機(jī)處理流程。輸入部分:它可以是本地視頻、音頻文件、Internet網(wǎng)絡(luò)、視頻和音頻采集卡:輸出部分:它可以是本地文件、顯示器(顯卡)和聲卡;邏輯處理部分:也就是DirectShow的核心部分,從圖上看包括:源過(guò)濾器、傳輸過(guò)濾器、渲染過(guò)濾器以及管理這3個(gè)過(guò)濾器的過(guò)濾器圖管理器對(duì)象。

10-1  DirectShow  技術(shù)框架圖

在應(yīng)用程序中,為了完成對(duì)多媒體數(shù)據(jù)的處理,需要將若干過(guò)濾器連接起來(lái),一個(gè)的輸出作為另一個(gè)的輸入,這樣連接在一起的一組過(guò)濾器稱(chēng)為過(guò)濾器圖(Filter Graph)。過(guò)濾器圖也決定著每一步該使用哪一個(gè)過(guò)濾囂及這些過(guò)濾器之間是如何連接的。這樣,多媒體數(shù)據(jù)流就在過(guò)濾器流水線上,從源過(guò)濾器經(jīng)由中間過(guò)濾器移動(dòng)到播放過(guò)濾器,從而最終完成播放。在這個(gè)過(guò)程中完成了對(duì)數(shù)據(jù)的讀取、解碼、將數(shù)據(jù)輸出到相應(yīng)的設(shè)備、播放等操作。

10.1.2過(guò)濾器( Filter)

 DirectShow是基于模塊化的開(kāi)發(fā)框架,每個(gè)功能操作如捕獲、回放和轉(zhuǎn)換都采用COM組件方式,每個(gè)COM組件就稱(chēng)為Filter。Filter是完成DirectShow處理過(guò)程的基本單元。DirectShow提供了一系列標(biāo)準(zhǔn)的Filters用于應(yīng)用開(kāi)發(fā),開(kāi)發(fā)者也可以開(kāi)發(fā)自己的Filter來(lái)擴(kuò)展DirectShow的功能,但必須是以COM形式建立的。DirectX為用戶(hù)提供了DirectShow基類(lèi)庫(kù)(DirectShow Base Class Library),用戶(hù)自定義的過(guò)濾器都可以從基類(lèi)庫(kù)提供的基類(lèi)和接口派生出來(lái)。

過(guò)濾器主要分為以下幾種類(lèi)型:
  (1)源過(guò)濾器(source filter):源過(guò)濾器引入數(shù)據(jù)到過(guò)濾器圖表中,數(shù)據(jù)來(lái)源可以是文件、網(wǎng)絡(luò)、照相機(jī)等。不同的源過(guò)濾器處理不同類(lèi)型的數(shù)據(jù)源。
 ?。?)變換過(guò)濾器(transform filter):變換過(guò)濾器的工作是獲取輸入流,處理數(shù)據(jù),并生成輸出流。變換過(guò)濾器對(duì)數(shù)據(jù)的處理包括編解碼、格式轉(zhuǎn)換、壓縮解壓縮等。
 ?。?)渲染過(guò)濾器(renderer filter):渲染過(guò)濾器在過(guò)濾器圖表里處于最后一級(jí),它們接收數(shù)據(jù)并把數(shù)據(jù)提交給外設(shè)。
 ?。?)分割過(guò)濾器(splitter filter):分割過(guò)濾器把輸入流分割成多個(gè)輸出。例如,AVI分割過(guò)濾器把一個(gè)AVI格式的字節(jié)流分割成視頻流和音頻流。
 ?。?)混合過(guò)濾器(mux filter):混合過(guò)濾器把多個(gè)輸入組合成一個(gè)單獨(dú)的數(shù)據(jù)流。例如,AVI混合過(guò)濾器把視頻流和音頻流合成一個(gè)AVI格式的字節(jié)流。
  過(guò)濾器的這些分類(lèi)并不是絕對(duì)的,例如一個(gè)ASF讀過(guò)濾器(ASF Reader Filter)既是一個(gè)源過(guò)濾器又是一個(gè)分割過(guò)濾器。

在DirectShow中,一組相連的過(guò)濾器稱(chēng)為一個(gè)過(guò)濾器圖表(Filter Graph),從而完成比單個(gè)過(guò)濾器更復(fù)雜的多媒體任務(wù)。過(guò)濾器圖表用來(lái)連接過(guò)濾器以控制媒體流,它也可以將數(shù)據(jù)返回給應(yīng)用程序,并搜索所支持的過(guò)濾器。過(guò)濾器有三種可能的狀態(tài):運(yùn)行、停止和暫停。暫停是一種中間狀態(tài),停止?fàn)顟B(tài)到運(yùn)行狀態(tài)必定經(jīng)過(guò)暫停狀態(tài)。暫??梢岳斫鉃閿?shù)據(jù)就緒狀態(tài),是為了快速切換到運(yùn)行狀態(tài)而設(shè)計(jì)的。在暫停狀態(tài)下,數(shù)據(jù)線程是啟動(dòng)的,但被渲染過(guò)濾器阻塞了。通常情況下,過(guò)濾器圖表中所有過(guò)濾器的狀態(tài)是一致的。

  過(guò)濾器接收輸入和產(chǎn)生輸出,信息通過(guò)過(guò)濾器管腳( PIN)在過(guò)濾器之間傳遞。一個(gè)管腳(PIN)是一個(gè)過(guò)濾器端口,它可以是輸入端口也可以是輸出端口。

  過(guò)濾器Filter具有三個(gè)狀態(tài):運(yùn)行、停止、暫停。當(dāng)一個(gè)Filter運(yùn)行時(shí),它就處理媒體數(shù)據(jù)流:當(dāng)停止時(shí),Filter就不再處理數(shù)據(jù),暫停狀態(tài)用于臨時(shí)暫停過(guò)濾器運(yùn)行。

10.1.3  Filter Graph Manager

DirectShow專(zhuān)門(mén)提供了一個(gè)高級(jí)接口——過(guò)濾器圖表管理器(Filter Graph Manager,F(xiàn)GM)——用來(lái)控制過(guò)濾器圖表中的過(guò)濾器。同時(shí),它也能為一個(gè)特定的媒體文件選配過(guò)濾器,渲染播放該文件。過(guò)濾器圖表管理器是COM 形式的,它的功能有:協(xié)調(diào)過(guò)濾器間的狀態(tài)轉(zhuǎn)變;建立參考時(shí)鐘;把事件(event)傳送給應(yīng)用程序;為應(yīng)用程序提供建立過(guò)濾器圖表的方法等。
  這些功能可通過(guò)過(guò)濾器圖表管理器接口IGraphBuilder、IMediaControl、IMediaEvent、IMediaEventEx、IVideoWindow、IBasicAudio、IBasicVideo、IMediaSeeking、IMediaPosition、IVideoFrameStep等實(shí)現(xiàn)。

在開(kāi)發(fā)基于DirectShow技術(shù)的應(yīng)用程序時(shí),都必須創(chuàng)建多個(gè)過(guò)濾器(Filter)并進(jìn)行恰當(dāng)?shù)倪B接,于是數(shù)據(jù)流就可以從源過(guò)濾器輸入,經(jīng)過(guò)一系列過(guò)濾器(Filter)傳遞,最后到達(dá)RenderFilter輸出,被用戶(hù)所使用。這些過(guò)濾器的集合就叫做過(guò)濾器圖(Filter Graph)。圖10-2演示如何使用Filter來(lái)播放AVI視頻文件。

     圖10-2播放帶聲音的視頻文件過(guò)濾器圖形

下面簡(jiǎn)要介紹采用Filter播放視頻文件的流程。本流程將會(huì)在本章第2節(jié)的媒體播放器中

被具體代碼實(shí)現(xiàn)。

    (l)首先從一個(gè)文件中讀取AVI數(shù)據(jù),形成字節(jié)流。(這個(gè)工作由源Filter完成)。

    (2)檢查AVI數(shù)據(jù)流的頭格式,然后通過(guò)AVI分割Filter,將視頻流和音頻流分開(kāi)。

    (3)解碼視頻流,根據(jù)壓縮格式的不同,選取不同的decoder filters

    (4)通過(guò)Renderer Filter重畫(huà)視頻圖像。

    (5)音頻流送到聲卡進(jìn)行播放,一般采用缺省的DirectSound Device Filter

    Filter Graph Manager也是一個(gè)COM對(duì)象,用來(lái)控制Filter Graph中所有的Filter,主要有以下的功能:

   協(xié)調(diào)Filters之間的狀態(tài)改變。Filters的狀態(tài)改變必須以一種特殊順序發(fā)生。因此,應(yīng)用程序并不將狀態(tài)改變的命令直接發(fā)給Filter,而是發(fā)送給Filter Graph Manager一個(gè)簡(jiǎn)單命令,由Manager將命令分發(fā)給Graph中的每一個(gè)Filter。Seeking也是按同樣的方式工作,先由應(yīng)用程序?qū)?/span>Seek命令發(fā)送到Filter Graph Manager,然后由其分發(fā)給每個(gè)Filters

 建立參考時(shí)鐘。Graph中的Filter都采用同一個(gè)時(shí)鐘,稱(chēng)為參考時(shí)鐘(Reference Clock),參考時(shí)鐘可以確保所有的數(shù)據(jù)流同步。視頻楨或者音頻Sample應(yīng)該被提交的時(shí)間稱(chēng)為Presentation Time,它是相對(duì)于參考時(shí)鐘來(lái)確定的。Filter Graph Manager應(yīng)該選擇一個(gè)參考時(shí)鐘,可以選擇聲卡上的時(shí)鐘,也可以選擇系統(tǒng)時(shí)鐘。

傳遞事件到應(yīng)用程序。Filter Graph Manager采用事件隊(duì)列機(jī)制將Graph中發(fā)生的事件通知給應(yīng)用程序,這個(gè)機(jī)制類(lèi)似于Windows的消息循環(huán)。

提供應(yīng)用程序建立Filter Graph的方法。Filter Graph Manager給應(yīng)用程序提供了將Filter添加進(jìn)Graph的方法、連接Filter以及斷開(kāi)Filter連接的方法。

  Filter Graph Manager沒(méi)有的一個(gè)功能就是把數(shù)據(jù)從一個(gè)Filter移動(dòng)到另一個(gè)Filter,這是由Filters自己通過(guò)它們的Pin連接完成的。處理過(guò)程總是在不同的線程進(jìn)行。

10.1.4  Pin

  過(guò)濾器可以和一個(gè)或多個(gè)過(guò)濾器相連,連接的單向接口也是COM形式的,稱(chēng)為引腳,就是Pin。過(guò)濾器利用引腳在各個(gè)過(guò)濾器間傳輸數(shù)據(jù)。每個(gè)引腳都是從Ipin這個(gè)COM對(duì)象派生出來(lái)的。每個(gè)引腳都是過(guò)濾器的私有對(duì)象,過(guò)濾器可以動(dòng)態(tài)的創(chuàng)建引腳,銷(xiāo)毀引腳,自由控制引腳的生存時(shí)間。引腳可以分為輸入引腳(Input pin)和輸出引腳(Output pin)兩種類(lèi)型,兩個(gè)相連的引腳必須是不同種類(lèi)的,即輸入引腳只能和輸出引腳相連,且連接的方向總是從輸出引腳指向輸入引腳。
      Pin就是兩個(gè)過(guò)濾器相連的接口。每個(gè)Pin都是從IPin這個(gè)COM對(duì)象派生出來(lái)的。每個(gè)Pin都是過(guò)濾器私有對(duì)象,過(guò)濾器可以動(dòng)態(tài)地創(chuàng)建和銷(xiāo)毀Pin.自由地控制Pin的生存時(shí)間。Pin可以分為兩類(lèi):輸入Pin和輸出Pin。兩個(gè)相連的Pin必須是不同種類(lèi)的,即輸入Pin只能同輸出Pin相連。數(shù)據(jù)就從相連的Pin中流動(dòng),從上一級(jí)過(guò)濾器到下一級(jí)過(guò)濾器。兩個(gè)過(guò)濾器的Pin相連的時(shí)候,有一個(gè)協(xié)商的過(guò)程,兩者必須統(tǒng)一數(shù)據(jù)流的類(lèi)型、緩存的大小和數(shù)據(jù)傳送的機(jī)制等。如果協(xié)商沒(méi)有統(tǒng)一,這兩個(gè)過(guò)濾器就無(wú)法連接。

10.1.5 DirectShow接口定義介紹

上面簡(jiǎn)要介紹了DirectShow技術(shù)框架,下面就來(lái)介紹DirectShow SDK提供的相關(guān)COM接口,通過(guò)這些接口可以非常方便地實(shí)現(xiàn)DirectShow應(yīng)用編程,DirectShow常用接口如表10-1所示。

                        表 10-1DirectShow常用接口

接口

描述

IAMCollection

過(guò)濾器圖表對(duì)象集合,例如過(guò)濾器或引腳。

IAMStats

允許應(yīng)用程序從圖表管理器中檢索性能數(shù)據(jù)。過(guò)濾器可以使用此接口記錄性能數(shù)據(jù)。

IBasicAudio

允許應(yīng)用程序控制音頻流的音量和平衡。

IBaseFilter

提供用于控制過(guò)濾器的方法。應(yīng)用程序可以使用此接口枚舉引腳和查詢(xún)過(guò)濾器信息。

IBasicVideo

允許應(yīng)用程序設(shè)置視頻屬性,例如目標(biāo)矩形和源矩形

IBasicVideo2

從 IBasicVideo 接口派生,為應(yīng)用程序提供了一個(gè)附加方法,通過(guò)它可以檢索視頻流的首選縱橫比。

IConfigAsfWriter2

提供用于獲取和設(shè)置 WM ASF Writer過(guò)濾器寫(xiě)文件要使用的高級(jí)流格式(Advanced Streaming Format,ASF)配置文件的方法和用于支持 Windows Media Format 9 Series SDK 中的新功能(例如雙向編碼和對(duì)反交錯(cuò)視頻的支持)的方法。

IDeferredCommand

允許應(yīng)用程序取消或修改該應(yīng)用程序先前使用 IQueueCommand 接口排入隊(duì)列的圖形-控制命令。

IFilterInfo

管理過(guò)濾器的信息并提供訪問(wèn)過(guò)濾器和表示過(guò)濾器上的引腳的 IPinInfo 接口。

IFileSinkFilter

在將媒體流寫(xiě)入文件的過(guò)濾器上實(shí)現(xiàn)。

IFileSourceFilter

在從文件讀媒體流的過(guò)濾器上實(shí)現(xiàn)。

IGraphBuilder

為應(yīng)用程序提供創(chuàng)建過(guò)濾器圖表的方法。

IMediaControl

提供方法來(lái)控制經(jīng)過(guò)過(guò)濾器圖表的數(shù)據(jù)流。它包含運(yùn)行、暫停和停止圖形的方法。

IMediaEvent

包含用來(lái)檢索事件通知和用于重寫(xiě)過(guò)濾器圖表管理器的默認(rèn)事件處理的方法。

IMediaEventEx

從 IMediaEvent 派生并添加方法來(lái)啟用一個(gè)應(yīng)用程序窗口,以便在事件發(fā)生時(shí)接收消息。

IMediaPosition

用于尋找數(shù)據(jù)流的位置。

IMediaSeeking

提供搜索數(shù)據(jù)流位置和設(shè)置播放速率的方法。

IMediaTypeInfo

包含用于檢索引腳連接的媒體類(lèi)型的方法。

IPinInfo

包含用于檢索引腳信息和連接引腳的方法。

IQueueCommand

允許應(yīng)用程序預(yù)先將圖形-控制命令排入隊(duì)列。

IRegFilterInfo

提供對(duì) Windows 注冊(cè)表中的過(guò)濾器的訪問(wèn),以及向過(guò)濾器圖表中添加已注冊(cè)的過(guò)濾器。

IVideoFrameStep

用于步進(jìn)播放視頻流,可使DirectShow應(yīng)用程序,包括DVD播放器一次只播放一幀視頻。

IVideoWindow

包含用于設(shè)置窗口所有者、窗口的位置和尺寸及其他窗口屬性的方法。

IWmProfileManager

用于創(chuàng)建配置文件、加載現(xiàn)有的配置文件和保存配置文件。

10.2媒體播放器示例

 Windows Embedded Compact7支持使用DirectShow技術(shù)來(lái)捕獲、播放和轉(zhuǎn)換多媒體內(nèi)容。嵌入式設(shè)備通常包含音頻和視頻硬件解碼器。由于嵌入式設(shè)備中的硬件專(zhuān)屬于嵌入式平臺(tái),開(kāi)發(fā)者需要實(shí)現(xiàn)DirectShow過(guò)濾器來(lái)讓DirectShow在特定的平臺(tái)運(yùn)行。為了盡快實(shí)現(xiàn)一個(gè)DirectShow過(guò)濾器,一般推薦在WINCE7下使用DirectShow基類(lèi)來(lái)完成。本節(jié)主要介紹利用DirectShow在WINCE平臺(tái)上如何實(shí)現(xiàn)一個(gè)媒體播放器。一個(gè)播放過(guò)濾器圖表包括一個(gè)源過(guò)濾器,一個(gè)多路分配過(guò)濾器,一個(gè)活多個(gè)解碼器濾波器以及一個(gè)或多個(gè)渲染過(guò)濾器。對(duì)于某些格式,WINCE7還包括一個(gè)新的緩沖過(guò)濾器,即Buffering Stream Filter。該過(guò)濾器位于源過(guò)濾器和多路分配器之間,管理IMediaSample緩沖池。如果使用Buffering Stream Filter,下行的過(guò)濾器只需要很少的緩沖區(qū)管理工作。

圖3提供了一個(gè)包含Buffering Stream Filter的過(guò)濾器圖表。值得一提的是,在圖10-3中,有的過(guò)濾器由操作系統(tǒng)中提供,有的過(guò)濾器是平臺(tái)特有的,還有過(guò)濾器既可由操作系統(tǒng)提供,也可以為平臺(tái)特有。

10-3 DirectShow 實(shí)現(xiàn)媒體播放器的過(guò)濾器圖表

當(dāng)然,我們?cè)趯?shí)現(xiàn)視頻和音頻解碼器、渲染器時(shí)可以有不同的選擇。例如,可以利用一個(gè)軟件模塊將視頻解碼器和渲染器合并,另一個(gè)軟件模塊將音頻解碼器和渲染器合并。還有一種方式是創(chuàng)建單個(gè)模塊,該模塊包括視頻解碼器和渲染器、音頻解碼器和渲染器。取決于不同的實(shí)現(xiàn)方式,圖10-3所示的過(guò)濾器圖表可修改為圖10-4所示的配置。

10-4 媒體播放器的過(guò)濾器圖表的其他配置

如果某些媒體格式不需要緩沖流過(guò)濾器,圖3和圖4中的Buffering Stream Filter可以去除,此時(shí)源過(guò)濾器和多路分配過(guò)濾器直接相連。

WINCE7所支持的編解碼格式如表2所示。

10-2 WINCE7支持的DirectShow編解碼器

在實(shí)現(xiàn)DirectShow過(guò)濾器時(shí),我們必須實(shí)現(xiàn)一些接口和方法。為了減少需要開(kāi)發(fā)的代碼量,DirectShow基類(lèi)提供了許多通用代碼,所以我們推薦在過(guò)濾器開(kāi)發(fā)過(guò)程中盡可能地使用基類(lèi)。一個(gè)過(guò)濾器的主要功能部分包括輸入引腳,輸出引腳以及過(guò)濾器本身的邏輯。但是需要注意的是,特殊的過(guò)濾器可能沒(méi)有輸入引腳或輸出引腳。例如,如圖2所示,源過(guò)濾器沒(méi)有輸入引腳,渲染過(guò)濾器沒(méi)有輸出引腳。一般而言,我們繼承一些相關(guān)的基類(lèi)來(lái)開(kāi)發(fā)一個(gè)類(lèi)所對(duì)應(yīng)的輸入引腳、輸出引腳以及過(guò)濾器邏輯。

10-5DirectShow解碼器過(guò)濾器類(lèi)圖

在第1節(jié)中簡(jiǎn)要介紹了Direct Show的基本技術(shù)框架,下面就以一個(gè)實(shí)際的媒體播放器為例進(jìn)行說(shuō)明,使讀者對(duì)應(yīng)用DirectShow編程有更深入地了解。本倒是通過(guò)DirectShowIFilterGpaph->Render函數(shù)來(lái)自動(dòng)渲染視頻、音頻文件。這里能夠播放哪些媒體文件,跟系統(tǒng)注冊(cè)相關(guān)的Filter有很大關(guān)系。

下面就來(lái)講述如何利用DirectShow技術(shù)來(lái)搭建一個(gè)媒體播放器。

(l)建立新項(xiàng)目。

使用VS2008選擇智能設(shè)備模板,利用MFC智能設(shè)備應(yīng)用程序向?qū)?chuàng)建一個(gè)基于對(duì)話(huà)框的應(yīng)用程序EricMeidaPlayer,編譯環(huán)境設(shè)置為yinchengOS SDK。

(2)新建CEricMediaControl類(lèi),用于封裝媒體文件播放等功能。

 CEricMediaControl類(lèi)是一個(gè)通用c++類(lèi),無(wú)基類(lèi)。其類(lèi)圖如圖10-6所示。

10-6 媒體播放類(lèi)圖

  CEricMediaControl類(lèi)基于DirectShow技術(shù)并且封裝了媒體播放技術(shù),提供打開(kāi)媒體文件、播放、暫停、終止、全屏、設(shè)置當(dāng)前播放位置等常用方法。基于CEricMediaControl類(lèi)可以非常方便地制作媒體播放程序,讀者也可以在此類(lèi)的基礎(chǔ)上加以修改升級(jí),以實(shí)現(xiàn)更強(qiáng)的功能。

 下面就來(lái)具體實(shí)現(xiàn)CEricMediaControl類(lèi)。

    1)CEricMediaControl類(lèi)添加如下私有變量,用于定義播放媒體文件播放所需的

DSHOW接口,代碼如下所示。

   private:

//DSHOW 接口

IGraphBuilder *m_pGB ;  

IMediaControl *m_pMC ;

IMediaEventEx *m_pME ;

IVideoWindow  *m_pVW ;

IBasicAudio *m_pBA ;

IBasicVideo   *m_pBV ;

IMediaSeeking *m_pMS ;

//顯示視頻的窗口句柄

HWND m_hOwnerWnd;  

  備注:這里需要引用dshow.h頭文件。

  #include<show.h>

  2)定義媒體播放事件對(duì)應(yīng)的WINDOWS消息常量WM_GRAPHNOTIFY,定義如下:

  //定義DSHOW事件通知消息

  #define WM_GRAPHNOTIFY WM_USER+ 101

  3)實(shí)現(xiàn)CEricMediaControl類(lèi)的構(gòu)造函數(shù)和析構(gòu)函數(shù)。在構(gòu)造函數(shù)里,將DSHOW相關(guān)

接口初始化為NULL,并初始化COM環(huán)境;在析構(gòu)函數(shù)里,釋放DSHOW接口并釋放COM

環(huán)境。CEricMediaControl類(lèi)構(gòu)造函數(shù)和析構(gòu)函數(shù)的實(shí)現(xiàn)如下所示。

//構(gòu)造函數(shù)

CEricMediaControl::CEricMediaControl(void)

{

//DSHOW接口置空

m_pGB = NULL;

m_pMC = NULL;

m_pME = NULL;

m_pVW = NULL;

m_pBA = NULL;

m_pBV = NULL;

m_pMS = NULL;

//初始化 COM 環(huán)境

CoInitialize(NULL); 

}

//析構(gòu)函數(shù)

CEricMediaControl::~CEricMediaControl(void)

{

//釋放DSHOW接口

UnInitDShow();

//釋放COM 環(huán)境

CoUninitialize();

}

    4)CEricMediaControl類(lèi)添加InitDShowUninitDShow兩個(gè)私有方法。InitDShow方法用于初始化DShow接口并渲染媒體文件;UnlnitDShow方法用于釋放DShow接口。讀者應(yīng)特別注意InitDShow方法,該方法直接描述了如何利用DShow接口逐步播放視頻文件。

  這個(gè)兩個(gè)方法的定義如下:

 private:

//初始化DSHOW接口

BOOL InitDShow(LPCTSTR strFileName  /*視頻文件名*/

,HWND hOwnerWnd  /*顯示視頻的窗口句柄*/

,HWND hNotifyWnd /*接收DSHOW事件消息的串口句柄*/

);

//釋放DSHOW接口

BOOL UnInitDShow();

InitDShowUnlnitDShow方法的實(shí)現(xiàn)如下所示。

/*

*函數(shù)介紹: 初始化DShow接口,并渲染好視頻文件

*入口參數(shù): strFileName: 視頻文件名

hOwnerWnd: 顯示視頻的窗口句柄

hNotifyWnd: 接收DSHOW事件消息的串口句柄

*出口參數(shù):(無(wú))

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::InitDShow(LPCTSTR strFileName  /*視頻文件名*/

,HWND hOwnerWnd  /*顯示視頻的窗口句柄*/

,HWND hNotifyWnd /*接收DSHOW事件消息的串口句柄*/

)

{

HRESULT hResult;

//1步:創(chuàng)建IGraphBuilder接口

hResult = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB);

if (hResult != S_OK)

{

return FALSE;

}

//2步:利用IGraphBuilder渲染視頻文件

hResult = m_pGB->RenderFile(strFileName,NULL);

if (hResult != S_OK )

{

//

if (hResult == VFW_S_PARTIAL_RENDER)

{

TRACE(L"Some of the streams in this movie are in an unsupported format.\n");

}

else if (hResult == VFW_S_AUDIO_NOT_RENDERED)

{

TRACE(L"Partial success; the audio was not rendered.\n");

}

else if (hResult == VFW_S_DUPLICATE_NAME)

{

TRACE(L"Success; the Filter Graph Manager modified the filter name to avoid duplication..\n");

}

else if (hResult == VFW_S_VIDEO_NOT_RENDERED)

{

TRACE(L"Partial success; some of the streams in this movie are in an unsupported format.\n");

}

else

{

//釋放DSHOW接口

UnInitDShow();

return FALSE;

}

}

//3步:得到媒體播放控制接口

hResult = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC); 

if (hResult != S_OK)

{

//釋放DSHOW接口

UnInitDShow();

return FALSE;

}

//4步:得到媒體播放位置搜索接口

hResult = m_pGB->QueryInterface(IID_IMediaSeeking,(void**)&m_pMS);

if (hResult != S_OK)

{

//釋放DSHOW接口

UnInitDShow();

return FALSE;

}

//設(shè)置查找定位的時(shí)間單位,這里設(shè)置:100納秒(十億分之一秒)

GUID guid_timeFormat = TIME_FORMAT_MEDIA_TIME;

m_pMS->SetTimeFormat(&guid_timeFormat);

//5步:得到Filter Graph媒體事件接口

hResult = m_pGB->QueryInterface(IID_IMediaEventEx,(void**)&m_pME);

if (hResult != S_OK)

{

//釋放DSHOW接口

UnInitDShow();

return FALSE;

}

//設(shè)置媒體事件通知消息窗口

m_pME->SetNotifyWindow((OAHWND)hNotifyWnd, WM_GRAPHNOTIFY, 0);

//6步:得到視頻播放窗口接口

 hResult = m_pGB->QueryInterface(IID_IVideoWindow, (void **)&m_pVW);

 if (hResult != S_OK)

 {

//釋放DSHOW接口

UnInitDShow();

return FALSE;

 }

 //設(shè)置視頻播放窗口句柄

 m_pVW->put_Owner((OAHWND)hOwnerWnd);

 //設(shè)置視頻窗口格式

     m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);

 //7步:得到基礎(chǔ)視頻流接口

 hResult = m_pGB->QueryInterface(IID_IBasicVideo, (void **)&m_pBV);

    if (hResult != S_OK)

 {

//釋放DSHOW接口

UnInitDShow();

return FALSE;

 }

 //8步:得到基礎(chǔ)音頻流接口

 hResult = m_pGB->QueryInterface(IID_IBasicAudio, (void **)&m_pBA);

    if (hResult != S_OK)

 {

//釋放DSHOW接口

UnInitDShow();

return FALSE;

 }

return TRUE;

}

/*

*函數(shù)介紹: 卸載DShow系列接口

*入口參數(shù): (無(wú))

*出口參數(shù):(無(wú))

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::UnInitDShow()

{

//1,釋放媒體播放控制接口

if (m_pMC != NULL)

{

//停止視頻播放

m_pMC->Stop(); 

m_pMC->Release();

m_pMC = NULL;

}

//2,釋放媒體事件接口

if (m_pME != NULL)

{

//消息通知窗口置空

m_pME->SetNotifyWindow(NULL, 0, 0);

m_pME->Release();

m_pME = NULL;

}

//3,釋放視頻播放窗口接口

if (m_pVW != NULL)

{

//隱藏視頻窗口

m_pVW->put_Visible(OAFALSE);

//設(shè)置視頻播放窗口句柄為空

m_pVW->put_Owner(NULL);

m_pVW->Release();

m_pVW = NULL;

}

//4,釋放基礎(chǔ)音頻流接口

if (m_pBA != NULL)

{

m_pBA->Release();

m_pBA = NULL;

}

//5,釋放基礎(chǔ)視頻流接口

if (m_pBV != NULL)

{

m_pBV->Release();

m_pBV = NULL;

}

//6,釋放媒體搜索接口

if (m_pMS != NULL)

{

m_pMS->Release();

m_pMS = NULL;

}

//7,最后釋放FilterGpaph接口

if (m_pGB != NULL)

{

m_pGB->Release();

m_pGB = NULL;

}

return TRUE;

}

5)CEricMediaControl類(lèi)添加4個(gè)共有方法,供外部調(diào)用。這4個(gè)方法分別為OpenFile(打開(kāi)視頻文件)、VfideoRun(視頻播放)、VideoPause(視頻暫停)、VideoStop(視頻停止)。打開(kāi)視頻文件方法,調(diào)用前面講述的InitDShow方法,來(lái)初始化視頻播放文件。視頻播放、暫停、停止等方法通過(guò)IMediaControl接口調(diào)用相關(guān)方法來(lái)實(shí)現(xiàn)媒體流的控制。

 這4個(gè)方法具體定義如下:

 public:

//打開(kāi)視頻文件

BOOL OpenFile(LPCTSTR strFileName /*視頻文件名*/

,HWND hOwnerWnd  /*顯示視頻的窗口句柄*/

,HWND hNotifyWnd /*接收DSHOW事件消息的串口句柄*/

);

//播放視頻

BOOL VideoRun();

//暫停視頻

BOOL VideoPause();

//停止視頻

BOOL VideoStop();

4個(gè)方法的實(shí)現(xiàn)如下所示。

/*

*函數(shù)介紹:打開(kāi)視頻文件

*入口參數(shù):strFileName:視頻文件名

           hOwnerWnd:顯示視頻的窗口句柄

           hNotifyWnd:接收DSHOW事件消息的串口句柄

*出口參數(shù):(無(wú))

*返回值:TRUE,成功打開(kāi)視頻文件;FALSE:打開(kāi)視頻文件失敗

*/

BOOL  CEricMediaControl:OpenFileLPCTSTR strFileName /*視頻文件名*/

    ,HWND hOwnerWnd/*顯示視頻的窗口句柄*/

    ,HWND hNotifyWnd/*接收DSHOW事件消息的串口句柄*/

//存儲(chǔ)顯示視頻窗口句柄

m_hOwnerWnd = hOwnerWnd;

//重置DSHOW接口

UninitDShow();

//打開(kāi)視頻文件,并對(duì)DSHOW接口做初始化工作

return  InitDShow( strFileName, hOwnerWnd,hNotifyWnd)

/*

*函數(shù)介紹:括放視頻

*入口參數(shù);(無(wú))

*出口參數(shù):(無(wú))

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL  CEricMediaControl::VideoRun()

//檢測(cè)IMediaControl控制接口有效性

ifm_pMC== NULL

{

Return FALSE;

}

//播放視頻

HRESULT hResult = m_pMC->Run();

if(hResult !=S_OK)

{

Return FALSE;

}

Return TRUE;

}

/*

*函數(shù)介紹;暫停視頻

*入口參數(shù):(無(wú))

*出口參數(shù):(無(wú))

*返回值: TRUE:成功:FALSE:失敗

*/

BOOL  CEricMediaControl::VideoPause()

//檢測(cè)IMediaControl控制接口有效性

if (m_pMC==NULL)

{

    return FALSE;

}

//暫停視頻

HRESULT hResult = m_pMC->Pause();

If(hResult i= S_OK)

{

Return FALSE;

}

Return TRUE;

}

/*

*函數(shù)介紹:停止視頻

*入口參數(shù):(無(wú))

*出口參數(shù):(無(wú))

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::VideoStop()

{

HRESULT hResult;

//檢測(cè)IMediaControl控制接口有效性

if(m_pMC ==NULL)

{

Return FALSE;

}

//停止視頻

hReSult = m_pMC->Stop();

 if (hResult  != S_OK)

{

Return FALSE;

}

//將當(dāng)前播放位置置0

LONGLONG pos:0;

hResult : m_pMS->SetPositions(&pos, AM_SEEKIFIG_AbsolutePositionin9

                          NULL, AM SEEKING NoPositioning);

  6)為類(lèi)CEricMediaControl類(lèi)添加7個(gè)共有方法,用于設(shè)置媒體播放屬性以及得到媒體播放屬性。這7個(gè)方法分別為FitVideoWindow(設(shè)置視頻顯示比例)、FuIIScreen(全屏顯示)、GetFuIIScreenStatus(得到是否是全屏顯示)、GetMediaEvent(得到DShow播放事件)、SetPositions(設(shè)置播放進(jìn)度)、GetCurrentPos(得到當(dāng)前播放進(jìn)度)、GelDuration(得到媒體文件時(shí)間長(zhǎng)度)。具體定義如下:

    public:

//設(shè)置視頻顯示比例

BOOL FitVideoWindow(FLOAT fScale);

//全屏顯示

BOOL FullScreen();

//得到是否是全屏顯示

BOOL GetFullScreenStatus();

//得到DShow播放事件

BOOL GetMediaEvent(long *lEventCode);

//設(shè)置播放進(jìn)度,單位

BOOL SetPositions(DWORD dwPos /*設(shè)置當(dāng)前播放進(jìn)度*/);

//得到視頻播放當(dāng)前的位置,單位:秒

BOOL GetCurrentPos(DWORD &dwPos  /*out 當(dāng)前播放進(jìn)度*/);

//得到視頻文件時(shí)間長(zhǎng)度,單位:秒

BOOL GetDuration(DWORD &dwLength);

7個(gè)函數(shù)的實(shí)現(xiàn)如下所示。

/*

*函數(shù)介紹:  設(shè)置視頻顯示比例

*入口參數(shù):  fScale : 顯示比例, <= 1.0

*出口參數(shù): (無(wú))

*返回值:TRUE:成功;FALSE:失敗,此處有點(diǎn)問(wèn)題

*/

BOOL CEricMediaControl::FitVideoWindow(FLOAT fScale)

{

    LONG lHeight, lWidth;

int iSeek = 0;

double dblScaleX,dblScaleY;

    HRESULT hr = S_OK;

LONG lDeflateX = 0;

LONG lDeflateY = 0;

    CRect clientRect;

CRect dstRect;

//

if (m_pBV == NULL)

{

return FALSE;

}

//放縮比例必須小于等于1

if (fScale > 1.0)

{

return FALSE;

}

//得到原始視頻尺寸

    hr = m_pBV->GetVideoSize(&lWidth, &lHeight);

if (hr != S_OK)

{

return FALSE;

}

//設(shè)置拉伸后的尺寸

lWidth = lWidth * fScale;

lHeight = lHeight * fScale;

//得到視頻播放窗口的尺寸

GetClientRect(m_hOwnerWnd, &clientRect);

lDeflateX = (clientRect.Width() - clientRect.Width() * fScale) / 2;

lDeflateY = (clientRect.Height() - clientRect.Height() * fScale) / 2;

//重新設(shè)置客戶(hù)區(qū)域

clientRect.DeflateRect(lDeflateX,lDeflateY);

    

if ( (lWidth <= clientRect.Width())

&& (lHeight <= clientRect.Height()))

{

dstRect.left = (clientRect.right - clientRect.left - lWidth) /2;

dstRect.right = dstRect.left + lWidth;

dstRect.top  = (clientRect.bottom - clientRect.top - lHeight) /2;

dstRect.bottom = dstRect.top + lHeight;

}

else 

{

dblScaleX =double(clientRect.Width()) / double(lWidth) ;

dblScaleY =  double(clientRect.Height()) / double(lHeight) ;

if (dblScaleX <= dblScaleY)

{

dstRect.left = clientRect.left;

dstRect.right = clientRect.right;

iSeek =(clientRect.Height() - clientRect.Width()*(double(lHeight) / double(lWidth)))/2;

dstRect.top = clientRect.top + iSeek;

dstRect.bottom = dstRect.top + clientRect.Width()*(double(lHeight) / double(lWidth));

}

else

{

dstRect.top = clientRect.top;

dstRect.bottom = clientRect.bottom;

iSeek =(clientRect.Width() - clientRect.Height()*(double(lWidth) / double(lHeight)))/2;

dstRect.left = clientRect.left + iSeek;

dstRect.right = dstRect.left + clientRect.Height()*(double(lWidth) / double(lHeight));

}

}

//設(shè)置視頻播放位置

    m_pVW->SetWindowPosition(dstRect.left,dstRect.top,dstRect.Width(),dstRect.Height());

    return TRUE;

}

/*

*函數(shù)介紹:  全屏顯示

*入口參數(shù): (無(wú))

*出口參數(shù): (無(wú))

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::FullScreen()

{

LONG lMode = 0;

static HWND hDrain=0;

if (m_pBV == NULL)

{

return FALSE;

}

//得到全屏狀態(tài)

m_pVW->get_FullScreenMode(&lMode);

if (lMode == OAFALSE)

    {

// Save current message drain

        m_pVW->get_MessageDrain((OAHWND *) &hDrain);

        // Set message drain to application main window

        m_pVW->put_MessageDrain((OAHWND)m_hOwnerWnd );

//設(shè)置全屏幕

        lMode = OATRUE;

        m_pVW->put_FullScreenMode(lMode);

    }

    else

    {

        //切換到非全屏模式

        lMode = OAFALSE;

        m_pVW->put_FullScreenMode(lMode);

 // Undo change of message drain

        m_pVW->put_MessageDrain((OAHWND) hDrain);

        // Reset video window

        FitVideoWindow(1);

        m_pVW->SetWindowForeground(-1);

}

return TRUE;

}

/*

*函數(shù)介紹:  得到是否全屏幕播放

*入口參數(shù): (無(wú))

*出口參數(shù): (無(wú))

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::GetFullScreenStatus()

{

LONG lMode = 0;

if (m_pBV == NULL)

{

return FALSE;

}

m_pVW->get_FullScreenMode(&lMode);

if (lMode == OAFALSE)

{

return FALSE;

}

else

{

return TRUE;

}

}

/*

*函數(shù)介紹:  得到媒體事件

*入口參數(shù): (無(wú))

*出口參數(shù): lEventCode

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::GetMediaEvent(long *lEventCode)

{

    LONG evCode, evParam1, evParam2;

    HRESULT hr=S_OK;

if (m_pME == NULL)

{

return FALSE;

}

hr = m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0);

    if (SUCCEEDED(hr))

{

        *lEventCode = evCode;

// Spin through the events

        hr = m_pME->FreeEventParams(evCode, evParam1, evParam2);

return TRUE;

}

return FALSE;

}

/*

*函數(shù)介紹:  設(shè)置播放進(jìn)度

*入口參數(shù): dwPos :播放進(jìn)度,單位秒

*出口參數(shù): (無(wú))

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::SetPositions(DWORD dwPos /*設(shè)置當(dāng)前播放進(jìn)度*/)

{

//設(shè)置絕對(duì)位置,轉(zhuǎn)化成納秒為單位

LONGLONG llPos = dwPos * 10000 * 1000;

if (m_pMS == NULL)

{

return FALSE;

}

//設(shè)置視頻播放當(dāng)前位置

HRESULT hr = m_pMS->SetPositions(&llPos,AM_SEEKING_AbsolutePositioning ,

                                   NULL, AM_SEEKING_NoPositioning);

if (hr == S_OK)

{

return TRUE;

}

else

{

return FALSE;

}

}

/*

*函數(shù)介紹:  得到視頻文件播放長(zhǎng)度,單位秒

*入口參數(shù): dwLength :視頻文件時(shí)間長(zhǎng)度

*出口參數(shù): dwLength :視頻文件時(shí)間長(zhǎng)度

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::GetDuration(DWORD &dwLength)

{

dwLength = 0;

if (m_pMS == NULL)

{

return FALSE;

}

//得到視頻總時(shí)間長(zhǎng)度

LONGLONG llDuration;

HRESULT hResult = m_pMS->GetDuration(&llDuration);

if (hResult != S_OK)

{

return FALSE;

}

//轉(zhuǎn)換成以秒為單位

llDuration = llDuration / 10000 ;

llDuration = llDuration / 1000;

dwLength  = (DWORD)llDuration;

return TRUE;

}

/*

*函數(shù)介紹:  得到媒體當(dāng)前播放進(jìn)度位置,單位秒

*入口參數(shù): dwPos :當(dāng)前播放進(jìn)度,單位秒

*出口參數(shù): dwPos :當(dāng)前播放進(jìn)度,單位秒

*返回值:TRUE:成功;FALSE:失敗

*/

BOOL CEricMediaControl::GetCurrentPos(DWORD &dwPos)

{

dwPos = 0;

LONGLONG llPos = 0;

if (m_pMS== NULL)

{

return FALSE;

}

//得到當(dāng)前視頻播放位置

HRESULT hResult = m_pMS->GetCurrentPosition(&llPos);

if (hResult != S_OK)

{

return FALSE;

}

//轉(zhuǎn)換成以秒為單位

llPos = llPos / 10000 ;

llPos = llPos / 1000;

dwPos  = (DWORD)llPos;

return TRUE;

}

    至此,CEricMediaContorl類(lèi)就編寫(xiě)完成了。下面將基于CEricMediaContorl類(lèi)演示如何使用它實(shí)現(xiàn)播放視頻、音頻文件的功能。若此時(shí)編譯工程,將會(huì)發(fā)現(xiàn)有一堆連接錯(cuò)誤提示。那是因?yàn)闆](méi)有鏈接strmiids.lib靜態(tài)庫(kù)。

選擇“EricMediaPlayer屬性頁(yè)”一“鏈接囂” 一“輸入”一“附加依賴(lài)項(xiàng)”,輸入strmiids.lib,即可無(wú)誤地編譯本工程。

    (3)設(shè)計(jì)媒體播放器主窗口。

    1) include“CEricMedia Control.h”

    2)CEricMeidaPlayerDlg類(lèi)添加mVideoControl成員變量,類(lèi)型為之前創(chuàng)建的CEricMediaControl類(lèi)。定義如下。

    privrate

    CEricMediaControl m_VideoControl;//媒體播放對(duì)象

    備注:由于引用了CEricMediaControl類(lèi),因此需要在EricMediaPJayerDlg.h文件中添加對(duì)CEricMediaControl類(lèi)定義文件的引用。

 

    3)實(shí)現(xiàn)“打開(kāi)”按鈕單擊事件。單擊“打開(kāi)”按鈕,將可以選擇要播放的媒體文件。“打開(kāi)”按鈕單擊事件的實(shí)現(xiàn)如下所示。

//打開(kāi)視頻文件

void CEricMeidaPlayerDlg::OnBnClickedBtnOpen()

{

DWORD dwMax = 0;

//得到媒體播放窗口

CWnd *pVideoWnd = GetDlgItem(IDC_WND_VIDEO);

//得到進(jìn)度條窗口

CProgressCtrl *pPrgWnd = (CProgressCtrl*)GetDlgItem(IDC_PRG_VIDEO);

//定義媒體播放文件名

CString strFileName;

TCHAR szFilters[]= _T("windows media video Files (*.wmv)|*.wmv|video Files (*.avi)|*.avi|All Files (*.*)|*.*||");

CFileDialog fileDlg (TRUE, _T("Open video files"), _T("*.wmv"),

OFN_FILEMUSTEXIST , szFilters, this);

//打開(kāi)文件選擇對(duì)話(huà)框

if( fileDlg.DoModal () !=IDOK )

{

return;

}

//得到要播放的視頻文件名

strFileName = fileDlg.GetPathName();

//打開(kāi)視頻文件

if (m_VideoControl.OpenFile(strFileName,pVideoWnd->m_hWnd,m_hWnd))

{

//設(shè)置視頻尺寸

m_VideoControl.FitVideoWindow(1.0);

//得到視頻文件時(shí)間長(zhǎng)度

m_VideoControl.GetDuration(dwMax);

//設(shè)置進(jìn)度條范圍

pPrgWnd->SetRange(0,dwMax);

pPrgWnd->SetPos(0);

}

else

{

AfxMessageBox(L"Can't play the video,because the system can't find some codec program!");

}

}

  4)實(shí)現(xiàn)“播放”、“暫?!?、“停止”和“全屏”按鈕單擊事件,具體實(shí)現(xiàn)代碼如下所示。

//播放視頻

void CEricMeidaPlayerDlg::OnBnClickedBtnPlay()

{

m_VideoControl.VideoRun();

}

//暫停視頻

void CEricMeidaPlayerDlg::OnBnClickedBtnPause()

{

m_VideoControl.VideoPause();

}

//停止視頻

void CEricMeidaPlayerDlg::OnBnClickedBtnStop()

{

m_VideoControl.VideoStop();

}

//全屏

void CEricMeidaPlayerDlg::OnBnClickedBtnFull()

{

m_VideoControl.FullScreen();

}

  5)實(shí)現(xiàn)視頻窗口(IDC_WND_VIDEO)單擊事件,用于從全屏狀態(tài)回到正常狀態(tài),如下所示。

//視頻窗口單擊事件

//用于從全屏狀態(tài)回到正常狀態(tài)

void CEricMeidaPlayerDlg::OnStnClickedWndVideo()

{

if (m_VideoControl.GetFullScreenStatus())

{

//切換到正常狀態(tài)

m_VideoControl.FullScreen();

}

}

6)實(shí)現(xiàn)媒體播放事件通知消息(WM ORAPHNOTIFY)函數(shù)。

首先為CEricMediaPlayerDlg類(lèi)添加自定義消息處理函數(shù)定義,定義如下:

//媒體插放事件消息處理函數(shù)

afx_msg LRESULT OnNotifyMedia(WPARAM wParam, LPARAM lParam);

注意,該定義應(yīng)添加在DECLARE_MESSAOE_MAP()語(yǔ)句之前。

OnNotifyMedia函數(shù)的實(shí)現(xiàn)如下所示。

//媒體播放事件通知

LRESULT CEricMeidaPlayerDlg::OnNotifyMedia(WPARAM WParam, LPARAM LParam)

{

long lEventCode;

if (m_VideoControl.GetMediaEvent(&lEventCode))

{

//收到播放結(jié)束事件

if (lEventCode == EC_COMPLETE)

{

if (m_VideoControl.VideoStop())

{

//

}

}

}

return (LRESULT)0;

}

  最后,需要將OnNotifyMedia消息處理函數(shù)和消息WM GRAPHNOTIFY關(guān)聯(lián)起來(lái),即在

BEGIN_MESSAGE_MAP宏中添加如下代碼實(shí)現(xiàn)關(guān)聯(lián):

ON_MESSAGE(WM_GRAPHNOTIFY, OnNotifyMedia)

    7)添加1個(gè)定時(shí)器,用于更新媒體播放進(jìn)度。

    在BOOL CEricMeidaPlayerDlg::OnInitDialog()函數(shù)中添加如下代碼,用于啟動(dòng)1個(gè)定時(shí)器。

//啟動(dòng)定時(shí)器,用于更新媒體播放進(jìn)度

SetTimer(1,1000,NULL);

    定時(shí)器消息處理函數(shù)的實(shí)現(xiàn)如下所示。

//WM_TIMER,定時(shí)器處理函數(shù)

void CEricMeidaPlayerDlg::OnTimer(UINT_PTR nIDEvent)

{

//得到進(jìn)度條窗口

CProgressCtrl *pPrgWnd = (CProgressCtrl*)GetDlgItem(IDC_PRG_VIDEO);

DWORD dwPos = 0;

//得到媒體當(dāng)前播放進(jìn)度

m_VideoControl.GetCurrentPos(dwPos);

//設(shè)置進(jìn)度條位置

pPrgWnd->SetPos(dwPos);

CDialog::OnTimer(nIDEvent);

}

至此,媒體播放器示例就編寫(xiě)完成了。

打開(kāi)Windows Embedded Compact 7虛擬機(jī),將該程序復(fù)制到共享目錄,

執(zhí)行之,如圖10-7

10-7選擇程序并運(yùn)行

運(yùn)行效果如下圖10-8

10-8程序效果圖

單擊“打開(kāi)”按鈕,選擇一個(gè)電影,我們這里選擇鴻門(mén)宴的剪輯,然后單擊“播放”按鈕就可以觀看視頻了。

10-9播放電影圖

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多