`

技术交流: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=0
  c=IN IP4 224.2.1.2/20/1
  m=audio 1000 RTP/AVP 12
  m=video 2000 RTP/AVP 101
  a=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 96
  c=IN IP4 239.60.60.60
  a=rtpmap:96 x-qt
  m=video 2700 RTP/AVP 96
  a=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<=pres.getNumStreams(); i++) {
  System.out.println ("stream: " + i + ": " +
  pres.getIndStream(i));
  Stream aStream = pres.getIndStream (i);
  if (pres.hasCharacteristic(aStream,
  StdQTConstants.audioMediaCharacteristic)) {
  audioStream = aStream;
  break;
  }
  }
  System.out.println ("audioStream = " + audioStream);
  pres.setVolumes (audioStream, 100, 100);
  System.out.println ("created presentation, gworld == " +
  pres.getGWorld() + ", size == "+
  mediaParams.getWidth() + "x" +
  mediaParams.getHeight() + ", streams == " +
  pres.getNumStreams());
  
  //*******这不是真正地必要的, 但它将告诉你怎么通过Presentation游览来挑选各自的流媒体。 Presentation.getIndStream 会由索引返回一个Stream(附注QuickTime 索引都是基于1)。它重复这些audioMediaCharacteristic 请求查找音频流 (对于录影, 您就要请求visualMediaCharacteristic) 。 这个实例在audioStream上为左右声道设置音量最大值为100。
  
  最后, println从Presentation和MediaParams转存一些有意义的元数据。
  
  配置Presentation
  
  SettingsDialog sd = new SettingsDialog (pres);
  System.out.println ("Did settings");
  pres.preroll();
  broadcasting = false;
  
  这是设置presentation最后的步骤。 SettingsDialog存在用户以输入装置选择的音频和视频 (二个流媒体SDP 文件被指定在Presentation中) 。每个流媒体都可由一个压缩格式来定制 (MPEG-4, Sorenson Video 3, H.263, 等) 以及一个分包器(有时由压缩格式定义; 可观察它是否随着压缩格式的改变而自动改变) 。 这个GUI实例显示在图1 。


  图像1. 为一个Presentation SettingsDialog


  
  在此图中, 音频默认为计算机连线输入。更改它为iSight, 您需要点击Source按钮,提出的可选设备列表显示在图2上 。


  图2. 来源选择对话框


  
  最后就是调用Presentation.preroll(), 如同Movie.preroll(), 提供Presentation一个机会预先分配资源以及准备好开始流媒体Presentation。
  
  提供一个控制GUI
  
  // Make monitor window
  startStopButton = new Button ("Start");
  configButton = new Button ("Configure");
  startStopButton.addActionListener (this);
  configButton.addActionListener (this);
  Frame monitorFrame = new Frame ("QTJ Streaming");
  monitorFrame.setLayout (new BorderLayout());
  Panel buttonPanel = new Panel();
  buttonPanel.add (startStopButton);
  buttonPanel.add (configButton);
  monitorFrame.add (buttonPanel, BorderLayout.SOUTH);
  monitorFrame.pack();
  monitorFrame.setVisible(true);
  
  这个为控制和配置Presentation设置了很小的GUI,提供基本的一个起始/停止键和一个配置按钮。 按钮作为一个ActionListener提交给this, 意味着这个类将需要提供一个actionPerformed方法来处理按钮点击。 控制GUI 的屏幕截图显示在图3 。


  图3. 监控/控制窗体


  
  在这点上你也许会问一个有趣的问题: "从什么时候我们开始关心使用GUI提供server?"据推测, 这是从Classic Mac OS开始的一个传统, 它没有一个用命令行启动和传递参数的程序。但此外, 你通常会希望提供一个流媒体数据的预览, 并且如果您有一个预览视窗, 为什么会也没有一个配置的GUI?
  
  无论如何, 这是大概的讨论, 因为QTJ 6.1 不提供您能使用来预览的一个AWT Component。在有些方面有希望的是, QTFactory将得到一个新的超负荷为采用一个Presentation并且返回一个显示流媒体视频的Component的makeQTComponent。 它大概可能使用一些QuickDraw voodoo而完全放弃Java的东西。 如果,在各task()中回调(参见下面) 您采取GWorld被及早创建, 转换它成Pict, 并且作为一份唯一命名的文件, 您会看见每一个都是不同的, 意味GWorld每次都得到新数据。 所以如果您替换掉GWorld, 改为能给AWT Component在各通道上定义象素, 您会有银幕上的预览。何人有胆量如此做? 在quicktime-java list上查看。
  
  详细资料
  
  // add shutdown handler to make sure presentation
  // gets stopped
  Thread presentationStopper = new Thread() {
  public void run() {
  try {
  pres.stop();
  } catch (QTException qte) {}
  }
  };
  Runtime.getRuntime().addShutdownHook (presentationStopper);
  
  这个关闭异常分支确定Presentation在程序退出之前被终止。 这是重要的原因, 象SequenceGrabber, Presentation愉快继续运行在您的应用程序退出之后,绑定一个端口,严重的循环, 使用您的获取设备保留其它应用程序, 等。
  } catch ( QTException e ) {
  e.printStackTrace();
  System.exit (-1);
  }
  }
  
  最后, 构造函数捕捉并抛出所有的QTExceptions。
  public void actionPerformed (ActionEvent ae) {
  System.out.println ("actionPerformed");
  try {
  if (ae.getSource() == startStopButton) {
  if (broadcasting) {
  pres.stop();
  stopTasking();
  broadcasting = false;
  startStopButton.setLabel ("Start");
  System.out.println ("Stopped");
  } else {
  pres.start();
  startTasking();
  broadcasting = true;
  startStopButton.setLabel ("Stop");
  System.out.println ("Started");
  }
  } else if (ae.getSource() == configButton) {
  new SettingsDialog (pres);
  }
  } catch (QTException qte) {
  qte.printStackTrace();
  }
  }
  
  这是非常直接的处理起始/终止和设置按钮。如果点击的按钮是起始/终止, 设置GUI 就会调用在Presentation上的 start() 或stop(), 开始或停止正在执行的任务 (定期回调这个类的task()方法), 为下按钮点击目的设置broadcasting标志, 并且更改按钮标签。如果用户点击了配置, 它生成为Presentation新的SettingsDialog。
  
  public synchronized final void task() throws QTException {
  pres.idle(null);
  }}
  
  最后的这个方法实现了继承自Tasking的task()方法并且被在操作开始按钮调用startTasking()后定时的调用。使用简单的调用Presentation.idle(), 它提供了表达时间来从获取设备取得当前数据,对其编码并传输流出去。
  
  运行流媒体客户端
  
  最简单的使客户机看广播的方法是使用QuickTime 播放器打开服务器使用并创建Presentation的同样SDP 文件。这将调用SDP 输入程序连接到流媒体并且开始分析这些内容。注意客户机和服务器不能在同一台机器上, 明显地因为服务器为使用表示而占用端口, 拒绝客户机对这些端口的使用。 图4 显示在我的计算机上的流媒体的外观(那是正在播放我的Macross和Escaflowne玩具) 。


  图4. QuickTime流媒体客户端


  
  如果您使用QuickTime 播放器, 您能使用其得到信息指令显示两种流媒体以及他们的格式。 在表5, 您能看有二种媒体: 一条未压缩的44.1kHz 音频流, 和一条H.263 的视频流。


  图5. 客户端信息窗体


  
  结语
  
  对我来说,播放基于Java的QuickTime流媒体比想象的容易多了。 最简单的例子, 从获取设备播放, 只需要少于150 个代码行。 显然, 最困难的部份是了解SDP文件, 它被证明是非常的过分讲究并且它的说明文件包含大量应用程序级别程序员不会有的知识。同样不幸的是,QTJ不再提供预览组件, 但也许在将来会提供, 以及一小段的GWorld/QuickDraw 堆砌也许会在将来制造出这样的组件。
  
  本文只包括怎么为实时获取数据设置广播。其它可利用的Sourcers, 譬如来自磁盘或任意目录种的那些广播QuickTime 文件, 将会在以后的部分中讨论。

分享到:
评论

相关推荐

    QuickTime 流媒体服务器模块

    描述的是为开放源码的Darwin流媒体服务器创建QuickTime流媒体服务器(QTSS)模块所需要的编程接口,版本为4.0。QTSS编程接口为开发者提供了一种易于使用...这个版本的编程接口和版本5的QuickTime流媒体服务器互相兼容。

    java quicktime 开发包

    1. **QuickTime API**:Java QuickTime API提供了丰富的类和方法,用于操作QuickTime的媒体对象。这些API包括了播放、暂停、停止、快进、快退、调整音量等控制,以及获取媒体信息(如播放时长、帧率等)的功能。 2....

    流媒体技术基础,包括Windows Media、RealMedia、QuickTime、Flash流媒体

    在本文中,我们将深入探讨四种主要的流媒体技术:Windows Media、RealMedia、QuickTime和Flash流媒体。 首先,让我们详细了解Windows Media技术。Windows Media由微软公司开发,是一个全面的解决方案,涵盖了从内容...

    基于Java 开发QuickTime 程序

    API提供了处理流媒体、时间同步、动画控制等多种功能,使得Java程序员可以充分利用QuickTime的技术优势。 总的来说,基于Java的QuickTime开发涉及到组件的识别、选择和使用,以及与QuickTime电影的交互。通过理解...

    流媒体技术的Java实现 蒋爱权

    在流媒体技术中,支持的流式视频格式主要包括Real Networks公司的RealMedia,Apple公司的QuickTime以及Microsoft公司的Advanced Streaming Format(ASF)。这些格式各有特点,适用于不同类型的流媒体应用。 流媒体...

    PEAR::QuickTime-开源

    QuickTime技术的核心是其强大的媒体处理能力,包括编码、解码、时间同步和流媒体传输等。 开源软件标签表明了PEAR::QuickTime遵循开源协议,允许用户自由使用、修改和分发代码。这对于开发者来说是一个巨大的优势,...

    QuickTime for Java API.pdf

    QuickTime for Java API.pdf 本文主要介绍了如何使用 QuickTime for Java API 创建视频内容,并将其应用于 iPod 媒体播放器。首先,文章介绍了移动视频市场的前景和潜力,然后推荐了一些移动视频的...* 数字媒体技术

    Quicktime 5 Installer

    - **互联网流媒体**:QuickTime 5.0支持实时流媒体技术,用户可以在网上观看直播视频或者流式音频,无需等待整个文件下载完成。 - **3D图形支持**:这一版本开始支持3D图形,用户可以播放包含3D特效的媒体内容,为...

    quicktimesdk.zip_quicktime_quicktime 播放器_quicktimesdk

    QuickTime技术支持多种媒体格式,包括视频、音频、图像和3D图形,因此在多媒体应用开发中非常流行,特别是在需要高清晰度播放功能时。 "quicktime播放器"是苹果公司的著名多媒体播放器,它能够播放各种格式的音频和...

    Quicktime_File_Format.rar_march_quicktime_quicktime file

    5. **扩展性**:QuickTime格式具有良好的扩展性,可以通过插件系统添加对新格式的支持,使得它能够处理不断出现的新媒体标准和技术。 6. **互动性**:QuickTime不仅支持简单的播放,还支持交互式内容,如电影剪辑、...

    quick time for java docs

    Quick Time for Java(QTJ)是Apple公司推出的一项技术,旨在让Java应用程序能够利用QuickTime技术来处理多媒体内容,如视频、音频、图像等。它为Java开发者提供了一套丰富的API,使得在Java环境中集成多媒体功能变...

    QuickTime播放器.zip

    6. 网络流媒体:QuickTime可以播放通过HTTP、RTSP等协议传输的网络流媒体内容。 然而,随着QuickTime在Windows平台上的退役,用户应考虑转向其他多媒体播放器,如VLC Media Player、PotPlayer或Microsoft的Media ...

    quicktime播放器.rar

    - 网络流媒体:QuickTime支持HTTP、RTSP和FTP等协议,可播放网络上的实时流媒体内容。 4. 使用方法: 要使用QuickTime播放器,首先需要在兼容的操作系统上安装该软件。在播放媒体文件时,可以直接双击文件,如果...

    QuickTime SDK 7.3

    QuickTime SDK 7.3 是一个专为Windows平台设计的软件开发工具包,它使得开发者能够利用Apple的QuickTime技术创建、编辑和播放多媒体内容。这个SDK为Visual C++(VC)用户提供了一整套的接口和库,允许他们将高质量的...

    移动流媒体技术(基于3g技术)

    移动流媒体技术是一种基于3G技术的新型通信方式,它使得用户可以在移动设备上实时接收和播放音频、视频等多媒体内容。3G技术的发展为移动流媒体提供了高速、稳定的网络环境,使得用户无需等待整个文件下载完毕即可...

    QuickTime_7.79.80.95.1457943615

    4. **网络流媒体**:QuickTime支持通过互联网实时传输音频和视频流,用户可以观看在线的音频和视频内容。 5. **插件扩展**:QuickTime允许安装各种插件来增强其功能,比如支持更多格式的播放、增加特殊效果等。 6....

    jmf流媒体播放器软件

    JMF(Java Media Framework)流媒体播放器软件是一种基于Java技术的多媒体处理框架,主要用于处理音频、视频和动画等内容。这个软件在IT领域,尤其是开发P2P流媒体系统时,扮演着重要的角色。JMF为开发者提供了一个...

    基于JMF技术实现流媒体格式的转换

    流媒体技术的核心在于它能实现多媒体数据的实时传输和回放,这主要是通过“流”技术来实现的。 流媒体文件通常存储在网络服务器上,经过压缩处理,以便用户能够在下载过程中同步播放媒体内容。这种播放方式依赖于...

    quicktime—sdk

    4. **Streaming Support**: QuickTime SDK支持实时流媒体技术,开发者可以构建实时音频和视频流的应用程序。 在VS2013中配置ARToolkit时,QuickTime SDK的作用可能体现在以下几个方面: 1. **视频播放**: ...

    linux流媒体服务器

    流媒体技术分为两种主要的传输方式:顺序流传输和实时流传输。顺序流传输适用于高质量的多媒体片段,用户可以在线回放已下载的部分,但无法跳跃到未下载的内容。而实时流传输则保证了媒体信号带宽与网络状况匹配,...

Global site tag (gtag.js) - Google Analytics