Sử dụng MediaPlayer để chạy Video trong Android
Bài đăng này đã không được cập nhật trong 3 năm
Về mặt kỹ thuật, một số thiết bị điện thoại di động đã có khả năng hỗ trợ video từ trước 2004. Tuy nhiên trên thực tế, video trên điện thoại di động chỉ thực sự phổ biến từ sự ra đời của iPhone vào năm 2007. Kể từ đó, mỗi chiếc điện thoại thông minh đều được hỗ trợ play video. Và với Android cũng như vậy.
Những định dạng (format) được hỗ trợ
Android hỗ trợ những định dạng thông thường mà các thiết bị di động khác được hỗ trợ. Đó là định dạng 3GP (.3gp) và MPEG-4 (.mp4). 3GP là một chuẩn video có nguồn gốc từ MPEG-4 đặc biệt để sử dụng cho các thiết bị di động.
Kể từ Android 3.0 trở lên được hỗ trợ thêm định dạng WebM.
Sử dụng MediaPlayer
Các trạng thái của MediaPlayer
Đối tượng MediaPlayer hoạt động theo máy trạng thái. Có nghĩa là các hoạt động phải được thực hiện theo một thứ tự cụ thể và các phương thức khác nhau chỉ được gọi khi đối tượng đang ở trạng thái chính xác để xử lý chúng.
Lớp MediaPlayer định nghĩa một vài listener cho phép ứng dụng sử dụng nó để lắng nghe những thông báo về các thay đổi trạng thái khác nhau để có những hành động phù hợp.
Sơ đồ trạng thái của MediaPlayer
Ví dụ cụ thể
Sau đây là ví dụ cụ thể sử dụng MediaPlayer để play video trong ứng dụng.
Import MediaPlayer và các interface để sử dụng:
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
SurfaceHolder và SurfaceView sẽ được sử dụng để draw video:
import android.view.SurfaceHolder;
import android.view.SurfaceView;
Activity sẽ implement tất cả các listener lắng nghe thay đổi trạng thái của MediaPlayer
và interface SurfaceHolder.Callback
cho phép nhận được thông báo về thay đổi của một SurfaceView
.
public class CustomVideoPlayer extends Activity implements OnCompletionListener, OnErrorListener, OnInfoListener, OnPreparedListener, OnSeekCompleteListener, OnVideoSizeChangedListener, SurfaceHolder.Callback {
Display currentDisplay;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
...
}
Khai báo đối tượng MediaPlayer
MediaPlayer mediaPlayer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Tham chiếu đến đối tượng SurfaceView
được định nghĩa trong layout XML và tham chiếu đến SurfaceHolder
cho phép theo dõi những thay đổi xảy ra đối với video.
surfaceView = (SurfaceView)this.findViewById(R.id.SurfaceView);
surfaceHolder = surfaceView.getHolder();
Vì activity đã implement SurfaceHolder.Callback
, chúng ta sẽ add lắng nghe callback cho SurfaceHolder:
surfaceHolder.addCallback(this);
Bây giờ, bắt đầu tạo đối tượng MediaPlayer
, không truyền tham số để nhận được đối tượng ở trạng thái "idle".
mediaPlayer = new MediaPlayer();
Chỉ định lắng nghe các sự kiện khác nhau:
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnVideoSizeChangedListener(this);
Trước khi kết thúc phương thức onCreate()
, truyền vào đối tượng video cho MediaPlayer thông qua đường dẫn filePath
. Phương thức setDataSource()
trên MediaPlayer có thể nhảy vào các ngoại lệ.
try {
mediaPlayer.setDataSource(filePath);
} catch (IllegalArgumentException e) {
Log.v(LOGTAG,e.getMessage());
finish();
} catch (IllegalStateException e) {
Log.v(LOGTAG,e.getMessage());
finish();
} catch (IOException e) {
Log.v(LOGTAG,e.getMessage());
finish();
}
Vì activity đã implement SurfaceHolder.Callback
và surfaceHolder
đã đăng ký lắng nghe các callback, nên 3 phương thức sau sẽ được kích hoạt.
surfaceCreated
sẽ được gọi khi Surface trong SurfaceView
được tạo.
public void surfaceCreated(SurfaceHolder holder) {
Log.v(LOGTAG,"surfaceCreated Called");
Khi Surface được tạo ra, chúng ta có thể xác định rằng các MediaPlayer
sử dụng Surface để play bằng cách gọi phương thức setDisplay
truyền vào đối tượng SurfaceHolder.
mediaPlayer.setDisplay(holder);
Cuối cùng, sau khi đã xác định Surface, chúng ta có thể gọi prepare
. Phương thức prepare
sẽ block thread chính chứ không thực hiện trong thread background. Để thực hiện ở chế độ background, không để ứng dụng bị treo, sử dụng phương thức prepareAsyn
. Dù bằng cách nào, vì OnPreparedListener
đã được implement trong activity, phương thức onPrepared
sẽ được gọi khi thực hiện xong prepare.
Phương thức prepare
có thể nhảy ra các ngoại lệ:
try {
mediaPlayer.prepare();
} catch (IllegalStateException e) {
Log.v(LOGTAG,e.getMessage());
finish();
} catch (IOException e) {
Log.v(LOGTAG,e.getMessage());
finish();
}
surfaceChanged
sẽ được gọi khi width, height hoặc tham số khác của SurfaceView thay đổi.
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){
Log.v(LOGTAG,"surfaceChanged Called");
}
surfaceDestroyed
sẽ được gọi khi Surface của SurfaceView bị huỷ.
public void surfaceDestroyed(SurfaceHolder holder) {
Log.v(LOGTAG,"surfaceDestroyed Called");
}
Vì MediaPlayer.OnCompletionListener
đã được implement và đăng ký lắng nghe, phương thức onCompletion
sẽ được gọi khi MediaPlayer
play xong video.
public void onCompletion(MediaPlayer mp) {
Log.v(LOGTAG,"onCompletion Called");
finish();
}
Activity có implement MediaPlayer.OnErrorListener
và được đăng ký lắng nghe cho đối tượng MediaPlayer
, do đó phương thức onError
sẽ được gọi khi có vấn đề xảy ra. Không may là không có nhiều thông tin lỗi, chỉ có 2 hằng số như sau:
public boolean onError(MediaPlayer mp, int whatError, int extra) {
Log.v(LOGTAG,"onError Called");
if (whatError == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
Log.v(LOGTAG,"Media Error, Server Died " + extra);
} else if (whatError == MediaPlayer.MEDIA_ERROR_UNKNOWN){
Log.v(LOGTAG,"Media Error, Error Unknown " + extra);
}
return false;
}
Return false từ phương thức này chỉ ra rằng các lỗi đã không được xử lý. Nếu một OnCompletionListener
được đăng ký, phương thức onCompletion
sẽ được gọi. Đối tượng MediaPlayer
sẽ được chuyển sang trạng thái "error". Nó có thể trở về trạng thái "idle" nếu gọi tới phương thức reset
.
Phương thức onInfo
được đặc tả trong OnInfoListener
được gọi khi có được thông tin cụ thể về video hoặc một cảnh báo được đưa ra.
public boolean onInfo(MediaPlayer mp, int whatInfo, int extra) {
if (whatInfo == MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING){
Log.v(LOGTAG,"Media Info, Media Info Bad Interleaving " + extra);
} else if (whatInfo == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
Log.v(LOGTAG,"Media Info, Media Info Not Seekable " + extra);
} else if (whatInfo == MediaPlayer.MEDIA_INFO_UNKNOWN) {
Log.v(LOGTAG,"Media Info, Media Info Unknown " + extra);
} else if (whatInfo == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING) {
Log.v(LOGTAG,"MediaInfo, Media Info Video Track Lagging " + extra);
}
return false;
}
Sau khi MediaPlayer prepare thành công, onPrepared
sẽ được gọi. Khi đó video có thể được start.
public void onPrepared(MediaPlayer mp) {
Log.v(LOGTAG,"onPrepared Called");
mp.start();
}
Kết quả màn hình ứng dụng sử dụng MediaPlayer
All rights reserved