專案目標
使用 JMF (Java Media Framework) 建立具備「開啟媒體檔案」、「循環播放切換」、「退出」功能的 AWT/Swing 媒體播放器,支援音訊/視訊多種格式,跨 Windows/Linux/Solaris 運行。
架構設計
| 層級 | 組件 | 技術選型 |
| UI 層 | 主視窗、選單列、檔案選擇器、視覺元件、控制面板 | AWT `Frame`/`MenuBar`/`FileDialog` + JMF `Player` 視覺/控制元件 |
| 媒體層 | 媒體定位、解碼、渲染、控制 | JMF `Manager`、`Player`、`Controller`、`DataSource` |
| 事件層 | 使用者操作、播放狀態變化 | AWT 事件監聽器 + JMF `ControllerListener` |
核心代碼骨架
import java.awt.*;
import java.awt.event.*;
import javax.media.*;
import javax.media.controller.*;
public class MediaPlayer extends Frame implements ActionListener, ControllerListener {
private Player player;
private Component visualComp, controlComp;
private boolean looping = false;
public MediaPlayer() {
setTitle("媒體播放器 1.0");
setLayout(new BorderLayout());
setBackground(Color.LIGHT_GRAY);
// 選單列
MenuBar mb = new MenuBar();
Menu fileMenu = new Menu("檔案");
MenuItem openItem = new MenuItem("開啟");
CheckboxMenuItem loopItem = new CheckboxMenuItem("循環播放");
MenuItem exitItem = new MenuItem("退出");
openItem.addActionListener(this);
loopItem.addActionListener(this);
exitItem.addActionListener(this);
fileMenu.add(openItem);
fileMenu.addSeparator();
fileMenu.add(loopItem);
fileMenu.addSeparator();
fileMenu.add(exitItem);
mb.add(fileMenu);
setMenuBar(mb);
// 視窗關閉處理
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { shutdown(); }
});
pack();
setSize(640, 480);
centerOnScreen();
setVisible(true);
}
private void centerOnScreen() {
Dimension scr = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frm = getSize();
setLocation((scr.width - frm.width)/2, (scr.height - frm.height)/2);
}
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if ("開啟".equals(cmd)) openFile();
else if ("循環播放".equals(cmd)) looping = ((CheckboxMenuItem)e.getSource()).getState();
else if ("退出".equals(cmd)) shutdown();
}
private void openFile() {
FileDialog fd = new FileDialog(this, "選擇媒體檔案", FileDialog.LOAD);
fd.setVisible(true);
String dir = fd.getDirectory();
String file = fd.getFile();
if (dir == null || file == null) return;
try {
if (player != null) player.close();
MediaLocator ml = new MediaLocator("file:" + dir + file);
player = Manager.createRealizedPlayer(ml);
player.addControllerListener(this);
// 視覺元件
if (visualComp != null) remove(visualComp);
visualComp = player.getVisualComponent();
if (visualComp != null) add(visualComp, BorderLayout.CENTER);
// 控制面板
if (controlComp != null) remove(controlComp);
controlComp = player.getControlPanelComponent();
if (controlComp != null) add(controlComp, BorderLayout.SOUTH);
validate();
player.start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
@Override
public void controllerUpdate(ControllerEvent e) {
if (e instanceof EndOfMediaEvent && looping) {
player.setMediaTime(new Time(0));
player.start();
}
}
private void shutdown() {
if (player != null) { player.close(); player = null; }
dispose();
System.exit(0);
}
public static void main(String[] args) {
new MediaPlayer();
}
}
JMF 關鍵類別速查
| 類別 | 角色 |
| `Manager` | 工廠:`createPlayer(DataSource)`、`createRealizedPlayer(MediaLocator)` |
| `Player` | 控制介面:`start()`/`stop()`/`setMediaTime()`/`getVisualComponent()`/`getControlPanelComponent()` |
| `ControllerListener` | 事件回調:`RealizeCompleteEvent`、`PrefetchCompleteEvent`、`EndOfMediaEvent`、`ControllerErrorEvent` |
| `MediaLocator` | 統一資源定位:`file:`、`http:`、`rtp:`、`javasound:` |
| `Format` | 媒體格式描述:`VideoFormat`、`AudioFormat` |
支援格式與編碼器
- JMF 2.1.1e 內建:GSM、MP3 (需授權)、H.261/H.263、MPEG-1、AVI、QuickTime、WAV、AIFF、AU。
- 擴展:安裝 JMF Registry 註冊第三方編解碼器 (如 FFmpeg JNI 橋接)。
- 查詢支援格式:`PackageManager.getPackageManager().getSupportedFormats()`。
已知限制與現代化替代
| 限制 | 現代替代方案 |
| JMF 2003 年後停更,無 H.264/HEVC/VP9 支援 | VLCJ (Java binding for libvlc) — 全格式、硬解、跨平台 |
| Applet 部署模式已死 | JavaFX `MediaPlayer` + `MediaView` (內建 H.264/AAC,模組化部署) |
| AWT/Swing 視覺元件重繪問題 | JavaFX 場景圖自動合成、GPU 加速 |
| 無模組化支援 (JPMS) | VLCJ / JavaFX 均為模組化庫 |
遷移建議
- 新專案直接採用 **JavaFX Media** (JDK 8+ 隨附、JDK 11+ 需獨立引入 `javafx-media` 模組)。
- 需播放專有格式/串流協定 (RTSP/RTMP/HLS) → **VLCJ 4.x** + `vlc` 系統安裝。
- 舊 JMF 專案維護:保留 JMF 2.1.1e JAR,配合 `jmf.jar`、`sound.jar`、`mediaplayer.jar` 置於模組路徑。