服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

java多媒体框架设计自动播放机实例详解

如果把java媒体框架(http://java.sun.com/jmf)看作客户端安装的媒体播放机的话,那么这种框架并不是非常激动人心。它只支持少量媒体类型,并且事实上这些媒体类型都被象windows媒体播放机以及quicktime等其它的应用程序支持。

但是从内容供应商的观点来看,下面这个事实更加有意义:jmf在所有的java类型中都可用,这使在客户端上不必要有任何特定的媒体技术就可以部署媒体--所需要的只是j2se java运行时间。

更重要的是它能利用.jar文件格式的一些性能把解码器和媒体组成到一个文件中,创建一个"自我播放电影",使用了象winzip和stuffit这样的压缩应用程序大致相同的方式来创建自我展开文档。

我们把此分为三个阶段:

1.使jmf能够播放.jar文件中的媒体。

2.只使用需要播放本地媒体所需的jmf的一部分创建一个轻量级.jar文件。

3.将代码和媒体放入.jar文件,并且创建一个合适的manifest文档以使它可以双击。

基本的jmf播放的关键是获得player,能解码和渲染你的媒体。一般来说,这通过使用manager获得合适的datasource来完成,在一个播放实例中提供了媒体流和流元数据,例如媒体格式。manager然后找到一个player来处理datasource。在两种情况下,manager结合一个带有程序包前缀列表(象javax.media、com.ibm.media等等)的反射方案来试图寻找合适的类,例如如果一个计划的播放程序不能接受提供给它的datasource,那么它就会抛出异常。

manager没有太多事要做,只是察看一下url中的协议和文件扩展名,所以虽然它可以很容易的知道如何处理file:///users/cadamson/mymp3stash/some.mp3,但是它不知道如何处理象jar:file:/users/cadamson/dev/jmftests/spmovie-old/src/gatsbymovie.jar!/movie/themovie.mov这样的url。

为了缓和这种情况,我们可以写一个datasource,说得更准确一点就是一个pulldatasource,担负为manager描述细节的责任。jarentrydatasource中没有一个方法特别难;我们提供的pullsourcestream还需要实现几个超级接口。

它有些不够完美,但是这个类依靠文件扩展名来返回"内容类型"。这多多少少有点象一个mime类型,除了使用句号代替斜线符号来格式化以外,所以它可被用于程序包名称(例如video/mpeg mime类型变成video.mpeg,所以manager可以找到com.sun.media.codec.video.mpeg包)。下面是我们的简单的实现:

public string getcontenttype() {
  
  try {
  
  url url = getlocator().geturl();
  
  string urlfile = url.getfile();
  
  if (urlfile.endswith(".mov"))
  
  return "video.quicktime";
  
  else if (urlfile.endswith(".mpg"))
  
  return "video.mpeg";
  
  else if (urlfile.endswith(".avi"))
  
  // manager needs '_' insted of '-'
  
  return "video.x_msvideo";
  
  else
  
  return "unknown";
  
  } catch (malformedurlexception murle) {
  
  return "unknown";
  
  }
  
  }
  

另一个烦恼是jmf源代码表明如果提供的流是seekable的话(这是一个提供随机存取seek()方法的接口),默认player只能播放一个quicktime datasource。如果寻找点在流的非常上流的地方,那么jarentrydatasource中的策略是使用inputstream.skip()。如果寻找点在当前读取点之后(调用tellpoint,因为它的值通过seekable.tell ()方法返回),然后它必须关闭inputstream,再重新打开,跳到寻找点。它使用一个内部的thoroughskip()方法来确定我们实际上停在哪里。

public long seek (long position) {
  
  try {
  
  if (position > tellpoint) {
  
  thoroughskip (position - tellpoint);
  
  } else {
  
  close();
  
  open();
  
  thoroughskip (position);
  
  }
  
  return tellpoint;
  
  } catch (ioexception ioe) {
  
  return 0; // bogus...
  
  }
  
  }
  

使用这个类,manager可以找到一个可用的player用于播放.jar文件中的.mov或者.avi文件。我们的示例的tinyplayer使用classloader.getresource ()方法来在类路径中寻找movie/themovie.mov或者movie/themovie.avi。当类路径只包含.jar文件的时候,我们将对其进行设置。

准备一个合适的.jar文件中的第一步是使用jmf的jmfcustomizer工具来创建一个jar,只使用播放我们的媒体所需要类,去掉用于流、捕捉、译码和其它对于一个简化的播放程序不需要的函数。不幸的是,sun在各种java版本的jmf中都不包含jmfcustomizer的帮助文件,但是各种定制屏幕很容易设计出来:

1.媒体源和媒体汇点:选择"媒体文件"和"播放"。

2.协议:只是"文件"。

3.源媒体格式:"quicktime (.mov)"和"avi"。

4.解码器:无论你计划在你的媒体中使用什么解码器,但是用于音频的大部分都是"a - law"、"u - law"或"ima4",用于视频的是"h263"。不要为编码器、封包器和解包器而费心。

5.渲染:在音频中,我们需要"javasound"用于java 1.3及1.3以上的版本,sunaudio用于sun的pre-1.3 jvm。对于视频,我们只需要awt。

其结果是本来用于我们的播放器的jar被从1.9 mb压缩到700k。

假定你已经编译了两个com.mac.invalidname.spmovie类,把它们添加到定制的jar中:

jar uf customized.jar com/mac/invalidname/spmovie/*.class

jmf的许可证有效期需要它的readme文件使用任何jmf或者定制子集来分布。我已经在misc目录中提供了,在tinyplayer的菜单项可以找到它:

jar uf customized.jar misc/

为了使这个.jar文件可双击,我们提供一个manifest文件告诉java运行时间在.jar文件中的哪个类中有在双击或者使用简单jar命令行变量的时候调用的main()方法。manifest还提供一个只包含jar自己的类路径:

main-class: com.mac.invalidname.spmovie.tinyplayer

class-path: .

这个manifest使用下面的命令来添加:

jar ufm customized.jar manifest-stub.txt

这个文件现在有用于播放jar中的一个电影的所有的代码。为了将来之用,请把它保存为spmovie-engine.jar文件,或者类似的文件。

现在引擎已经具备了,我们所需要的只有媒体了。正如你可从jmf支持类型页面看到的那样,所有java版本的jmf有一个相当有限的所支持解码器的集合。对于视频来说最好的选择可能是h.263,在很广泛的比特率下能够工作的很好,然而它可能在老机器上会执行得很困难,除非你压缩视频或者保持较低的帧速率。虽然音频较少是事先准备好的,但是我想ima 4:1执行得相当好。适当地编码或者译码你的媒体,并且把它复制为movie/themovie.mov或者movie/themovie.avi。如果你喜欢你也可以把.jar文件改名(我使用spmovie.jar)并且添加媒体:

jar u0f spmovie.jar media/

注意这里的"0"是数字零,而不是字母o;这表明我们不想压缩这个输入项,因为我们的媒体已经被压缩了。

千辛万苦,我们的自我播放电影终于做成了,这个文件知道在双击的时候运行什么类,提供了多路解编、解码和渲染一部电影所需的所有的代码,以及电影本身。如果你想看看这种小型自我播放电影,你可以去看看。

它扩展了小应用程序的概念,允许媒体在任何可用于java的浏览器中播放。

说白了,它是一个java虚拟机而不是媒体播放机。但是我们这种"一次编辑,到处播放"的思想是完全符合java的原先的目的的。

扫描关注微信公众号