文章詳情頁
QuickTime流媒體和Java
瀏覽:66日期:2024-06-14 08:21:13
內容: QuickTime流媒體和Java作者:Chris Adamson譯者:pawenwen版權聲明:任何獲得Matrix授權的網站,轉載時請務必以超鏈接形式標明文章原始出處和作者信息及本聲明作者:Chris Adamson;pawenwen原文地址:http://www.onjava.com/pub/a/onjava/2005/01/12/strmng_qtj.html中文地址:http://www.matrix.org.cn/resource/article/43/43950_QuickTime_Java.html關鍵詞: QuickTime Java這并不是即將問世的QuickTime for Java book一書的摘錄,雖然我希望是的。你看,問題是,在QTJ世界中大多數的我們都一直假定QTJ中的流媒體API已經損壞,我并不是想為此事而掩蓋什么。好的,我繼續來通過各種各樣的人通過不同的技術進行工作的掩蓋獲取去這樣做,但是我不想再來一次。此外,流媒體沖突的情況似乎特別的糟糕。沒有人能得到它的演示代碼工作方式――this post to the quicktime-java list 是令許多用戶對獲取蘋果公司的AudioBroadcaster 和DrawableBroadcaster 演示工作方式絕望的典型。讓事情更糟糕,演示之一依靠一個在QTJ 6.1版本中作為退回到原始的GUI提供的已經被取消的GUI預覽組件類,提供組件只對Movies ,MovieControllers 和GraphicsImporters ,而不是流式的Presentations ,視頻捕捉,或者某些圖形美好得像來自多種資源“合成制作。所以,官方給出的演示它首先看起來是不會工作,和現在的關鍵類有沖突(如果在Java 1.4中運行會拋出RuntimeExceptions異常)。預測實際的流式內容和QTJ 6.1看上去會非常糟糕。令我欣喜,甚至是有點吃驚的是,有報道稱流媒體能夠在QTJ 6.1中工作。在本文章中,我將介紹通過QTJ實現簡單的網絡廣播的基礎需求QuickTime的流媒體API,在Java中由只可在Mac OS(Classic和OS X)中運行的包quicktime.streaming聲明。在QTJ中存在Windows版本的類,但是它們卻不能工作。但是,你可以使用Windows版本的QuickTime作為流媒體的客戶端,如果在Java中運行并不是關鍵的,你可獲取Darwin Streaming Server,一個開源項目可在Windows 2000 Server 和2003 Server上運行如同在Solaris 9 和 Red Hat Linux 9上一樣。使用QuickTime流媒體最簡單的事情就是我在此說明的生動內容。你需要至少一個音頻輸入設備,如一個內置的麥克風或者一個耳機。當然,擁有一個QuickTime支持的攝像機,如一個iSight,將會更讓人印象深刻。Streaming 是什么,不是什么給出了術語“流的含義并不容易明確術語“Streaming 的正確含義。例如,QuickTime長期支持一種“快速啟動的特征――如果QuickTime明確擁有足夠的開始播放的資源并且不會用完目前下載速率下的資源一段錄像能開始播放――那是一些用戶將Streaming 的一種形式弄錯了。自然的,這有它自己的優勢:容易創建并且確保了所有的包都到達了客戶端。但是真正的 Streaming ,換句話說,Streaming 符合Internet工程工作小組(IETF)的標準,這是一個完全不同的問題,直到QuickTime 5才被支持,并且直到QTJ 6才支持Java。Streaming 的形式允許服務器控制傳輸,但很難在實時中保證最優化運行。客戶端未下載潛在的大文件,這樣的方法是獨特的便利的直接廣播。事實上,QuickTime的流媒體使用兩種“實時的流媒體傳輸協議:實時傳輸協議(RTP)來傳輸媒體數據包,實時流協議(RTSP)用于控制信息。RTP使用潛在的有損UDP連接,所以所有的人都有意的忍耐再傳輸期間的包的丟失。這就意味著客戶端需要友好的操作未獲取所有數據的視頻幀或者音頻例子。更好的方法是通過基于TCP/IP的連接,它可以使用不確定的重試(也會因此需要一個不確定的時間)來獲取丟失的包。Presentation和SDP文件在QuickTime中,流媒體傳輸等同一個電影――一個電影可以有音軌和視軌,一個元數據的聚集將它們全都聯系在一起,此表示會將一些多種的音頻和視頻流的元數據聯系起來。音頻和視頻你非常喜歡的流媒體種類也是值得關注的,自從某些其他的媒體類型(sprites,Flash內容)被QuickTime支持后并沒有操作好失去的包,并不適合作為流媒體傳播。你可能被建議去建立一個流媒體,你會需要創建一個Presentation 并開始它。但是現在呢?最普遍的這樣做的方法是創建一個會話描述協議(SDP)文件,將其放入靜態工廠方法Presentation.fromFile()。SDP文件以一種適當的簡單的文本格式,由RFC 2327和several updates所定義。我發現這些都是早期的理論而不是實際操作,但是稍后讓我們擔心的是執行詳細信息。這是一個被一些Apple的流媒體使用的例子,在Tim Monroe的QuickTime Toolkit Volume Two中:v=0c=IN IP4 224.2.1.2/20/1m=audio 1000 RTP/AVP 12m=video 2000 RTP/AVP 101a=rtpmap:101 H263-1998以下是每一行的解釋:· v=0:這是SDP的版本號。在這里版本號是0表示在SDP中沒有次要的號碼。· c=IN IP4 224.2.1.2/20/1:這是提供在描述中使用的連接的信息。IN IP4 表示是一個IPv4的網絡地址。224.2.1.2是地址(注意這是一個多點傳輸地址,所有許多的客戶端能連接到廣播),20是存在時間,1是臨近使用的多點傳輸地址的數量。· m=audio 1000 RTP/AVP 12:m=這一行定義了用于廣播的流媒體。在這里明顯的是audio,發送經由到RTP到端口1000。12在簡單的QCELP音頻中定義了有效負載類型。這些在RFC 3551中定義了。· m=video 2000 RTP/AVP 101:這一媒體行定義了一個video媒體流,由RTP傳輸到端口2000。有效負載類型為95,所以使用101表示在原始的RFC中視頻格式沒有給出負載類型,在SDP中替換它會被映射到一個眾所周知的常量中。· a=rtpmap:101 H263-1998:這個完成鍵入在前一行指出的動態負載。使用此類型,你會使用一個在96和127之間的值(本例中是101),然后用一個字符串命名此負載類型(H263-1998)。這當然好,但是當在我的例程序中使用它的時候,我只獲得了一個視頻流卻沒有聲音。所以,我使用了一個很不同的SDP,最初在QTJ的DrawableBroadcaster演示中出現。是的,他們不贊同這么做:m=audio 2656 RTP/AVP 96c=IN IP4 239.60.60.60a=rtpmap:96 x-qtm=video 2700 RTP/AVP 96a=rtpmap:96 x-qt這里最大的不同就是音頻和視頻都使用了相同的動態負載映射,這并不是針對一個真正的編碼器,而是一般的x-qt。在這里勝利的是你能在運行時間上挑選任一QuickTime的音頻和視頻編碼器,而不是在SDP文件中強迫導致。底側是這些可以不是由非QuickTime客戶端可分析的,反之使用十分標準的和/或者舊的編碼器并且在SDP中指定他們使它更像其他的客戶端(Real, JMF等)能夠操作你的系統。這就是你的SDP文件。現在不要加入一個Presentation。創建Presentation我們的流媒體服務器程序調用LittleBroadcast,這并沒有多少代碼,只有不過140行。在本文中,我將一步一步的進行,解釋一般的部分,但提供其全部的清單。在后面的Resources章節中有可用到一個.tar.gz文件,連同SDP文件和一個Ant構建文件。package com.mac.invalidname.qtjstreaming;import quicktime.*;import quicktime.std.*;import quicktime.util.*;import quicktime.qd.*;import quicktime.io.*;import quicktime.streaming.*;import quicktime.app.time.*;import java.io.*;import java.awt.*;import java.awt.event.*;public class LittleBroadcast extends Tasking implements ActionListener {這是一長串典型的引入QuickTime,包括了使用其QDGraphics來提供一個攝像機畫面以外的圖形界面的qd,讀取SDP文件的io,用于流媒體API的streaming,以及獲得給予Presentation運行時間的有效任務的time。最后一點,注意該類擴展直Tasking――提供周期性調用的task()。本應用程序中,它用于不斷的調用Presentation的idle()方法,并使其循環工作。你在本書中學習到也就是Movies所需要的,但是此任務幾乎一直都自動的為你所操作。使用Presentation并不好運。(或者為此事而捕獲,但有些離開本主題了。) boolean broadcasting = false; public static final int BROADCAST_WIDTH = 176; public static final int BROADCAST_HEIGHT = 144; Button startStopButton; Button configButton; Presentation pres; int presenterTimeScale = 600;這些是服務器的實例變量。是一個用于指定當開始/停止按鈕按下的時候做什么的標記。下面是一對廣播視頻大小的常量,緊跟著是服務器GUI的按鈕。最后是一個Presentation對象,以及它的時間尺度。(媒體的保持時間系統,一個600的時間尺度表示一秒種里有600個單位;600也是QuickTime中默認的。) public static void main (String[] args) { System.out.println ('main'); try { QTSession.open(); new LittleBroadcast(); } catch (QTException qte) { qte.printStackTrace(); } }在這個main中并沒有什么獨特的地方。我投入了所有的精力在構造函數上以防止為那些我需要的實例創建一個內部類。如果你擴展本代碼,你可能會發現這很有用。 public LittleBroadcast() throws QTException { System.out.println ('LittleBroadcast constructor'); QTFile file = new QTFile (new File ('little.sdp')); try { MediaParams mediaParams = new MediaParams(); mediaParams.setWidth (BROADCAST_WIDTH); mediaParams.setHeight (BROADCAST_HEIGHT); QDGraphics myGWorld = new QDGraphics (new QDRect ( BROADCAST_WIDTH, BROADCAST_HEIGHT)); mediaParams.setGWorld (myGWorld); PresParams presParams = new PresParams( presenterTimeScale, QTSConstants.kQTSSendMediaFlag |QTSConstants.kQTSAutoModeFlag | QTSConstants.kQTSDontShowStatusFlag, mediaParams ); pres = Presentation.fromFile(file, presParams );構造函數的第一事是裝載名為little.sdp的SDP文件。 但這并不是所有的都需要創建Presentation ――在調用Presentation.fromFile()的時候需要服務器應用程序設置一些必要的參數。首先,你要創建一個MediaParams對象,這樣你能設置視頻的高度和寬度。您必須做的其它重要事是提供照相機一個圖形界面,由QDGraphics創建MediaParams設置。是的, 名字是古怪的, 因為QTJ 設計員想注重與AWT Graphics對象的相似性, 但得到或設置這樣的對象的用途的所有方法是使用其本地API名字, GWorld。 最后, 你為所有的Presentation創建一個PresParams來設置參數。 這采取一個有些任意的時標, 一些算術上的行為標記彼此OR'ed, 以及MediaParams。 可能的行為標記, 都被定義在QTSConstants, 包括:· KQTSAutoModeFlag: 都使用默認值。 最重要地, 這些使用默認值Sourcer, Presentation的來源,是從各種各樣的輸入裝置執行獲取的SequenceGrabber。 它還可能播放一個在磁盤上或是任意目錄下的的QuickTime 文件; 稍后我將探討這些問題。· KQTDontShowStatusFlag: 不要創建一個會導致連接數和狀態信息總被顯示在客戶端的流媒體狀態處理程序。· KQTSSendMediaFlag:發送,不接收數據。· KQTSReceiveMediaFlag:接收,不發送數據。在SDP文件說明, 參數, 以及GWorld 設置下, 創建Presentation和Presentation.fromFile()。 // find audio stream Stream audioStream = null; for (int i=1; i
標簽:
Java
上一條:用Java實現自動在數據庫表中生成ID號下一條:一些入門的java小程序
相關文章:
排行榜