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