Java Media Framework 基礎(chǔ)教程作者:Eric Olson 來源:ibm 摘要:很少發(fā)現(xiàn)有關(guān)于jmf方面的中文資料,,這是在IBM上面找的一本書,,可作為jmf的入門學(xué)習(xí),業(yè)余時間翻譯了,。全書從三個例子入手,,簡單的介紹了jmf的使用。內(nèi)容表格 1. 關(guān)于此指南 2. 一個簡單的音頻播放器 3. JMF用戶接口組件 4. JMF概念 5. 傳播和接收媒體 6. 總結(jié)以及資源 第一節(jié). 關(guān)于此指南 此指南包含的內(nèi)容,? Java 媒體架構(gòu)(JMF)是一個令人激動的通用的API,,它允許Java開發(fā)者用許多不同的方法處理媒體。本指南主要通過使用工作的例子提供一個JMF的一些主 要的特征的概述,。閱讀完本指南后,,你將會明白JMF體系結(jié)構(gòu)中的主要播放功能。你同樣能正確的使用JMF,,使用現(xiàn)存的例子和可為更多特殊功能擴(kuò)展的源代 碼,。 本指南包含著以下主題: · 下載和安裝JMF · 主要的JMF類以及它們在JMF體系結(jié)構(gòu)中的應(yīng)用 · 播放本地的媒體文件 · 為媒體的存取和操作制作以和圖形用戶界面(GUI) · 通過網(wǎng)絡(luò)傳播媒體 · 通過網(wǎng)絡(luò)接收媒體 幾乎所有的媒體類型的操作和處理都可以通過JMF來實(shí)現(xiàn)。全面的討論JMF所提供的所有特征已經(jīng)超過了本指南的范圍,,我們將使用三個簡單的媒體應(yīng)用程序來學(xué)習(xí)此框架的構(gòu)建模塊,。通過這個方法,本指南將為你未來學(xué)習(xí)和實(shí)施更多特殊的應(yīng)用提供準(zhǔn)備,。 我應(yīng)該使用此指南嗎,? 本指南會帶你學(xué)習(xí)使用JMF工作的基礎(chǔ)。為完成這些,,我們會創(chuàng)建三個的獨(dú)立工作的例程序,。每個例子都會建立前一個例子的基礎(chǔ)上,顯示JMF功能性的不同方面,。 在 本指南中的例子假定你曾經(jīng)使用過并且已經(jīng)熟悉了Java程序語言,。除了Java核心和JMF的類之外,我們會使用一些Java AWT和Swing類(用于創(chuàng)建GUI),,也會有一些Java網(wǎng)絡(luò)類(用于在網(wǎng)絡(luò)中傳輸媒體),。對GUI和網(wǎng)絡(luò)類一些熟悉有助于你更快的明白觀點(diǎn)和這里的 例子,但并非是閱讀本指南必須的,。 我們將學(xué)習(xí)的例程序如下 · 一個簡單的音頻播放器(JMF的HelloWorld應(yīng)用):這個字符界面的播放器通過在命令行中簡單的輸入媒體文件的名字就可以播放大多數(shù)的音頻類型,。此音頻播放器的演示大體上顯示了JMF的特有的類。 · 一個圖形界面的媒體播放器:我們將使用JMF內(nèi)置的接口組件來建立圖形界面,所以在此練習(xí)中必須有一些圖形界面的編程經(jīng)驗,。這個媒體閱覽器演示使用了一些Java AWT和Swing類來為用戶顯示圖形組件,。 · 一個媒體廣播應(yīng)用:此應(yīng)用程序允許一個本地媒體文件通過網(wǎng)絡(luò)傳播。此程序能靈活的使媒體只傳輸?shù)街付ǖ木W(wǎng)絡(luò)節(jié)點(diǎn),,或者傳輸?shù)揭粋€子網(wǎng)絡(luò)中的所有節(jié)點(diǎn),。此演示使用了一些Java的網(wǎng)絡(luò)APIs來在網(wǎng)絡(luò)中傳輸媒體。 作為第三個練習(xí)的一部分,,我們將修改圖形界面的播放器,,讓其能接收并且播放媒體。 跳至23頁觀看Resources,,文章,,指南,和其他參考書目的列表,,這會幫助你學(xué)習(xí)到更到關(guān)于此指南包括的主題,。 安裝需求 要運(yùn)行此指南中的例程序,你需要如下的工具和組件: · Java 2 平臺,,標(biāo)準(zhǔn)版,,編譯和運(yùn)行演示程序 · Java媒體框架,版本2.1.1a或者更高 · 一塊已經(jīng)安裝并且配置號的適當(dāng)?shù)穆暱?br>· 一臺或者多臺測試機(jī)器 · 演示的源代碼文件在mediaplayer.jar中 最后的一個演示應(yīng)用顯示了JMF在網(wǎng)絡(luò)中的應(yīng)用,。如果需要,,此演示能運(yùn)行在一個獨(dú)立的機(jī)器上,使用此機(jī)器即是傳輸方也是接收方,??墒且^察到在網(wǎng)絡(luò)中使用JMF的所有功能,你仍然需要至少兩臺聯(lián)網(wǎng)的機(jī)器,。 在23頁中的Resources可下載Java 2平臺,完整的源代碼文件,,以及其他一些完成本指南所需要的工具,。 下載安裝文件 將JMF安裝到你的計算機(jī)中的第一步是在JMF的主頁中下載安裝文件,它同樣包括了JMF源代碼和API文檔的鏈接,。23頁的Resources中有下載JMF的鏈接,。 目 前,JMF有Windows, Solaris, Linux等版本,,以及可運(yùn)行在任何裝有虛擬機(jī)的計算機(jī)上一個純Java版本,。為了增加性能,你需要下載一個與你操作系統(tǒng)所適應(yīng)的版本,。任何在一個操作系 統(tǒng)JMF版本下書寫和編譯的代碼都可以方便的移植到另外的操作系統(tǒng)上,。例如,如果你下載了一個Solaris版本的JMF并且編譯了一個類,這些類就可以 在Linux上使用,,不會有任何問題,。 作為選擇,你可以選擇下載純Java版本,,或者跨平臺版本的JMF,。這些版本沒有使用操作系統(tǒng)特有的庫文件。如果沒有合適的JMF版本適合的操作系統(tǒng),,那么跨平臺版本就是一個不錯的選擇,。 安裝JMF 下載完JMF安裝程序后,雙擊安裝程序的圖標(biāo),。 大部分安裝程序都會有個選項,,安裝本地庫到系統(tǒng)目錄中;例如,,Windows版本安裝程序會有一個選項“Move DLLs to Windows/System directory.”,。最好將此選項選中,因為它能確保這些操作系統(tǒng)的庫文件能正確的安裝 在安裝的過程中,,你還需要選擇項目來更新系統(tǒng)的CLASSPATH和PATH變量,。如果這些選項被關(guān)閉,那么在你編譯和運(yùn)行本指南的例程序的時候就需要在classpath中引入JMF的jar文件,。 關(guān)于作者 Eric Olson在Retek Inc工作的軟件工程師,。它在Java平臺上有四年的工作經(jīng)驗,并且在不同的基于Java的技術(shù)上富有經(jīng)驗,,包括JMF, Jini, Jiro, JSP, servlets, and EJBs,。Eric畢業(yè)于St. Paul, MN的St. Thomas大學(xué),獲得計算機(jī)科學(xué)的學(xué)位,。他在IBM的SanFrancisco項目組工作,,負(fù)責(zé)WebSphere商業(yè)組件。他同時再為Imation Corp.工作,,負(fù)責(zé)存儲應(yīng)用?,F(xiàn)在,他正在開發(fā)零售行業(yè)的基于web的軟件解決方案,。再業(yè)余的時間,,Eric和Paul Monday在Stereo Beacon上合作—一個分布式的點(diǎn)對點(diǎn)的基于JMF的媒體播放器。聯(lián)系 Eric [email protected]. 第二節(jié). 一個簡單的音頻播放器 瀏覽 在本節(jié)中,,我們將進(jìn)行創(chuàng)建一個簡單的音頻播放器的第一個練習(xí),。本例將介紹Manager類和Player接口,中兩個都是建立大多數(shù)基于JMF應(yīng)用的重要部分,。 本例的功能目標(biāo)是在字符界面下播放本地的音頻文件,。我們將學(xué)習(xí)此源代碼,,并了解每一行所做的任務(wù)。完成本節(jié)后,,你將會有一個基于JMF的可播放包括MP3, WAV, AU等多種音頻文件的演示程序,。 在本練習(xí)后的源代碼分類種可查詢文件SimpleAudioPlayer.java。 引入必要的類 SimpleAudioPlayer類中包括了一些調(diào)用,,在其前幾行中需要引入所有必要的類: import javax.media.*; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.MalformedURLException; The javax.media包是由JMF定義的多個包之一,。javax.media是一個核心包,包括了定義Manager類和Player接口等,。本節(jié)中,,我們主要學(xué)習(xí)Manager類和Player接口,其余的javax.media類放在后面的章節(jié)中,。 除了引入javax.media聲明外,,以上的代碼片斷引入了一些創(chuàng)建媒體播放器的輸入的聲明。 Player接口 在下面的代碼片斷中,,創(chuàng)建一個公共類SimpleAudioPlayer并舉例定義一個Player變量: public class SimpleAudioPlayer { private Player audioPlayer = null; 術(shù) 語Player聽起來由點(diǎn)熟悉,,因為它是建立在我們公用的音頻或者視頻播放器的基礎(chǔ)上的。事實(shí)上,,這個接口的例子就像是當(dāng)作它們的真實(shí)的副本,。 Players揭示了一個實(shí)體上的媒體播放器(如立體音箱系統(tǒng)或者VCR)涉及到功能上的方法。例如,,一個JMF媒體播放器可以開始和結(jié)束一個媒體流,。在 本節(jié)種,我們將使用Player的開始和結(jié)束功能,。 在一個文件上創(chuàng)建一個Player 使用JMF獲得一個特定媒體文件的Player實(shí)例非常簡單,。Manager類在JMF中如同一個工廠制作許多的特殊接口類型,包括Player接口,。因此,,Manager類的責(zé)任就是創(chuàng)建Player實(shí)例,如下例: public SimpleAudioPlayer(URL url) throws IOException, NoPlayerException, CannotRealizeException { audioPlayer = Manager.createRealizedPlayer(url); } public SimpleAudioPlayer(File file) throws IOException, NoPlayerException, CannotRealizeException { this(file.toURL()); } 如果你看完本節(jié)的代碼,,你可以注意到Manager類包含了創(chuàng)建一個Player實(shí)例的其他方法,。我們會研究其中的一些,如在后面的章節(jié)中的DataSource或者M(jìn)ediaLocator的實(shí)例化,。 Player的狀態(tài) JMF定義了大量的一個Player實(shí)例可能存在的不同狀態(tài)。如下: · Prefetched · Prefetching · Realized · Realizing · Started · Unrealized 使用這些狀態(tài) 因 為使用媒體常常是資源非常密集的,,由JMF對象揭示的許多方法都是不閉塞的,,允許一系列事件監(jiān)聽的狀態(tài)改變的異步通知。例如,,一個Player在它可以啟 動之前,,必須經(jīng)過Prefetched和Realized狀態(tài)。由于這些狀態(tài)的改變都需要一些時間來完成,JMF媒體應(yīng)用可以分配一個線程來初始化創(chuàng)建 Player實(shí)例,,然后再繼續(xù)其他的操作,。當(dāng)Player準(zhǔn)備就緒的時候,它會通知應(yīng)用程序其狀態(tài)已經(jīng)改變,。 在一個如同我們的這樣簡單的 程序中,,多功能性的類型并不是很重要。處于這個原因,,Manager類也提供了一些創(chuàng)建Realized player的有用方法,。調(diào)用一個createRealizedPlayer()方法來阻塞調(diào)用線程,直到player達(dá)到Realized狀態(tài),。為了調(diào) 用一個無阻塞的創(chuàng)建player的方法,,我們在Manager類中使用了一個createPlayer()方法。下面的一行代碼中創(chuàng)建了一個我們需要在例 程序中使用的 Realized player: audioPlayer = Manager.createRealizedPlayer(url); 啟動和停止Player 設(shè)定一個Player實(shí)例的啟動或是停止就如同調(diào)用Player的一個簡單的認(rèn)證方法,,如下所示: public void play() { audioPlayer.start(); } public void stop() { audioPlayer.stop(); audioPlayer.close(); } 調(diào)用SimpleAudioPlayer類中的play()方法來實(shí)現(xiàn)調(diào)用Player實(shí)例的start()方法,。調(diào)用此方法后,你能聽到本地的喇叭的聲音文件,。同樣的,,stop()方法使player停止并且關(guān)閉掉Player對象。 對 于讀取和或者播放本地媒體文件來說,,關(guān)閉Player實(shí)例釋放所有資源是一個有用的方法,。因為這是一個簡單的例子,關(guān)閉Player是終止一個會話可接受 的方法,。但是在實(shí)際的應(yīng)用中,,你需要小心的確認(rèn)在除掉Player之前必須要關(guān)閉掉。一但你已經(jīng)關(guān)閉掉player,,在再次播放一個媒體之前你必須要創(chuàng)建 一個新的Player實(shí)例(等待它的狀態(tài)改變),。 建立一個SimpleAudioPlayer 最后,這個媒體播放應(yīng)用程序要包含一個可以從命令提示行中輸入命令而調(diào)用的main()方法,。在此main()方法中,,我們將調(diào)用創(chuàng)建SimpleAudioPlayer的方法: File audioFile = new File(args[0]); SimpleAudioPlayer player = new SimpleAudioPlayer(audioFile); 在播放音頻文件之前的唯一的一些事情就是調(diào)用已經(jīng)創(chuàng)建的音頻player的方法play(),如下所示: player.play(); 要停止和清除掉音頻player,,在main()方法中也應(yīng)該有如下調(diào)用: player.stop(); 編譯和運(yùn)行SimpleAudioPlayer 通過在命令提示行輸入javac SimpleAudioPlayer.java來編譯例程序,。所創(chuàng)建的文件SimpleAudioPlayer.class在當(dāng)前工作目錄中。 然后在命令提示行中鍵入如下命令來運(yùn)行例程序: java SimpleAudioPlayer audioFile 將audioFile替換成你本地機(jī)器上的音頻文件,。所有的相對文件名都試相對于當(dāng)前的工作目錄,。你會看到一些當(dāng)前正在播放文件的標(biāo)志信息。要終止播放,,按下回車鍵,。 如果編譯失敗,,確認(rèn)JMF的jar文件已經(jīng)正確的包含在CLASSPATH環(huán)境變量中。 第三節(jié). JMF用戶界面組件 播放視頻 在 前一節(jié)中,,我們學(xué)習(xí)了建立一個通過字符界面播放音頻文件的應(yīng)用程序,。JMF中一個最重要的特點(diǎn)就是你不需要為了配置媒體播放器而去了解媒體文件的格式;一 切都內(nèi)置了,。舉一個例子,,再我們前面的例子中,需要使用MP3格式的時候,,我們不需要讓應(yīng)用程序為一個MP3文件建立一個特殊的Player,。 如同你將會再本節(jié)所見到的,對于視頻文件的操作同樣有效,。JMF有所有媒體文件類型接口的詳細(xì)資料,。 處理視頻媒體與音頻最大的不同就是,我們必須建立一個能播放視頻的顯示屏幕,。幸運(yùn)的是,,JMF能處理許多的這些資料。如同再上例一樣我們會建立一個Player對象,,并且使用很多的可視組件來直接從JMF對象中創(chuàng)建我們的可視的媒體瀏覽器,。 本節(jié)中,我們將學(xué)習(xí)兩個例程序,。In this section, we'll walk through the second example application. 請再后面的練習(xí)的源代碼分布中查閱MediaPlayerFrame.java,。 關(guān)于例子 在 本節(jié)中,我們將創(chuàng)建一個能顯示和運(yùn)行本地音頻和視頻媒體的應(yīng)用程序,。作為練習(xí)的一部分,,我們將研究JMF內(nèi)置的一些GUI組件。熟悉AWT和Swing將 有助于你理解本例,,但這并不是必須的,。除非需要直接涉及到JMF的GUI組件,或者我們是不會詳細(xì)介紹源代碼的,。你可以在源代碼的注釋中找到這里未涉及的 詳細(xì)說明,。 本例中我們使用的許多概念,類和方法都和第一個例子的類似,。建立Player的基本操作大都一樣,。最大的不同就是我們需要對Player對象專研更深一點(diǎn),特別當(dāng)需要從Player獲取媒體信息的時候,。 如何開始 視頻播放器例子被設(shè)計得如同音頻播放例子一樣通過命令行來運(yùn)行,,但是本例需要建立在GUI基礎(chǔ)上。如同在上節(jié)一樣,,我們先通過媒體文件名調(diào)用應(yīng)用,。然后,應(yīng)用程序顯示一個帶有可操作媒體組件的窗體,。 在MediaPlayerFrame開始的一行中我們定義了類并擴(kuò)展自,,javax.swing.Jframe類。這就是使媒體播放器如同一個在桌面上的單獨(dú)窗體的方法,。任何客戶機(jī)程序創(chuàng)建了本媒體播放對象后都可以通過調(diào)用Jframe類中定義的show()方法來顯示,。 下面是一個MediaPlayerFrame正在播放MPEG電影的屏幕截圖: 獲取GUI組件 Player界面有一些方法來獲取已選擇可視組件的涉及。在MediaPlayerFrame中,,我們使用如下組件: · player.getVisualComponent()是一個播放所有視頻媒體的可視組件,。 · player.getControlPanelComponent() 是一個操作時間軸的可視組件(包括開始,停止,,回放),,也包含了一些媒體流的有用信息。 · player.getGainControl().getControlComponent() 是操作音量(增加)的可視組件,。getGainControl()方法返回一個GainControl實(shí)例,,可用于改變節(jié)目的增加等級。 使用可視化組件 上面的界面方法都返回一個java.awt.Component類的實(shí)例,。沒個實(shí)例都視可加載到我們窗體上的可視組件,。這些組件都與Player有直接的聯(lián)系,所以在這些組件上的所有可視元素的處理都會產(chǎn)生Player播放媒體后相應(yīng)的變化,。 在 我們將這些組件加入到我們的窗體的之前,,必須要保證它們不為空。因為并不是所有的媒體播放器包括每一種可視組件,,我們只需添加相關(guān)播放器類型的組件,。比 如,一般來說一個音頻播放器沒有可視組件,,所以getVisualComponent()就要返回空,。你不會想在音頻播放器窗體上添加可視組件的。 獲得媒體的特殊控制 一 個Player實(shí)例也可以通過getControl()和getControls()方法來暴露其控制,,getControls()返回一個控制對象集,, 而getControl()返回一個控制。不同的播放器類型可選擇為特殊的操作來暴露控制集去指定的媒體類型,,或者用于獲取該媒體的傳輸機(jī)制,。如果你在寫 一個只支持某些媒體類型的播放器,你需要依靠某些在Player實(shí)例中可用Control對象,。 由于我們的播放器是非常抽象的,,被設(shè)計于播放多種 不同媒體類型,我們簡單的為用戶暴露所有的Control對象,。如果找到任何擴(kuò)展的控制集,,我們就可使用getControlComponent()方法 來增加相應(yīng)的可視控件到標(biāo)簽面板上,。通過這個辦法,用戶就可以觀察播放器上的所有組件,。以下代碼片斷將所有的控制對象暴露給用戶: Control[] controls = player.getControls(); for (int i = 0; i < controls.length; i++) { if (controls[i].getControlComponent() != null) { tabPane.add(controls[i].getControlComponent()); } } 為 了使一個真實(shí)的應(yīng)用程序能用Control實(shí)例做一些有用的事(除了能顯示可視組件之外),,應(yīng)用程序需要知道該Control的特殊類型,并分配它,。此 后,,應(yīng)用程序就可使用這些control來控制媒體節(jié)目了。例如,,如果你知道你經(jīng)常使用的媒體暴露 javax.media.control.QualityControl類型的Control,,你能使用QualityControl界面,之后在 QualityControl界面上通過調(diào)用各種方法來改變性質(zhì)設(shè)定,。 使用一個MediaLocator 在我們新的基于GUI的媒體播放器和我們的第一個簡單播放器之間最大的不同就是,,我們使用一個MediaLocator對象而不是URL來創(chuàng)建Player實(shí)例,如下所示: public void setMediaLocator(MediaLocator locator) throws IOException, NoPlayerException, CannotRealizeException { setPlayer(Manager.createRealizedPlayer(locator)); } 我 們將在稍后的章節(jié)中討論這個變化的原因,。目前,,在網(wǎng)絡(luò)上資源站點(diǎn)上,關(guān)于MediaLocator對象和URL的描述被認(rèn)為是非常相似的,。事實(shí)上,,你可以 從一個URL創(chuàng)建一個MediaLocator,也可以從MediaLocator獲取到URL,。我們的新媒體播放器一個URL中創(chuàng)建一個 MediaLocator,,并使用該MediaLocator通過文件創(chuàng)建了一個Player。 編譯和運(yùn)行MediaPlayerFrame 通過在命令提示行輸入javac MediaPlayerFrame.java來編譯例程序,。在工作目錄下將創(chuàng)建一個名為MediaPlayerFrame.class的文件,。 在命令提示行中鍵入如下來運(yùn)行例程序: java MediaPlayerFrame mediaFile 你需要用你本機(jī)上的一個媒體文件來替換掉mediaFile(音頻或者視頻文件都可以)。所有的相對文件名都是相對于當(dāng)前工作目錄,。你會看見一個顯示控制媒體文件的GUI控制集的窗口,。欲了解JMF支持的音頻和視頻文件列表,在23頁的資源,。 如果初始編譯時失敗,,請確認(rèn)JMF的jar文件已經(jīng)包含在當(dāng)前的CLASSPATH環(huán)境變量中。 MediaPlayerFrame在行動 在本節(jié)前你看見的一個視頻播放器正在播放MPEG視頻文件的屏幕截圖,。下面的屏幕截圖顯示了一個音頻播放器正在播放一個MP3文件: 要更多的學(xué)習(xí)本練習(xí)中的例子,,查看完成的MediaPlayerFrame源代碼。 第四節(jié). JMF概念 JMF體系結(jié)構(gòu) 你 曾見過了使用JMF播放本地媒體文件是多么的容易,,現(xiàn)在我們將后退一步,,來看看一幅是如何通過JMF創(chuàng)建了如此成熟的基于媒體的應(yīng)用程序的大的畫面,是如 何通過JMF創(chuàng)建了如此成熟的基于媒體的應(yīng)用程序。全面的了解JMF體系結(jié)構(gòu)是沒有意義的,,本節(jié)將給你一個大體的概念,,關(guān)于高級的JMF組件是如何組合起 來創(chuàng)建想得到的東西。 JMF的組件結(jié)構(gòu)非常的靈活,,它的組件一般可以分成三個部分: · Input描述某種被用于在進(jìn)程休息的時候作為一個輸入的媒體,。 · process執(zhí)行某些輸入上的活動。一個過程有一個明確的輸入和輸出,。大量的過程可用, 能被用于一個輸入或者一批輸入。這些過程能被聯(lián)系起來,,一個過程的輸出被用于另外一個過程的輸入,。在這種風(fēng)格中,大量的過程可能被應(yīng)用于一個輸入,。(這段 期間是可選擇的——我們開始的兩個例子沒有包含真正的數(shù)據(jù)過程,,只有一個來自文件的輸入和一個通過Player的輸出。) · Output 描述了媒體的某些目的地,。 從這些描述中,,你可以想象到JMF組件體系結(jié)構(gòu)聽起來就好像在一個典型的立體聲系統(tǒng)或者VCR之后。很容易設(shè)想到,,使用JMF就如同打開電視或者在立體聲音箱系統(tǒng)下調(diào)節(jié)聲音的風(fēng)格,。例如,錄制喜愛的電視節(jié)目的簡單的動作能在這些組件的基礎(chǔ)中: · Input 是電視廣播流,,在同一個頻道運(yùn)輸音頻和視頻,。 · Process 是一個記錄設(shè)備(就是,一個VCR或者許多的數(shù)字設(shè)備)轉(zhuǎn)換模擬或者數(shù)字音頻視頻廣播流成適合復(fù)制到磁帶或其他媒體上的格式,。 · Output 是記錄已格式化軌跡(音頻和視頻)到某些類型的媒體上,。 JMF資料處理模式 以下圖片說明了JMF數(shù)據(jù)處理模塊并對每個類型給出了例子: 使用此模式,很容易明白我們前面的兩個例子,,從文件中輸入音頻和視頻并輸出到本地計算機(jī)上,。在后面的章節(jié)中,我們也會談?wù)撘恍┩ㄟ^傳播和接收音頻媒體的JMF網(wǎng)絡(luò)功能,。 處理模型例子 將JMF 的輸入,,處理和輸出模式聯(lián)系起來,我們能開始想象許多基于媒體的操作都可能通過JMF完成,。一個例子,,轉(zhuǎn)換一種媒體類型為其他類型并將其輸出存儲到一個新 的文件。舉一個例子,,我們想要在不損壞原始文件的前提下轉(zhuǎn)化一個WAV格式的音頻文件為MP3格式,。以下的過程模式插圖,就是我們將開始執(zhí)行轉(zhuǎn)換的步驟: 本例的輸入是一個WAV文件,。它被一個媒體格式轉(zhuǎn)換工具加工,,并輸出到一個新的文件?,F(xiàn)在,讓我們看看JMF API中的這個模式的每一步,。我們使用輸入,,處理和輸出模式作為概念上的路標(biāo)。 JMF輸入 再JMF中,,一般由一個MediaLocator對象來描述一個輸入,。如先前規(guī)定的, MediaLocator的外觀和行為都非常象一個URL,,這樣它可以唯一確定網(wǎng)絡(luò)上的一個資源,。事實(shí)上,使用一個URL來創(chuàng)建一個MediaLocator是完全可能的,;我們在前面的兩個例子中就是這樣做的,。 為 了我們的媒體轉(zhuǎn)換例子,我們需要建立一個MediaLocator來描述最初的WAV文件,。如同我們將在后面的章節(jié)中見到的,,一個 MediaLocator也可以用于描述一個跨越網(wǎng)絡(luò)中媒體流。在這個案例中,,MediaLocator會描述傳播的URL――很像一個被URL指定的在 Web上的資源,,用于取代指定一個本地文件系統(tǒng)的文件來建立MediaLocator。 一個MediaLocator和一個URL之間的不同 要 成功的建立一個URL對象,,需要適當(dāng)?shù)膉ava.net.URLStreamHandler安裝于系統(tǒng)中,。這個流處理的用途是能夠處理被URL描述的流類 型。一個MediaLocator對象并沒有這個需要,。例如,,我們的下個應(yīng)用程序?qū)⑹褂脤?shí)時傳輸協(xié)議(RTP)在網(wǎng)絡(luò)上傳輸音頻。由于多數(shù)的系統(tǒng)都未為 RTP協(xié)議安裝一個URLStreamHandler,,所以創(chuàng)建一個URL對象會失敗,。在這個應(yīng)用中,只有MediaLocator對象會成功,。 要理解更多關(guān)于URL對象以及創(chuàng)建和注冊一個URLStreamHandler的信息,,查閱JDK幫助文檔(查看23頁資源)。 JMF處理機(jī) 當(dāng) 我們使用JMF的時候,,應(yīng)用程序的處理機(jī)組件被Processor接口實(shí)例描述,。你需要已有些熟悉Processor,它擴(kuò)展至Player接口,。由于 Processor繼承直Player接口,,它同樣也從Player繼承所有可用屬性。另外,Processor增加了兩個屬性:Configuring 和Configured,。這些擴(kuò)展的屬性(和與之關(guān)聯(lián)的方法)用于Processor從輸入流收集信息時的通信,。 在我們的最后的例程序中,我們將建立一個Processor用于將MP3編碼格式的音頻轉(zhuǎn)換成適合在網(wǎng)絡(luò)上傳播的格式,。在稍后的板塊中我們會討論創(chuàng)建一個簡單的Processor的步驟,。 JMF輸出 有 少許的方法用于描述JMF中處理模式的輸出狀態(tài)。最簡單的(并且我們將在最后一個例子中使用的)是javax.media.DataSink接口,。一個 DataSink讀取媒體內(nèi)容并且將其傳送到一些目的地,。本節(jié)中最開始的音頻格式轉(zhuǎn)換過程中,MP3(輸出)文件將被DataSink描述,。在我們最后一 個例子中,,我們將使用一個DataSink在實(shí)際上完成網(wǎng)絡(luò)中傳播音頻媒體的工作。一個DataSink是在Manager類中,,由指定一個 DataSource(輸入到DataSink)和一個MediaLocator(輸出到DataSink)完成的。 一個DataSource實(shí)例描述可用于Players,,Processors和DataSinks的輸入數(shù)據(jù),。一個處理機(jī)的輸出也被描述成一個DataSource對象。 這就是為什么處理器能彼此聯(lián)系起來,,在同一媒體數(shù)據(jù)中完成多種操作,。這也是來自Processor的輸出能作為輸入被Player或者DataSink使用的原因(它可將媒體傳遞到輸出目的地)。 一個DataSink的最后目的文件由一個MediaLocator對象說明,。如同前面一樣,,MediaLocator描述一個網(wǎng)絡(luò)資源;這就是媒體流將被傳遞的地方,。 第五節(jié).傳播接收媒體 JMF和實(shí)時傳輸協(xié)議(RTP) 許 多的友善網(wǎng)絡(luò)的特征直接建立在JMF中,,這些使為客戶端程序通過網(wǎng)絡(luò)傳輸和接收媒體非常容易。當(dāng)在一個網(wǎng)絡(luò)上的一個用戶想要接收任何種類的媒體流的時候,, 它不需要在觀看媒體前等待全部的廣播下載到機(jī)器上,;用戶可以實(shí)時的觀看廣播。在流媒體中些提出了這個概念,。通過流媒體,,一個網(wǎng)絡(luò)客戶端能接收到其他機(jī)器上 廣播的音頻,甚至獲取正在發(fā)生的實(shí)況視頻廣播,。 在IETF RFC 1889中定義了實(shí)時傳輸協(xié)議(RTP),。發(fā)展在快速和可靠的狀態(tài)下通過網(wǎng)絡(luò)傳輸時間極其敏感的數(shù)據(jù),RTP在JMF中用于提供給用戶向其他網(wǎng)絡(luò)節(jié)點(diǎn)中傳輸媒體流的方法,。 在 本節(jié)中,,我們將學(xué)習(xí)我們的最后一個例程序。這里,你將學(xué)習(xí)到如何傳輸一個存儲在一臺機(jī)器上的MP3文件到另外的在同一個網(wǎng)絡(luò)的機(jī)器上去,。實(shí)際的MP3源文 件并不從主計算機(jī)上移除,,它也不使復(fù)制到其他機(jī)器上去;事實(shí)上它將會轉(zhuǎn)換成能使用RTP傳輸?shù)奈募袷讲⑼ㄟ^網(wǎng)絡(luò)發(fā)送,。一旦被一個客戶端接收到,,源文件 (現(xiàn)在是RTP信息包的形式)可以再次傳輸,這一次是在接收機(jī)器上可播放的一種格式,。 在MediaTransmitter.java文件中源代碼查看學(xué)習(xí)以下練習(xí),。 設(shè)置處理模式 我們可以在前面的章節(jié)中定義的處理模式的基礎(chǔ)下來討論我們的最終的例子。在傳輸機(jī)器上,,處理模式看起來像這樣: 事實(shí)上,,MediaTransmitter對象源代碼包括了以下三行: private MediaLocator mediaLocator = null; private DataSink dataSink = null; private Processor mediaProcessor = null; 這三個實(shí)例變量可以直接映射到前面的處理模式圖表,如下: · mediaProcessor變量是我們的處理器,;它將負(fù)責(zé)轉(zhuǎn)換音頻文件從MP3文件模式到一個適合通過RTP協(xié)議傳輸?shù)母袷健?br>· dataSink變量是我們的輸出塊,。 · 當(dāng)我們建立DataSink時我們需要指定一個MediaLocator,它是DataSink的目的文件,。 當(dāng)我們通過運(yùn)行DataSink我們的處理過的媒體,,它將傳輸?shù)轿覀冊贛ediaLocator中指定的地點(diǎn)。 RTP MediaLocator 在 前面的兩個練習(xí)中,,我們通過從文件中獲得的一個URL建立了MediaLocator實(shí)例,。 在本練習(xí)中,我們必須建立一個MediaLocator來描述網(wǎng)絡(luò)上媒體傳播輸出流,;換句話說,,我們必須創(chuàng)建一個能我們的音頻傳播的目的地的 MediaLocator。一個RTP MediaLocator符合如下規(guī)則,,看起來就像一個典型的URL: rtp://address:port/content-type 讓我們看看上面URL規(guī)范的每一段: · address 是將傳輸?shù)拿襟w的地址,。以單播的模式傳輸(一個專用IP地址),地址將會是有意接收的機(jī)器的IP地址,。以廣播的模式傳播(到子網(wǎng)中的所有機(jī)器),,地址將會 是以255作為最后的一塊的子網(wǎng)地址。舉個例子,,如果我再子網(wǎng)中可指定地址為192.168.1和想要傳播到子網(wǎng)中的所有節(jié)點(diǎn),,我可以指定 192.168.1.255作為地址;這樣允許子網(wǎng)中的每個節(jié)點(diǎn)監(jiān)聽廣播媒體,。 · port 必須是被傳輸者和接收者都允許的一個端口,。 · content-type 是媒體流類型。在我們的案子中,,這個將會是音頻,。 下面的一個簡單的RTP傳播MediaLocator例子會讓所有在指定網(wǎng)絡(luò)中的機(jī)器接收到媒體流: rtp://192.168.1.255:49150/audio 創(chuàng)建一個處理機(jī) 在setDataSource()方法中我們首先要做的就是創(chuàng)建一個Processor實(shí)例,。 下面的Processor的職責(zé)是轉(zhuǎn)換MP3音頻媒體為一個RTP來表示: public void setDataSource(DataSource ds) throws IOException, NoProcessorException, CannotRealizeException, NoDataSinkException { mediaProcessor = Manager.createRealizedProcessor( new ProcessorModel(ds, FORMATS, CONTENT_DESCRIPTOR)); 在Manager類中,我們能創(chuàng)建一個Processor對象,,通過兩種方法中的一種: createProcessor ()或者createRealizedProcessor(),。你很可能會注意到這兩個方法樣式的顯示和前面例子中創(chuàng)建一個Player的方法很相似。在 目前的例子中,,我們將創(chuàng)建一個已實(shí)現(xiàn)的Processor,。我們這樣做是因為我們使用的應(yīng)用非常簡單,在Processo處于Realized狀態(tài)時我們 不需要關(guān)心任何真實(shí)的工作。 創(chuàng)建一個ProcessorModel 創(chuàng)建一個已實(shí)現(xiàn)的Processor,我們需要創(chuàng)建一個為Processor描述輸入和輸出媒體類型的ProcessorModel實(shí)例,。為了創(chuàng)建ProcessorModel,我們需要下面的一些: · 一個DataSource,,將被處理的媒體(輸入文件)。 · 一個javax.media.Format數(shù)組,描述輸入媒體的格式。 · 一個javax.media.protocol.ContentDescriptor實(shí)例,,為我們的處理機(jī)描述輸出格式。傳送者的DataSource是通過一個參數(shù)傳遞到此方法,。 定義輸入和輸出格式 因 為我們的MediaTransmitter類會被時常用于將輸入媒體格式(MP3)轉(zhuǎn)換成一種輸出格式(音頻RTP),,中學(xué)對象被定義成靜態(tài)。我們創(chuàng)建一 個新的javax.media.format.AudioFormat實(shí)例用于描述媒體輸入類型(在java幫助文檔中查看可用格式),。這就是我們的處理 機(jī)可以獲取MP3音頻文件的原因。 我們也創(chuàng)建一個javax.media.protocol.ContentDescriptor實(shí)例來描述想要處理機(jī)輸出的,。在我們的案子中,,這是一個RTP媒體流。 這就是為什么我們的處理機(jī)可以只制造RTP流,。 下面的代碼片斷顯示了我們?nèi)绾卧O(shè)置格式和內(nèi)容描述符變量,,用于創(chuàng)建ProcessorModel對象: private static final Format[] FORMATS = new Format[] { new AudioFormat(AudioFormat.MPEG_RTP)}; private static final ContentDescriptor CONTENT_DESCRIPTOR = new ContentDescriptor(ContentDescriptor.RAW_RTP); 連接輸入,處理機(jī)和輸出 現(xiàn)在我們有一個處于Realized狀態(tài)的Processor,,我們需要設(shè)置DataSink以能實(shí)際上傳播RTP媒體,。創(chuàng)建DataSink是簡單的大概使用另外一個調(diào)用給Manager對象,如下所示: dataSink = Manager.createDataSink(mediaProcessor.getDataOutput(), mediaLocator); createDataSink ()方法獲取新Processor的輸出(作為一個DataSource參數(shù))和MediaLocator對象,,我們和MediaTransmitter 對象同時建立的,。通過這樣,你能開始我們的不同的組件是如何在處理模式中聯(lián)系起來的:我們從一個Processor中獲取輸出并使用他們作為輸入到其他組 件,。在這個特殊的應(yīng)用中,,Processor輸出用于傳輸媒體的DataSink的一個輸入。 創(chuàng)建一個DataSource實(shí)例 在這點(diǎn)上,,我們?nèi)慷际亲龊驮O(shè)置我們的媒體播放器的廣播傳輸,。 我們需要創(chuàng)建DataSource對象,,我們用于創(chuàng)建處理機(jī)(就是,在我們的MediaTransmitter中,,參數(shù)傳遞到setDataSource()方法),。下面是創(chuàng)建一個DataSource實(shí)例的代碼: File mediaFile = new File(args[1]); DataSource source = Manager.createDataSource(new MediaLocator( mediaFile.toURL())); 這 段代碼是在MediaTransmitter對象中的vmain()方法。這里我們通過從命令行輸入的第二個參數(shù)創(chuàng)建一個File對象,。我們通過文件創(chuàng)建 一個MediaLocator,,而后通過位置創(chuàng)建一個DataSource。這個新近創(chuàng)建的DataSource是一個涉及到傳送者的輸入文件,。我們能使 用這個DataSource初始化傳輸者,。 開始和停止MediaTransmitter 我們通過調(diào)用其中的startTransmitting()方法來開始MediaTransmitter,如下所示: public void startTransmitting() throws IOException { mediaProcessor.start(); dataSink.open(); dataSink.start(); } 這個方法首先開啟處理機(jī),,然后打開并啟動DataSink,。在這個調(diào)用后,接收機(jī)器就可在媒體傳送者上監(jiān)聽,。 停止傳輸者是非常簡單的,。以下代碼將DataSink和Processor都停止和關(guān)閉掉: public void stopTransmitting() throws IOException { dataSink.stop(); dataSink.close(); mediaProcessor.stop(); mediaProcessor.close(); } 編譯和運(yùn)行MediaTransmitter 通過在命令行中輸入javac MediaTransmitter.java來編譯例程序,可在你的工作目錄中生成一個同名的.class文件,。 要運(yùn)行例程序,,在命令提示行中輸入以下代碼: java MediaTransmitter rtpMediaLocator audioFile 此例將創(chuàng)建一個myAudio.mp3文件的媒體廣播。不要忘記將rtpMediaLocator替換成一個媒體傳輸?shù)腞TP URL,,如同先前討論的,。 你同樣也需要將audioFile替換成你本機(jī)的音頻文件名。 所有的相對文件名都是相對于當(dāng)前工作目錄的,。你會看見一些信息標(biāo)志正在播放的文件,。按下Enter鍵來停止播放。 為傳送者的一個例命令行交互如下: java MediaTransmitter rtp://192.168.1.255:49150/audio myAudio.mp3 如果初始編輯失敗,,確定JMF的jar文件包含CLASSPATH環(huán)境變量中,。要近一步探索本程序和練習(xí),請查閱MediaTransmitter源代碼,。 接收傳輸?shù)拿襟w 現(xiàn)在你可能會問,,“如果沒有人可以看或者收聽的話,這個傳播媒體有什么好的,?” 幸運(yùn)的是,,設(shè)定一個接收傳播媒體的客戶端只需要對我們在第二個例程序的MediaPlayerFrame源代碼做很小的改動。 MediaPlayerFrame類需要一個很小的調(diào)節(jié)來接收和播放音頻文件,。在main()方法中,,你需要注釋掉如下的一行: mpf.setMediaLocator(new MediaLocator(new File(args[0]).toURL())); 并且輸入如下的一行: mpf.setMediaLocator(new MediaLocator(args[0])); 這個簡單的改動允許我們通過String來創(chuàng)建一個MediaLocator對象,而不是通過創(chuàng)建一個File來創(chuàng)建MediaLocator,。 其他代碼都一樣,。 指定RTP URL 在12頁的說明編譯和運(yùn)行MediaPlayerFrame介紹了如何編譯和運(yùn)行MediaPlayerFrame例程序,。這唯一的不同就是你需要為傳輸者指定RTP URL。為接收者的例命令行交互如下: java MediaPlayerFrame rtp://192.168.1.255:49150/audio
|
|