转自:http://www.codefans.net/articles/1750.shtml
Java写一个视频播放器,在“Java通过java.applet.AudioClip接口播放简短的音频片断”演示了如何用Java API 来播放音频剪辑片断,读者会发现,如果使用上例中的程序来播放较大的声音文件( 当然格式必须支持的),程序不会响应, 根本不能得到声音。这是由于java.applet.AudioClip 对象不能容纳大量的音频数据。为了解决这个问题,本例将演示如何得到一个真正意义上的媒体播放器,效果如图2-2 所示。它既可以播放音频也可以播放视频(当然格式必须是支持的),这个JAVA视频播放器将用到sun 开发的一个附加API 包——JMF API 包,即Java MediaFramework API。它不是J2SE SDK 中的标准包,因此必须另外到Sun 公司下载 。作者用的是JMF2.1.1 跨平台版本,当然也可以使用Windows 版本或Solaris 版本的。
首先介绍一下JMF API 包的下载和安装及在JBuilder 中的集成。作者使用的是跨平台的2.1.1zip包版本,可以在如下地址下载:http://java.sun.com/products/java-media/jmf/2.1.1/download.html
另外,还可以在http://java.sun.com/products/java-media/jmf/2.1.1/documentation.html上下载JMF API 的相关文档和帮助。将下载下来的JMF2.1.1.zip 包解压到c 盘根目录下(当然可以是其他位置),然后设置环境变量,在Windows 系统中如下:
set JMFHOME=c:\JMF2.1.1 set CLASSPATH=%JMFHOME%\lib\jmf.jar;.;%CLASSPATH%
如果读者使用IDE 开发java 程序,也可以很容易地将JMF API 包集成到开发工具上。以BorlandJBuilder 为例,单击Tools 菜单下的Configure Libraries 项,在弹出的对话框中,单击New 按钮,在新的弹出框中设置Name:JMF,Location:User Home, 并根据解压的JMF 包的位置, 如c:\JMF2.1.1,添加API;然后打开Project 菜单下的Default Project Properties 项,在弹出框的Paths面板中选择Required Libraries 面板项添加API ,如User Home 下的JMF。本例中,为了播放媒体,相应的需要一个媒体播放器Player 对象,可以通过调用Manager 的createPlayer()方法得到,因为此方法是静态方法,所以不需要创建Manager 的实例,代码如下:
player = Manager.createPlayer(new MediaLocator(mediaURL));//根据声音文件的路径实例化一个Player 对象
播放器完成从数据源接收数据,申请播放资源,并以精确的时间顺序根据每一道(Track)的数据格式分别提交到各自的资源目标,如扬声器、显示器。另外,javax.media.Player 接口实现了Controller 接口,因而提供了方法java.awt.ComponentgetControlPanelComponent()来得到播放控制组件、java.awt.Component getVisualComponent()
来得到可视化的画面组件。一个播放器具有6 种状态,分别是Unrealized、Realizing、Realized、Prefetching、Prefetched和Started。当一个播放器创建时,处于UnRealized 状态,此时它对要播放的媒体一无所知。各个状态之间的转换,体现了媒体播放的全过程。
当播放器调用realize()方法后,播放器由Unrealized 状态进入Realizing 状态,此时播放器可以判定资源的请求,同时查询它的所有非独占资源(独占资源是指,每次只能提供给一个播放器的资源,如特定的硬件资源等),如果需要还可以从网上下载相关的资源。Realizing 是一个时间密集的任务,若成功完成,则播放器进入Realized 状态。进入Realized 之后,播放器已经得知它需要哪些资源及相关的媒体类型信息,并可以提交数据,获得可视化组件和控制组件,但此时播放器仍然不拥有任何资源,其他播放器也可以启动。
当播放器调用prefetch()方法后,随即进入Prefetching 状态。此时,播放器已经装载了媒体数据,获得了播放资源,正准备播放它的媒体数据。当播放器的媒体被重新定位或播放率的改变,会导致播放器重新进入Prefetching 状态。成功完成Prefetching 后,播放器进入Prefetched 状态,可以播放媒体。调用start()方法后播放器进入最终的Started 状态,播放器将播放器的时基时间和媒体时间映射成它正在运行的时钟时间,媒体开始播放。另外,本例使用ControllerListener 接口来监听Player 对象的各个状态之间转变时的事件,并完成相应的处理。程序代码如下:
1. 新建一个Project,取名为JVideoDemo1。
2. 新建一个Application,取名为JVideoDemo1;主窗体取名为MainFrame,标题为JVideoDemo1。
3. 利用wizards|implement interface 使MainFrame 类实现ControllerListener,并添加新的属性,代码如下:
public class MainFrame extends JFrame implements ControllerListener{ 2 private JPanel contentPane; 3 private BorderLayout borderLayout1 = new BorderLayout(); 4 Component vc = null; //视频播放组件 5 Component cc = null; //视频播放控制组件 6 Player player = null; //播放器对象 7 …… 8 }
4. 编写一个新的MainFrame 类的构造方法,参数是一个String 对象,并在此方法中实例化一个Player 对象。
01 public MainFrame(String mediaURL){ 02 this(); //调用默认的构造方法,以便执行jbInit()方法中的初始化工作。 03 //实例化一个Player 对象player 04 try{ 05 Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, new Boolean(true));//很重要的一行,可以解决Swing 组 06 //件和awt 组件混用可能带来的麻烦 07 player = Manager.createPlayer(new MediaLocator(mediaURL));//根据声音文件的路径实例化一个Player 对象 08 }catch(IOException err){ 09 exitProc ("Could not find the player"); //显示消息并退出程序 10 }catch(NoPlayerException err){ 11 exitProc ("Could not create the player"); //显示消息并退出程序 12 } 13 if(player==null){ 14 exitProc("Could not create the player"); //显示消息并退出程序 15 } 16 player.addControllerListener(this); //play 对象添加ControllerListener 17 player.prefetch(); //获取媒体数据 18 }}
5. 实现ControllerListener 接口中的方法controllerUpdate(),用于处理ControllerEvent 事件:
01 public void controllerUpdate(ControllerEvent e){ 02 //如果控制事件是关闭,则程序退出 03 if (e instanceof ControllerClosedEvent){ 04 System.exit(0); 05 } 06 //如果控制事件是媒体数据播放完毕,则player 设置新的媒体时间,重新开始播放 07 if (e instanceof EndOfMediaEvent){ 08 player.setMediaTime(new Time(0)); 09 player.start(); 10 return; 11 } 12 //如果控制事件是获得媒体数据完成,则开始播放 13 if (e instanceof PrefetchCompleteEvent){ 14 player.start(); 15 return; 16 } 17 //如果控制事件是Realize 完成,则播放器player 获得播放画面的组件,用于媒体可视化播放,并将组件加到 18 //MainFrame 窗口中;同时获得播放控制组件,也添加到MainFrame 窗口上,用于控制媒体的播放 19 if (e instanceof RealizeCompleteEvent){ 20 vc = player.getVisualComponent(); 21 if (vc!=null) 22 this.getContentPane().add(vc,BorderLayout.CENTER); 23 cc = player.getControlPanelComponent(); 24 if (cc!=null) 25 this.getContentPane().add(cc,BorderLayout.SOUTH); 26 this.pack(); 27 this.setResizable(false);//窗口大小适合媒体画面,并不可改变。 28 this.setVisible(true); 29 } 30 }}
6. 编写终止方法exitProc (),该方法接收Stirng 对象为参数,并显示此String 对象,然后程序退出。
1 private void exitProc (String str){ 2 System.out.println(str); 3 System.exit(-1); 4 }
7. 在JVideoDemo1 类中,修改实例化MainFrame 对象所用的构造方法,传入媒体文件的地址,演示播放该媒体文件。具体如下:
MainFrame frame = new MainFrame(ClassLoader.getSystemResource("media/sport.mov").toString());