视频播放、音频播放在Android平台的应用非常广泛,最近正好学习研究了一下播放器层面的Android实现,
对底层播放器做了二次的封装,主要进行的工作如下:
§ 主要实现
1、播放控制
(1)简化播放接口处理
(2)增加一些友好型播控接口:快退、快进、重新播放等。
(3)单视频、多视频列表播放
2、播放状态
(1)播放状态控制
(2)播放状态调用时及时反馈
(3)较全的播放信息,通过回调接口隔时通知
(4)视频缓冲动画自动处理
(5)播放显示画面尺寸、位置自由设定
(6)播放HTTP源时,支持Headers设置
(7)增加快退、快进开关
3、其他
(1)音量控制
(2)视频源广告支持
4、待补充完善
(1)资源单独进行预加载
§ MediaPlayer状态机参考
§ 主要结构设计
1、主要接口
IPlayController:负责播放控制
IPlayerUI:负责播放控制的UI处理
IPlaySetter:负责播放控制的参数设置
IPlayerEventListener:播放回调事件通知接口
MediaPlayerEvent:播放事件载体
2、适配、分发、通知线程
MediaPlayerAdapter:原生态播放器适配
NotifyEventThread:回调通知监听线程
PlayDispatcher:播放器外观分发处理
3、构造、处理、状态
PlayerBuilder:构造播放器基础信息,用户接口
PlayerHandler:主线程操作处理
StatusCommander:播放控制命令状态处理
VolumeController:音量控制处理
4、外观、状态、UI
WMediaPlayer:播放器外观层
PlayContext:播放器上下文
StatusResolver:播放器实时状态信息
UIHandler:负责UI效果处理
§ 源码下载
为方便需要的朋友进一步的进行定制,先将实现的代码提供给大家,附带了DEMO示例。点击下载
部分示例代码:
public class MainActivity extends Activity implements OnClickListener {
public static final String playUrl = "/mnt/sdcard/test.mp4";
private WMediaPlayer player = new WMediaPlayer();
private SurfaceView sv = null;
private TextView txtStatus;
private SeekBar seekbar = null;
private ProgressBar progressBar = null;
private Button btnPlay, btnPause, btnUnPause, btnStop, btnReplay,
btnVolume, btnStatus, btnClose, btnSeekUp, btnSeekDown, btnLoad;
private int volume = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
// Intent it = new Intent(getBaseContext(), PlayerActivity.class);
// startActivity(it);
sv = (SurfaceView) findViewById(R.id.surfaceView1);
SurfaceHolder sh = sv.getHolder();
sh.addCallback(sc);
}
private SurfaceHolder.Callback sc = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
// test
PlayerBuilder builder = PlayerBuilder.getInstance();
builder.setContext(getBaseContext());
builder.setSurfaceView(sv);
// builder.setVolumeBar(seekbar);
builder.setVolumeBar(progressBar);
builder.setLoadingAnim(LoadAnimType.Animation, R.anim.loads_redload);
builder.setEventListener(eventListener);
player.setBuilder(builder);
player.setPlayUrl(playUrl);
// player.setPlayList();
player.play();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
};
IPlayerEventListener eventListener = new IPlayerEventListener() {
@Override
public void onMediaPlayerEvent(MediaPlayerEvent event) {
}
};
@Override
protected void onDestroy() {
player.destroy();
super.onDestroy();
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.btnPlay:
player.play();
break;
case R.id.btnPause:
player.pause();
break;
case R.id.btnUnPause:
player.unpause();
break;
case R.id.btnStop:
player.stop();
break;
case R.id.btnClose:
player.close();
break;
case R.id.btnReplay:
player.replay();
break;
case R.id.btnSeekUp:
player.seek(player.getStatusResolver().getCurTime() + 30);
break;
case R.id.btnSeekDown:
player.seek(player.getStatusResolver().getCurTime() - 30);
break;
case R.id.btnVolume:
volume++;
player.getVolumeController().setVolume(volume);
// player.getPlayer().setVolume(0.5f, 0.5f);
break;
case R.id.btnStatus:
String status = Utils.gson.toJson(player.getStatusResolver());
txtStatus.setText(status);
break;
case R.id.btnLoad:
UIHandler.getInstance()
.showLoading(
PlayerBuilder.getInstance().getPlayContext()
.getAnimResId());
break;
default:
break;
}
}