您的位置:首页技术文章
文章详情页

QuickTime流媒体和Java

【字号: 日期:2024-06-14 08:21:13浏览:52作者:猪猪
内容: 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
相关文章: