視頻播放、音頻播放在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;
}
}