现在的位置: 首页 > 综合 > 正文

JMF API 中文指导台湾版(2)

2013年01月18日 ⁄ 综合 ⁄ 共 17743字 ⁄ 字号 评论关闭
JavaTM Media Framework API Guide    NO.3
 September 11, 2000
 
Controlling a Player 
       Creating a Player 
       Displaying Media Interface Components 
       Setting the Playback Rate 
       Setting the Start Position 
       Preparing to Start 
       Starting and Stopping the Presentation 
       Releasing Player Resources 
Querying a Player 
       Getting the Playback Rate 
       Getting the Media Time 
       Getting the Time-Base Time 
       Getting the Duration of the Media Stream 
Responding to Media Events 
        Implementing the ControllerListener Interface 
       Using ControllerAdapter 
Synchronizing Multiple Media Streams 
       Using a Player to Synchronize Controllers 
       Synchronizing Players Directly 
Example: Playing an MPEG Movie in an Applet 
      Overview of PlayerApplet 
      Initializing the Applet 
      Controlling the Player 
      Responding to Media Events 
Presenting RTP Media Streams 
      Listening for RTP Format Changes 
 

Presenting Time-Based Media with JMF
以JMF呈現以time-base為主的 Media像是audio或video,我們可以使用 Playback去控制媒體,或是讓使用者用控制面板去控制錄放功能。
如果有多個media streams,要撥放每一個,都需要用單獨的player去撥放;若要同步撥放它們,需要使用一個player物件去控制其他的operation。
Processor是種特殊裝置的player,它可以去處理、控制展示前的媒體資料,不論是使用基本的或較高階的player都需要用到一些methods去管理錄放裝置,MediaPlayer bean是可以提供一個簡單的方法在我們在Applet或Applictation實現media player,當選擇不同的串流媒體時,MediaPlayer bean會自動產生一個新的player。

Controlling a Player
撥放media stream,我們需要先建構一個plyaer,安裝並且準備執行。
Creating a Player
我們可以透過media Manager間接地去建構一個player,首先取得player的元件,並且將它們加至Applet或Application上。如果你需要建立一個新的player,你可以從Manager去呼叫createPlayercreateProcessor。Manager使用media URL或MediaLocator去具體的建立一個player,使用URL必須要安裝URLStreamHandler才行,MediaLocator則沒有限制。
Blocking Until a Player is Realized
在Realized狀態下,Player可以呼叫許多methods,當我們呼叫createRealizedPlayer去建立一個Player時,我們可以保證Player是在Realized狀態下;這個method提供一個間單的步驟去建立player。當這個method被呼叫,它會被blocks住直到player完成Realized。同樣地,Manager也提供了createRealizeProcessor方法來建構一個Realized Processor。
Using a ProcessorModel to Create a Processor 
Processor只能使用Processor Model,它定義了Processor輸入與輸出條件,用ProcessorModel建立processor時,我們需要呼叫Manager.createRealizedProcessor method(Example3-1)去建立一個Realized Processor,可以產生一個44.1kHz 16-bit的IMA4編碼立體聲音軌。
Example 3-1: Constructing a Processor with a ProcessorModel.
AudioFormat afs[] = new AudioFormat[1]; 
afs[0] = new AudioFormat("ima4", 44100, 16, 2); 
Manager.
createRealizedProcessor(new ProcessorModel(afs, null)); 
這個例子並沒有說明資料的來源(URL),但是可以利用擷取設備去擷取聲音或影像經過處裡編成IMA4的格式。需注意的是,當我們在PorcessorModel去建立一個Realized Processor時,我們將不能夠透過Processor object's TrackControls去詳述processing options(詳細資料在p.71)。

Displaying Media Interface Components 
一般player有兩種使用者介面元件:visual component、control-panel component,有些會多加volume controls、download-progress bars。
Displaying a Visual Component 
Media撥放都會有一個視覺元件,甚至有些聲音也會有視覺元件,像是波器或是活動字幕。
為了顯示視覺元件,我們可以:
  1. 呼叫getVisualComponent取得元件
  2. 將原件加入到Applet或Application視窗
你可以透過visualComponent存取所有player物件的屬性、像是x、y軸,而Player components的layout是透過AWT layout做管理。
Displaying a Control Panel Component 
Player通常有一個控制面板供使用者使用,像撥放、停止、暫停‧‧‧‧
每一個Player提供一個內定的control panel。為了顯示一個內定的control panel,我們可以:
  1. 呼叫getControlPanelComponent取得元件
  2. 將傳回元件加到展示視窗
使用者也可以自訂GUI控制元件,如果將制定元件註冊像ControllerListeners,也可以在player更換的時更新它們。
Displaying a Gain-Control Component
Player可以implement GainControl interface來得到聲音的調節裝置。GainControl提供一個可以調整聲音的methods,像是setLevel和setMute。為了顯示GainControlComponent,我們可以:
  1. 從player取得GainControl須呼叫getGainControl,如果傳回null表示沒有支援GainControl interface
  2. 從傳回的GainControl中呼叫getControlControl
  3. 將傳回的元件加入視窗中
須注意:getControl不能傳回Player object's GainControl,只能呼叫getGainControl來access GainControl。
Displaying Custom Control Components
許多player有其他附加的功能,例如亮度、對比,你可以呼叫getControls method找出player支援哪些自訂元件。
Example 3-2: 使用 getControls 找出支援哪些控制.
Control[] controls = player.getControls();
       for (int i = 0; i < controls.length; i++) {
           if (controls[i] instanceof CachingControl) {
                cachingControl = (CachingControl) controls[i];
             }
        } 

Displaying a Download-Progress Component
CachingControl介面是player的一個特殊的型態,可以記載下載的進度,CachingControl提供一個內建的progress-bar,這個progress-barr會在下載進行時自動更新,在Applet內為了使用這個功能,我們必須:
  1. implement ControllerListener interface並且在controllerUpdate中去listen CachingControlEvents
  2. 第一次接收CachingControlEvents
  1. 在事件中呼叫getCachingControl取得caching control
  2. 在CachingControl中呼叫getProgressBar取得內定的projress-bar元件
  3. 加入元件至Applet中
  1. 在每個時間中必須去接收CachingControlEvent用來check是否下載完成,當getContrentProgress傳回來的值等於getContentLength,則移除progress-bar
如果我們要implement自己的progress-bar component,我們必須隨時listen CachingControlEvent和update download progress。

Setting the Playback Rate
Player object's rate決定了media time如何改變,它著重於time-base time;它定義在每一個base-time time中media time前進了多少單位 ,例如,當rate設定為2.0時表示Player撥放時將會比time-based快兩倍的速度撥放。
理論上,Player object's rate可以設定為any real number,negative rates表示player中的media 是倒轉的。對於設定比例,我們可以呼叫setReat,當setReat被呼叫,Method會傳回一個actually set的rate。如果沒有改變將會將rate內定為1.0。

Setting the Start Position
設定player物件的媒體時間相當於設定讀取媒體的時點,媒體資料來源若像是一個檔案,媒體時間是有限制的,最大媒體時間就是媒體流結束的地方,我們可以呼叫setMediaTime可以設定想要的時間。
Frame Positioning
有些player允許尋找特定影像frame,讓你可以容易的設定media起始點。為了要設定frame 的位置,我們可以呼叫FramePositioningControl來尋找method,當你找到frame,就可以設定Player media time的值與frame開始的值相一致,會發出mediaTimeSetEvent。
有些player可以在媒體時間與框架位址間轉換,你可以使用FramePositioningControl mapFrameToTime與mapTimeToFrame 兩種methods存取資料。

Preparing to Start
有些媒體player並不會立即開始,因為在開始前要視某些硬體與軟體連接情況而定,例如沒有啟動過的player需要在記憶體中配置媒體資料緩衝區,如果是網路裝置上的媒體,則需要先建立網路連線。
Realizing and Prefetching a Player
JMF 流程中的兩個階段:Realizing 與 Prefetching。在Player運轉開始後可以執行ControllerListener介面去控制。
可以呼叫realize讓player進入Realizing狀態以及開始realization程序、也可以呼叫Prefetch讓player進入Prefetching程序。realize 與 prefetch methods是非同步的且會自動回傳的。當player完成運作會丟出RealizeCompleteEvent 或 PrefetchCompleteEvent表示player完成這些運作。
Player可以透過setMediaTime設定媒體時間,會傳回Realize狀態並且增加前置時間。
記住Prefetched狀態會佔住系統資源,因為像音效卡一次只能提供一個程式使用,Prefetched狀態會阻礙到其他player的撥放。
Determining the Start Latency
可以呼叫getStartLatency決定開始需要多少時間,將會傳回一個最大可能的開始前置時間,getStartLatenc也可能傳回LATENCY_UNKNOWN 。開始的前置時間是由getStartLatency依Player object's 目前狀態的不同而定。

Starting and Stopping the Presentation
Clock和Player interface定義著starting和stopping的method。
Starting the Presentation
Start mrthod告訴player立即開始展示,如果有需要會執行realize 與prefetch運作,如果在Started Player中start被呼叫後,將丟出startEvent。
Clock定義了syncStart  method,可以用在synchronization(同步)上。
在media stream中要start a Player,必須:
  1.  呼叫setMediaTime.設定想要的開始點
  2.  呼叫player中的start
Stopping the Presentation
有四種情況將被停止:
  1. 當stop method被呼叫時
  2. 當到達指定停止的時間時
  3. 當媒體撥放完畢時
  4. 接收速度低於撥放裝置可接受值時
當Player被停止時,假如媒體來源是被控制住的,那media time也會被凍結住。如果是串流媒體則不能凍結媒體時間,媒體時間會繼續前進。當Stopped重新開始,時間會從暫停的地方繼續前進。如果執行stop於一個已經停止的player,將會丟出一個StopByRequestEvent
Stopping the Presentation at a Specified Time 
我們可以呼叫setStopTime來指定Player何時要停止,媒體時間到達設定時間就會停止。如果正在撥放媒體的時間已經超過設定的時間,將會立即停止撥放。如果已經設定過停止時間,再去設定就會產生一個錯誤。
你可以呼叫getStopTime取得currently scheduled stop time.(目前停止時間表單),如果clock沒有scheduled stop time,getStopTime會傳回Clock.RESET,如果移除設定的時間,媒體將會撥放到結束為止。

Releasing Player Resources 
我們可以呼叫deallocate method釋放player全部的資源,像緩衝器、內部記憶體。deallocate method只能在停止的player上呼叫。為了避免產生ClockStartedErrors,我們必須先呼叫stop再呼叫deallocate。在Prefetching 或 Prefetched狀態呼叫deallocate將會回到Realized狀態,如果是在Realized狀態呼叫deallocate player會丟出一個DeallocateEvent並且傳回一個 Unrealized狀態。
當你完成一個player或是不再使用,你必須呼叫close,它會釋放所有的資源,所有的控制元件關閉後會丟出一個ControllerClosedEvent,並且不能重新開啟,否則會產生錯誤。

Querying a Player
Player有提供一切資訊,例如撥放比例、媒體時間以及長度。
Getting the Playback Rate
呼叫getRate可以傳回撥放裝置比例值。
Getting the Media Time 
呼叫getMediaTime可以得到媒體時間,如果不是目前的媒體資料,將會顯示媒體展示的開始點。
圖為Frame duration and media time.
例如有一個player撥放一個frame要5秒,原本的比例設定為0.2
如果開始時間在0.0,就會從0.0到5.0會撥放第一個frame,如果從2.0開始撥放,直到5.0時,第一個畫面只會顯示3秒。
Getting the Time-Base Time
我們可以由Player object's TimeBase和呼叫getTime,得到Player object's 目前的time-base time:
myCurrentTBTime = player1.getTimeBase().getTime();
當player正在執行,可以呼叫mapToTimeBase取得時間基準。
Getting the Duration of the Media Stream
我們可以從Controllers去implement Duration interface,知道知道串流媒體的長度,這一個interface只定義了單一的method:getDuration。如果無法決定媒體長度的話,當我們呼叫getDuration,會傳回DURATION_UNKNOWN。但是像現場立即的廣播不知道長度,執行get Duration則會傳回一個DURATION_UNBOUNDED。
Responding to Media Events
ControllerListener是一個Asynchronous interface(非同步介面),透過Controller objects處理事件產生,可以去管理像prefetching的operations。
Implementing the ControllerListener Interface
為了Implementing the ControllerListener Interface,必須:
  1. 在class中 implement ControllerListener interface
  2. Register that class as a listener by calling addControllerListener on the Controller that you want to receive events from. 
當一個Controller丟出event時,它會在其他的觸發事件上去呼叫controllerUpdate,而ControllerUpdate像是在執行一連串的if-else敘述。

Example 3-3: Implementing controllerUpdate.

if (event instanceof EventType){
...
} else if (event instanceof OtherEventType){
...
}
有些ControllerEvents包含額外的狀態資訊,例如StartEvent
StopEvent classes定義一個method允許你當事件發生時可以重新取得媒體時間。

Using ControllerAdapter
用ControllerAdapter執行ControllerListener介面
Example 3-4: Using ControllerAdapter.
 player.addControllerListener(new ControllerAdapter() {

    public void endOfMedia(EndOfMediaEvent e) {

      Controller controller = e.getSource();

       controller.stop();

       controller.setMediaTime(new Time(0));

       controller.deallocate();
    }
 })


Synchronizing Multiple Media Streams
同步複合的串流媒體錄放裝置要結合TimeBase,需要用到clock介面的getTimeBasesetTimeBase methods定義,例如要同步兩個player,player1要使用player2的時間。
player1.setTimeBase(player2.getTimeBase());

當player同步之後還是可以個別的控制。


Using a Player to Synchronize Controllers
同步player直接使用syncStart,JMF提供一個簡單的方法,一個player可以管理運作任何的控制器。
一般而言需要同步player或是控制器,必須使用到addController裝置,它比個別管理同步的player更快速、簡單、更少錯誤。

當player採用控制器控制
Controller採用player物件基準時間
Player物件時間長度變長
Player物件前置時間變長

Adding a Controller
addController method加入一個控制器到player,必須回到Realized狀態,否則會送出NotRealizedError,在player1還沒有移除控制器時player2不能使用。在player2呈現player1控制:

player2.addController(player1);

Controlling Managed Controllers
Function
Stopped Player
Started Player
setMediaTime
Invokes setMediaTime on all managed Controllers.
Stops all managed Controllers, invokes setMediaTime, and restarts Controllers.
setRate
Invokes setRate on all managed Controllers. Returns the actual rate that was supported by all Controllers and set.
Stops all managed Controllers, invokes setRate, and restarts Controllers. Returns the actual rate that was supported by all Controllers and set.
start
Ensures all managed Controllers are Prefetched and invokes syncStart on each of them, taking into account their start latencies.
Depends on the Player implementation. Player might immediately post a StartEvent.
realize
The managing Player immediately posts a RealizeCompleteEvent. To be added, a Controller must already be realized.
The managing Player immediately posts a RealizeCompleteEvent. To be added, a Controller must already be realized.
prefetch
Invokes prefetch on all managed Controllers.
The managing Player immediately posts a PrefetchCompleteEvent, indicating that all managed Controllers are Prefetched.
stop
No effect.
Invokes stop on all managed Controllers.
deallocate
Invokes deallocate on all managed Controllers.
It is illegal to call deallocate on a Started Player.
setStopTime
Invokes setStopTime on all managed Controllers. (Player must be Realized.)
Invokes setStopTime on all managed Controllers. (Can only be set once on a Started Player.)
syncStart
Invokes syncStart on all managed Controllers.
It is illegal to call syncStart on a Started Player.
close
Invokes close on all managed Controllers.
It is illegal to call close on a Started Player.
Table 3-1: Calling control methods on a managing player.Removing a Controller使用removeController method移除player上的控制器,在player2上釋放player1的控制:
player2.removeController(player1);

Synchronizing Players Directly在一些情況,需要靠自己去管理複合的同步player物件,可以個別控制比例、媒體時間,你必須:
1.     每一個同步player註冊觸發事件
2.     決定哪一個player基準時間作為其他player的基準時間
3.     設定player的撥放比例,如果沒有支援設定的比例,會傳回比例已經使用(這裡沒有可以詢問是否支援比例的裝置)
4.     所有player進入同步狀態  
5.     player物件同步運作
  • 設定每一個player的媒體時間
  • Prefetch所有player
  • 決定同步player的最大前置開始時間
  • 呼叫syncStart開始同步player物件
如果要改變同步player的時間
1.     首先setMediaTime設定所以同步player物件
2.     呼叫每個player準備開始
3.     當第二次設定被接受,呼叫每一個player停止
4.     setMediaTime設定每一個player新的時間
5.     重新執行prefetching運作
6.     全部的player都在prefetched狀態,呼叫syncStart   

Example: Playing an MPEG Movie in an Applet
java Applet撥放MPEG電影,包含視覺元件與控制面板
HTML中的標記:
Example 3-5: Invoking PlayerApplet.
 <APPLET CODE=ExampleMedia.PlayerApplet 

WIDTH=320 HEIGHT=300> 
 <PARAM NAME=FILE VALUE="sample2.mpg">

 </APPLET>
 
PlayerApplet定義五個步驟
1.     init-透過Applet標記建立一個player
2.     start-當PlayerApplet啟動,開始player
3.     stop-當PlayerApplet停止
4.     destroy-當PlayerApplet移除,關閉player
5.     controllerUpdate-回應player事件
Example 3-6: PlayerApplet.
import java.applet.*;
import java.awt.*;
import java.net.*;
import javax.media.*;

public class PlayerApplet extends Applet implements ControllerListener {
   Player player = null;
   public void init() {
      setLayout(new BorderLayout());
      String mediaFile = getParameter("FILE");
      try {
         URL mediaURL = new URL(getDocumentBase(), mediaFile);
         player = Manager.createPlayer(mediaURL);
         player.addControllerListener(this);
      }

      catch (Exception e) {

         System.err.println("Got exception "+e);
      }

     }

   public void start() {

       player.start();

   }

   public void stop() {
     player.stop();
      player.deallocate();
   }

     public void destroy() {
      player.close();
   }

     public synchronized void controllerUpdate(ControllerEvent event) {

        if (event instanceof RealizeCompleteEvent) {
         Component comp;
         if ((comp = player.getVisualComponent()) != null)
            add ("Center", comp);
          if ((comp = player.getControlPanelComponent()) != null)

            add ("South", comp);     
          validate();
      }

   }
}

 
Initializing the Applet
1.     接收Applet檔案參數
2.     利用檔案參數確定媒體檔案並且建立URL物件
3.     呼叫Manager.createPlayer建立一個player
4.     呼叫addControllerListener註冊applet上的控制觸發事件
Example 3-7: Initializing PlayerApplet.
 public void init() {
    setLayout(new BorderLayout()); 
    // 1. Get the FILE parameter.
    String mediaFile = getParameter("FILE");
    try {
       // 2. Create a URL from the FILE parameter. The URL 
       // class is defined in java.net.
       URL mediaURL = new URL(getDocumentBase(), mediaFile);
       // 3. Create a player with the URL object.
       player = Manager.createPlayer(mediaURL);
       // 4. Add PlayerApplet as a listener on the new player.
       player.addControllerListener(this);
    } 
    catch (Exception e) {
       System.err.println("Got exception "+e);
    }
 }
   

Controlling the Player
這個class定義當Applet包含打開與關閉,自動呼叫startstop methods。
Example 3-8: Starting the Player in PlayerApplet.
 public void start() {
    player.start();
 }
 
Example 3-9: Stopping the Player in PlayerApplet.
 public void stop() {
    player.stop();
    player.deallocate();
 }
 
當Applet離開Player釋放資源供其他player使用並且關閉。
Example 3-10: Destroying the Player in PlayerApplet.
    public void destroy() {
       player.close();
    }
 

Responding to Media Events
PlayerApplet回應一個事件,丟出RealizeCompleteEvent,PlayerApple顯示player的元件
Example 3-11: Responding to media events in PlayerApplet.
 public synchronized void controllerUpdate(ControllerEvent event) 
{
    if (event instanceof RealizeCompleteEvent) {
       Component comp;
       if ((comp = player.getVisualComponent()) != null)
          add ("Center", comp);         
       if ((comp = player.getControlPanelComponent()) != null)
          add ("South", comp);
       validate();
    }
 }
 
PlayerApple等待Player丟出RealizeCompleteEvent,然後顯示內含的視覺元件,與控制面板,呼叫validate觸發layout管理,顯示新加入的元件。
Presenting Media with the MediaPlayer Bean透過MediaPlayer Bean展示媒體
使用MediaPlayer Java Bean是一個間單的方法在Applet或Applications上展示串流媒體,也可以在這上面定義自己的元件。它會再選擇不同的串流媒體時自動產生一個新的player,一個MediaPlayer Bean有幾個特殊用具可以設定
Property
Type
Default
Description
Show control panel
Boolean
Yes
Controls whether or not the video control panel is visible.
Loop
Boolean
Yes
Controls whether or not the media clip loops continuously.
Media location
String
N/A
The location of the media clip to be played. It can be an URL or a relative address. For example:
file:///e:/video/media/
Sample1.mov

http://webServer/media/Sample1.mov

media/Sample1.mov
Show caching
control
Boolean
No
Controls whether or not the download-progress bar is displayed.
Fixed Aspect Ratio
Boolean
Yes
Controls whether or not the media's original fixed aspect ratio is maintained.
Volume
int
3
Controls the audio volume.
MediaPlayer Bean撥放媒體
1.     MediaPlayer 建立一個instance
 MediaPlayer mp1 = new javax.media.bean.playerbean.MediaPlayer();
2.     設定要撥放的位址
mp1.setMediaLocation(new java.lang.String("file:///E:/jvideo/media/
Sample1.mov"));
3.     開始MediaPlayer
    mp1.start();
4.      停止錄放裝置
       mp1.stop();  

Presenting RTP Media Streams展示RTP串流媒體
透過MediaLocator得到RTP-session的參數,JMF player可以展示RTP串流媒體。
Example 3-12: Creating a Player for an RTP session.
         String url= "rtp://224.144.251.104:49150/audio/1";

       MediaLocator mrl= new MediaLocator(url);

         if (mrl == null) {
             System.err.println("Can't build MRL for RTP");
             return false;
        }

         // Create a player for this rtp session
         try {
             player = Manager.createPlayer(mrl);

         } catch (NoPlayerException e) {

            System.err.println("Error:" + e);
            return false;
         } catch (MalformedURLException e) {
           System.err.println("Error:" + e);

           return false;
       } catch (IOException e) {

            System.err.println("Error:" + e);

            return false;

        }
在session中資料是detected,player會丟出RealizeCompleteEvent,藉由觸發事件可以得到視覺與控制元件。  

Listening for RTP Format Change
當player丟出FormatChangeEvent,它顯示格式改變,你必須先移除舊的player元件然後取得新的元件。
Example 3-13: Listening for RTP format changes.
     public synchronized void controllerUpdate(ControllerEvent ce) {

        if (ce instanceof FormatChangeEvent) {
           Dimension vSize = new Dimension(320,0);
           Component oldVisualComp = visualComp;

               if ((visualComp = player.getVisualComponent()) != null) {
                if (oldVisualComp != visualComp) {
                  if (oldVisualComp != null) {
                      oldVisualComp.remove(zoomMenu);
                    }                    
                  framePanel.remove(oldVisualComp);
                      vSize = visualComp.getPreferredSize();
                      vSize.width = (int)(vSize.width * defaultScale);
                      vSize.height = (int)(vSize.height * defaultScale);
                                      framePanel.add(visualComp);

             
                  visualComp.setBounds(0,0,vSize.width,vSize.height); 
                    addPopupMenu(visualComp);
                 }
            }
             Component oldComp = controlComp;
             controlComp = player.getControlPanelComponent();
             if (controlComp != null) 
             {
                 if (oldComp != controlComp)

                 {
                    framePanel.remove(oldComp);
                    framePanel.add(controlComp);
                  
                    if (controlComp != null) {

                       int prefHeight = controlComp.getPreferredSize().height;

                      controlComp.setBounds(0,vSize.height,vSize.width,prefHeight); 
        }

                }

           }

        }
    }

 
 
 
 

 

抱歉!评论已关闭.