视频播放、音频播放在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; } }