视频播放二:MediaPlayer+SurfaceView

参考:

Android MediaPlayer+SurfaceView播放视频(附Demo)
MediaPlayer+SurfaceView 视频播放 示例
Android MediaPlayer和VideoView的使用

demo地址

获得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布局宽,但是高是自适应的,自动调整宽高比到视频原始比例,所以不会有拉伸。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值