Android音视频基础part2——Android中自带Media Api

视频播放和音频播放

自带api,播放视频和音频。

音视频播放演变

MediaPlayer

我们平时最常使用MediaPlayer类来进行音视频的播放,其实它完成的是一个解码并播放的过程,并且是一个高度封装的工具类。使用它播放视频的时候我们还要配合SurfaceView或者TextureView来进行,后面的两个UI控件完成画面的展示。后来在前面的基础之上,系统提供了一个封装好的VideoView,为我们带来更简洁的调用。
任何事情都是有利弊两端的,简便使用的同时带来了可扩展性的问题。MediaPlayer的调用位于java层,内部的很多具体实现虽然也位于java层但是并不对应用开发者开放。那么就会带来一些问题,例如:视频容器文件格式的支持问题;缓冲区大小的定制;下载进度等。为了解决上面的问题,Media Codec API组应运而生。

Media Codec API组

MediaPlayer把Extractor,和Codec API全部封锁在了Framework层,应用层完全接触不到。在新的API设计里面,这些api都对开发者开放了,我们可以定制自己的播放器了。
在这里面,最重要的就是MediaExtractor和MediaCodec这两个类,第一个功能是对容器文件进行读取控制,第二个是对数据进行编解码。

Android目前支持的视频,音频,图片格式和通信协议

Android目前支持的视频,音频,图片格式和通信协议;这是官方的说明

MediaPlayer相关

MediaPlayer状态切换

MediaPlayer的生命周期状态切换十分重要,对于正确使用具有指导意义

。下面是状态切换图:MediaPlayer状态切换图

主要的状态

  • Idle 状态
  • End 状态
  • Error 状态
  • Initialized状态
  • Prepared状态
  • Preparing状态
  • Started状态
  • Paused状态
  • Stopped状态
  • PlaybackCompleted状态

状态切换,切换流程

  • 椭圆代表MediaPlayer驻留的状态
  • 带箭头直线代表播放控制且驱动MediaPlayer状态进行切换过渡。 有两种类型的带箭头直线,单箭头表示的是同步调用,双箭头代表异步调用
Idle 状态

Idle:清闲,备用状态。

进入Idle状态可以通过两种途径,一种是直接new MediaPlayer()创建一个实例,便进入Idle状态;另一种在使用完之后调用reset()方法,进入Idle状态;

进入Idle状态不同途径的不同

  • new MediaPlayer()的方式:Idle状态下,调用如下stop(), seekTo(),getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setVolume(float, float), pause(), start(), prepare(), prepareAsync()等方法(此处不完全列出),即使事先注册了setOnErrorListener,也不会受到onError的回调,同时MediaPlayer实例的状态也不会发生变化。
  • reSet()方式:Idle状态下,调用如下stop(), seekTo(),getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setVolume(float, float), pause(), start(), prepare(), prepareAsync()等方法(此处不完全列出),如果事先注册了setOnErrorListener,那么就会回调onError方法。
    推荐:Idle状态之后不要做例如上面的错误操作,如果是reSet之后到达Idle状态,最好随手调用release方法,释放掉资源使其到达End状态。

注意 new MediaPlayer()和MediaPlayer.create()构造实例的不同
使用new MediaPlayer()会进入Idle状态,而MediaPlayer.create()由源码可知调用prepare()进入了Prepared状态。

End状态

当在Idle状态中此时调用release方法,此时进入End状态;release方法作用是将MediaPlayer的实例的所有占用的资源完全释放,End状态下MediaPlayer的资源完全释放,处于完全结束状态。及时释放所占用资源很重要,建议在不在使用的时候及时释放。

Error状态

造成Error状态的情况比较多,在实际开发中如果不熟悉MediaPlayer的状态流程,使用的场景又较复杂,在开发中很可能出现,例如不支持的文件格式,视频的分辨率问题等等。所以事先setOnErrorListener注册错误监听器很有必要,可以帮助我们找到错误原因。
如果想逃出Error状态, 可以使用 reset() 方法进入 Idle 状态;

Initalized状态

在 Idle 状态调用 setDataSource() 方法, MediaPlayer 到 Initialized 状态;注意只能在Idle状态下调用setDataSource() 进入,如果其他状态下调用则会抛出异常。

Prepared状态和Preparing状态

Initialized 状态时候调用 prepareAsync() 方法(异步方式),或者prepare()方法(同步方式)会进入Prepared状态。
注意:1.只有Initialized 状态时候通过上面两种方式才能进入Prepared状态,其他状态下想通过上面两个方法中一种进入Prepared状态都会报异常。2.使用prepareAsync() 方法(异步方式)的时候会进入一个短暂的Preparing状态,事先注册好setOnCompletionListener,进入Prepared状态的时候会有回调。3.Prepared状态下可以设置音视频的属性(音量setVolume等),播放循环模式(setLooping()),常亮setScreenOnWhilePlaying等。

Started (开始) 状态

在 Prepared 状态调用 start() 方法, MediaPlayer 即到了 Started 状态;
判断 MediaPlayer 是否在 Started 状态 : 在任何状态下调用 isPlaying() 方法, 可以判断 MediaPlayer 是否在 Started 状态;Started状态下,可以在事先注册好的setOnBufferingUpdateListener中监听onBufferingUpdate得到相应的缓存进度。Started状态下,再调用start方法不会起总用。

Paused状态

Started 状态调用 pause() 方法, MediaPlayer 会进入 Paused 状态;Paused 状态调用 start() 方法, 恢复 Started 状态。
Started 状态转换为 Paused状态是瞬间的; 在 Paused 状态调用 start() 方法, 会进入 Started 状态,恢复之前的播放进度,这个过程是异步的,需要一段时间;当处于Paused状态的MediaPlayer重复调用pause方法是无效的。

Stoped状态

在 Prepared, Started, Paused, PlaybackCompleted 状态下 调用 stop() 方法, MediaPlayer 都会变为Stopped 状态;此状态下不同于Paused状态可以通过start方法恢复为Started状态,只能通过prepare方法或者prepareAsync方法回到Prepared状态,再通过start方法回到Started状态。处于Stoped状态时候重复调用stop方法无效。

PlaybackCompleted状态

如果播放时候开启了重复播放模式setLooping(true),Started状态在音频或者视频播放完成之后将重新进行播放。
如果没有 开启重复播放模式(默认),Started状态在播放完成之后会变为PlaybackCompleted模式。我们可以在事先注册的setOnCompletionListener()中的onCompletion中收到回调,我们也可以下这里直接调用start方法来恢复到Started状态。

播放进度调整seekTo()

该方法可以在 Prepared, Started,Paused, PlaybackCompleted 状态进行调用;
我们可以事先注册监听器setOnSeekCompleteListener,在onSeekComplete中获取回调;可以通过getCurrentPosition()获取播放进度。

MediaPlayer的使用

这里没有贴出具体的调用代码,百度一下都出来,涉及具体的使用还要自己去处理,但是我想看懂上面的状态切换图之后,面对问题的时候就不会太慌了。同时在新的api中可以看出,自带的MediaPlayer添加了字幕和保护版权的加密处理。

猜你喜欢

转载自blog.csdn.net/gongxiaoou/article/details/87939485