|
package com.electric.chargingpile.view;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
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.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.FrameLayout;
import android.widget.MediaController;
import android.widget.TableLayout;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
import tv.danmaku.ijk.media.player.misc.ITrackInfo;
public class UpVideoView2 extends FrameLayout implements MediaController.MediaPlayerControl {
private String TAG = "UpVideoView2";
// settable by the client
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;
// All the stuff we need for playing and showing a video
private IRenderView.ISurfaceHolder mSurfaceHolder = null;
private IjkMediaPlayer mMediaPlayer = null;
// private int mAudioSession;
private int mVideoWidth;
private int mVideoHeight;
private int mSurfaceWidth;
private int mSurfaceHeight;
private int mVideoRotationDegree;
private MediaController mMediaController;
private IMediaPlayer.OnCompletionListener mOnCompletionListener;
private IMediaPlayer.OnPreparedListener mOnPreparedListener;
private int mCurrentBufferPercentage;
private IMediaPlayer.OnErrorListener mOnErrorListener;
private IMediaPlayer.OnInfoListener mOnInfoListener;
private IMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener;
private IjkMediaPlayer.OnNativeInvokeListener mOnNativeInvokeListener;
private int mSeekWhenPrepared; // recording the seek position while preparing
private boolean mCanPause = true;
private boolean mCanSeekBack = true;
private boolean mCanSeekForward = true;
private int bufferSize = -1;
private boolean isAutoPlay = true;
private static final int MSG_CACHE_DRU = 20160101;
private static final int CACHE_WATER = 1 * 1000;
private long mPrepareStartTime = 0;
private long mPrepareEndTime = 0;
private long mSeekStartTime = 0;
private long mSeekEndTime = 0;
// OnNativeInvokeListener what
public static final int AVAPP_EVENT_WILL_HTTP_OPEN = 1; //AVAppHttpEvent
public static final int AVAPP_EVENT_DID_HTTP_OPEN = 2; //AVAppHttpEvent
public static final int AVAPP_EVENT_WILL_HTTP_SEEK = 3; //AVAppHttpEvent
public static final int AVAPP_EVENT_DID_HTTP_SEEK = 4; //AVAppHttpEvent
public static final int AVAPP_EVENT_ASYNC_STATISTIC = 0x11000; //AVAppAsyncStatistic
public static final int AVAPP_EVENT_ASYNC_READ_SPEED = 0x11001; //AVAppAsyncReadSpeed
public static final int AVAPP_EVENT_IO_TRAFFIC = 0x12204; //AVAppIOTraffic
public static final int AVAPP_CTRL_WILL_TCP_OPEN = 0x20001; //AVAppTcpIOControl
public static final int AVAPP_CTRL_DID_TCP_OPEN = 0x20002; //AVAppTcpIOControl
public static final int AVAPP_CTRL_WILL_HTTP_OPEN = 0x20003; //AVAppIOControl
public static final int AVAPP_CTRL_WILL_LIVE_OPEN = 0x20005; //AVAppIOControl
public static final int AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN = 0x20007; //AVAppIOControl
// OnNativeInvokeListener bundle key
public static final String AVAPP_EVENT_URL = "url";
public static final String AVAPP_EVENT_ERROR = "error";
public static final String AVAPP_EVENT_HTTP_CODE = "http_code";
// private android.os.Handler mHandler = new android.os.Handler() {
// @Override
// public void handleMessage(Message msg) {
// switch (msg.what) {
// case MSG_CACHE_DRU:
// if (mMediaPlayer != null) {
//
// Log.e(TAG, "audio_cache_time:" + mMediaPlayer.getAudioCachedDuration() + " audio_cache_size" + mMediaPlayer.getAudioCachedBytes() + " video_cache_time:" + mMediaPlayer.getVideoCachedDuration() + " video_cache_size:" + mMediaPlayer.getVideoDecodeFramesPerSecond());
// Log.e(TAG, "audio_cache_pac:" + mMediaPlayer.getAudioCachedPackets() + " video_cache_pac:" + mMediaPlayer.getAudioCachedPackets());
//
// if (mMediaPlayer.getAudioCachedDuration() > CACHE_WATER || mMediaPlayer.getVideoCachedDuration() > CACHE_WATER)
// resume();
// }
// mHandler.removeMessages(MSG_CACHE_DRU);
// mHandler.sendEmptyMessageDelayed(MSG_CACHE_DRU, 500);
// }
// }
// };
/** Subtitle rendering widget overlaid on top of the video. */
// private RenderingWidget mSubtitleWidget;
/**
* Listener for changes to subtitle data, used to redraw when needed.
*/
// private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
private Context mAppContext;
private IRenderView mRenderView;
private int mVideoSarNum;
private int mVideoSarDen;
private boolean isFullState;
private ViewGroup.LayoutParams mRawParams;
// private MonitorRecorder monitorRecorder;
private float playSpeed = .0f;
private long bufferTime;
private long startbufferTime;
private static int PURSUETIME = 10 * 1000;
private boolean isAutoPursue = true;
public boolean isAutoPursue() {
return isAutoPursue;
}
public void setAutoPursue(boolean autoPursue) {
isAutoPursue = autoPursue;
}
private String ua = null;// user agent
public boolean isFullState() {
return isFullState;
}
public UpVideoView2(Context context) {
super(context);
initVideoView(context);
}
public UpVideoView2(Context context, AttributeSet attrs) {
super(context, attrs);
initVideoView(context);
}
public UpVideoView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initVideoView(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public UpVideoView2(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initVideoView(context);
}
// REMOVED: onMeasure
// REMOVED: onInitializeAccessibilityEvent
// REMOVED: onInitializeAccessibilityNodeInfo
// REMOVED: resolveAdjustedSize
private void initVideoView(Context context) {
mAppContext = context.getApplicationContext();
TextureRenderView renderView = new TextureRenderView(getContext());
setRenderView(renderView);
mVideoWidth = 0;
mVideoHeight = 0;
// REMOVED: getHolder().addCallback(mSHCallback);
// REMOVED: getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
// REMOVED: mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
// monitorRecorder = new MonitorRecorder(mAppContext);
// user agent
WebView webview;
webview = new WebView(context);
webview.layout(0, 0, 0, 0);
WebSettings settings = webview.getSettings();
this.ua = settings.getUserAgentString();
}
public void setRenderView(IRenderView renderView) {
if (mRenderView != null) {
if (mMediaPlayer != null)
mMediaPlayer.setSurface(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();
LayoutParams lp = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT,
Gravity.CENTER);
renderUIView.setLayoutParams(lp);
addView(renderUIView);
mRenderView.addRenderCallback(mSHCallback);
mRenderView.setVideoRotation(mVideoRotationDegree);
}
/**
* Sets video path.
*
* @param path the path of the video.
*/
public void setVideoPath(String path) {
setVideoURI(Uri.parse(path));
}
/**
* Sets video URI.
*
* @param uri the URI of the video.
*/
public void setVideoURI(Uri uri) {
setVideoURI(uri, null);
}
/**
* Sets video URI using specific headers.
*
* @param uri the URI of the video.
* @param headers the headers for the URI request.
* Note that the cross domain redirection is allowed by default, but that can be
* changed with key/value pairs through the headers parameter with
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
* to disallow or allow cross domain redirection.
*/
private void setVideoURI(Uri uri, Map<String, String> headers) {
mUri = uri;
if (uri.toString().startsWith("http")) {
if (headers == null) {
headers = new HashMap<>();
}
headers.put("X-Accept-Video-Encoding", "h265");
}
mHeaders = headers;
mSeekWhenPrepared = 0;
openVideo();
requestLayout();
invalidate();
}
// REMOVED: addSubtitleSource
// REMOVED: mPendingSubtitleTracks
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);
}
}
@TargetApi(Build.VERSION_CODES.M)
private void openVideo() {
Log.i(TAG, "openVideo");
if (mUri == null || mSurfaceHolder == null) {
Log.i(TAG, "openVideo return mSurfaceHolder == null:" + (mSurfaceHolder == null));
// not ready for playback just yet, will try again later
return;
}
Log.i(TAG, "openVideo start");
// we shouldn't clear the target state, because somebody might have
// called start() previously
release(false);
//开始播放时间
// monitorRecorder.start();
// monitorRecorder.setPlayUrl(mUri.toString());
// mHandler.removeMessages(MSG_CACHE_DRU);
// mHandler.sendEmptyMessageDelayed(MSG_CACHE_DRU, 500);
AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
try {
mMediaPlayer = new IjkMediaPlayer();
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", isAutoPlay ? 1 : 0);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 1024 * 400);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 0);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", "64000");
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec_mpeg4", 1);
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1);
// mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
// mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
// mMediaPlayer.setLooping(true);
// mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "sync", "ext");
// mMediaPlayer.setSpeed(1.03f);
if (bufferSize != -1) {
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", bufferSize);
}
// TODO: create SubtitleController in MediaPlayer, but we need
// a context for the subtitle renderers
final Context context = getContext();
// REMOVED: SubtitleController
// REMOVED: mAudioSession
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnNativeInvokeListener(mNativeInvokeListener);
mMediaPlayer.setOnInfoListener(mInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mCurrentBufferPercentage = 0;
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);
mPrepareStartTime = System.currentTimeMillis();
mMediaPlayer.prepareAsync();
if (playSpeed != .0f) {
mMediaPlayer.setSpeed(playSpeed);
}
// 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 ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
} catch (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);
return;
} finally {
// REMOVED: mPendingSubtitleTracks.clear();
}
}
public void setMediaController(MediaController controller) {
if (mMediaController != null) {
mMediaController.hide();
}
mMediaController = controller;
attachMediaController();
}
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());
}
}
IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
new IMediaPlayer.OnVideoSizeChangedListener() {
public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
if (mOnVideoSizeChangedListener != null) {
mOnVideoSizeChangedListener.onVideoSizeChanged(mp, width, height, sarNum, 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();
}
}
};
IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
public void onPrepared(IMediaPlayer mp) {
mPrepareEndTime = System.currentTimeMillis();
// monitorRecorder.firstPacket();
mCurrentState = STATE_PREPARED;
mMediaPlayer.pause();
// Get the capabilities of the player for this stream
// REMOVED: Metadata
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mMediaPlayer);
}
if (mMediaController != null) {
mMediaController.setEnabled(true);
}
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
// monitorRecorder.setVideoSize(mVideoHeight, mVideoWidth);
// monitorRecorder.setFirstPlayState(0);
// monitorRecorder.getMetaData(mMediaPlayer._getMetaData());
int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
if (seekToPosition != 0) {
seekTo(seekToPosition);
}
if (mVideoWidth != 0 && mVideoHeight != 0) {
Log.i(TAG, "onPrepared mVideoWidth != 0 && mVideoHeight != 0");
//Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
// REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
if (mRenderView != null) {
Log.i(TAG, "onPrepared mRenderView != null");
mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
Log.i(TAG, "onPrepared 1");
// We didn't actually change the size (it was already at the size
// we need), so we won't get a "surface changed" callback, so
// start the video here instead of in the callback.
if (mTargetState == STATE_PLAYING) {
Log.i(TAG, "onPrepared 2");
start();
if (mMediaController != null) {
mMediaController.show();
}
} else if (!isPlaying() &&
(seekToPosition != 0 || getCurrentPosition() > 0)) {
Log.i(TAG, "onPrepared 3");
if (mMediaController != null) {
// Show the media controls when we're paused into a video and make 'em stick.
mMediaController.show(0);
}
}
}
}
} else {
// We don't know the video size yet, but should start anyway.
// The video size might be reported to us later.
if (mTargetState == STATE_PLAYING) {
Log.i(TAG, "onPrepared start");
start();
}
}
}
};
private IMediaPlayer.OnCompletionListener mCompletionListener =
new IMediaPlayer.OnCompletionListener() {
public void onCompletion(IMediaPlayer mp) {
mCurrentState = STATE_PLAYBACK_COMPLETED;
mTargetState = STATE_PLAYBACK_COMPLETED;
if (mMediaController != null) {
mMediaController.hide();
}
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
}
}
};
private IjkMediaPlayer.OnNativeInvokeListener mNativeInvokeListener = new IjkMediaPlayer.OnNativeInvokeListener() {
@Override
public boolean onNativeInvoke(int what, Bundle args) {
Log.i(TAG, "onNativeInvoke:" + what);
if (mOnNativeInvokeListener != null) {
mOnNativeInvokeListener.onNativeInvoke(what, args);
}
return false;
}
};
private IMediaPlayer.OnInfoListener mInfoListener =
new IMediaPlayer.OnInfoListener() {
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.e(TAG, "卡顿时间:" + bufferTime);
startbufferTime = System.currentTimeMillis();
if (bufferTime > PURSUETIME && isAutoPursue) {
bufferTime = 0;
resume();
Log.e(TAG, "卡顿重连追帧");
break;
}
if (isAutoPursue) {
reportError();
}
Log.d(TAG, "MEDIA_INFO_BUFFERING_START:");
break;
case IMediaPlayer.MEDIA_INFO_BUFFERING_END:
Log.e(TAG, "结束缓冲:" + bufferTime);
if (startbufferTime != 0 && isAutoPursue) {
bufferTime = System.currentTimeMillis() - startbufferTime;
if (bufferTime > 2000) {
bufferTime = 0;
resume();
}
}
cancelReport();
// monitorRecorder.BufferEnd();
Log.d(TAG, "MEDIA_INFO_BUFFERING_END:");
break;
case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH:
// recorder.setBandwidth(arg2);
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() {
public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
Log.e(TAG, "Error: " + framework_err + "," + impl_err);
// monitorRecorder.errorDate("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) {
String messageId;
if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
messageId = "Invalid progressive playback";
} else {
messageId = "Unknown";
}
new AlertDialog.Builder(getContext())
.setMessage(messageId)
.setPositiveButton("OK",
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() {
public void onBufferingUpdate(IMediaPlayer mp, int percent) {
mCurrentBufferPercentage = percent;
}
};
private IMediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(IMediaPlayer mp) {
mSeekEndTime = System.currentTimeMillis();
}
};
/**
* 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;
}
public void setOnVideoSizeListener(IMediaPlayer.OnVideoSizeChangedListener l) {
mOnVideoSizeChangedListener = l;
}
/**
* @see AVAPP_EVENT_WILL_HTTP_OPEN
* @see AVAPP_EVENT_HTTP_CODE
* @param l
*/
public void setOnNativeInvokeListener(IjkMediaPlayer.OnNativeInvokeListener l) {
mOnNativeInvokeListener = l;
}
// REMOVED: mSHCallback
private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
if (mp == null)
return;
if (holder == null) {
mp.setSurface(null);
return;
}
holder.bindToMediaPlayer(mp);
}
IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {
@Override
public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {
if (holder.getRenderView() != mRenderView) {
Log.e(TAG, "onSurfaceChanged: unmatched render callback\n");
return;
}
Log.i(TAG, "onSurfaceChanged");
mSurfaceWidth = w;
mSurfaceHeight = h;
boolean isValidState = (mTargetState == STATE_PLAYING);
boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
if (mMediaPlayer != null && isValidState && hasValidSize) {
if (mSeekWhenPrepared != 0) {
seekTo(mSeekWhenPrepared);
}
start();
}
}
@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;
}
Log.i(TAG, "onSurfaceCreated");
mSurfaceHolder = holder;
if (mMediaPlayer != null) {
Log.i(TAG, "onSurfaceCreated bindSurfaceHolder");
bindSurfaceHolder(mMediaPlayer, holder);
} else {
Log.i(TAG, "onSurfaceCreated openVideo");
// onSurfaceCreated在调用过start之后触发
if (mTargetState == STATE_PLAYING) {
openVideo();
if (mMediaPlayer != null) {
Log.i(TAG, "onSurfaceCreated bindSurfaceHolder");
bindSurfaceHolder(mMediaPlayer, holder);
mCurrentState = STATE_PLAYING;
start();
}
}
}
}
@Override
public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
Log.i(TAG, "onSurfaceDestroyed1");
if (holder.getRenderView() != mRenderView) {
Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n");
return;
}
Log.i(TAG, "onSurfaceDestroyed2");
// 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();
if (mMediaController != null) mMediaController.hide();
// release(true);
releaseWithoutStop();
}
};
public void releaseWithoutStop() {
if (mMediaPlayer != null){
Log.i(TAG, "releaseWithoutStop");
mMediaPlayer.setSurface(null);
}
}
/*
* release the media player in any state
*/
public void release(boolean cleartargetstate) {
if (mMediaPlayer != null) {
Log.i(TAG, "release:" + cleartargetstate);
mMediaPlayer.reset();
mMediaPlayer.release();
// mHandler.removeMessages(MSG_CACHE_DRU);
// monitorRecorder.endRecode();
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 onTouchEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
}
@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 {
toggleMediaControlsVisiblity();
}
}
return super.onKeyDown(keyCode, event);
}
private void toggleMediaControlsVisiblity() {
if (mMediaController.isShowing()) {
mMediaController.hide();
} else {
mMediaController.show();
}
}
@Override
public void start() {
Log.i(TAG, "start");
if (isInPlaybackState()) {
Log.i(TAG, "start isInPlaybackState");
mMediaPlayer.start();
mCurrentState = STATE_PLAYING;
mRenderView.getView().setBackgroundDrawable(null);
} else {
Log.i(TAG, "start isInPlaybackState false mMediaPlayer == null:" + (mMediaPlayer == null) + " mCurrentState" + mCurrentState);
}
mTargetState = STATE_PLAYING;
}
@Override
public void pause() {
if (isInPlaybackState()) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
mCurrentState = STATE_PAUSED;
}
}
mTargetState = STATE_PAUSED;
}
public void suspend() {
release(false);
}
public void resume() {
openVideo();
}
@Override
public int getDuration() {
if (isInPlaybackState()) {
return (int) mMediaPlayer.getDuration();
}
return -1;
}
@Override
public int getCurrentPosition() {
if (isInPlaybackState()) {
if (mCurrentState == STATE_PLAYBACK_COMPLETED) {
return (int) mMediaPlayer.getDuration();
}
return (int) mMediaPlayer.getCurrentPosition();
}
return 0;
}
@Override
public void seekTo(int msec) {
if (isInPlaybackState()) {
mSeekStartTime = System.currentTimeMillis();
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;
}
private boolean isInPlaybackState() {
return (mMediaPlayer != null &&
mCurrentState != STATE_ERROR &&
mCurrentState != STATE_IDLE &&
mCurrentState != STATE_PREPARING);
}
@Override
public boolean canPause() {
return mCanPause;
}
@Override
public boolean canSeekBackward() {
return mCanSeekBack;
}
@Override
public boolean canSeekForward() {
return mCanSeekForward;
}
@Override
public int getAudioSessionId() {
return mMediaPlayer.getAudioSessionId();
}
// REMOVED: getAudioSessionId();
// REMOVED: onAttachedToWindow();
// REMOVED: onDetachedFromWindow();
// REMOVED: onLayout();
// REMOVED: draw();
// REMOVED: measureAndLayoutSubtitleWidget();
// REMOVED: setSubtitleWidget();
// REMOVED: getSubtitleLooper();
//-------------------------
// Extend: Aspect Ratio
//-------------------------
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];
public int toggleAspectRatio() {
mCurrentAspectRatioIndex++;
mCurrentAspectRatioIndex %= s_allAspectRatio.length;
mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
if (mRenderView != null)
mRenderView.setAspectRatio(mCurrentAspectRatio);
return mCurrentAspectRatio;
}
public void setAspectRatio(int aspectRatio) {
mCurrentAspectRatio = aspectRatio;
if (mRenderView != null)
mRenderView.setAspectRatio(mCurrentAspectRatio);
}
public ITrackInfo[] getTrackInfo() {
if (mMediaPlayer == null)
return null;
return mMediaPlayer.getTrackInfo();
}
public void selectTrack(int stream) {
MediaPlayerCompat.selectTrack(mMediaPlayer, stream);
}
public void deselectTrack(int stream) {
MediaPlayerCompat.deselectTrack(mMediaPlayer, stream);
}
public int getSelectedTrack(int trackType) {
return MediaPlayerCompat.getSelectedTrack(mMediaPlayer, trackType);
}
public void fullScreen(Activity activity) {
if (!isFullState) {
if (activity.getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// DisplayMetrics metrics = new DisplayMetrics();
// activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
// mRawParams = getLayoutParams();
// ViewGroup.LayoutParams fullParams;
// if (mRawParams instanceof RelativeLayout.LayoutParams) {
// fullParams = new RelativeLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels);
// } else if (mRawParams instanceof LinearLayout.LayoutParams) {
// fullParams = new LinearLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels);
// } else if (mRawParams instanceof LayoutParams) {
// fullParams = new LayoutParams(metrics.widthPixels, metrics.heightPixels);
// } else {
// new AlertDialog.Builder(getContext())
// .setMessage("nonsupport parent layout, please do it by yourself")
// .setPositiveButton("OK",
// new DialogInterface.OnClickListener() {
// public void onClick(DialogInterface dialog, int whichButton) {
// }
// })
// .setCancelable(false)
// .show();
// return;
// }
// setLayoutParams(fullParams);
isFullState = true;
}
}
public void exitFullScreen(Activity activity) {
if (isFullState) {
if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
// setLayoutParams(mRawParams);
isFullState = false;
}
}
// TODO: 16/5/20 设置播放前至少缓存时间
private void setCacheDuration(long cacheDuration) {
this.cacheDuration = cacheDuration;
}
public long cacheDuration;
/**
* 设置默认背景图片
*
* @param rec
*/
public void setImage(int rec) {
if (mRenderView != null) {
mRenderView.getView().setBackgroundResource(rec);
}
}
public void setImage(Drawable background) {
if (mRenderView != null) {
mRenderView.getView().setBackgroundDrawable(background);
}
}
/**
* 设置缓冲区大小 单位(B) 默认 15MB
*
* @param size
*/
public void setBufferSize(int size) {
bufferSize = size;
}
/**
* 设置是否自动开始播放 默认false
*
* @param autoPlay
*/
public void setAutoStart(boolean autoPlay) {
isAutoPlay = autoPlay;
}
/**
* 设置播放速度
*/
public void setSpeed(float speed) {
playSpeed = speed;
if (mMediaPlayer != null) {
mMediaPlayer.setSpeed(speed);
}
}
public float getSpeed(float speed) {
if (mMediaPlayer != null) {
return mMediaPlayer.getSpeed(.0f);
}
return .0f;
}
private void reportError() {
Log.e(TAG, "reportError");
postDelayed(reconnection, 20000);
}
private void cancelReport() {
Log.e(TAG, "cancelReport");
removeCallbacks(reconnection);
}
private Runnable reconnection = new Runnable() {
@Override
public void run() {
release(true);
mErrorListener.onError(mMediaPlayer, -1001, 0);
}
};
}
|