在 Android 视频播放器 (一): 使用 VideoView 播放视频 我们讲了一下如何使用 VideoView 播放视频, 了解了基本的播放器的一些知识和内容. 也知道 VideoView 内部封装的就是 MediaPlayer, 本文就介绍如何使用 MediaPlayer 播放视频.
一, 简介
MediaPlayer 是 Android 中的一个多媒体播放类, 其提供的 API 能满足简单的大部分音视频的播放需求.
下面简单介绍一下 MediaPlayer:
MediaPlayer 是使用 Surface 进行视频的展示的.
MediaPlayer 只支持 mp4,avi,3gp 格式的视频, 支持格式相对单一.
MediaPlayer 可以播放网络视频, 支持的网络视频的协议为: Http 协议和 RTSP 协议两种.
二, MediaPlayer 使用方法
MediaPlayer 的提供的方法如下:
void setDataSource(String path) : 通过一个具体的路径来设置 MediaPlayer 的数据源, path 可以是本地的一个路径, 也可以是一个网络路径
void setDataSource(Context context, Uri uri): 通过给定的 Uri 来设置 MediaPlayer 的数据源, 这里的 Uri 可以是网络路径或是一个 ContentProvider 的 Uri.
void setDataSource(MediaDataSource dataSource) : 通过提供的 MediaDataSource 来设置数据源
void setDataSource(FileDescriptor fd): 通过文件描述符 FileDescriptor 来设置数据源
int getCurrentPosition() : 获取当前播放的位置
int getAudioSessionId() : 返回音频的 session ID
int getDuration() : 得到文件的时间
TrackInfo[] getTrackInfo() : 返回一个 track 信息的数组
boolean isLooping (): 是否循环播放
boolean isPlaying(): 是否正在播放
void pause () : 暂停
void start () : 开始
void stop () : 停止
void prepare(): 同步的方式装载流媒体文件.
void prepareAsync(): 异步的方式装载流媒体文件.
void reset(): 重置 MediaPlayer 至未初始化状态.
void release (): 回收流媒体资源.
void seekTo(int msec): 指定播放的位置 (以毫秒为单位的时间)
void setAudioStreamType(int streamtype) : 指定流媒体类型
void setLooping(boolean looping) : 设置是否单曲循环
void setNextMediaPlayer(MediaPlayer next) : 当前这个 MediaPlayer 播放完毕后, MediaPlayer next 开始播放
void setWakeMode(Context context, int mode): 设置 CPU 唤醒的状态.
setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) : 网络流媒体的缓冲变化时回调
setOnCompletionListener(MediaPlayer.OnCompletionListener listener) : 网络流媒体播放结束时回调
setOnErrorListener(MediaPlayer.OnErrorListener listener) : 发生错误时回调
setOnPreparedListener(MediaPlayer.OnPreparedListener listener): 当装载流媒体完毕的时候回调.
Android 通过 MediaPlayer 控制播放器的状态的方式来控制媒体文件的播放, 其中:
prepare() 和 prepareAsync() 提供了同步和异步两种方式设置播放器进入 prepare 状态, 需要注意的是, 如果 MediaPlayer 实例是由 create 方法创建的, 那么第一次启动播放前不需要再调用 prepare() 了, 因为 create 方法里已经调用过了.
start() 是真正启动文件播放的方法,
pause() 和 stop() 比较简单, 起到暂停和停止播放的作用,
seekTo() 是定位方法, 可以让播放器从指定的位置开始播放, 需要注意的是该方法是个异步方法, 也就是说该方法返回时并不意味着定位完成, 尤其是播放的网络文件, 真正定位完成时会触发 OnSeekComplete.onSeekComplete(), 如果需要是可以调用 setOnSeekCompleteListener(OnSeekCompleteListener) 设置监听器来处理的.
release() 可以释放播放器占用的资源, 一旦确定不再使用播放器时应当尽早调用它释放资源.
reset() 可以使播放器从 Error 状态中恢复过来, 重新会到 Idle 状态.
使用 MediaPlayer 播放视频的步骤如下:
创建 MediaPlayer 对象, 并让它加载指定的视频文件;
在界面布局文件中定义 SurfaceView 控件, 或在程序中创建 SurfaceView 控件, 并为 SurfaceView 的 SurfaceHolder 添加 Callback 监听器;
调用 MediaPlayer 对象的 setDisney(SurfaceHolder sh) 方法将所播放的视频图像输出到指定的 SurfaceView 控制;
调用 MediaPlayer 的 start(),stop(),pause() 方法来控制视频播放.
下图是一个 MediaPlayer 对象被支持的播放控制操作驱动的声明周期和状态. 其中, 椭圆代表 MediaPlayer 可能驻留的状态, 弧线表示驱动 MediaPlayer 在各个状态之间迁移的播放控制操作. 这里有两种类型的弧线. 由单箭头开始的弧线代表同步方法调用, 而以双箭头开头的弧线代表异步方法调用.
三, 使用 MediaPlayer 实现视频播放
下面我们将展示如何使用 MediaPlayer 播放香港卫视的视频流:
1. 声明权限
需要在 AndroidManifest.xml 添加权限.
<uses-permission android:name="android.permission.INTERNET" />
2. 编写 SurfaceView 布局
- <?xml version="1.0" encoding="utf-8"?>
- <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <SurfaceView
- android:id="@+id/surface_view"
- android:layout_width="match_parent"
- android:layout_height="195dp" />
- </LinearLayout>
- </android.support.constraint.ConstraintLayout>
3. 编写播放视频代码
- public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
- SurfaceView surfaceView;
- SurfaceHolder surfaceHolder;
- MediaPlayer mediaPlayer;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- surfaceView = findViewById(R.id.surface_view);
- surfaceHolder = surfaceView.getHolder();
- surfaceHolder.addCallback(this);
- mediaPlayer = new MediaPlayer();
- try {
- mediaPlayer.setDataSource("http://live.hkstv.hk.lxdns.com/live/hks/playlist.m3u8");
- } catch (IOException e) {
- e.printStackTrace();
- }
- mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer mp) {
- mp.start();
- }
- });
- }
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Surface surface = holder.getSurface();
- mediaPlayer.setSurface(surface);
- mediaPlayer.prepareAsync();
- }
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- }
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- }
- }
四, MediaPlayer 使用注意事项
在使用 start() 播放流媒体之前, 需要装载流媒体资源. 这里最好使用 prepareAsync() 用异步的方式装载流媒体资源. 因为流媒体资源的装载是会消耗系统资源的, 在一些硬件不理想的设备上, 如果使用 prepare() 同步的方式装载资源, 可能会造成 UI 界面的卡顿, 这是非常影响用于体验的. 因为推荐使用异步装载的方式, 为了避免还没有装载完成就调用 start() 而报错的问题, 需要绑定 MediaPlayer.setOnPreparedListener() 事件, 它将在异步装载完成之后回调. 异步装载还有一个好处就是避免装载超时引发 ANR((Application Not Responding) 错误.
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setDataSource(path);
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- // 通过异步的方式装载媒体资源
- mediaPlayer.prepareAsync();
- mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer mp) {
- // 装载完毕回调
- mediaPlayer.start();
- }
- });
使用完 MediaPlayer 需要回收资源. MediaPlayer 是很消耗系统资源的, 所以在使用完 MediaPlayer, 不要等待系统自动回收, 最好是主动回收资源
- if (mediaPlayer != null && mediaPlayer.isPlaying()) {
- mediaPlayer.stop();
- mediaPlayer.release();
- mediaPlayer = null;
- }
来源: https://www.cnblogs.com/renhui/p/9269040.html