package tv.danmaku.media.list; import java.io.IOException; import java.lang.ref.WeakReference; import tv.danmaku.android.util.DebugLog; import tv.danmaku.media.AbsMediaPlayer; import tv.danmaku.media.ModuleInfo; import tv.danmaku.media.resource.PlayIndex; import tv.danmaku.media.resource.Segment; import tv.danmaku.media.vsl.LibVlcVideoSegmentListLoader; import android.content.Context; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.AsyncTask; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; public class DefMediaListPlayer extends AbsMediaPlayer implements MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnVideoSizeChangedListener { public static final String TAG = DefMediaListPlayer.class.getName(); private String mMetaListUrl; private DefMediaSegmentPlayer mSegmentPlayer; private LibVlcVideoSegmentListLoader mIndexResolver; private PlayIndex mPlayIndex; private long mTotalDuration; private SurfaceHolder mSurfaceHolder; boolean mListPlayerPrepared; boolean mIsMediaSwitchEnd; public static DefMediaListPlayer create(Context context, PlayIndex.Resolver resolver) { return new DefMediaListPlayer(context, resolver); } protected DefMediaListPlayer(Context context, PlayIndex.Resolver resolver) { mIndexResolver = new LibVlcVideoSegmentListLoader(context, resolver); } private DefMediaSegmentPlayer createItemPlayer() { DefMediaSegmentPlayer itemPlayer = new DefMediaSegmentPlayer(); itemPlayer.setOnBufferingUpdateListener(this); itemPlayer.setOnCompletionListener(this); itemPlayer.setOnErrorListener(this); itemPlayer.setOnInfoListener(this); itemPlayer.setOnPreparedListener(this); itemPlayer.setOnSeekCompleteListener(this); itemPlayer.setOnVideoSizeChangedListener(this); itemPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); itemPlayer.setScreenOnWhilePlaying(true); SurfaceHolder holder = mSurfaceHolder; if (holder != null) itemPlayer.setDisplay(holder); return itemPlayer; } @Override public int getCurrentPosition() { if (mSegmentPlayer == null) return 0; try { return mSegmentPlayer.getCurrentPosition(); } catch (IllegalStateException e) { e.printStackTrace(); return 0; } } @Override public int getDuration() { if (mPlayIndex == null) return 0; return (int) mTotalDuration; } @Override public int getVideoHeight() { if (mSegmentPlayer == null) return 0; return mSegmentPlayer.getVideoHeight(); } @Override public int getVideoWidth() { if (mSegmentPlayer == null) return 0; return mSegmentPlayer.getVideoWidth(); } @Override public boolean isPlaying() { try { return mSegmentPlayer.isPlaying(); } catch (IllegalStateException e) { e.printStackTrace(); return false; } } @Override public void start() throws IllegalStateException { if (mSegmentPlayer == null) return; mSegmentPlayer.start(); } @Override public void stop() throws IllegalStateException { if (mSegmentPlayer == null) return; mSegmentPlayer.stop(); } @Override public void pause() throws IllegalStateException { if (mSegmentPlayer == null) return; mSegmentPlayer.pause(); } @Override public void prepareAsync() throws IllegalStateException { AsyncLoader loader = new AsyncLoader(this); loader.execute(mMetaListUrl); } private static class AsyncLoader extends AsyncTask<String, Void, PlayIndex> { private WeakReference<DefMediaListPlayer> mWeakPlayer; public AsyncLoader(DefMediaListPlayer player) { mWeakPlayer = new WeakReference<DefMediaListPlayer>(player); } @Override protected PlayIndex doInBackground(String... params) { if (params.length <= 0) return null; DefMediaListPlayer player = mWeakPlayer.get(); if (player == null) return null; if (!player.mIndexResolver.loadIndex(true)) return null; return player.mIndexResolver.getPlayIndex(); } @Override protected void onPostExecute(PlayIndex result) { DefMediaListPlayer player = mWeakPlayer.get(); if (player == null) return; if (result == null) { if (player.mOnErrorListener != null) { player.mOnErrorListener.onError(player, 1, 1); } return; } if (result.mSegmentList == null || result.mSegmentList.isEmpty()) { if (player.mOnErrorListener != null) { player.mOnErrorListener.onError(player, 1, 1); } return; } try { DefMediaSegmentPlayer itemPlayer = player.createItemPlayer(); itemPlayer.setSegment(0, 0, result.mSegmentList.get(0)); player.mSegmentPlayer = itemPlayer; player.mPlayIndex = result; player.mTotalDuration = result.getTotalDuration(); player.mSegmentPlayer.prepareAsync(); return; } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (player.mOnErrorListener != null) { player.mOnErrorListener.onError(player, 1, 1); } } } @Override public void release() { if (mSegmentPlayer == null) return; mSegmentPlayer.release(); } @Override public void reset() { if (mSegmentPlayer == null) return; mSegmentPlayer.reset(); } @Override public void seekTo(int msec) throws IllegalStateException { DebugLog.e(TAG, "seek to " + msec); if (mPlayIndex == null) return; int order = mPlayIndex.getOrderByTime(msec); if (order < 0) { DebugLog.e(TAG, "seek to invalid segment " + order); return; } Segment segment = mPlayIndex.mSegmentList.get(order); if (segment == null) { DebugLog.e(TAG, "seek to null segment " + order); return; } int startTime = mPlayIndex.getStartTime(order); int msecOffset = msec - startTime; DebugLog.e(TAG, String.format("seek to segment[%d:%d] %d", order, startTime, msecOffset)); if (mSegmentPlayer != null) { int playerIndex = mSegmentPlayer.getOrder(); if (order == playerIndex) { mSegmentPlayer.seekTo(msecOffset); return; } mSegmentPlayer.release(); } mSegmentPlayer = createItemPlayer(); try { mSegmentPlayer.setSegment(order, startTime, segment); mSegmentPlayer.prepareAsync(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // TOOD: init seek not supported by stagefright yet /* * mItemPlayer.seekTo(msec); */ } @Override public void setDataSource(String uri) throws IOException, IllegalArgumentException, IllegalStateException { DebugLog.v(TAG, "def play list " + uri); if (!mIndexResolver.parseIndexMrl(uri)) throw new IllegalArgumentException("unsupport mrl"); mMetaListUrl = uri; } @Override public void setDisplay(SurfaceHolder holder) { mSurfaceHolder = holder; if (holder != null) holder.addCallback(mSurfaceCallback); if (mSegmentPlayer != null) mSegmentPlayer.setDisplay(holder); } private SurfaceHolder.Callback mSurfaceCallback = new Callback() { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } public void surfaceCreated(SurfaceHolder holder) { } public void surfaceDestroyed(SurfaceHolder holder) { if (mSegmentPlayer != null) { mSegmentPlayer.release(); } } }; @Override public void setAudioStreamType(int streamMusic) { if (mSegmentPlayer == null) return; mSegmentPlayer.setAudioStreamType(streamMusic); } @Override public void setScreenOnWhilePlaying(boolean screenOn) { if (mSegmentPlayer == null) return; mSegmentPlayer.setScreenOnWhilePlaying(screenOn); } @Override public void enableLog(boolean enable) { // not support } @Override public boolean isBufferingEnd() { return mIsMediaSwitchEnd; } @Override public ModuleInfo getModuleInfo() { return ModuleInfo.getAndroidListModuleInfo(); } @Override public void onBufferingUpdate(MediaPlayer mp, int percent) { if (mOnBufferingUpdateListener != null) { DefMediaSegmentPlayer segmentPlayer = mSegmentPlayer; if (segmentPlayer == null) return; int totalDuration = getDuration(); if (totalDuration <= 0) return; Segment segment = segmentPlayer.getSegment(); if (segment == null || segment.mDuration <= 0) return; int bufferedTime = segment.mDuration * percent / 100; int totalPercent = (segmentPlayer.getStartTime() + bufferedTime) * 100 / totalDuration; mOnBufferingUpdateListener.onBufferingUpdate(this, totalPercent); } } @Override public void onCompletion(MediaPlayer mp) { DebugLog.v(TAG, "onCompletion"); try { if (mPlayIndex != null && mSegmentPlayer != null) { int count = mPlayIndex.mSegmentList.size(); int nextOrder = mSegmentPlayer.getOrder() + 1; if (nextOrder < count) { mSegmentPlayer.release(); mIsMediaSwitchEnd = false; if (mOnInfoListener != null) { mOnInfoListener.onInfo(this, MediaPlayer.MEDIA_INFO_BUFFERING_START, 0); } Segment nextSegment = mPlayIndex.mSegmentList .get(nextOrder); if (nextSegment != null) { mSegmentPlayer = createItemPlayer(); int startTime = mPlayIndex.getStartTime(nextOrder); mSegmentPlayer.setSegment(nextOrder, startTime, nextSegment); mSegmentPlayer.prepareAsync(); } return; } } if (mOnCompletionListener != null) { mOnCompletionListener.onCompletion(this); } return; } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (mOnErrorListener != null) { mOnErrorListener.onError(this, 1, 1); } } @Override public boolean onError(MediaPlayer mp, int what, int extra) { DebugLog.v(TAG, "onError"); if (mOnErrorListener != null) { return mOnErrorListener.onError(this, what, extra); } return false; } @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { if (mOnInfoListener != null) { return mOnInfoListener.onInfo(this, what, extra); } return true; } @Override public void onPrepared(MediaPlayer mp) { mIsMediaSwitchEnd = true; if (mListPlayerPrepared) { // TOOD: init seek not supported by stagefright yet if (mOnInfoListener != null) { mOnInfoListener.onInfo(this, MediaPlayer.MEDIA_INFO_BUFFERING_START, 0); } mp.start(); } else { if (mOnPreparedListener != null) { mOnPreparedListener.onPrepared(this); } mListPlayerPrepared = true; } } @Override public void onSeekComplete(MediaPlayer mp) { if (mOnSeekCompleteListener != null) { mOnSeekCompleteListener.onSeekComplete(this); } } @Override public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { if (mOnVideoSizeChangedListener != null) { mOnVideoSizeChangedListener.onVideoSizeChanged(this, width, height); } } }