参考:
Android MediaPlayer+SurfaceView播放视频(附Demo)
MediaPlayer+SurfaceView 视频播放 示例
Android MediaPlayer和VideoView的使用
获得MediaPlayer实例:
可以直接new或者调用create方法创建:
MediaPlayer mp = new MediaPlayer();
MediaPlayer mp = MediaPlayer.create(this, R.raw.test); //无需再调用setDataSource
注意事项:
播放的是res/raw目录下的音频文件,
创建MediaPlayer调用的是create方法,第一次启动播放前不需要再调用prepare(),
如果是使用构造方法构造的话,则需要调用一次prepare()方法!
另外create还有这样的形式:
create(Context context, Uri uri, SurfaceHolder holder)
通过Uri和指定 SurfaceHolder 【抽象类】 创建一个多媒体播放器。
设置播放文件:
MediaPlayer mp = MediaPlayer.create(this, R.raw.test); //①raw下的资源
mp.setDataSource("/sdcard/test.mp3"); //②本地文件路径
mp.setDataSource("http://www.xxx.com/music/test.mp3");//③网络URL文件
mp.setDataSource(this, "http://www.xxx.com/music/test.mp3")//④URI
另外setDataSource()方法有多个,里面有这样一个类型的参数:FileDescriptor
在使用这个API的时候,需要把文件放到res文件夹平级的assets文件夹里,然后使用下述代码设置DataSource:
AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
fileDescriptor.getStartOffset(),
fileDescriptor.getLength());
//public void setDataSource(FileDescriptor fd, long offset, long length)
其他方法
getCurrentPosition( ):得到当前的播放位置
getDuration() :得到文件的时间
getVideoHeight() :得到视频高度
getVideoWidth() :得到视频宽度
isLooping():是否循环播放
isPlaying():是否正在播放
pause():暂停
prepare():准备(同步)
prepareAsync():准备(异步)
release():释放MediaPlayer对象
reset():重置MediaPlayer对象
seekTo(int msec):指定播放的位置(以毫秒为单位的时间)
setAudioStreamType(int streamtype):指定流媒体的类型
setDisplay(SurfaceHolder sh):设置用SurfaceHolder来显示多媒体
setLooping(boolean looping):设置是否循环播放
setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener):网络流媒体的缓冲监听
setOnCompletionListener(MediaPlayer.OnCompletionListener listener):网络流媒体播放结束监听
setOnErrorListener(MediaPlayer.OnErrorListener listener):设置错误信息监听
setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener):视频尺寸监听
setScreenOnWhilePlaying(boolean screenOn):设置是否使用SurfaceHolder显示
setVolume(float leftVolume, float rightVolume):设置音量
start():开始播放
stop():停止播放
SurfaceView
SurfaceView在视频播放中起到显示画面的作用,而视频的播放主要通过MediaPlayer来控制。
SurfaceView 允许我们在非UI主线程中改变SurfaceView的内容,由于这个特点游戏开发在界面处理上大多会选择SurfaceView。
SurfaceView双缓冲
SurfaceView和大部分视频应用一样,把视频流解析成一帧帧的图像进行显示,但是如果把这个解析的过程放到一个线程中完成,可能在上一帧图像已经显示过后,下一帧图像还没有来得及解析,这样会导致画面的不流畅或者声音和视频不同步的问题。所以SurfaceView和大部分视频应用一样,通过双缓冲的机制来显示帧图像。
那么什么是双缓冲呢?双缓冲可以理解为有两个线程轮番去解析视频流的帧图像,当一个线程解析完帧图像后,把图像渲染到界面中,同时另一线程开始解析下一帧图像,使得两个线程轮番配合去解析视频流,以达到流畅播放的效果。
surfaceview+MediaPlayer播放视频
使用步骤:
1、调用player.setDataSource()方法设置要播放的资源,可以是文件、文件路径、或者URL。
新建一个MediaPlayer: mPlayer=new MediaPlayer();
通常在新建一个MediaPlayer实体后,会对给它增加需要的监听事件,MediaPlayer的监听事件有:
MediaPlayer.OnPreparedListener:
//MediaPlayer进入准备完成的状态触发,表示媒体可以开始播放了。
MediaPlayer.OnSeekCompleteListener:
//调用MediaPlayer的seekTo方法后,MediaPlayer会跳转到媒体指定的位置,当跳转完成时触发。
//需要注意的时,seekTo并不能精确的挑战,它的跳转点必须是媒体资源的关键帧。
MediaPlayer.OnBufferingUpdateListener:
//网络上的媒体资源缓存进度更新的时候会触发。
MediaPlayer.OnCompletionListener:
//媒体播放完毕时会触发。但是当OnErrorLister返回false,
//或者MediaPlayer没有设置OnErrorListener时,这个监听也会被触发。
MediaPlayer.OnVideoSizeChangedListener:
//视频宽高发生改变的时候会触发。当所设置的媒体资源没有视频图像、MediaPlayer
//没有设置展示的holder或者视频大小还没有被测量出来时,获取宽高得到的都是0.
MediaPlayer.OnErrorListener:
//MediaPlayer出错时会触发,无论是播放过程中出错,还是准备过程中出错,都会触发。
2、调用MediaPlayer.setDisplay(holder)设置surfaceHolder,surfaceHolder可以通过surfaceview的getHolder()方法获得。
将需要播放的资源路径交给MediaPlayer实体:mPlayer.setDataSource(source);
3、调用MediaPlayer.prepare()来准备。
让MediaPlayer去获取解析资源,调用prepare()或者prepareAsync()方法,前一个是同步方法,后一个是异步方法,通常我们用的比较多的是后者:mPlayer.prepareAsync();
4、调用MediaPlayer.start()来播放视频。
进入准备完成状态后,调用start()方法开始播放,如果是调用prepare()方法准备,在prepare()方法后,可以直接开始播放。如果是调用prepareAsync()方法准备,需要在OnPreparedListener()监听中开始播放:mPlayer.start();
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
mediaPlayer.setDisplay(holder);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mediaPlayer != null) {
seekBar.setProgress(0);
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
if (timer != null) {
timer.cancel();
}
}
}
});
注意:
SurfaceView播放视频时,如果不进行设置,视频宽高总是等于定义的SurfaceView布局宽高,所以视频可能会被拉伸变形。而使用VideoView时,视频宽度等于VideoView布局宽,但是高是自适应的,自动调整宽高比到视频原始比例,所以不会有拉伸。