作者:温尚书,华清远见嵌入式学院讲师。
在上一篇文章中,我们讨论了如何在android中播放视频,并且讲解了VideoView的使用。本篇文章将继续上篇文章的主题,来学习如何使用MediaPlayer来播放视频。
对于MediaPlayer,要熟练掌握它的用法,一定要熟悉下面这张MediaPlayer的方法调用和状态转换图。
这张MediaPLayer状态图看起来很复杂,但实际上,只要理解了它的基本过程,就不会那么难了。我们可以结合我们播放视频的过程来了解,我们如果需要播放一个视频,大致的流程是:创建播放器对象?设置需要播放的视频的来源?对视频进行解码等准备工作?开始播放?(暂停?重启)?停止播放。对应这些流程,在MediaPlayer中都定义了相关的方法,而且,在调用这些方法后,MediaPlayer可以进入不同的状态。这些方法和状态都很好理解,读者可以参照上图来了解。另外,因为在设置播放的视频的视频数据源之后,它需要对其进行解码(调用prepare()方法),这是一个比较耗时的操作,所以为了避免应用程序阻止在这里,可以使用它的prepareAsync()方法配合OnPreparedListener监听器来让其异步操作。注意,只有MediaPlayer的准备工作做完后,才能开始播放。
MediaPlayer本身不能显示视频内容,它只能控制视频的播放。如果要使用MediaPlayer来播放视频,还需要配合SurfaceView来显示视频。关于SurfaceView的用法,限于篇幅在这里不再赘述。而要将MediaPlayer中解码的视频数据在SurfaceView中播放,需要调用MediaPlayer中的setDisplay()方法,它接受一个SurfaceHolder对象,可以将我们用于播放视频的SurfaceView对应的SurfaceHolder对象作为参数,这样,MediaPlayer和SurfaceView就建立起了关联。还有一个需要注意的是,要正确设置SurfaceView的大小(Size)和视频的大小相匹配。
以下为MediaPlayer中的主要方法和说明:
●setDataSource():设置播放的数据源。参数可以是字符串、FileDescriptor或者Uri等。
●setDisplay():接受一个SurfaceHolder参数,用于设置播放视频的SurfaceView。
●prepare()/prepareAsync():准备MediaPlayer准备播放。它们的区别在于前者是同步方法,后者是异步方法,且后者一般需要配合OnPreparedListener监听器。
●start():开始播放多媒体。
● pause():暂停播放多媒体。
●seekTo():改变播放进度。
●stop():停止播放多媒体。
下面我们来看一个例子:
package com.stylingandroid.viewpager;
import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
public class MediaPlayerVideo extends Activity implements
OnCompletionListener,
OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback {
private static final String TAG = "MediaPlayerDemo";
private int mVideoWidth;
private int mVideoHeight;
private MediaPlayer mMediaPlayer;
SurfaceView mPreview;
private SurfaceHolder holder;
private String path;
private Bundle extras;
private boolean mIsVideoSizeKnown = false;
private boolean mIsVideoReadyToBePlayed = false;
/**
*
* when the activity is first created.
*/
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
mPreview = (SurfaceView) findViewById(R.id.surfaceview);
holder = mPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
extras = getIntent().getExtras();
}
private void playVideo() {
clean();
try{
// 创建一个MediaPlayer对象
mMediaPlayer = new MediaPlayer();
// 设置播放的视频数据源
mMediaPlayer.setDataSource(path);
// 将视频输出到SurfaceView
mMediaPlayer.setDisplay(holder);
// 播放准备,使用异步方式,配合OnPreparedListener
mMediaPlayer.prepareAsync();
// 设置相关的监听器
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnVideoSizeChangedListener(this);
// 设置音频流类型
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
} catch (Exception e) {
e.printStackTrace();
}
}
public void onCompletion(MediaPlayer arg0) {
Log.d(TAG, "onCompletion");
}
//获得视频的宽和高
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
Log.v(TAG, "onVideoSizeChanged");
if (width == 0 || height == 0) {
Log.e(TAG, "invalid video width(" + width + ") or height(" + height + ")");
return;
}
mIsVideoSizeKnown = true;
mVideoWidth = width;
mVideoHeight = height;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
//实现OnPreparedListener中的方法,当视频准备完毕会调用这个回调方法,开始播放
public void onPrepared(MediaPlayer mediaplayer) {
Log.d(TAG, "onPrepared");
mIsVideoReadyToBePlayed = true;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) {
Log.d(TAG, "surfaceChanged");
}
public void surfaceDestroyed(SurfaceHolder surfaceholder) {
Log.d(TAG, "surfaceDestroyed");
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated");
playVideo();
}
@Override
protected void onPause() {
releaseMediaPlayer();
clean();
super.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
releaseMediaPlayer();
clean();
}
// 释放MediaPlayer
private void releaseMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
}
// 资源清理工作
private void clean() {
mVideoWidth = 0;
mVideoHeight = 0;
mIsVideoReadyToBePlayed = false;
mIsVideoSizeKnown = false;
}
// 播放视频的方法
private void startVideoPlayback() {
Log.v(TAG, "startVideoPlayback");
holder.setFixedSize(mVideoWidth, mVideoHeight);
mMediaPlayer.start();
}
}
其中的main.xml这个layout很简单,就是一个SurfaceView,如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.
android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:gravity="center" android:layout_height="fill_parent">
<SurfaceView android:id="@+id/surfaceView1"
android:layout_width="800px"
android:layout_height="600px"></SurfaceView>
</LinearLayout>
文章来源:华清远见嵌入式学院,原文地址:http://www.embedu.org/Column/Column503.htm