Skip to content

Instantly share code, notes, and snippets.

@TedaLIEz
Created January 16, 2017 08:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TedaLIEz/2529d8741ece851c63cbc9b66aedfc57 to your computer and use it in GitHub Desktop.
Save TedaLIEz/2529d8741ece851c63cbc9b66aedfc57 to your computer and use it in GitHub Desktop.
FFplay *.ffconcat file in android example
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);
}
}
}
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