Pham_loi
Chức vụ: 08:10:34, 24-05-2016 |
MIDP 2.0 cùng với Mobile Media API 1.1 (MMAPI) đưa ra các khả năng đa phương tiện cho các thiết bị di động, bao gồm việc chơi và ghi lại các dữ liệu âm thanh và hình ảnh từ nhiều nguồn khác nhau. Dĩ nhiên, không phải tất cả các thiết bị di động đều hỗ trợ hết, và MMAPI được thiết kế theo một cách để tận dụng các lợi thế sẵn có và phớt lờ đi những gì nó không hỗ trợ. MIDP 2.0 kèm theo một tập con MMAPI để đảm bảo rằng nếu gặp một thiết bị không hỗ trợ MMAPI, bạn vẫn có thể sử dụng phiên bản gọn hơn. Phiên bản gọn này chỉ hỗ trợ âm thanh (kể cả các giao điệu) và loại trừ mọi thứ liên quan đến hình ảnh hay video.
Trong bài học này, bạn sẽ học cách kết hợp các khả năng đa phương tiện trong MIDlet của bạn. Bạn sẽ học cách truy vấn một thiết bị để lấy về các thông tin khả năng hỗ trợ của thiết bị. Bạn cũng sẽ học cách playback từ các vị trí khác nhau. Nhưng trước tiên, một lý thuyết nhỏ được yêu cầu là hiểu cơ bản các MMAPI và các tập con của nó trong MIDP 2.0.
1.Đằng sau Mobile Media API (MMAPI)
MMAPI định nghĩa superset các khả năng đa phương tiện hiện diện trong MIDP 2.0. Bắt đầu là JSR 135 và hiện hành là phiên bản 1.1. Phiên bản hiện hành bao gồm thêm một số thay đổi tài liệu và các cập nhật an ninh, và được phân phối dưới một file jar trong J2ME wireless toolkit 2.2. Mặc dù với các mô tả phát hành về trạng thái toolkit mà MMAPI 1.1 kèm theo, phiên bản thực sự là 1.0.
MMAPI được xây dựng trên một trừu tượng mức cao với tất cả các thiết bị đa phương tiện có thể được trên một thiết bị bị giới hạn tài nguyên 0. Sự trừu tượng này rõ ràng ở trong 3 class hình thành các khối thao tác mà bạn làm với API này. Những lớp này là các giao diện Player và Control, và lớp Manager. Một lớp khác nữa, lớp trừu tượng DataSource, được dùng để định vị các tài nguyên, nhưng trừ phi bạn muốn định nghĩa một cách mới để đọc dữ liệu bạn chắc chắn sẽ không bao giờ cần sử dụng nó trực tiếp.
Nói tóm lại, bạn sử dụng lớp Manager để tạo các thể hiện Player cho phương tiện khác nhau bằng cách chỉ rõ các thể hiện DataSource. Các thể hiện Player vì thế được tạo ra là có khả năng cấu hình bằng cách sử dụng các thể hiện Control. Chẳng hạn, hầu hết mọi thể hiện Player sẽ hỗ trợ về mặt lý thuyết một VolumeControl để điều khiển volume của Player. Hình 1 cho thấy quá trình này.
[imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-h1.png?w=630[/img
Hình 1 – Quá trình tạo và quản lý Player
Lớp Manager là lớp trung tâm cho việc tạo ra các player – bộ chơi và nó cung cấp 3 phương thức để cho biết nguồn của phương tiện. Những phương thức này, tất cả đều là phương thức tĩnh, là createPlayer(DataSource source), createPlayer(InputStream stream, String type) và createPlayer(String locator). Phương thức cuối cùng được ưa thích vì nó cung cấp một cú pháp dạng URI cho việc định vị phương tiện. Chẳng hạn, nếu bạn muốn tạo một thể hiện Player trên một file âm thanh nền web, bạn có thể sử dụng createPlayer“http:. Tương tự, để tạo một Player media thu lấy âm thanh, bạn có thể sử dụng createPlayer“capture:, và còn nhiều nữa. Bảng sau cho biết các cú pháp hỗ trợ với các ví dụ mẫu:
Kiểu phương tiện
Cú pháp điển hình
Capture audio
“capture://audio” để bắt lấy audio trên thiết bị ghi lại audio mặc định hoặc “capture://devmic0?encoding=pcm” bắt lại audio trên thiết bị devmic0 khi PCM encoding
Capture video
“capture://video” để ghi lại video từ thiết bị ghi video mặc định hoặc “capture://devcam0?encoding=rgb888&width=100&height=50” để ghi lại từ camera thứ hai, trong chế độ rgb888 và với chiều rộng và chiều cao chỉ định
Nghe radio trong thiết bị
“capture://radio?f=105.1&st=stereo” để chỉnh đến tần số FM 105.1 FM và chế độ stereo
Bắt đầu streaming video/audio/text từ một nguồn bên ngoài
“rtp://host:port/type” trong đó type là một trong số: audio, video hoặc text
Chơi các giai điệu và MIDI
“device://tone” sẽ cho bạn một player bạn có thể sử dụng để chạy các giai điệu hoặc
“device://midi” sẽ cho bạn một player bạn có thể sử dụng để chạy MIDI
Một danh sách các giao thức được hỗ trợ cho một kiểu nội dung xác định có thể được lấy về bằng cách gọi phương thức getSupportedProtocols(String contentType) sẽ trả về một mảng String. Chẳng hạn, nếu bạn gọi phương thức này với đối số “audio/x-wav” thì phương thức sẽ trả về một mảng với 3 giá trị: http, file và capture. Điều này cho bạn biết rằng bạn có thể lấy về kiểu nội dung “audio/x-wav”, bằng các giao thức http và file, và bắt lấy nó bằng giao thức capture. Tương tự, một danh sách các kiểu nội dung được hỗ trợ cho một giao thức xác định có thể được truy cập bằng cách gọi phương thức getSupportedContentTypes(String protocol). Vì thế, việc gọi getSupportedContentTypes(“capture”) sẽ trả về audio/x-wav và video/vnd.sun.rgb565, cho biết rằng bạn có thể bắt lấy audio chuẩn và video nén rgb565. Chú ý rằng việc chuyển giá trị null vào trong những phương thức này sẽ trả về tất cả giao thức và kiểu nội dung được hỗ trợ.
Một khi một thể hiện Player được tạo ra sử dụng các phương thức lớp Manager, thể hiện Player đó cần đi qua nhiều giai đoạn trước khi được sử dụng. Trong lúc được tạo ra, player ở trạng thái UNREALIZED và phải là REALIZED và PREFETCHED trước khi có thể STARTED. REALIZE là một quá trình player xem xét nguồn hay các tài nguyên media cuối và có đủ thông tin để bắt đầu việc thu thập chúng. PREFETCH xảy ra sau REALIZE và player thực sự yêu cầu những tài nguyên media này. Cả hai quá trình REALIZE và PREFETCH có thể tiêu tốn thời gian và tài nguyên, nhưng việc chúng thực hiện trước khi player bắt đầu đảm bảo rằng không có độ trễ khi thực sự bắt đầu xảy ra. Một khi player được bắt đầu, bằng phương thức start),[, bạn gọi thẳng phương thức [bstop)[ trên thể hiện Player để khởi động lại từ điểm dừng trước (nếu player đến cuối media, nghĩa là nó sẽ bắt đầu lại từ điểm bắt đầu).
Phong cách lập trình tốt nhất yêu cầu bạn gọi các phương thức realize)[ trước khi gọi phương thức start)[ gọi thẳng phương thức prefetch)[, hoặc gọi phương thức [brealize)[, nhưng nếu bạn gọi thẳng những phương thức này trước tiên, bạn sẽ có một thể hiện Player sẽ bắt đầu play ngay khi bạn gọi [bstart)[ trên nó, sau khi thể hiện Player không thể được tái sử dụng lại. Thay vì đóng lại, bạn có thể hủy phân bổ một player bằng cách gọi phương thức deallocate(), sẽ trả về player tương ứng với trạng thái REALIZED, do đó giải phóng tất cả tài nguyên sẽ được yêu cầu.
Hình 2 cho thấy các trạng thái và quá trình chuyển tiếp giữa chúng
[imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-h2.png?w=630[/img
Hình 2 – Các trạng thái media player và quá trình chuyển tiếp giữa chúng
Sự thông báo các chuyển tiếp giữa các trạng thái khác nhau có thể được chuyển giao để gắn các listener trên một player. Đến lúc kết thúc, một thể hiện Player cho phép bạn gắn một PlayerListener bằng cách sử dụng phương thức addPlayerListener(PlayerListener listener). Hầu hết tất cả các trạng thái chuyển tiếp đều được thông báo cho listener qua phương thức playerUpdate(Player player, String event, Object eventData).
Một player cũng cho phép kiểm soát các thuộc tính của media mà nó đang play bằng cách sử dụng các control. Một control là một chức năng xử lý media điển hình cho mỗi dạng media cụ thể. Chẳng hạn, VideoControl điều khiển hiển thị của video, trong khi MIDIControl cung cấp truy cập đến các thuộc tính của các thiết bị MIDI. Dĩ nhiên có vài control có thể phổ biến qua nhiều thiết bị khác nhau, VolumeControl là một ví dụ. Bởi vì giao diện Player kế thừa giao diện Controllable, cung cấp các phương tiện để truy vấn danh sách các control có sẵn. Bạn có thể làm việc này bằng cách gọi phương thức getControls)[, trả về một Control (null nếu controlType không được hỗ trợ).
Như đã nói trước đây, MIDP 2.0 chứa một tập con của MMAPI 1.1. Điều này đảm bảo rằng thiết bị đó chỉ hỗ trợ MIDP 2.0 vẫn có thể một phương thức phát hiện và sử dụng phù hợp có thể tăng cường nếu rộng hơn API hiện tại. Tập con chỉ hỗ trợ các giai điệu và audio chỉ với 2 điều khiển, ToneControl và VolumeControl. Thêm nữa, nguồn tài nguyên không được hỗ trợ, và kể từ đây, lớp Manager trong MIDP 2.0 được rút gọn đi và không cung cấp createPlayer(DataSource source) nữa.
Trong các mục tiếp đây, bạn sẽ học cách chơi audio và video từ nhiều nguồn khác nhau trong MIDlet đa phương tiện của bạn.
2.Sử dụng Mobile Media API (MMAPI)
Có lẽ cách dễ nhất để học MMAPI là bắt đầu thử play một file audio đơn giản. Tất cả các thao tác multimedia, dù đó là audio playback hay video capture đều sẽ theo các khuôn mẫu tương tự nhau. Lớp Manager sẽ được dùng để tạo một thể hiện Player sử dụng một String locator. Sau đó Player sẽ được REALIZE, PREFETCH và PLAY cho đến lúc đóng nó lại. Có nhiều khác biệt nhỏ, và tôi sẽ chỉ ra trong quá trình học.
Hình 3 cho thấy các thao tác cho audio file playback đơn giản.
[imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-h3.png?w=630[/img
Hình 3 – Audio file playback đơn giản
Khi người dùng chạy MIDlet, anh ta đã được xác định play chỉ các bài hát trong danh sách, như là bài “Siren from jar”. Khi chọn bài hát này, màn hình thay đổi với văn bản “Playing media” và có 2 lệnh xuất hiên bên dưới: Stop và Pause, cho người dùng lựa chọn. Media đang được chơi và người dùng có thể tạm dừng lại hay dừng hẳn và trở về danh sách bài hát.
Mã tương ứng quá trình trên:
<?php
package com.j2me.part4;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.media.Player;
import javax.microedition.media.Control;
import javax.microedition.media.Manager;
import javax.microedition.media.PlayerListener;
public class MediaMIDlet extends MIDlet
implements CommandListener, PlayerListener {
private Display display;
private List itemList;
private Form form;
private Command stopCommand;
private Command pauseCommand;
private Command startCommand;
private Hashtable items;
private Hashtable itemsInfo;
private Player player;
public MediaMIDlet() {
display = Display.getDisplay(this);
// creates an item list to let you select multimedia files to play
itemList = new List("Select an item to play", List.IMPLICIT);
// stop, pause and restart commands
stopCommand = new Command("Stop", Command.STOP, 1);
pauseCommand = new Command("Pause", Command.ITEM, 1);
startCommand = new Command("Start", Command.ITEM, 1);
// a form to display when items are being played
form = new Form("Playing media");
// the form acts as the interface to stop and pause the media
form.addCommand(stopCommand);
form.addCommand(pauseCommand);
form.setCommandListener(this);
// create a hashtable of items
items = new Hashtable();
// and a hashtable to hold information about them
itemsInfo = new Hashtable();
// and populate both of them
items.put("Siren jar", "file://siren.wav");
itemsInfo.put("Siren jar", "audio/x-wav");
}
public void startApp() {
// when MIDlet is started, use the item list to display elements
for(Enumeration en = items.keys(); en.hasMoreElements();) {
itemList.append((String)en.nextElement(), null);
}
itemList.setCommandListener(this);
// show the list when MIDlet is started
display.setCurrent(itemList);
}
public void pauseApp() {
// pause the player
try {
if(player != null) player.stop();
} catch(Exception e) {}
}
public void destroyApp(boolean unconditional) {
if(player != null) player.close(); // close the player
}
public void commandAction(Command command, Displayable disp) {
// generic command handler
// if list is displayed, the user wants to play the item
if(disp instanceof List) {
List list = ((List)disp);
String key = list.getString(list.getSelectedIndex());
// try and play the selected file
try {
playMedia((String)items.get(key), key);
} catch (Exception e) {
System.err.println("Unablelay: " + e);
e.printStackTrace();
}
} else if(disp instanceof Form) {
// if showing form, means the media is being played
// and the user is trying to stop or pause the player
try {
if(command == stopCommand) { // if stopping the media play
player.close(); // close the player
display.setCurrent(itemList); // redisplay the list of media
form.removeCommand(startCommand); // remove the start command
form.addCommand(pauseCommand); // add the pause command
} else if(command == pauseCommand) { // if pausing
player.stop(); // pauses the media, note that it is called stop
form.removeCommand(pauseCommand); // remove the pause command
form.addCommand(startCommand); // add the start (restart) command
} else if(command == startCommand) { // if restarting
player.start(); // starts from where the last pause was called
form.removeCommand(startCommand);
form.addCommand(pauseCommand);
}
} catch(Exception e) {
System.err.println(e);
}
}
}
/* Creates Player and plays media for the first time */
private void playMedia(String locator, String key) throws Exception {
// locate the actual file, we are only dealing
// with file based media here
String file = locator.substring(
locator.indexOf("file://") + 6,
locator.length());
// create the player
// loading it as a resource and using information about it
// from the itemsInfo hashtable
player = Manager.createPlayer(
getClass().getResourceAsStream(file), (String)itemsInfo.get(key));
// a listener to handle player events like starting, closing etc
player.addPlayerListener(this);
player.setLoopCount(-1); // play indefinitely
player.prefetch(); // prefetch
player.realize(); // realize
player.start(); // and start
}
/* Handle player events */
public void playerUpdate(Player player, String event, Object eventData) {
// if the event is that the player has started, show the form
// but only if the event data indicates that the event relates to newly
// stated player, as the STARTED event is fired even if a player is
// restarted. Note that eventData indicates the time at which the start
// event is fired.
if(event.equals(PlayerListener.STARTED) &&
new Long(0L).equals((Long)eventData)) {
display.setCurrent(form);
} else if(event.equals(PlayerListener.CLOSED)) {
form.deleteAll(); // clears the form of any previous controls
}
}
}
?>
Copy code
package com.j2me.part4;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.media.Player;
import javax.microedition.media.Control;
import javax.microedition.media.Manager;
import javax.microedition.media.PlayerListener;
public class MediaMIDlet extends MIDlet
implements CommandListener, PlayerListener {
private Display display;
private List itemList;
private Form form;
private Command stopCommand;
private Command pauseCommand;
private Command startCommand;
private Hashtable items;
private Hashtable itemsInfo;
private Player player;
public MediaMIDlet() {
display = Display.getDisplay(this);
// creates an item list to let you select multimedia files to play
itemList = new List("Select an item to play", List.IMPLICIT);
// stop, pause and restart commands
stopCommand = new Command("Stop", Command.STOP, 1);
pauseCommand = new Command("Pause", Command.ITEM, 1);
startCommand = new Command("Start", Command.ITEM, 1);
// a form to display when items are being played
form = new Form("Playing media");
// the form acts as the interface to stop and pause the media
form.addCommand(stopCommand);
form.addCommand(pauseCommand);
form.setCommandListener(this);
// create a hashtable of items
items = new Hashtable();
// and a hashtable to hold information about them
itemsInfo = new Hashtable();
// and populate both of them
items.put("Siren jar", "file://siren.wav");
itemsInfo.put("Siren jar", "audio/x-wav");
}
public void startApp() {
// when MIDlet is started, use the item list to display elements
for(Enumeration en = items.keys(); en.hasMoreElements();) {
itemList.append((String)en.nextElement(), null);
}
itemList.setCommandListener(this);
// show the list when MIDlet is started
display.setCurrent(itemList);
}
public void pauseApp() {
// pause the player
try {
if(player != null) player.stop();
} catch(Exception e) {}
}
public void destroyApp(boolean unconditional) {
if(player != null) player.close(); // close the player
}
public void commandAction(Command command, Displayable disp) {
// generic command handler
// if list is displayed, the user wants to play the item
if(disp instanceof List) {
List list = ((List)disp);
String key = list.getString(list.getSelectedIndex());
// try and play the selected file
try {
playMedia((String)items.get(key), key);
} catch (Exception e) {
System.err.println("Unablelay: " + e);
e.printStackTrace();
}
} else if(disp instanceof Form) {
// if showing form, means the media is being played
// and the user is trying to stop or pause the player
try {
if(command == stopCommand) { // if stopping the media play
player.close(); // close the player
display.setCurrent(itemList); // redisplay the list of media
form.removeCommand(startCommand); // remove the start command
form.addCommand(pauseCommand); // add the pause command
} else if(command == pauseCommand) { // if pausing
player.stop(); // pauses the media, note that it is called stop
form.removeCommand(pauseCommand); // remove the pause command
form.addCommand(startCommand); // add the start (restart) command
} else if(command == startCommand) { // if restarting
player.start(); // starts from where the last pause was called
form.removeCommand(startCommand);
form.addCommand(pauseCommand);
}
} catch(Exception e) {
System.err.println(e);
}
}
}
/* Creates Player and plays media for the first time */
private void playMedia(String locator, String key) throws Exception {
// locate the actual file, we are only dealing
// with file based media here
String file = locator.substring(
locator.indexOf("file://") + 6,
locator.length());
// create the player
// loading it as a resource and using information about it
// from the itemsInfo hashtable
player = Manager.createPlayer(
getClass().getResourceAsStream(file), (String)itemsInfo.get(key));
// a listener to handle player events like starting, closing etc
player.addPlayerListener(this);
player.setLoopCount(-1); // play indefinitely
player.prefetch(); // prefetch
player.realize(); // realize
player.start(); // and start
}
/* Handle player events */
public void playerUpdate(Player player, String event, Object eventData) {
// if the event is that the player has started, show the form
// but only if the event data indicates that the event relates to newly
// stated player, as the STARTED event is fired even if a player is
// restarted. Note that eventData indicates the time at which the start
// event is fired.
if(event.equals(PlayerListener.STARTED) &&
new Long(0L).equals((Long)eventData)) {
display.setCurrent(form);
} else if(event.equals(PlayerListener.CLOSED)) {
form.deleteAll(); // clears the form of any previous controls
}
}
}
?>
Copy code
Code 1 – Audio playback đơn giản
Bây giờ bạn có một audio player đơn giản. Để bắt đầu, MIDler hiển thị một danh sách các media có thể play được. Lúc đó, như trong hình ảnh, chỉ có một media có tên “Siren from jar”. Chú ý rằng trong mã, “Siren from jar” tương ứng với một truy cập đến file audio. Điều này ngụ ý rằng vị trí thực của media sẽ là trong file jar. Khi người dùng chọn bài hát này, một đối tượng Player được tạo ra theo phương thức playMedia(). Phương thức này nạp player, gắn một listener cho nó, tìm nạp trước, realize và cuối cùng, khởi động player. Và cũng chú ý rằng player này chơi media liên tục.
Bởi vì listener cho Player chính là lớp MIDlet, phương thức playerUpdate() bắt lấy các sự kiện player. Vì thế, khi người dùng bắt đầu nghe bài hát, Form được hiển thị, cho phép người dùng stop hay pause lại. Việc chọn Stop đưa người dùng trở lại danh sách, trong khi chọn Pause chỉ tạm dừng chơi và chơi lại từ điểm đánh dấu khi được khởi động lại.
Bằng việc tạo ra lớp generic này, bây giờ dễ dàng để thêm các dạng media khác cho player. Bên cạnh audio, video là các kiểu media chính sẽ được play. Để cho phép MIDlet play video, chỉ cần thay đổi trong phương thức playerUpdate(), để tạo một video screen. Việc này được thực hiện như trong đoạn mã sau, những phần thay đổi được tô đậm:
<?php
/* Handle player events */
public void playerUpdate(Player player, String event, Object eventData) {
// if the event is that the player has started, show the form
// but only if the event data indicates that the event relates to newly
// stated player, as the STARTED event is fired even if a player is
// restarted. Note that eventData indicates the time at which the start
// event is fired.
If(event.equals(PlayerListener.STARTED) &&
new Long(0L)Equals((Long)eventData)) {
// see if we can show a video control, depending on whether the media
// is a video or not
VideoControl vc = null;
if((vc = (VideoControl)player.getControl("VideoControl")) != null) {
Item videoDisp =
(Item)vc.initDisplayMode(vc.USE_GUI_PRIMITIVE, null);
form.append(videoDisp);
}
display.setCurrent(form);
} else if(event.equals(PlayerListener.CLOSED)) {
form.deleteAll(); // clears the form of any previous controls
}
}
?>
Copy code
/* Handle player events */
public void playerUpdate(Player player, String event, Object eventData) {
// if the event is that the player has started, show the form
// but only if the event data indicates that the event relates to newly
// stated player, as the STARTED event is fired even if a player is
// restarted. Note that eventData indicates the time at which the start
// event is fired.
If(event.equals(PlayerListener.STARTED) &&
new Long(0L)Equals((Long)eventData)) {
// see if we can show a video control, depending on whether the media
// is a video or not
VideoControl vc = null;
if((vc = (VideoControl)player.getControl("VideoControl")) != null) {
Item videoDisp =
(Item)vc.initDisplayMode(vc.USE_GUI_PRIMITIVE, null);
form.append(videoDisp);
}
display.setCurrent(form);
} else if(event.equals(PlayerListener.CLOSED)) {
form.deleteAll(); // clears the form of any previous controls
}
}
?>
Copy code
Các thay đổi trên cho phép bạn chơi các file video với sự trợ giúp đắc lực của MediaMIDlet này. Nếu phương thức quyết định cho player đó có một VideoControl, có thể trình bày ra bằng cách tạo một GUI cho nó. GUI này sau đó được gắn vào form hiện hành. Dĩ nhiên, bây giờ bạn cần gắn một video vào danh sách để bạn có thể thử nghiệm nó.
Nhớ lại rằng không phải tất cả các thiết bị di động đều chơi tất cả các file video (hay các file audio). Để xem danh sách các file video được hỗ trợ theo từng thiết bị, hãy sử dụng phương thức Manager.getSupportedContentTypes(null). Trong trường hợp của Wireless Toolkit, video/mpeg được hỗ trợ sẵn, nếu bạn có một file video có tên huetoday.mpg, hãy thêm vào trong danh sách như sau:
<?php
items.put("Promoo from jar", "file://huetoday.mpg");
itemsInfo.put("Promoo from jar", "video/mpeg");
?>
Copy code
items.put("Promoo from jar", "file://huetoday.mpg");
itemsInfo.put("Promoo from jar", "video/mpeg");
?>
Copy code
Đặt video huetoday.mpg vào trong thư mục res, và bây giờ bạn có thể chọn và play file video đó khi MIDlet chạy lên. Kết quả có thể tương tự như hình 4 sau:
[imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-h4.png?w=630[/img
Hình 4 – Video playback với MediaMIDlet
3.Truyền tải stream media qua đường truyền mạng
Cũng giống như mọi file media khác, đặc biệt là các file video, sẽ không được phân bổ với MIDlet của bạn, trừ phi chúng thực sự có kích thước nhỏ. Với một ứng dụng MIDlet thành công, khả năng stream media qua đường mạng là một yếu tố cần thiết. MediaMIDlet có thể chơi các media qua đường mạng một cách dễ dàng bằng cách chỉ rõ một file dựa trên giao thức HTTP. Tuy nhiên, có hai vấn đề cần được làm sáng tỏ ngay sau đây.
Thứ nhất, truy cập media qua đường mạng yêu cầu các quyền truy cập từ phía người dùng cuối. Sau hết, người dùng phải chịu một mức phí mạng nào đó. Có nhiều cách để lấy được các quyền truy cập này và lưu các kết quả bên trong môi trường MIDlet, nhưng tôi sẽ không đi sâu chi tiết ở đây.
Thứ hai, truy cập media qua đường mạng có thể là một hành động tiêu tốn khá nhiều thời gian. Hành động này sẽ không được thực hiện trong thread chính của ứng dụng, trong trường hợp bị ràng buộc vào một mạng bị giới hạn tốc độ. Tất cả các truy cập mạng sẽ được thực hiện trong một thread riêng rẽ.
Hãy nhớ kỹ 2 vấn đề này, Code 2 cho thấy một phần Code 1 đã được thay đổi (mã được thêm vào là để play các file video). Vấn đề đầu tiên đã được chăm sóc cẩn thận bởi AMS bên dưới. Nó hỏi thẳng quyền truy cập người dùng một khi truy cập mạng được yêu cầu. Vấn đề thứ hai lại được chăm sóc cẩn thận bằng cách phân tách mã truy cập media mạng trong một thread riêng.
<?php
package com.j2me.part4;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Alert;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.media.Player;
import javax.microedition.media.Control;
import javax.microedition.media.Manager;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.VideoControl;
public class MediaMIDletV2 extends MIDlet
implements CommandListener {
private Display display;
private List itemList;
private Form form;
private Hashtable items;
public MediaMIDletV2() {
display = Display.getDisplay(this);
// creates an item list to let you select multimedia files to play
itemList = new List("Select an item to play", List.IMPLICIT);
// a form to display when items are being played
form = new Form("Playing media");
// create a hashtable of items
items = new Hashtable();
// and populate both of them
items.put("Siren web", "http://www.craftbits.com/j2me/siren.wav");
items.put(
"Promo Video from web",
"http://www.craftbits.com/j2me/promo.mpg");
}
public void startApp() {
// when MIDlet is started, use the item list to display elements
for(Enumeration en = items.keys(); en.hasMoreElements();) {
itemList.append((String)en.nextElement(), null);
}
itemList.setCommandListener(this);
// show the list when MIDlet is started
display.setCurrent(itemList);
}
public void pauseApp() {
}
public void destroyApp(Boolean unconditional) {
}
public void commandAction(Command command, Displayable disp) {
// generic command handler
// if list is displayed, the user wants to play the item
if(disp instanceof List) {
List list = ((List)disp);
String key = list.getString(list.getSelectedIndex());
// try and play the selected file
try {
playMedia((String)items.get(key));
} catch (Exception e) {
System.err.println("Unablelay: " + e);
e.printStackTrace();
}
}
}
/* Creates Player and plays media for the first time */
private void playMedia(String locator) throws Exception {
PlayerManager manager =
new PlayerManager(form, itemList, locator, display);
form.setCommandListener(manager);
Thread runner = new Thread(manager);
runner.start();
}
}
class PlayerManager implements Runnable, CommandListener, PlayerListener {
Form form;
List list;
Player player;
String locator;
Display display;
private Command stopCommand;
private Command pauseCommand;
private Command startCommand;
public PlayerManager(Form form, List list, String locator, Display display) {
this.form = form;
this.list = list;
this.locator = locator;
this.display = display;
// stop, pause and restart commands
stopCommand = new Command("Stop", Command.STOP, 1);
pauseCommand = new Command("Pause", Command.ITEM, 1);
startCommand = new Command("Start", Command.ITEM, 1);
// the form acts as the interface to stop and pause the media
form.addCommand(stopCommand);
form.addCommand(pauseCommand);
}
public void run() {
try {
// since we are loading data over the network, a delay can be
// expected
Alert alert = new Alert("Loading. Please wait ....");
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
player = Manager.createPlayer(locator);
// a listener to handle player events like starting, closing etc
player.addPlayerListener(this);
player.setLoopCount(-1); // play indefinitely
player.prefetch(); // prefetch
player.realize(); // realize
player.start(); // and start
} catch(Exception e) {
System.err.println(e);
e.printStackTrace();
}
}
public void commandAction(Command command, Displayable disp) {
if(disp instanceof Form) {
// if showing form, means the media is being played
// and the user is trying to stop or pause the player
try {
if(command == stopCommand) { // if stopping the media play
player.close(); // close the player
display.setCurrent(list); // redisplay the list of media
form.removeCommand(startCommand); // remove the start command
form.removeCommand(pauseCommand); // remove the pause command
form.removeCommand(stopCommand); // and the stop command
} else if(command == pauseCommand) { // if pausing
player.stop(); // pauses the media, note that it is called stop
form.removeCommand(pauseCommand); // remove the pause command
form.addCommand(startCommand); // add the start (restart) command
} else if(command == startCommand) { // if restarting
player.start(); // starts from where the last pause was called
form.removeCommand(startCommand);
form.addCommand(pauseCommand);
}
} catch(Exception e) {
System.err.println(e);
}
}
}
/* Handle player events */
public void playerUpdate(Player player, String event, Object eventData) {
// if the event is that the player has started, show the form
// but only if the event data indicates that the event relates to newly
// stated player, as the STARTED event is fired even if a player is
// restarted. Note that eventData indicates the time at which the start
// event is fired.
if(event.equals(PlayerListener.STARTED) &&
new Long(0L)Equals((Long)eventData)) {
// see if we can show a video control, depending on whether the media
// is a video or not
VideoControl vc = null;
if((vc = (VideoControl)player.getControl("VideoControl")) != null) {
Item videoDisp =
(Item)vc.initDisplayMode(vc.USE_GUI_PRIMITIVE, null);
form.append(videoDisp);
}
display.setCurrent(form);
} else if(event.equals(PlayerListener.CLOSED)) {
form.deleteAll(); // clears the form of any previous controls
}
}
}
?>
Copy code
package com.j2me.part4;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Alert;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.media.Player;
import javax.microedition.media.Control;
import javax.microedition.media.Manager;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.VideoControl;
public class MediaMIDletV2 extends MIDlet
implements CommandListener {
private Display display;
private List itemList;
private Form form;
private Hashtable items;
public MediaMIDletV2() {
display = Display.getDisplay(this);
// creates an item list to let you select multimedia files to play
itemList = new List("Select an item to play", List.IMPLICIT);
// a form to display when items are being played
form = new Form("Playing media");
// create a hashtable of items
items = new Hashtable();
// and populate both of them
items.put("Siren web", "http://www.craftbits.com/j2me/siren.wav");
items.put(
"Promo Video from web",
"http://www.craftbits.com/j2me/promo.mpg");
}
public void startApp() {
// when MIDlet is started, use the item list to display elements
for(Enumeration en = items.keys(); en.hasMoreElements();) {
itemList.append((String)en.nextElement(), null);
}
itemList.setCommandListener(this);
// show the list when MIDlet is started
display.setCurrent(itemList);
}
public void pauseApp() {
}
public void destroyApp(Boolean unconditional) {
}
public void commandAction(Command command, Displayable disp) {
// generic command handler
// if list is displayed, the user wants to play the item
if(disp instanceof List) {
List list = ((List)disp);
String key = list.getString(list.getSelectedIndex());
// try and play the selected file
try {
playMedia((String)items.get(key));
} catch (Exception e) {
System.err.println("Unablelay: " + e);
e.printStackTrace();
}
}
}
/* Creates Player and plays media for the first time */
private void playMedia(String locator) throws Exception {
PlayerManager manager =
new PlayerManager(form, itemList, locator, display);
form.setCommandListener(manager);
Thread runner = new Thread(manager);
runner.start();
}
}
class PlayerManager implements Runnable, CommandListener, PlayerListener {
Form form;
List list;
Player player;
String locator;
Display display;
private Command stopCommand;
private Command pauseCommand;
private Command startCommand;
public PlayerManager(Form form, List list, String locator, Display display) {
this.form = form;
this.list = list;
this.locator = locator;
this.display = display;
// stop, pause and restart commands
stopCommand = new Command("Stop", Command.STOP, 1);
pauseCommand = new Command("Pause", Command.ITEM, 1);
startCommand = new Command("Start", Command.ITEM, 1);
// the form acts as the interface to stop and pause the media
form.addCommand(stopCommand);
form.addCommand(pauseCommand);
}
public void run() {
try {
// since we are loading data over the network, a delay can be
// expected
Alert alert = new Alert("Loading. Please wait ....");
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
player = Manager.createPlayer(locator);
// a listener to handle player events like starting, closing etc
player.addPlayerListener(this);
player.setLoopCount(-1); // play indefinitely
player.prefetch(); // prefetch
player.realize(); // realize
player.start(); // and start
} catch(Exception e) {
System.err.println(e);
e.printStackTrace();
}
}
public void commandAction(Command command, Displayable disp) {
if(disp instanceof Form) {
// if showing form, means the media is being played
// and the user is trying to stop or pause the player
try {
if(command == stopCommand) { // if stopping the media play
player.close(); // close the player
display.setCurrent(list); // redisplay the list of media
form.removeCommand(startCommand); // remove the start command
form.removeCommand(pauseCommand); // remove the pause command
form.removeCommand(stopCommand); // and the stop command
} else if(command == pauseCommand) { // if pausing
player.stop(); // pauses the media, note that it is called stop
form.removeCommand(pauseCommand); // remove the pause command
form.addCommand(startCommand); // add the start (restart) command
} else if(command == startCommand) { // if restarting
player.start(); // starts from where the last pause was called
form.removeCommand(startCommand);
form.addCommand(pauseCommand);
}
} catch(Exception e) {
System.err.println(e);
}
}
}
/* Handle player events */
public void playerUpdate(Player player, String event, Object eventData) {
// if the event is that the player has started, show the form
// but only if the event data indicates that the event relates to newly
// stated player, as the STARTED event is fired even if a player is
// restarted. Note that eventData indicates the time at which the start
// event is fired.
if(event.equals(PlayerListener.STARTED) &&
new Long(0L)Equals((Long)eventData)) {
// see if we can show a video control, depending on whether the media
// is a video or not
VideoControl vc = null;
if((vc = (VideoControl)player.getControl("VideoControl")) != null) {
Item videoDisp =
(Item)vc.initDisplayMode(vc.USE_GUI_PRIMITIVE, null);
form.append(videoDisp);
}
display.setCurrent(form);
} else if(event.equals(PlayerListener.CLOSED)) {
form.deleteAll(); // clears the form of any previous controls
}
}
}
?>
Copy code
Code 2 – Truy cập media qua đường mạng trong một thread riêng
Như bạn có thể thấy, tất cả mã tương tác với media đã được di chuyển vào lớp PlayerManager, và chạy trong một thread riêng. Hình 5 cho thấy cách tương tác với MIDlet.
[imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-h5.png?w=630[/img
Hình 5 – Quá trình truy cập qua đường mạng
Chú ý cách MIDlet hỏi quyền truy cập người dùng vào mạng trước khi player được tạo ra. Quyền truy cập được cập một lần và có giá trị trong suốt thời gian MIDlet chạy; vì thế, các truy cập mạng sau đó không yêu cầu màn hình hỏi quyền truy cập này nữa.
Như vậy là đến phần cuối của series 1 về J2ME. Tôi chỉ có thể đưa ra một tổng quan ngắn gọn về Mobile Media API và các tập con của nó trong MIDP 2.0 cùng một số ví dụ đơn giản. Có vài thứ khác mà bạn có thể làm thêm với API này, như tạo ra và play các tone – giai điệu, ghi âm hay ghi hình hay radio streaming qua đường mạng. Hãy khám phá thêm tài liệu API và sử dụng các ví dụ đã có trong các bài học để cải thiện các khả năng hoạt động trong MIDlet của bạn. Chúc các bạn thành công.
Dịch từ today.java.net
Chỉnh sửa lúc 2016-05-27 02:03 bởi Pham_loi
: 0 ♥
Trực Tuyến:
Khách: 1