Android 从头搭建视频播放器——SystemMediaPlayerImpl
Posted 牧秦丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 从头搭建视频播放器——SystemMediaPlayerImpl相关的知识,希望对你有一定的参考价值。
【android】 从头搭建视频播放器(2)——SystemMediaPlayerImpl
转载请注明出处:http://blog.csdn.net/arnozhang12/article/details/48734139
1、MediaPlayer 简介
首先,我们基于系统的 android.media.MediaPlayer
实现我们的 BaseMediaPlayer
。当然,我们也可以使用其他第三方的 Player 来实现,具体就在实际使用中按需求来做。
那么,我们需要先对 MediaPlayer 做一些必要的了解。通过网上的资料搜索,我认为这篇文章对 MediaPlayer
的各种状态迁移和使用规范做了较好的阐述:
我从这篇文章里面借了一张图如下:
通过对上图的理解,结合播放器的功能特性,抽离出了主要的状态迁移如下:
我们着重需要关注的方法列表如下:
方法 | 特性 |
---|---|
new MediaPlayer()创建一个 MediaPlayer,处于 Idle 状态 | |
reset() | 重置 MediaPlayer,使其切换到 Idle 状态 |
setDataSource(context, uri) | 设置视频数据源,切换到 Initialized 状态 |
prepare() | 准备数据,同步方法,完成后将切换到 Prepared 状态 |
prepareAsync() | 异步准备数据,处于 Preparing 状态,准备完毕后通过回调 OnPreparedListener.onPrepared 方法,处于 Prepared 状态 |
start() | 开始/恢复播放,切换到 Started 状态 |
seekTo(millSeconds) | 跳转进度 |
pause() | 暂停播放,切换到 Paused 状态 |
stop() | 停止播放,切换到 Stopped 状态 |
release() | 释放播放器资源,切换到终止 End 状态,这时候不允许对 MediaPlayer 做任何操作了 |
setDisplay(surfaceHolder) | 设置画面展示 SurfaceHolder |
2、关注的回调
MediaPlayer 有众多回调 Listener,我们需要着重关注:
回调 | 特性 |
---|---|
MediaPlayer.OnPreparedListener | 视频通过 prepareAsync 异步准备好之后回调 |
MediaPlayer.OnCompletionListener | 视频播放完成后的回调 |
MediaPlayer.OnVideoSizeChangedListener | 视频画面大小更改的回调,我们一般通过这个回调更改 SurfaceView 的大小及位置,以达到等比例缩放播放的效果 |
MediaPlayer.OnBufferingUpdateListener | 视频缓冲进度更改回调,一般我们通过这个回调更改 SeekBar 的 SecondaryProgress |
MediaPlayer.OnErrorListener | 播放器内部发生错误回调,一般是错误的调用或者其他错误引起 |
3、使用 MediaPlayer 必需的步骤
接下来我们基于系统的 MediaPlayer 实现 SystemMediaPlayerImpl
,它继承自 BaseMediaPlayer。一般使用 MediaPlayer 有如下步骤:
步骤 | 内容 |
---|---|
初始化 | new MediaPlayer |
设置一系列 Listener | OnPreparedListener 等等 |
设置数据源 | setDataSource. 可以是本地文件,也可以是网络数据 Url |
处理 OnPreparedListener.onPrepared 回调 | 设置画面展示 SurfaceHolder,并调用 start 开始播放。如果需要从视频的某个位置播放,可在这里调用 seekTo(millSeconds) 直接跳转 |
处理 OnVideoSizeChangedListener.onVideoSizeChanged 回调 | 在此通过获取到的视频画面大小调整 SurfaceView 的位置及大小,达到等比例缩放的效果 |
处理 OnBufferingUpdateListener.onBufferingUpdate 回调 | 再次可以更新界面上的进度条的缓冲进度 |
处理 OnCompletionListener.onCompletion 回调 | 在此处理播放完成通知,可以按需求来做按章节连续播放或者退出页面等等上层业务逻辑 |
处理 OnErrorListener.onError 回调 | 处理错误,进行 UI 的展示更新等等 |
4、SystemMediaPlayerImpl
我们根据上面的步骤,结合 上一篇文章 中介绍的 BaseMediaPlayer,实现出 SystemMediaPlayerImpl 如下:
/**
* SystemMediaPlayerImpl.java
*
* @author arnozhang
* @email zyfgood12@163.com
* @date 2015.9.25
*/
public class SystemMediaPlayerImpl extends BaseMediaPlayer
private MediaPlayer mMediaPlayer;
public SystemMediaPlayerImpl(Context context, SurfaceView surfaceView)
super(context, surfaceView);
init();
private void init()
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudiostreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnPreparedListener(onPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
mMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
mMediaPlayer.setOnErrorListener(mOnErrorListener);
mMediaPlayer.setOnCompletionListener(mOnCompletionListener);
@Override
public void play(VideoInfo videoInfo)
if (mMediaPlayer == null)
return;
super.play(videoInfo);
// Clear old display and Reset.
mMediaPlayer.setDisplay(null);
mMediaPlayer.reset();
try
mMediaPlayer.setDataSource(mContext, Uri.parse(videoInfo.getCurrentStreamUrl()));
catch (IOException e)
e.printStackTrace();
// Prepare For Play.
mMediaPlayer.prepareAsync();
notifyStartPlay();
notifyLoading();
@Override
public void pause()
if (mMediaPlayer == null || !mMediaPlayerIsPrepared)
return;
if (mMediaPlayer.isPlaying())
mMediaPlayer.pause();
notifyPaused();
@Override
public void resume()
if (mMediaPlayer == null || !mMediaPlayerIsPrepared)
return;
mMediaPlayer.start();
notifyResumed();
@Override
public void stop()
if (mMediaPlayer == null)
return;
if (mMediaPlayer.isPlaying())
mMediaPlayer.stop();
notifyStopped();
@Override
public void seekTo(int millSeconds)
if (mMediaPlayer != null)
mMediaPlayer.seekTo(millSeconds);
@Override
public void setVolume(float volume)
if (mMediaPlayer != null)
mMediaPlayer.setVolume(volume, volume);
@Override
public int getDuration()
return mMediaPlayer != null ? mMediaPlayer.getDuration() : 0;
@Override
public int getCurrentPosition()
return mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : 0;
@Override
public void doDestroy()
clearLoadingFailed();
mMediaPlayer.release();
mMediaPlayer = null;
@Override
public boolean isPlaying()
return mMediaPlayer != null && mMediaPlayer.isPlaying();
@Override
protected void playWithDisplayHolder(SurfaceHolder holder)
mMediaPlayer.setDisplay(holder);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.start();
mMediaPlayer.seekTo(0);
trySeekToStartPosition();
private void clearLoadingFailed()
ThreadManager.getInstance().getUIHandler().removeCallbacks(mLoadingFailedRunnable);
MediaPlayer.OnPreparedListener onPreparedListener = new MediaPlayer.OnPreparedListener()
public void onPrepared(MediaPlayer player)
mAutoPlayWhenHolderCreated = false;
mMediaPlayerIsPrepared = true;
mIsLoading = false;
clearLoadingFailed();
notifyFinishLoading();
// Start Play.
SurfaceHolder holder = mSurfaceView.getHolder();
if (holder == null)
mAutoPlayWhenHolderCreated = true;
else
playWithDisplayHolder(holder);
;
private void trySeekToStartPosition()
int seekToPosition = mVideoInfo.getCurrentPosition();
if (mMediaPlayer != null && mMediaPlayerIsPrepared && mVideoSizeInitialized && seekToPosition > 0)
mMediaPlayer.seekTo(seekToPosition);
MediaPlayer.OnCompletionListener mOnCompletionListener =
new MediaPlayer.OnCompletionListener()
public void onCompletion(MediaPlayer player)
player.seekTo(0);
notifyPlayComplete();
;
MediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener =
new MediaPlayer.OnVideoSizeChangedListener()
public void onVideoSizeChanged(MediaPlayer player, int width, int height)
mVideoWidth = player.getVideoWidth();
mVideoHeight = player.getVideoHeight();
updateSurfaceSize();
mVideoSizeInitialized = true;
trySeekToStartPosition();
;
MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener =
new MediaPlayer.OnBufferingUpdateListener()
public void onBufferingUpdate(MediaPlayer player, int percent)
mBufferPercent = percent;
;
MediaPlayer.OnErrorListener mOnErrorListener = new MediaPlayer.OnErrorListener()
public boolean onError(MediaPlayer player, int what, int extra)
String errorWhat;
switch (what)
case 1:
errorWhat = "MEDIA_ERROR_UNKNOWN";
break;
case 100:
errorWhat = "MEDIA_ERROR_SERVER_DIED";
break;
default:
errorWhat = "!";
String errorExtra;
switch (extra)
case -1010:
errorExtra = "MEDIA_ERROR_UNSUPPORTED";
break;
case -1007:
errorExtra = "MEDIA_ERROR_MALFORMED";
break;
case -1004:
errorExtra = "MEDIA_ERROR_IO";
break;
case -110:
errorExtra = "MEDIA_ERROR_TIMED_OUT";
break;
default:
errorExtra = "!";
String msg = String.format("what:%#x,%s extra:%#x,%s", what, errorWhat, extra, errorExtra);
notifyError(what, msg);
return true;
;
下一篇我们将介绍手势检测与控制。
以上是关于Android 从头搭建视频播放器——SystemMediaPlayerImpl的主要内容,如果未能解决你的问题,请参考以下文章
Android 从头搭建视频播放器——SystemMediaPlayerImpl