Created
January 16, 2017 08:33
-
-
Save TedaLIEz/2529d8741ece851c63cbc9b66aedfc57 to your computer and use it in GitHub Desktop.
FFplay *.ffconcat file in android example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.content.DialogInterface; | |
import android.content.res.Resources; | |
import android.media.AudioManager; | |
import android.media.MediaPlayer; | |
import android.net.Uri; | |
import android.os.Build; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.RequiresApi; | |
import android.support.v7.app.AlertDialog; | |
import android.text.TextUtils; | |
import android.util.AttributeSet; | |
import android.util.Log; | |
import android.view.Gravity; | |
import android.view.KeyEvent; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.widget.FrameLayout; | |
import android.widget.MediaController; | |
import android.widget.TextView; | |
import com.hustunique.jianguo.ijkplayerdemo.R; | |
import java.io.File; | |
import java.io.IOException; | |
import java.util.Map; | |
import tv.danmaku.ijk.media.player.IMediaPlayer; | |
import tv.danmaku.ijk.media.player.IjkMediaPlayer; | |
import tv.danmaku.ijk.media.player.IjkTimedText; | |
import tv.danmaku.ijk.media.player.misc.IMediaDataSource; | |
/** | |
* Created by JianGuo on 1/14/17. | |
* Take a look at line 553-554 | |
*/ | |
public class IjkVideoView extends FrameLayout implements MediaController.MediaPlayerControl { | |
private String TAG = "IjkVideoView"; | |
private Uri mUri; | |
private Map<String, String> mHeaders; | |
// all possible internal states | |
private static final int STATE_ERROR = -1; | |
private static final int STATE_IDLE = 0; | |
private static final int STATE_PREPARING = 1; | |
private static final int STATE_PREPARED = 2; | |
private static final int STATE_PLAYING = 3; | |
private static final int STATE_PAUSED = 4; | |
private static final int STATE_PLAYBACK_COMPLETED = 5; | |
// mCurrentState is a VideoView object's current state. | |
// mTargetState is the state that a method caller intends to reach. | |
// For instance, regardless the VideoView object's current state, | |
// calling pause() intends to bring the object to a target state | |
// of STATE_PAUSED. | |
private int mCurrentState = STATE_IDLE; | |
private int mTargetState = STATE_IDLE; | |
private IRenderView.ISurfaceHolder mSurfaceHolder = null; | |
private IMediaPlayer mMediaPlayer = null; | |
private int mVideoWidth; | |
private int mVideoHeight; | |
private int mSurfaceWidth; | |
private int mSurfaceHeight; | |
private int mVideoRotationDegree; | |
private IMediaController mMediaController; | |
private IMediaPlayer.OnCompletionListener mOnCompletionListener; | |
private IMediaPlayer.OnPreparedListener mOnPreparedListener; | |
private int mCurrentBufferPercentage; | |
private IMediaPlayer.OnErrorListener mOnErrorListener; | |
private IMediaPlayer.OnInfoListener mOnInfoListener; | |
private int mSeekWhenPrepared; // recording the seek position while preparing | |
private boolean mCanPause = true; | |
private boolean mCanSeekBack = true; | |
private boolean mCanSeekForward = true; | |
private Context mAppContext; | |
private IRenderView mRenderView; | |
private int mVideoSarNum; | |
private int mVideoSarDen; | |
private TextView subtitleDisplay; | |
private static final int[] s_allAspectRatio = { | |
IRenderView.AR_ASPECT_FIT_PARENT, | |
IRenderView.AR_ASPECT_FILL_PARENT, | |
IRenderView.AR_ASPECT_WRAP_CONTENT, | |
// IRenderView.AR_MATCH_PARENT, | |
IRenderView.AR_16_9_FIT_PARENT, | |
IRenderView.AR_4_3_FIT_PARENT}; | |
private int mCurrentAspectRatioIndex = 0; | |
private int mCurrentAspectRatio = s_allAspectRatio[0]; | |
IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = | |
new IMediaPlayer.OnVideoSizeChangedListener() { | |
public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) { | |
mVideoWidth = mp.getVideoWidth(); | |
mVideoHeight = mp.getVideoHeight(); | |
mVideoSarNum = mp.getVideoSarNum(); | |
mVideoSarDen = mp.getVideoSarDen(); | |
if (mVideoWidth != 0 && mVideoHeight != 0) { | |
if (mRenderView != null) { | |
mRenderView.setVideoSize(mVideoWidth, mVideoHeight); | |
mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen); | |
} | |
// REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight); | |
requestLayout(); | |
} | |
} | |
}; | |
private IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() { | |
@Override | |
public void onPrepared(IMediaPlayer mp) { | |
mCurrentState = STATE_PREPARED; | |
if (mOnPreparedListener != null) { | |
mOnPreparedListener.onPrepared(mp); | |
} | |
if (mMediaController != null) { | |
mMediaController.setEnabled(true); | |
} | |
mVideoWidth = mp.getVideoWidth(); | |
mVideoHeight = mp.getVideoHeight(); | |
int seekToPosition = mSeekWhenPrepared; | |
if (seekToPosition != 0) { | |
seekTo(seekToPosition); | |
} | |
if (mVideoWidth != 0 && mVideoHeight != 0) { | |
if (mRenderView != null) { | |
mRenderView.setVideoSize(mVideoWidth, mVideoHeight); | |
mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen); | |
if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth || mSurfaceHeight == mVideoHeight) { | |
if (mTargetState == STATE_PLAYING) { | |
start(); | |
if (mMediaController != null) { | |
mMediaController.show(); | |
} | |
} else if (!isPlaying() && (seekToPosition != 0 || getCurrentPosition() > 0)) { | |
if (mMediaController != null) { | |
mMediaController.show(0); | |
} | |
} | |
} | |
} | |
} else { | |
if (mTargetState == STATE_PLAYING) { | |
start(); | |
} | |
} | |
} | |
}; | |
private IMediaPlayer.OnCompletionListener mCompletionListener = new IMediaPlayer.OnCompletionListener() { | |
@Override | |
public void onCompletion(IMediaPlayer mp) { | |
mCurrentState = STATE_PLAYBACK_COMPLETED; | |
mTargetState = STATE_PLAYBACK_COMPLETED; | |
if (mMediaController != null) { | |
mMediaController.hide(); | |
} | |
if (mOnCompletionListener != null) { | |
mOnCompletionListener.onCompletion(mp); | |
} | |
} | |
}; | |
private IMediaPlayer.OnInfoListener mInfoListener = new IMediaPlayer.OnInfoListener() { | |
@Override | |
public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) { | |
if (mOnInfoListener != null) { | |
mOnInfoListener.onInfo(mp, arg1, arg2); | |
} | |
switch (arg1) { | |
case IMediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING: | |
Log.d(TAG, "MEDIA_INFO_VIDEO_TRACK_LAGGING:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: | |
Log.d(TAG, "MEDIA_INFO_VIDEO_RENDERING_START:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_BUFFERING_START: | |
Log.d(TAG, "MEDIA_INFO_BUFFERING_START:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_BUFFERING_END: | |
Log.d(TAG, "MEDIA_INFO_BUFFERING_END:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH: | |
Log.d(TAG, "MEDIA_INFO_NETWORK_BANDWIDTH: " + arg2); | |
break; | |
case IMediaPlayer.MEDIA_INFO_BAD_INTERLEAVING: | |
Log.d(TAG, "MEDIA_INFO_BAD_INTERLEAVING:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE: | |
Log.d(TAG, "MEDIA_INFO_NOT_SEEKABLE:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_METADATA_UPDATE: | |
Log.d(TAG, "MEDIA_INFO_METADATA_UPDATE:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE: | |
Log.d(TAG, "MEDIA_INFO_UNSUPPORTED_SUBTITLE:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT: | |
Log.d(TAG, "MEDIA_INFO_SUBTITLE_TIMED_OUT:"); | |
break; | |
case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED: | |
mVideoRotationDegree = arg2; | |
Log.d(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + arg2); | |
if (mRenderView != null) | |
mRenderView.setVideoRotation(arg2); | |
break; | |
case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START: | |
Log.d(TAG, "MEDIA_INFO_AUDIO_RENDERING_START:"); | |
break; | |
} | |
return true; | |
} | |
}; | |
private IMediaPlayer.OnErrorListener mErrorListener = new IMediaPlayer.OnErrorListener() { | |
@Override | |
public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) { | |
Log.d(TAG, "Error: " + framework_err + "," + impl_err); | |
mCurrentState = STATE_ERROR; | |
mTargetState = STATE_ERROR; | |
if (mMediaController != null) { | |
mMediaController.hide(); | |
} | |
/* If an error handler has been supplied, use it and finish. */ | |
if (mOnErrorListener != null) { | |
if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { | |
return true; | |
} | |
} | |
/* Otherwise, pop up an error dialog so the user knows that | |
* something bad has happened. Only try and pop up the dialog | |
* if we're attached to a window. When we're going away and no | |
* longer have a window, don't bother showing the user an error. | |
*/ | |
if (getWindowToken() != null) { | |
Resources r = mAppContext.getResources(); | |
int messageId; | |
if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { | |
messageId = R.string.VideoView_error_text_invalid_progressive_playback; | |
} else { | |
messageId = R.string.VideoView_error_text_unknown; | |
} | |
new AlertDialog.Builder(getContext()) | |
.setMessage(messageId) | |
.setPositiveButton(R.string.VideoView_error_button, | |
new DialogInterface.OnClickListener() { | |
public void onClick(DialogInterface dialog, int whichButton) { | |
/* If we get here, there is no onError listener, so | |
* at least inform them that the video is over. | |
*/ | |
if (mOnCompletionListener != null) { | |
mOnCompletionListener.onCompletion(mMediaPlayer); | |
} | |
} | |
}) | |
.setCancelable(false) | |
.show(); | |
} | |
return true; | |
} | |
}; | |
private IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() { | |
@Override | |
public void onBufferingUpdate(IMediaPlayer mp, int percent) { | |
mCurrentBufferPercentage = percent; | |
} | |
}; | |
private IMediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() { | |
@Override | |
public void onSeekComplete(IMediaPlayer mp) { | |
} | |
}; | |
private IMediaPlayer.OnTimedTextListener mOnTimedTextListener = new IMediaPlayer.OnTimedTextListener() { | |
@Override | |
public void onTimedText(IMediaPlayer mp, IjkTimedText text) { | |
if (text != null) { | |
subtitleDisplay.setText(text.getText()); | |
} | |
} | |
}; | |
public IjkVideoView(Context context) { | |
this(context, null); | |
} | |
public IjkVideoView(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
} | |
public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
initVideoView(context); | |
} | |
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) | |
public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { | |
super(context, attrs, defStyleAttr, defStyleRes); | |
initVideoView(context); | |
} | |
private void initVideoView(Context context) { | |
mAppContext = context.getApplicationContext(); | |
initRenders(); | |
mVideoHeight = mVideoWidth = 0; | |
setFocusable(true); | |
setFocusableInTouchMode(true); | |
requestFocus(); | |
mCurrentState = STATE_IDLE; | |
mTargetState = STATE_IDLE; | |
subtitleDisplay = new TextView(context); | |
subtitleDisplay.setTextSize(24); | |
subtitleDisplay.setGravity(Gravity.CENTER); | |
FrameLayout.LayoutParams layoutParams_txt = new FrameLayout.LayoutParams( | |
FrameLayout.LayoutParams.MATCH_PARENT, | |
FrameLayout.LayoutParams.WRAP_CONTENT, | |
Gravity.BOTTOM); | |
addView(subtitleDisplay, layoutParams_txt); | |
} | |
private void initRenders() { | |
TextureRenderView renderView = new TextureRenderView(getContext()); | |
if (mMediaPlayer != null) { | |
renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer); | |
renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight()); | |
renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), | |
mMediaPlayer.getVideoSarDen()); | |
renderView.setAspectRatio(mCurrentAspectRatio); | |
} | |
setRenderView(renderView); | |
} | |
public void setMediaController(IMediaController controller) { | |
if (mMediaController != null) { | |
mMediaController.hide(); | |
} | |
mMediaController = controller; | |
attachMediaController(); | |
} | |
IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() { | |
@Override | |
public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) { | |
if (holder.getRenderView() != mRenderView) { | |
Log.e(TAG, "onSurfaceCreated: unmatched render callback\n"); | |
return; | |
} | |
mSurfaceHolder = holder; | |
if (mMediaPlayer != null) | |
bindSurfaceHolder(mMediaPlayer, holder); | |
else | |
openVideo(); | |
} | |
@Override | |
public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int width, int height) { | |
if (holder.getRenderView() != mRenderView) { | |
Log.e(TAG, "onSurfaceChanged: unmatched render callback\n"); | |
return; | |
} | |
mSurfaceWidth = width; | |
mSurfaceHeight = height; | |
boolean isValidState = (mTargetState == STATE_PLAYING); | |
boolean hasValidSize = !mRenderView.shouldWaitForResize() | |
|| (mVideoWidth == width && mVideoHeight == height); | |
if (mMediaPlayer != null && isValidState && hasValidSize) { | |
if (mSeekWhenPrepared != 0) { | |
seekTo(mSeekWhenPrepared); | |
} | |
start(); | |
} | |
} | |
@Override | |
public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) { | |
if (holder.getRenderView() != mRenderView) { | |
Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n"); | |
return; | |
} | |
// after we return from this we can't use the surface any more | |
mSurfaceHolder = null; | |
// REMOVED: if (mMediaController != null) mMediaController.hide(); | |
// REMOVED: release(true); | |
releaseWithoutStop(); | |
} | |
}; | |
private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) { | |
if (mp == null) { | |
return; | |
} | |
if (holder == null) { | |
mp.setDisplay(null); | |
return; | |
} | |
holder.bindToMediaPlayer(mp); | |
} | |
private void releaseWithoutStop() { | |
if (mMediaPlayer != null) { | |
mMediaPlayer.setDisplay(null); | |
} | |
} | |
private void setRenderView(IRenderView renderView) { | |
if (mRenderView != null) { | |
if (mMediaPlayer != null) | |
mMediaPlayer.setDisplay(null); | |
View renderUIView = mRenderView.getView(); | |
mRenderView.removeRenderCallback(mSHCallback); | |
mRenderView = null; | |
removeView(renderUIView); | |
} | |
if (renderView == null) | |
return; | |
mRenderView = renderView; | |
renderView.setAspectRatio(mCurrentAspectRatio); | |
if (mVideoWidth > 0 && mVideoHeight > 0) | |
renderView.setVideoSize(mVideoWidth, mVideoHeight); | |
if (mVideoSarNum > 0 && mVideoSarDen > 0) | |
renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen); | |
View renderUIView = mRenderView.getView(); | |
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( | |
FrameLayout.LayoutParams.WRAP_CONTENT, | |
FrameLayout.LayoutParams.WRAP_CONTENT, | |
Gravity.CENTER); | |
renderUIView.setLayoutParams(lp); | |
addView(renderUIView); | |
mRenderView.addRenderCallback(mSHCallback); | |
mRenderView.setVideoRotation(mVideoRotationDegree); | |
} | |
public void setVideoPath(String path) { | |
setVideoURI(Uri.parse(path)); | |
} | |
public void setVideoURI(Uri uri) { | |
setVideoURI(uri, null); | |
} | |
private void setVideoURI(Uri uri, Map<String, String> headers) { | |
mUri = uri; | |
mHeaders = headers; | |
mSeekWhenPrepared = 0; | |
openVideo(); | |
requestLayout(); | |
invalidate(); | |
} | |
private void openVideo() { | |
if (mUri == null || mSurfaceHolder == null) { | |
return; | |
} | |
release(false); | |
AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE); | |
am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); | |
try { | |
mMediaPlayer = createPlayer(); | |
mMediaPlayer.setOnPreparedListener(mPreparedListener); | |
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); | |
mMediaPlayer.setOnCompletionListener(mCompletionListener); | |
mMediaPlayer.setOnErrorListener(mErrorListener); | |
mMediaPlayer.setOnInfoListener(mInfoListener); | |
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); | |
mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener); | |
mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener); | |
mCurrentBufferPercentage = 0; | |
String scheme = mUri.getScheme(); | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M | |
&& (TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) { | |
IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString())); | |
mMediaPlayer.setDataSource(dataSource); | |
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { | |
mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders); | |
} else { | |
mMediaPlayer.setDataSource(mUri.toString()); | |
} | |
bindSurfaceHolder(mMediaPlayer, mSurfaceHolder); | |
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); | |
mMediaPlayer.setScreenOnWhilePlaying(true); | |
mMediaPlayer.prepareAsync(); | |
// REMOVED: mPendingSubtitleTracks | |
// we don't set the target state here either, but preserve the | |
// target state that was there before. | |
mCurrentState = STATE_PREPARING; | |
attachMediaController(); | |
} catch (IOException | IllegalArgumentException ex) { | |
Log.w(TAG, "Unable to open content: " + mUri, ex); | |
mCurrentState = STATE_ERROR; | |
mTargetState = STATE_ERROR; | |
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); | |
} | |
} | |
private void attachMediaController() { | |
if (mMediaPlayer != null && mMediaController != null) { | |
mMediaController.setMediaPlayer(this); | |
View anchorView = this.getParent() instanceof View ? | |
(View) this.getParent() : this; | |
mMediaController.setAnchorView(anchorView); | |
mMediaController.setEnabled(isInPlaybackState()); | |
} | |
} | |
private boolean isInPlaybackState() { | |
return (mMediaPlayer != null && | |
mCurrentState != STATE_ERROR && | |
mCurrentState != STATE_IDLE && | |
mCurrentState != STATE_PREPARING); | |
} | |
private IMediaPlayer createPlayer() { | |
IjkMediaPlayer ijkMediaPlayer = null; | |
if (mUri != null) { | |
ijkMediaPlayer = new IjkMediaPlayer(); | |
IjkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "safe", 0); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "protocol_whitelist", "ffconcat,file,http,https"); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0); | |
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48); | |
} | |
return ijkMediaPlayer; | |
} | |
public void release(boolean clearTargetState) { | |
if (mMediaPlayer != null) { | |
mMediaPlayer.reset(); | |
mMediaPlayer.release(); | |
mMediaPlayer = null; | |
// REMOVED: mPendingSubtitleTracks.clear(); | |
mCurrentState = STATE_IDLE; | |
if (clearTargetState) { | |
mTargetState = STATE_IDLE; | |
} | |
AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE); | |
am.abandonAudioFocus(null); | |
} | |
} | |
@Override | |
public boolean onKeyDown(int keyCode, KeyEvent event) { | |
boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && | |
keyCode != KeyEvent.KEYCODE_VOLUME_UP && | |
keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && | |
keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && | |
keyCode != KeyEvent.KEYCODE_MENU && | |
keyCode != KeyEvent.KEYCODE_CALL && | |
keyCode != KeyEvent.KEYCODE_ENDCALL; | |
if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { | |
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || | |
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { | |
if (mMediaPlayer.isPlaying()) { | |
pause(); | |
mMediaController.show(); | |
} else { | |
start(); | |
mMediaController.hide(); | |
} | |
return true; | |
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { | |
if (!mMediaPlayer.isPlaying()) { | |
start(); | |
mMediaController.hide(); | |
} | |
return true; | |
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP || | |
keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { | |
if (mMediaPlayer.isPlaying()) { | |
pause(); | |
mMediaController.show(); | |
} | |
return true; | |
} else { | |
toggleMediaControlsVisibility(); | |
} | |
} | |
return super.onKeyDown(keyCode, event); | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
if (isInPlaybackState() && mMediaController != null) { | |
toggleMediaControlsVisibility(); | |
} | |
return false; | |
} | |
@Override | |
public boolean onTrackballEvent(MotionEvent event) { | |
if (isInPlaybackState() && mMediaController != null) { | |
toggleMediaControlsVisibility(); | |
} | |
return false; | |
} | |
private void toggleMediaControlsVisibility() { | |
if (mMediaController.isShowing()) { | |
mMediaController.hide(); | |
} else { | |
mMediaController.show(); | |
} | |
} | |
/** | |
* Register a callback to be invoked when the media file | |
* is loaded and ready to go. | |
* | |
* @param l The callback that will be run | |
*/ | |
public void setOnPreparedListener(IMediaPlayer.OnPreparedListener l) { | |
mOnPreparedListener = l; | |
} | |
/** | |
* Register a callback to be invoked when the end of a media file | |
* has been reached during playback. | |
* | |
* @param l The callback that will be run | |
*/ | |
public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l) { | |
mOnCompletionListener = l; | |
} | |
/** | |
* Register a callback to be invoked when an error occurs | |
* during playback or setup. If no listener is specified, | |
* or if the listener returned false, VideoView will inform | |
* the user of any errors. | |
* | |
* @param l The callback that will be run | |
*/ | |
public void setOnErrorListener(IMediaPlayer.OnErrorListener l) { | |
mOnErrorListener = l; | |
} | |
/** | |
* Register a callback to be invoked when an informational event | |
* occurs during playback or setup. | |
* | |
* @param l The callback that will be run | |
*/ | |
public void setOnInfoListener(IMediaPlayer.OnInfoListener l) { | |
mOnInfoListener = l; | |
} | |
@Override | |
public void start() { | |
if (isInPlaybackState()) { | |
mMediaPlayer.start(); | |
mCurrentState = STATE_PLAYING; | |
} | |
mTargetState = STATE_PLAYING; | |
} | |
@Override | |
public void pause() { | |
if (isInPlaybackState()) { | |
if (mMediaPlayer.isPlaying()) { | |
mMediaPlayer.pause(); | |
mCurrentState = STATE_PAUSED; | |
} | |
} | |
mTargetState = STATE_PAUSED; | |
} | |
@Override | |
public int getDuration() { | |
if (isInPlaybackState()) { | |
return (int) mMediaPlayer.getDuration(); | |
} | |
return -1; | |
} | |
@Override | |
public int getCurrentPosition() { | |
if (isInPlaybackState()) { | |
return (int) mMediaPlayer.getCurrentPosition(); | |
} | |
return 0; | |
} | |
@Override | |
public void seekTo(int msec) { | |
if (isInPlaybackState()) { | |
mMediaPlayer.seekTo(msec); | |
mSeekWhenPrepared = 0; | |
} else { | |
mSeekWhenPrepared = msec; | |
} | |
} | |
@Override | |
public boolean isPlaying() { | |
return isInPlaybackState() && mMediaPlayer.isPlaying(); | |
} | |
@Override | |
public int getBufferPercentage() { | |
if (mMediaPlayer != null) { | |
return mCurrentBufferPercentage; | |
} | |
return 0; | |
} | |
@Override | |
public boolean canPause() { | |
return mCanPause; | |
} | |
@Override | |
public boolean canSeekBackward() { | |
return mCanSeekBack; | |
} | |
@Override | |
public boolean canSeekForward() { | |
return mCanSeekForward; | |
} | |
@Override | |
public int getAudioSessionId() { | |
return 0; | |
} | |
public void stopPlayback() { | |
if (mMediaPlayer != null) { | |
mMediaPlayer.stop(); | |
mMediaPlayer.release(); | |
mMediaPlayer = null; | |
mCurrentState = STATE_IDLE; | |
mTargetState = STATE_IDLE; | |
AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE); | |
am.abandonAudioFocus(null); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.AsyncTask; | |
import android.os.Bundle; | |
import android.support.v7.app.ActionBar; | |
import android.support.v7.app.AppCompatActivity; | |
import android.support.v7.widget.Toolbar; | |
import com.hustunique.jianguo.ijkplayerdemo.media.AndroidMediaController; | |
import com.hustunique.jianguo.ijkplayerdemo.media.IjkVideoView; | |
import tv.danmaku.ijk.media.player.IjkMediaPlayer; | |
public class MainActivity extends AppCompatActivity { | |
private AndroidMediaController mMediaController; | |
private IjkVideoView mVideoView; | |
private boolean mBackPressed = false; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
mVideoView = (IjkVideoView) findViewById(R.id.video_view); | |
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); | |
setSupportActionBar(toolbar); | |
ActionBar actionBar = getSupportActionBar(); | |
mMediaController = new AndroidMediaController(this, false); | |
mMediaController.setSupportActionBar(actionBar); | |
// init player | |
IjkMediaPlayer.loadLibrariesOnce(null); | |
IjkMediaPlayer.native_profileBegin("libijkplayer.so"); | |
mVideoView.setMediaController(mMediaController); | |
new AsyncTask<Void, Void, Void>() { | |
@Override | |
protected Void doInBackground(Void... params) { | |
// Note that the duration is counted in seconds. | |
String data = "ffconcat version 1.0\n" + | |
"file http://k.youku.com/player/getFlvPath/sid/048455411693812bdd99a_00/st/flv/fileid/030001010058774A2CB9A9059E49FE220E3CC1-C869-0180-6843-BF9932E316E8?ypp=0&myp=0&K=afa53a85a7e5c378282c0be9%26sign%3D253e61392b8eff662013212ab183c891&ctype=12&token=0544&ev=1&ep=ciacHkyIUs8B4yrcgD8bNXi2fX5eXP4J9h%2BFgNJjALshQO%2B4nU%2FTtO%2B5P%2FZCE%2FBsditwZenzq6XkGTMVYYNLr2EQ30%2BgOfrm9vTg5d8lzZkDZGw1c8uivFSeRjT1&hd=1&oip=1939659569\n" + | |
"duration 178.667\n" + | |
"file http://k.youku.com/player/getFlvPath/sid/048455417446012115ebe_00/st/flv/fileid/0300010100587615E18FCC059E49FE0E9FBA38-2F1A-8CA4-CF5B-6D259E2DB1AB?ypp=0&myp=0&K=fb386578479b75df282c0be9%26sign%3D76b64c31b582d61b852d66229b9e9677&ctype=12&token=0504&ev=1&ep=ciacHkyIUs8H4SfZiD8bZi3nISVaXP4J9h%2BFgNJjALshQO%2B5mDukxpXGPYxCE%2FBsditwZeuEoqaVG0McYfI1qBkQ1z3ZPfqTiPWR5asnxpUJExtCAMymxlSeRjD1&hd=1&oip=1939659569\n" + | |
"duration 156.200"; | |
Util.writeToFile("test.ffconcat", data, MainActivity.this); | |
return null; | |
} | |
@Override | |
protected void onPostExecute(Void aVoid) { | |
super.onPostExecute(aVoid); | |
mVideoView.setVideoPath(MainActivity.this.getFileStreamPath("test.ffconcat").getAbsolutePath()); | |
mVideoView.start(); | |
} | |
}.execute(); | |
} | |
@Override | |
public void onBackPressed() { | |
mBackPressed = true; | |
super.onBackPressed(); | |
} | |
@Override | |
protected void onStop() { | |
super.onStop(); | |
if (mBackPressed) { | |
mVideoView.stopPlayback(); | |
mVideoView.release(true); | |
} | |
IjkMediaPlayer.native_profileEnd(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment