Android MediaPlayer和SurfaceView播放音视频

Android支持的媒体格式列表,可见:Supported Media Formats文档
在播放网络上的视频流时,Android原生的MediaPlayer支持两种协议,HTTP和RTSP,这两种协议最大的不同是,RTSP协议支持实时流媒体的播放,而HTTP协议不支持。因为VideoView的底层实现是MediaPlayer,因此VideoView也支持以上两种协议

(1)获得MediaPlayer实例:

MediaPlayer mp = new MediaPlayer();
MediaPlayer mp = MediaPlayer.create(this, R.raw.test); //无需再调用setDataSource

(2)设置播放文件:

MediaPlayer.create(this, R.raw.test); //①raw下的资源
mp.setDataSource("/sdcard/test.mp3"); //②本地文件路径
mp.setDataSource("http://www.xxx.com/music/test.mp3");//③网络URL文件

生命周期:

状态1:Idel(空闲)状态
当 mediaplayer创建或者执行reset()方法后处于这个状态。

状态2:Initialized(已初始化)状态
当调用mediaplayer的setDataResource()方法给mediaplayer设置播放的数据源后,mediaplayer会处于该状态。

状态3:Prepared(准备就续)状态
设置完数据源后,调用mediaplayer的prepare()方法,让mediaplayer准备播放。值得一提的是,这里除了prepare()方法,还有prepareAsnyc()方法,此方法是异步方法,一般用于网络视频的缓冲。当缓冲完毕后,就会触发准备完毕的事件。我们要做的就是监听该事件(OnPreparedListener),当缓冲完成时,执行相应的操作。在此状态上,我们可以调用seekTo()方法定位视频,此方法不改变mediaplayer的状态;亦可调用stop()放弃视频播放,使mediaplayer处于Stopped状态。一般我们会在此状态上调用start()方法开始播放视频。

状态4:Started(开始)状态
当处于Prepared状态、Paused状态和PlayebackCompeleted状态时,调用Started()方法即可进入该状态。在该状态中,mediaplayer开始播放视频,可以通过seekTo()方法和start()方法改变视频播放的进度,当Looping为真且播放完毕后,它会重新开始播放(即循环播放);否则播放完毕后,会触发事件并调用OnCompletionaListener.OnCompletion()方法,进行特定操作,并进入PlaybackCompleted状态。在此状态中,亦可调用pause()方法或者stop()方法让视频暂停或停止,此时mediaplayer分别处于Stopped和Paused状态。

状态5:Stopped(停止)状态
当 mediaplayer处于Prepared、Started、Paused、PlaybackCompleted状态时,调用stop()方法即可进入本状态。应特别注意的是,在本状态中,若想重新开始播放,不能直接调用start()方法,必须调用prepare()方法或prepareAsync()方法重新让mediaplayer处于Prepared状态方可调用start()方法播放视频。

状态6:Paused(暂停)状态
当mediaplayer处于Started状态是,调用pause()方法即可进入本状态。在本状态里,可直接调用start()方法使,mediaplayer回到Started状态,亦可调用stop()方法停止视频播放,让播放器处于停止态。

状态7:PlaybackCompleted(播放完成)状态
当mediaplayer播放完成且Looping为假时即可进入本状态。在本状态可调用start()方法使mediaplayer回到Started状态(注意此时是从头开始播放);亦可调用stop()方法使mediaplayer处于停止态,结束播放。

状态8:Error(错误)状态
当mediaplayer出现错误时处于此状态。
 

使用MediaPlayer + SurfaceView播放视频

MediaPlayer主要用于播放音频,没有提供图像输出界面,所以我们需要借助其他的组件来显示MediaPlayer播放的图像输出

主要实现逻辑:
调用getHolder获得一个SurfaceHolder对象,在这里完成SurfaceView相关的设置,设置了类型以及一个Callback接口
surfaceHolder.SURFACE_TYPE_PUSH_BUFFERS不让SurfaceView自己维护双缓冲,交给MediaPlayer管理。
双缓冲指内部有2个线程,A更新界面时,B进行后台计算,当各自完成任务时互相交换,避免线程阻塞,提高响应速度。

public void onCreate(Bundle savedInstanceState) {

        surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            public void surfaceDestroyed(SurfaceHolder holder) {}
            public void surfaceCreated(SurfaceHolder holder) {
                if (position > 0) {
                        play();
                        // 并直接从指定位置开始播放
                        mediaPlayer.seekTo(position);
                        position = 0;   
                }
            }
   public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
        });
    }
}
—————————————————————————————————————————————————————————————————————

private void play() {
            mediaPlayer.reset();
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            Uri uri = Uri.parse(url1);
            mediaPlayer.setDataSource(getApplicationContext(), uri);
            // 把视频画面输出到SurfaceView
            mediaPlayer.setDisplay(surfaceView.getHolder());
            mediaPlayer.prepare();
            mediaPlayer.start();
    }
}


最后附上:SurfaceView和View的区别

View子类SurfaceView
SurfaceView有两个子类GLSurfaceView和VideoView

View主要适用于主动更新的情况下,而SurfaceView主要适用于被动更新,例如频繁地刷新
View在主线程中对画面进行刷新,而SurfaceView通常会通过一个子线程来进行页面的刷新
View在绘图时没有使用双缓冲机制,而SufaceView在底层实现机制中就已经实现了双缓冲机制

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值