ijkplayer打造完美视频播放器

1.ijkplayer简介

ijkplayer是一个基于FFmpeg的轻量级Android/iOS视频播放器。FFmpeg的是全球领先的多媒体框架,能够解码,编码, 转码,复用,解复用,流,过滤器和播放大部分的视频格式。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。

2.功能的展示

      

支持横竖屏切换展示,上下滑动声音亮度的调节等功能。

3. androidStudio 接入

1)添加.so库:

如图所示:将.so文件添加到自己的项目中:

2)在Gradle中添加依赖:

// Bili required, enough for most devices.
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
compile 'pub.devrel:easypermissions:1.0.1'

3)开始代码的实现

1.创建一个类CusIjkView,继承frameLayout,(自定义播放器样式)

代码如下:
// 打印日志的TAG
private String TAG = this.getClass().getSimpleName();
// mCurrentState is a  object's current state.
private int mCurrentState = PlayStateParams.STATE_IDLE;
// 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 mTargetState = PlayStateParams.STATE_IDLE;
// 播放地址通过客户端可设置
private Uri mUri;
// 播放器的一些基本配置
private Map<String, String> mHeaders;
// 所有我们需要播放和显示视频的东西
private IRenderView.ISurfaceHolder mSurfaceHolder = null;
// 视频宽度
private int mVideoWidth;
// 视频高度
private int mVideoHeight;
// 窗口宽度
private int mSurfaceWidth;
// 窗口高度
private int mSurfaceHeight;
// 视频旋转角度
private int mVideoRotationDegree;
// 媒体播放器
private IMediaPlayer mMediaPlayer;
// 媒体控制器
private IMediaController mMediaController;
// 播放完成监听
private IMediaPlayer.OnCompletionListener mOnCompletionListener;
// 播放准备监听
private IMediaPlayer.OnPreparedListener mOnPreparedListener;
// 播放缓冲监听
private int mCurrentBufferPercentage;
// 播放错误监听
private IMediaPlayer.OnErrorListener mOnErrorListener;
// 播放其他信息监听
private IMediaPlayer.OnInfoListener mOnInfoListener;
// 为记录seek位置而做准备
private long mSeekWhenPrepared;
private Context mAppContext;
private IRenderView mRenderView;
private int mVideoSarNum;
private int mVideoSarDen;
// 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[mCurrentAspectRatioIndex];
// Extend: Render
public static final int RENDER_SURFACE_VIEW = 1;
public static final int RENDER_TEXTURE_VIEW = 2;
private List<Integer> mAllRenders = new ArrayList<>();
// 使用编解码器硬编码还是软编码,true 硬编码 false 为软编码
private boolean usingMediaCodec;
// 使用编解码是否自转
private boolean usingMediaCodecAutoRotate;
private boolean usingAndroidPlayer;
private boolean usingOpenSLES;
private boolean enableBackgroundPlay;

public CusIjkView(Context context) {
    super(context);
    initVideoView(context);
}

public CusIjkView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initVideoView(context);
}

public CusIjkView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initVideoView(context);
}

/**
 * 初始化视频view
 */
private void initVideoView(Context context) {
    mAppContext = context.getApplicationContext();

    initRenders();

    mVideoWidth = 0;
    mVideoHeight = 0;

    // 设置为可触摸并且获取焦点
    setFocusable(true);
    setFocusableInTouchMode(true);
    requestFocus();

    mCurrentState = PlayStateParams.STATE_IDLE;
    mTargetState = PlayStateParams.STATE_IDLE;
}

/**
 * 设置渲染器
 */
public 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();

    LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
    renderUIView.setLayoutParams(lp);
    addView(renderUIView);

    mRenderView.addRenderCallback(mSHCallback);
    mRenderView.setVideoRotation(mVideoRotationDegree);
}

/**
 * 设置旋转角度
 */
public void setPlayerRotation(int rotation) {
    mVideoRotationDegree = rotation;
    if (mRenderView != null) {
        mRenderView.setVideoRotation(mVideoRotationDegree);
    }
}

/**
 * 旋转渲染器
 */
public void setRender(int render) {
    switch (render) {
        case RENDER_TEXTURE_VIEW: {
            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);
            break;
        }
        case RENDER_SURFACE_VIEW: {
            SurfaceRenderView renderView = new SurfaceRenderView(getContext());
            setRenderView(renderView);
            break;
        }
        default:
            Log.e(TAG, String.format(Locale.getDefault(), "invalid render %d\n", render));
            break;
    }
}

/**
 * 设置视频路径
 */
public void setVideoPath(String path) {
    setVideoURI(Uri.parse(path));
}

/**
 * 设置视频URI
 */
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;
    mHeaders = headers;
    mSeekWhenPrepared = 0;
    openVideo();
    requestLayout();
    invalidate();
}

/**
 * 停止视频
 */
public void stopPlayback() {
    if (mMediaPlayer != null) {
        mMediaPlayer.stop();
        mMediaPlayer.release();
        mMediaPlayer = null;

        mCurrentState = PlayStateParams.STATE_IDLE;
        mTargetState = PlayStateParams.STATE_IDLE;

        AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
        if (am != null) {
            am.abandonAudioFocus(null);
        }
    }
}

/**
 * 打开视频
 */
private void openVideo() {
    if (mUri == null || mSurfaceHolder == null) {
        return;
    }

    release(false);

    AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
    if (am != null) {
        am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
    }

    try {
        if (usingAndroidPlayer) {
            mMediaPlayer = new AndroidMediaPlayer();
        } else {
            IjkMediaPlayer ijkMediaPlayer = null;
            if (mUri != null) {
                ijkMediaPlayer = new IjkMediaPlayer();
                IjkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
                if (usingMediaCodec) {
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
                    if (usingMediaCodecAutoRotate) {
                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
                    } else {
                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);
                    }
                } else {
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
                }

                if (usingOpenSLES) {
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
                } else {
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
                }

                // Auto Select=,RGB 565=fcc-rv16,RGB 888X=fcc-rv32,YV12=fcc-yv12,默认为RGB 888X
                String pixelFormat = "";
                if (TextUtils.isEmpty(pixelFormat)) {
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
                } else {
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat);
                }
                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_FORMAT, "timeout", 10000000);
                ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", 1);

                ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
            }
            mMediaPlayer = ijkMediaPlayer;
        }

        if (enableBackgroundPlay) {
            mMediaPlayer = new TextureMediaPlayer(mMediaPlayer);
        }

        if (mMediaPlayer == null) {
            return;
        }

        // 视频准备播放监听
        mMediaPlayer.setOnPreparedListener(mPreparedListener);
        // 视频播放完成监听
        mMediaPlayer.setOnCompletionListener(mCompletionListener);
        // 视频错误监听
        mMediaPlayer.setOnErrorListener(mErrorListener);
        // 视频其他信息监听
        mMediaPlayer.setOnInfoListener(mInfoListener);
        // 视频界面大小改变监听
        mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
        // 视频缓冲监听
        mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
        mCurrentBufferPercentage = 0;
        String scheme = mUri.getScheme();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                && usingAndroidPlayer && (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();
        // 这里不设置目标状态,但保护的目标状态
        mCurrentState = PlayStateParams.STATE_PREPARING;
        attachMediaController();
    } catch (IOException | IllegalArgumentException ex) {
        Log.w(TAG, "Unable to open content: " + mUri, ex);
        mCurrentState = PlayStateParams.STATE_ERROR;
        mTargetState = PlayStateParams.STATE_ERROR;
        mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
    }
}

public void setMediaController(IMediaController 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) {
        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);
            }
            requestLayout();
        }
    }
};

IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
    public void onPrepared(IMediaPlayer mp) {
        // 这里不设置目标状态,但保护的目标状态
        mCurrentState = PlayStateParams.STATE_PREPARED;

        if (mOnPreparedListener != null) {
            mOnPreparedListener.onPrepared(mMediaPlayer);
        }
        if (mMediaController != null) {
            mMediaController.setEnabled(true);
        }
        if (mOnInfoListener != null) {
            mOnInfoListener.onInfo(mMediaPlayer, mCurrentState, 0);
        }

        mVideoWidth = mp.getVideoWidth();
        mVideoHeight = mp.getVideoHeight();

        long seekToPosition = mSeekWhenPrepared;
        if (seekToPosition != 0) {
            seekTo((int) 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 == PlayStateParams.STATE_PLAYING) {
                        start();
                        if (mMediaController != null) {
                            mMediaController.show();
                        }
                    } else if (!isPlaying() &&
                            (seekToPosition != 0 || getCurrentPosition() > 0)) {
                        if (mMediaController != null) {
                            mMediaController.show(0);
                        }
                    }
                }
            }
        } else {
            if (mTargetState == PlayStateParams.STATE_PLAYING) {
                start();
            }
        }
    }
};

private IMediaPlayer.OnCompletionListener mCompletionListener = new IMediaPlayer.OnCompletionListener() {
    public void onCompletion(IMediaPlayer mp) {
        mCurrentState = PlayStateParams.STATE_COMPLETED;
        mTargetState = PlayStateParams.STATE_COMPLETED;
        if (mMediaController != null) {
            mMediaController.hide();
        }
        if (mOnCompletionListener != null) {
            mOnCompletionListener.onCompletion(mMediaPlayer);
        }
        if (mOnInfoListener != null) {
            mOnInfoListener.onInfo(mMediaPlayer, PlayStateParams.STATE_COMPLETED, 0);
        }
    }
};

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.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() {
    public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
        Log.d(TAG, "Error: " + framework_err + "," + impl_err);
        mCurrentState = PlayStateParams.STATE_ERROR;
        mTargetState = PlayStateParams.STATE_ERROR;
        if (mMediaController != null) {
            mMediaController.hide();
        }

        if (mOnErrorListener != null) {
            mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err);
        }
        if (mOnInfoListener != null) {
            if (mOnInfoListener.onInfo(mMediaPlayer, framework_err, 0)) {
                return true;
            }
        }

        if (getWindowToken() != null) {
            String message = "Unknown error";

            if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
                message = "Invalid progressive playback";
            }

            new AlertDialog.Builder(getContext())
                    .setMessage(message)
                    .setPositiveButton("error", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            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;
    }
};

/**
 * Register a callback to be invoked when the media file is loaded and ready to go.
 */
public void setOnPreparedListener(IMediaPlayer.OnPreparedListener listener) {
    mOnPreparedListener = listener;
}

/**
 * Register a callback to be invoked when the end of a media file has been reached during playback.
 */
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.
 */
public void setOnErrorListener(IMediaPlayer.OnErrorListener l) {
    mOnErrorListener = l;
}

/**
 * Register a callback to be invoked when an informational event occurs during playback or setup.
 */
public void setOnInfoListener(IMediaPlayer.OnInfoListener l) {
    mOnInfoListener = l;
}

private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
    if (mp == null)
        return;

    if (holder == null) {
        mp.setDisplay(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;
        }

        mSurfaceWidth = w;
        mSurfaceHeight = h;
        boolean isValidState = (mTargetState == PlayStateParams.STATE_PLAYING);
        boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
        if (mMediaPlayer != null && isValidState && hasValidSize) {
            if (mSeekWhenPrepared != 0) {
                seekTo((int) 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;
        }

        mSurfaceHolder = holder;
        if (mMediaPlayer != null)
            bindSurfaceHolder(mMediaPlayer, holder);
        else
            openVideo();
    }

    @Override
    public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
        if (holder.getRenderView() != mRenderView) {
            Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n");
            return;
        }
        mSurfaceHolder = null;
        releaseWithoutStop();
    }
};

public void releaseWithoutStop() {
    if (mMediaPlayer != null)
        mMediaPlayer.setDisplay(null);
}

/**
 * release the media player in any state
 */
public void release(boolean clearTargetState) {
    if (mMediaPlayer != null) {
        mMediaPlayer.reset();
        mMediaPlayer.release();
        mMediaPlayer = null;
        mCurrentState = PlayStateParams.STATE_IDLE;

        if (clearTargetState) {
            mTargetState = PlayStateParams.STATE_IDLE;
        }

        AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
        if (am != null) {
            am.abandonAudioFocus(null);
        }
    }
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (isInPlaybackState() && mMediaController != null) {
        toggleMediaControlsVisibility();
    }
    return false;
}

@Override
public boolean onTrackballEvent(MotionEvent ev) {
    if (isInPlaybackState() && mMediaController != null) {
        toggleMediaControlsVisibility();
    }
    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 {
            toggleMediaControlsVisibility();
        }
    }
    return super.onKeyDown(keyCode, event);
}

private void toggleMediaControlsVisibility() {
    if (mMediaController.isShowing()) {
        mMediaController.hide();
    } else {
        mMediaController.show();
    }
}

@Override
public void start() {
    if (isInPlaybackState()) {
        mMediaPlayer.start();
        mCurrentState = PlayStateParams.STATE_PLAYING;
    }
    mTargetState = PlayStateParams.STATE_PLAYING;
}

@Override
public void pause() {
    if (isInPlaybackState()) {
        if (mMediaPlayer.isPlaying()) {
            mMediaPlayer.pause();
            mCurrentState = PlayStateParams.STATE_PAUSED;
        }
    }
    mTargetState = PlayStateParams.STATE_PAUSED;
}

public void onPause() {
    release(false);
}

public void onResume() {
    openVideo();
}

@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;
}

private boolean isInPlaybackState() {
    return (mMediaPlayer != null &&
            mCurrentState != PlayStateParams.STATE_ERROR &&
            mCurrentState != PlayStateParams.STATE_IDLE &&
            mCurrentState != PlayStateParams.STATE_PREPARING);
}

@Override
public boolean canPause() {
    return true;
}

@Override
public boolean canSeekBackward() {
    return false;
}

@Override
public boolean canSeekForward() {
    return false;
}

@Override
public int getAudioSessionId() {
    return 0;
}

public void toggleAspectRatio() {
    mCurrentAspectRatioIndex++;
    mCurrentAspectRatioIndex %= s_allAspectRatio.length;
    mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
    if (mRenderView != null) {
        mRenderView.setAspectRatio(mCurrentAspectRatio);
    }
}

/**
 * 初始化渲染器
 */
private void initRenders() {
    mAllRenders.clear();
    mAllRenders.add(RENDER_SURFACE_VIEW); // 添加surface渲染
    int mCurrentRenderIndex;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        mAllRenders.add(RENDER_TEXTURE_VIEW); // 添加texture渲染
        mCurrentRenderIndex = 1;
    } else {
        mCurrentRenderIndex = 0;
    }
    int mCurrentRender = mAllRenders.get(mCurrentRenderIndex);
    setRender(mCurrentRender);
}

/**
 * 设置播放区域拉伸类型
 */
public void setAspectRatio(int aspectRatio) {
    for (int i = 0; i < s_allAspectRatio.length; i++) {
        if (s_allAspectRatio[i] == aspectRatio) {
            mCurrentAspectRatioIndex = i;
            if (mRenderView != null) {
                mRenderView.setAspectRatio(mCurrentAspectRatio);
            }
            break;
        }
    }
}

2.播放器功能的实现类(代码中有功能的注释)

  // 通知使用的flags
    private static final int MESSAGE_SHOW_PROGRESS = 1; // 同步进度
    private static final int MESSAGE_SEEK_NEW_POSITION = 3; // 设置新位置
    private static final int MESSAGE_HIDE_CENTER_BOX = 4; // 隐藏提示的box
    private static final int MESSAGE_RESTART_PLAY = 5; // 重新播放

    // 控件部分
    private final Activity mActivity; // 依附的容器Activity
    private final LayoutQuery mLayoutQuery; // 界面的中布局的查询器
    private final CusIjkView mIjkView; // 原生IjkPlayer
    private final View mTopBarView; // 播放器顶部控制bar
    private final View mBottomBarView; // 播放器底部控制bar
    private final ImageView mThumbnailImg; // 播放前的封面或缩略图
    private final ImageView mBackImage; // 视频返回按钮
    private final ImageView mBottomBarPlayerImage; // 视频bottomBar的播放按钮
    private final ImageView mCenterPlayerImage; // 视频中间的播放按钮
    private final ImageView mFullScreenImage; // 视频全屏按钮
    private final TextView mPlayerSpeedTv; // 视频加载速度
    private final SeekBar mProgressSeekBar; // 视频播放进度条

    // 视频相关参数
    private List<VideoIjkBean> mListVideos = new ArrayList<>(); // 码流列表
    private int mCurrStatus = PlayStateParams.STATE_IDLE; // 当前状态
    private int mCurrShowType = PlayStateParams.FIT_PARENT; // 视频显示比例,默认保持原视频的大小
    private final AudioManager mAudioManager; // 音频管理器
    private String mCurrVideoUrl; // 当前播放地址
    private int mCurrPlayPosition; // 当前播放位置
    private long mNewPosition = -1; // 滑动进度条得到的新位置,和当前播放位置是有区别的,mNewPosition =0也会调用设置的,故初始化值为-1
    private int mCurrVolume; // 当前声音大小
    private int mMaxVolume = 0; // 设备最大音量
    private final int mScreenWidthPix; // 获取当前设备的宽度
    private final int mPlayerViewInitHeight; // 记录播放器竖屏时的高度
    private float mCurrBrightness; // 当前亮度大小
    private int mBgState; // 记录进行后台时的播放状态0为播放,1为暂停
    private int mAutoConnectTime = 5000; // 自动重连的时间
    private boolean mIsPlayerSupport; // 第三方so是否支持,默认不支持,true为支持
    private boolean mIsLive; // 是否是直播,默认为非直播,true为直播false为点播。mIsLive()方法判断直播的方式比较片面
    private boolean mIsForbidTouch; // 禁止触摸,默认可以触摸,true为禁止false为可触摸
    private boolean mIsForbidHideControlPanel; // 禁止收起控制面板,默认可以收起,true为禁止false为可触摸
    private boolean mIsForbidDoubleUp; // 是否禁止双击,默认不禁止,true为禁止,false为不禁止
    private boolean mIsDragging; // 是否在拖动进度条中,默认为停止拖动,true为在拖动中,false为停止拖动
    private boolean mIsErrorStop = true; // 是否出错停止播放,默认是出错停止播放,true出错停止播放,false为用户点击停止播放
    private boolean mIsOnlyFullScreen; // 是否只有全屏,默认非全屏,true为全屏,false为非全屏
    private boolean mIsPortrait = true; // 是否是竖屏,默认为竖屏,true为竖屏,false为横屏
    private boolean mIsAutoReConnect = true; // 是否自动重连,默认5秒重连,true为重连,false为不重连
    private boolean mIsHideCenterPlayer; // 是否隐藏中间播放按钮,默认不隐藏,true为隐藏,false为不隐藏
    private boolean mIsHideTopBar; // 是否隐藏topBar,true为隐藏,false为不隐藏
    private boolean mIsHideBottomBar; // 是否隐藏bottomBar,true为隐藏,false为不隐藏
    private boolean mIsShowControlPanel; // 是否显示控制面板,默认为隐藏,true为显示false为隐藏
    private boolean mIsCharge; // 是否免费观看
    private int mMaxPlaytime; // 设置最大播放时间
    private boolean mIsHasSwitchStream; // 当前是否切换视频流,默认为否,true是切换视频流,false没有切换
    private boolean mIsNetWorkTip; // 播放时是否有网络提示,true为显示网络提示,false不显示网络提示
    private boolean mIsFirstPlayer = true; // 是否是第一次播放

    // 视频和UI的回调监听
    private Handler mHandler = new CusUiHandler();
    private AutoPlayRunnable mAutoPlayRunnable = new AutoPlayRunnable(); // 控制面板收起或者显示的轮询监听
    private OnPlayerBackListener mPlayerBack; // 视频的返回键监听
    private IMediaPlayer.OnInfoListener mOnInfoListener; // 视频播放时信息回调
    private OrientationEventListener mOrientationEventListener; // Activity界面方向监听
    private OnControlVisibilityChangeListener mOnControlVisibilityChangeListener; // 控制面板显示或隐藏监听

    // ========================================== 初始化 ========================================== //

    public PlayerView(Activity activity, View rootView) {
        this.mActivity = activity;

        try {
            IjkMediaPlayer.loadLibrariesOnce(null);
            IjkMediaPlayer.native_profileBegin("libijkplayer.so");
            mIsPlayerSupport = true;
        } catch (Throwable e) {
            e.printStackTrace();
        }

        try {
            int e = Settings.System.getInt(mActivity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
            float progress = 1.0F * (float) e / 255.0F;
            WindowManager.LayoutParams layout = this.mActivity.getWindow().getAttributes();
            layout.screenBrightness = progress;
            mActivity.getWindow().setAttributes(layout);
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }

        mAudioManager = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
        if (mAudioManager != null) {
            mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        }

        // 播放器整个界面
        View rootBoxRL;
        if (rootView == null) {
            mLayoutQuery = new LayoutQuery(mActivity);
            rootBoxRL = mActivity.findViewById(R.id.app_video_box);
            mIjkView = mActivity.findViewById(R.id.video_view);

            mTopBarView = mActivity.findViewById(R.id.app_video_top_box);
            mBottomBarView = mActivity.findViewById(R.id.ll_bottom_bar);
            mThumbnailImg = mActivity.findViewById(R.id.iv_trumb);
            mBackImage = mActivity.findViewById(R.id.app_video_finish);
            mBottomBarPlayerImage = mActivity.findViewById(R.id.app_video_play);
            mCenterPlayerImage = mActivity.findViewById(R.id.play_icon);
            mFullScreenImage = mActivity.findViewById(R.id.app_video_fullscreen);
            mPlayerSpeedTv = mActivity.findViewById(R.id.app_video_speed);
            mProgressSeekBar = mActivity.findViewById(R.id.app_video_seekBar);
            mProgressSeekBar.setMax(1000);
        } else {
            mLayoutQuery = new LayoutQuery(mActivity, rootView);
            rootBoxRL = rootView.findViewById(R.id.app_video_box);
            mIjkView = rootView.findViewById(R.id.video_view);

            mTopBarView = rootView.findViewById(R.id.app_video_top_box);
            mBottomBarView = rootView.findViewById(R.id.ll_bottom_bar);
            mThumbnailImg = rootView.findViewById(R.id.iv_trumb);
            mBackImage = rootView.findViewById(R.id.app_video_finish);
            mBottomBarPlayerImage = rootView.findViewById(R.id.app_video_play);
            mCenterPlayerImage = rootView.findViewById(R.id.play_icon);
            mFullScreenImage = rootView.findViewById(R.id.app_video_fullscreen);
            mPlayerSpeedTv = rootView.findViewById(R.id.app_video_speed);
            mProgressSeekBar = rootView.findViewById(R.id.app_video_seekBar);
            mProgressSeekBar.setMax(1000);
        }

        mProgressSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) {
                    long duration = getDuration();
                    int position = (int) ((duration * progress * 1.0) / 1000);
                    String time = generateTime(position);
                    mLayoutQuery.id(R.id.app_video_currentTime).text(time);
                    mLayoutQuery.id(R.id.app_video_currentTime_full).text(time);
                    mLayoutQuery.id(R.id.app_video_currentTime_left).text(time);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                mIsDragging = true;
                mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                long duration = getDuration();
                mIjkView.seekTo((int) ((duration * seekBar.getProgress() * 1.0) / 1000));
                mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);
                mIsDragging = false;
                mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_PROGRESS, 1000);
            }
        });

        View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v.getId() == R.id.app_video_fullscreen) {
                    toggleFullScreen();
                } else if (v.getId() == R.id.app_video_play || v.getId() == R.id.play_icon) {
                    if (mIjkView.isPlaying()) {
                        if (mIsLive) {
                            mIjkView.stopPlayback();
                        } else {
                            pausePlay();
                        }
                    } else {
                        startPlay();
                        if (mIjkView.isPlaying()) {
                            // TODO ijkPlayer内部的监听没有回调,只能手动修改状态
                            mCurrStatus = PlayStateParams.STATE_PREPARING;
                            hideStatusUI();
                        }
                    }
                    updatePausePlay();
                } else if (v.getId() == R.id.app_video_finish) {
                    backClick();
                } else if (v.getId() == R.id.app_video_netTie_icon) {
                    // 使用移动网络提示继续播放
                    mIsNetWorkTip = false;
                    hideStatusUI();
                    startPlay();
                    updatePausePlay();
                } else if (v.getId() == R.id.app_video_replay_icon) {
                    // 重新播放
                    mCurrStatus = PlayStateParams.STATE_ERROR;
                    hideStatusUI();
                    startPlay();
                    updatePausePlay();
                }
            }
        };

        mBottomBarPlayerImage.setOnClickListener(onClickListener);
        mCenterPlayerImage.setOnClickListener(onClickListener);
        mFullScreenImage.setOnClickListener(onClickListener);
        mBackImage.setOnClickListener(onClickListener);
        mLayoutQuery.id(R.id.app_video_netTie_icon).clicked(onClickListener);
        mLayoutQuery.id(R.id.app_video_replay_icon).clicked(onClickListener);

        mIjkView.setOnInfoListener(new IMediaPlayer.OnInfoListener() {
            @Override
            public boolean onInfo(IMediaPlayer mp, int what, int extra) {
                if (what == PlayStateParams.MEDIA_INFO_NETWORK_BANDWIDTH || what == PlayStateParams.MEDIA_INFO_BUFFERING_BYTES_UPDATE) {
                    if (mPlayerSpeedTv != null) {
                        mPlayerSpeedTv.setText(getFormatSize(extra));
                    }
                }
                statusChange(what);
                if (mOnInfoListener != null) {
                    mOnInfoListener.onInfo(mp, what, extra);
                }
                if (mIsCharge && mMaxPlaytime < getCurrPlayPosition()) {
                    mLayoutQuery.id(R.id.app_video_freeTie).visible();
                    pausePlay();
                }
                return true;
            }
        });

        final GestureDetector detector = new GestureDetector(mActivity, new PlayerGestureListener());
        rootBoxRL.setClickable(true);
        rootBoxRL.setOnTouchListener(new View.OnTouchListener() {
            @SuppressLint("ClickableViewAccessibility")
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
                    case MotionEvent.ACTION_DOWN:
                        if (mAutoPlayRunnable != null) {
                            mAutoPlayRunnable.stop();
                        }
                        break;
                }
                if (detector.onTouchEvent(motionEvent)) {
                    return true;
                }
                // 处理手势结束
                switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
                    case MotionEvent.ACTION_UP:
                        endGesture();
                        break;
                    default:
                        break;
                }
                return false;
            }
        });

        mOrientationEventListener = new OrientationEventListener(mActivity) {
            @Override
            public void onOrientationChanged(int orientation) {
                if (orientation >= 0 && orientation <= 30 || orientation >= 330 || (orientation >= 150 && orientation <= 210)) {
                    if (mIsPortrait) {
                        mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
                        mOrientationEventListener.disable();
                    }
                } else if ((orientation >= 90 && orientation <= 120) || (orientation >= 240 && orientation <= 300)) {
                    if (!mIsPortrait) {
                        mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
                        mOrientationEventListener.disable();
                    }
                }
            }
        };

        if (mIsOnlyFullScreen) {
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
        mIsPortrait = (getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        mPlayerViewInitHeight = rootBoxRL.getLayoutParams().height;
        mScreenWidthPix = mActivity.getResources().getDisplayMetrics().widthPixels;

        hideAllUI();

        if (!mIsPlayerSupport) {
            showStatus(mActivity.getResources().getString(R.string.not_support));
        } else {
            mLayoutQuery.id(R.id.ll_bg).visible();
        }
    }

    // ========================================= 生命周期 ========================================= //

    public void onPause() {
        mBgState = (mIjkView.isPlaying() ? 0 : 1);
        getCurrPlayPosition();
        mIjkView.onPause();
    }

    public void onResume() {
        mIjkView.onResume();
        if (mIsLive) {
            mIjkView.seekTo(0);
        } else {
            mIjkView.seekTo(mCurrPlayPosition);
        }
        if (mBgState != 0) {
            pausePlay();
        }
    }

    public void onDestroy() {
        mOrientationEventListener.disable();
        mHandler.removeMessages(MESSAGE_RESTART_PLAY);
        mHandler.removeMessages(MESSAGE_SEEK_NEW_POSITION);
        mIjkView.stopPlayback();
    }

    public void onConfigurationChanged(final Configuration newConfig) {
        mIsPortrait = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT;
        doOnConfigurationChanged(mIsPortrait);
    }

    public boolean onBackPressed() {
        if (!mIsOnlyFullScreen && getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            doOnNoAllScreen();
            return true;
        }
        return false;
    }

    // ========================================= 对外接口 ========================================= //

    /**
     * 设置播放信息监听回调
     */
    public void setOnInfoListener(IMediaPlayer.OnInfoListener onInfoListener) {
        this.mOnInfoListener = onInfoListener;
    }

    /**
     * 设置播放器中的返回键监听
     */
    public void setPlayerBackListener(OnPlayerBackListener listener) {
        this.mPlayerBack = listener;
    }

    /**
     * 设置控制面板显示隐藏监听
     */
    public void setOnControlPanelVisibilityChangListenter(OnControlVisibilityChangeListener listener) {
        this.mOnControlVisibilityChangeListener = listener;
    }

    /**
     * 显示缩略图
     */
    public void showThumbnail(OnShowThumbnailListener onShowThumbnailListener) {
        if (onShowThumbnailListener != null && mThumbnailImg != null) {
            onShowThumbnailListener.onShowThumbnail(mThumbnailImg);
        }
    }

    /**
     * 设置播放地址
     */
    public void setPlaySource(String stream, String url) {
        VideoIjkBean mVideoIjkBean = new VideoIjkBean();
        mVideoIjkBean.setStream(stream);
        mVideoIjkBean.setUrl(url);
        setPlaySource(mVideoIjkBean);
    }

    /**
     * 设置播放地址
     */
    public void setPlaySource(VideoIjkBean videoIjkBean) {
        mListVideos.clear();
        if (videoIjkBean != null) {
            mListVideos.add(videoIjkBean);

            if (mListVideos.size() > 0) {
                mCurrVideoUrl = mListVideos.get(0).getUrl();
                mListVideos.get(0).setSelect(true);
                isLive();
                if (mIjkView.isPlaying()) {
                    getCurrPlayPosition();
                    mIjkView.release(false);
                }
                mIsHasSwitchStream = true;
            }
        }
    }

    /**
     * 开始播放
     */
    public void startPlay() {
        if (mIsLive) {
            mIjkView.setVideoPath(mCurrVideoUrl);
            mIjkView.seekTo(0);
        } else {
            if (mIsHasSwitchStream || mCurrStatus == PlayStateParams.STATE_ERROR) {
                // TODO 换源之后声音可播,画面卡住,主要是渲染问题,目前只是提供了软解方式,后期提供设置方式
                mIjkView.setRender(CusIjkView.RENDER_TEXTURE_VIEW);
                mIjkView.setVideoPath(mCurrVideoUrl);
                mIjkView.seekTo(mCurrPlayPosition);
                mIsHasSwitchStream = false;
            }
        }
        hideStatusUI();
        if (mIsNetWorkTip && (NetworkUtils.getNetworkType(mActivity) == 4
                || NetworkUtils.getNetworkType(mActivity) == 5
                || NetworkUtils.getNetworkType(mActivity) == 6)) {
            mLayoutQuery.id(R.id.app_video_netTie).visible();
        } else {
            if (mIsCharge && mMaxPlaytime < getCurrPlayPosition()) {
                mLayoutQuery.id(R.id.app_video_freeTie).visible();
            } else {
                if (mIsPlayerSupport) {
                    mIjkView.start();
                    if (mIsFirstPlayer) {
                        mLayoutQuery.id(R.id.app_video_loading).visible();
                        mIsFirstPlayer = false;
                    }
                } else {
                    showStatus(mActivity.getResources().getString(R.string.not_support));
                }
            }
        }
    }

    /**
     * 暂停播放
     */
    public void pausePlay() {
        mCurrStatus = PlayStateParams.STATE_PAUSED;
        getCurrPlayPosition();
        mIjkView.pause();
    }

    /**
     * 停止播放
     */
    public void stopPlay() {
        mIjkView.stopPlayback();
        mIsErrorStop = true;
        if (mHandler != null) {
            mHandler.removeMessages(MESSAGE_RESTART_PLAY);
        }
    }

    public boolean isPlaying() {
        return mIjkView.isPlaying();
    }

    public void backClick() {
        if (!mIsOnlyFullScreen && !mIsPortrait) {
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            doOnNoAllScreen();
        } else {
            if (mPlayerBack != null) {
                mPlayerBack.onPlayerBack();
            } else {
                mActivity.finish();
            }
        }
    }

    /**
     * 设置播放位置
     */
    public void seekTo(int playtime) {
        mIjkView.seekTo(playtime);
    }

    /**
     * 获取当前播放位置
     */
    public int getCurrPlayPosition() {
        if (!mIsLive) {
            mCurrPlayPosition = mIjkView.getCurrentPosition();
        } else {
            mCurrPlayPosition = -1;
        }
        return mCurrPlayPosition;
    }

    /**
     * 获取视频播放总时长
     */
    public long getDuration() {
        return (long) mIjkView.getDuration();
    }

    /**
     * 百分比显示切换
     */
    public void toggleAspectRatio() {
        if (mIjkView != null) {
            mIjkView.toggleAspectRatio();
        }
    }

    /**
     * 设置视频名称
     */
    public void setTitle(String title) {
        mLayoutQuery.id(R.id.app_video_title).text(title);
    }

    /**
     * 设置最大观看时长
     *
     * @param isCharge    true为收费 false为免费即不做限制
     * @param maxPlaytime 最大能播放时长,单位秒
     */
    public void setChargeState(boolean isCharge, int maxPlaytime) {
        this.mIsCharge = isCharge;
        this.mMaxPlaytime = maxPlaytime * 1000;
    }

    /**
     * 设置播放区域拉伸类型
     */
    public void setScaleType(int showType) {
        mCurrShowType = showType;
        mIjkView.setAspectRatio(mCurrShowType);
    }

    /**
     * 旋转指定角度
     */
    public void setPlayerRotation(int rotation) {
        if (mIjkView != null) {
            mIjkView.setPlayerRotation(rotation);
            mIjkView.setAspectRatio(mCurrShowType);
        }
    }

    /**
     * 设置自动重连的模式或者重连时间,isAuto true 出错重连,false出错不重连,connectTime重连的时间
     */
    public void setAutoReConnect(boolean isAuto, int connectTime) {
        this.mIsAutoReConnect = isAuto;
        this.mAutoConnectTime = connectTime;
    }

    /**
     * 是否仅仅为全屏
     */
    public void setOnlyFullScreen(boolean isFull) {
        this.mIsOnlyFullScreen = isFull;
        tryFullScreen(mIsOnlyFullScreen);
        if (mIsOnlyFullScreen) {
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        } else {
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
        }
    }

    /**
     * 设置是否禁止双击
     */
    public void setForbidDoubleUp(boolean flag) {
        this.mIsForbidDoubleUp = flag;
    }

    /**
     * 设置是否禁止隐藏bar
     */
    public void setForbidHideControlPanel(boolean flag) {
        this.mIsForbidHideControlPanel = flag;
    }

    /**
     * 是否禁止触摸
     */
    public void forbidTouch(boolean forbidTouch) {
        this.mIsForbidTouch = forbidTouch;
    }

    /**
     * 隐藏返回键,true隐藏,false为显示
     */
    public void hideBack(boolean isHide) {
        mBackImage.setVisibility(isHide ? View.GONE : View.VISIBLE);
    }

    /**
     * 隐藏全屏按钮,true隐藏,false为显示
     */
    public void hideFullscreen(boolean isHide) {
        mFullScreenImage.setVisibility(isHide ? View.GONE : View.VISIBLE);
    }

    /**
     * 隐藏中间播放按钮,ture为隐藏,false为不做隐藏处理,但不是显示
     */
    public void hideCenterPlayer(boolean isHide) {
        mIsHideCenterPlayer = isHide;
        mCenterPlayerImage.setVisibility(mIsHideCenterPlayer ? View.GONE : View.VISIBLE);
    }

    /**
     * 是否隐藏topbar,true为隐藏,false为不隐藏,但不一定是显示
     */
    public void hideHideTopBar(boolean isHide) {
        mIsHideTopBar = isHide;
        mTopBarView.setVisibility(mIsHideTopBar ? View.GONE : View.VISIBLE);
    }

    /**
     * 是否隐藏bottonbar,true为隐藏,false为不隐藏,但不一定是显示
     */
    public void hideBottomBar(boolean isHide) {
        mIsHideBottomBar = isHide;
        mBottomBarView.setVisibility(mIsHideBottomBar ? View.GONE : View.VISIBLE);
    }

    /**
     * 是否隐藏上下bar,true为隐藏,false为不隐藏,但不一定是显示
     */
    public void hideControlPanl(boolean isHide) {
        hideBottomBar(isHide);
        hideHideTopBar(isHide);
    }

    /**
     * 显示菜单设置
     */
    public void showMenu() {
        if (!mIsForbidHideControlPanel) {
            mTopBarView.setVisibility(View.GONE);
            mBottomBarView.setVisibility(View.GONE);
        }
    }

    /**
     * 设置显示加载网速或者隐藏
     */
    public void setShowSpeed(boolean isShow) {
        mPlayerSpeedTv.setVisibility(isShow ? View.VISIBLE : View.GONE);
    }

    // ========================================= 内部实现 ========================================= //

    /**
     * 当前播放的是否是直播
     */
    private void isLive() {
        mIsLive = mCurrVideoUrl != null
                && (mCurrVideoUrl.startsWith("rtmp://")
                || (mCurrVideoUrl.startsWith("http://") && mCurrVideoUrl.endsWith(".m3u8"))
                || (mCurrVideoUrl.startsWith("http://") && mCurrVideoUrl.endsWith(".flv")));
    }

    /**
     * 隐藏所有界面
     */
    private void hideAllUI() {
        if (!mIsForbidHideControlPanel) {
            mTopBarView.setVisibility(View.GONE);
            mBottomBarView.setVisibility(View.GONE);
        }
        hideStatusUI();
    }

    /**
     * 显示或隐藏操作面板
     */
    private void operatorPanel() {
        mIsShowControlPanel = !mIsShowControlPanel;
        if (mIsShowControlPanel) {
            mTopBarView.setVisibility(mIsHideTopBar ? View.GONE : View.VISIBLE);
            mBottomBarView.setVisibility(mIsHideBottomBar ? View.GONE : View.VISIBLE);
            if (mIsLive) {
                mLayoutQuery.id(R.id.app_video_process_panl).invisible();
            } else {
                mLayoutQuery.id(R.id.app_video_process_panl).visible();
            }
            if (mIsOnlyFullScreen || mIsForbidDoubleUp) {
                mFullScreenImage.setVisibility(View.GONE);
            } else {
                mFullScreenImage.setVisibility(View.VISIBLE);
            }
            if (mOnControlVisibilityChangeListener != null) {
                mOnControlVisibilityChangeListener.change(true);
            }
            // 显示面板的时候再根据状态显示播放按钮
            if (mCurrStatus == PlayStateParams.STATE_PLAYING
                    || mCurrStatus == PlayStateParams.STATE_PREPARED
                    || mCurrStatus == PlayStateParams.STATE_PREPARING
                    || mCurrStatus == PlayStateParams.STATE_PAUSED) {
                if (mIsHideCenterPlayer) {
                    mCenterPlayerImage.setVisibility(View.GONE);
                } else {
                    mCenterPlayerImage.setVisibility(mIsLive ? View.GONE : View.VISIBLE);
                }
            } else {
                mCenterPlayerImage.setVisibility(View.GONE);
            }
            updatePausePlay();
            mHandler.sendEmptyMessage(MESSAGE_SHOW_PROGRESS);
            mAutoPlayRunnable.start();
        } else {
            if (mIsHideTopBar) {
                mTopBarView.setVisibility(View.GONE);
            } else {
                mTopBarView.setVisibility(mIsForbidHideControlPanel ? View.VISIBLE : View.GONE);

            }
            if (mIsHideBottomBar) {
                mBottomBarView.setVisibility(View.GONE);
            } else {
                mBottomBarView.setVisibility(mIsForbidHideControlPanel ? View.VISIBLE : View.GONE);

            }
            if (!mIsLive && mCurrStatus == PlayStateParams.STATE_PAUSED && !mIjkView.isPlaying()) {
                if (mIsHideCenterPlayer) {
                    mCenterPlayerImage.setVisibility(View.GONE);
                } else {
                    // 暂停时一直显示按钮
                    mCenterPlayerImage.setVisibility(View.VISIBLE);
                }
            } else {
                mCenterPlayerImage.setVisibility(View.GONE);
            }
            mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);
            if (mOnControlVisibilityChangeListener != null) {
                mOnControlVisibilityChangeListener.change(false);
            }
            mAutoPlayRunnable.stop();
        }
    }

    /**
     * 全屏切换
     */
    private void toggleFullScreen() {
        if (getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            doOnNoAllScreen();
        } else {
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            doOnAllScreen();
        }
        updateFullScreenButton();
    }

    /**
     * 进度条和时长显示的方向切换
     */
    private void toggleProcessDurationOrientation() {
        setProcessDurationOrientation(PlayStateParams.PROCESS_PORTRAIT);
    }

    /**
     * 设置进度条和时长显示的方向,默认为上下显示,true为上下显示false为左右显示
     */
    private void setProcessDurationOrientation(int portrait) {
        if (portrait == PlayStateParams.PROCESS_CENTER) {
            mLayoutQuery.id(R.id.app_video_currentTime_full).gone();
            mLayoutQuery.id(R.id.app_video_endTime_full).gone();
            mLayoutQuery.id(R.id.app_video_center).gone();
            mLayoutQuery.id(R.id.app_video_lift).visible();
        } else if (portrait == PlayStateParams.PROCESS_LANDSCAPE) {
            mLayoutQuery.id(R.id.app_video_currentTime_full).visible();
            mLayoutQuery.id(R.id.app_video_endTime_full).visible();
            mLayoutQuery.id(R.id.app_video_center).gone();
            mLayoutQuery.id(R.id.app_video_lift).gone();
        } else {
            mLayoutQuery.id(R.id.app_video_currentTime_full).gone();
            mLayoutQuery.id(R.id.app_video_endTime_full).gone();
            mLayoutQuery.id(R.id.app_video_center).visible();
            mLayoutQuery.id(R.id.app_video_lift).gone();
        }
    }

    /**
     * 获取界面方向
     */
    private int getScreenOrientation() {
        int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
        DisplayMetrics dm = new DisplayMetrics();
        mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
        int width = dm.widthPixels;
        int height = dm.heightPixels;
        int orientation;
        if ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) && height > width ||
                (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && width > height) {
            switch (rotation) {
                case Surface.ROTATION_0:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                    break;
                case Surface.ROTATION_90:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                    break;
                case Surface.ROTATION_180:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
                    break;
                case Surface.ROTATION_270:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
                    break;
                default:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                    break;
            }
        } else {
            switch (rotation) {
                case Surface.ROTATION_0:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                    break;
                case Surface.ROTATION_90:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                    break;
                case Surface.ROTATION_180:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
                    break;
                case Surface.ROTATION_270:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
                    break;
                default:
                    orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                    break;
            }
        }
        return orientation;
    }

    /**
     * 状态改变同步UI
     */
    private void statusChange(int newStatus) {
        if (newStatus == PlayStateParams.STATE_COMPLETED) {
            mCurrStatus = PlayStateParams.STATE_COMPLETED;
            mCurrPlayPosition = 0;
            hideAllUI();
            showStatus("播放结束");
        } else if (newStatus == PlayStateParams.STATE_PREPARING || newStatus == PlayStateParams.MEDIA_INFO_BUFFERING_START) {
            mCurrStatus = PlayStateParams.STATE_PREPARING;
            hideStatusUI(); // 视频缓冲
            mLayoutQuery.id(R.id.app_video_loading).visible();
        } else if (newStatus == PlayStateParams.MEDIA_INFO_VIDEO_RENDERING_START
                || newStatus == PlayStateParams.STATE_PLAYING
                || newStatus == PlayStateParams.STATE_PREPARED
                || newStatus == PlayStateParams.MEDIA_INFO_BUFFERING_END
                || newStatus == PlayStateParams.STATE_PAUSED) {
            if (mCurrStatus == PlayStateParams.STATE_PAUSED) {
                mCurrStatus = PlayStateParams.STATE_PAUSED;
            } else {
                mCurrStatus = PlayStateParams.STATE_PLAYING;
            }
            // 视频缓冲结束后隐藏缩列图
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    hideStatusUI();
                    // 显示控制bar
                    mIsShowControlPanel = false;
                    if (!mIsForbidTouch) {
                        operatorPanel();
                    }
                    mLayoutQuery.id(R.id.ll_bg).gone(); // 延迟0.5秒隐藏视频封面隐藏
                }
            }, 500);
        } else if (newStatus == PlayStateParams.MEDIA_INFO_VIDEO_INTERRUPT) {
            // 直播停止推流
            mCurrStatus = PlayStateParams.STATE_ERROR;
            if (!(mIsNetWorkTip && (NetworkUtils.getNetworkType(mActivity) == 4
                    || NetworkUtils.getNetworkType(mActivity) == 5
                    || NetworkUtils.getNetworkType(mActivity) == 6))) {
                if (mIsCharge && mMaxPlaytime < getCurrPlayPosition()) {
                    mLayoutQuery.id(R.id.app_video_freeTie).visible();
                } else {
                    hideAllUI();
                    if (mIsLive) {
                        showStatus("获取不到直播源");
                    } else {
                        showStatus(mActivity.getResources().getString(R.string.small_problem));
                    }
                    // 5秒尝试重连
                    if (!mIsErrorStop && mIsAutoReConnect) {
                        mHandler.sendEmptyMessageDelayed(MESSAGE_RESTART_PLAY, mAutoConnectTime);
                    }

                }
            } else {
                mLayoutQuery.id(R.id.app_video_netTie).visible();
            }
        } else if (newStatus == PlayStateParams.STATE_ERROR
                || newStatus == PlayStateParams.MEDIA_INFO_UNKNOWN
                || newStatus == PlayStateParams.MEDIA_ERROR_IO
                || newStatus == PlayStateParams.MEDIA_ERROR_MALFORMED
                || newStatus == PlayStateParams.MEDIA_ERROR_UNSUPPORTED
                || newStatus == PlayStateParams.MEDIA_ERROR_TIMED_OUT
                || newStatus == PlayStateParams.MEDIA_ERROR_SERVER_DIED) {
            mCurrStatus = PlayStateParams.STATE_ERROR;
            if (!(mIsNetWorkTip && (NetworkUtils.getNetworkType(mActivity) == 4
                    || NetworkUtils.getNetworkType(mActivity) == 5
                    || NetworkUtils.getNetworkType(mActivity) == 6))) {
                if (mIsCharge && mMaxPlaytime < getCurrPlayPosition()) {
                    mLayoutQuery.id(R.id.app_video_freeTie).visible();
                } else {
                    hideStatusUI();
                    showStatus(mActivity.getResources().getString(R.string.small_problem));
                    // 秒尝试重连
                    if (!mIsErrorStop && mIsAutoReConnect) {
                        mHandler.sendEmptyMessageDelayed(MESSAGE_RESTART_PLAY, mAutoConnectTime);
                    }
                }
            } else {
                mLayoutQuery.id(R.id.app_video_netTie).visible();
            }
        }
    }

    /**
     * 显示视频播放状态提示
     */
    private void showStatus(String statusText) {
        mLayoutQuery.id(R.id.app_video_replay).visible();
        mLayoutQuery.id(R.id.app_video_status_text).text(statusText);
    }

    /**
     * 界面方向改变时刷新界面
     */
    private void doOnConfigurationChanged(final boolean portrait) {
        if (mIjkView != null && !mIsOnlyFullScreen) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    tryFullScreen(!portrait);
                    if (portrait) {
                        mLayoutQuery.id(R.id.app_video_box).height(mPlayerViewInitHeight, false);
                    } else {
                        int heightPixels = mActivity.getResources().getDisplayMetrics().heightPixels;
                        int widthPixels = mActivity.getResources().getDisplayMetrics().widthPixels;
                        mLayoutQuery.id(R.id.app_video_box).height(Math.min(heightPixels, widthPixels), false);
                    }
                    updateFullScreenButton();
                }
            });
            mOrientationEventListener.enable();
        }
    }

    private void doOnAllScreen() {
        setFullScreen(true);
        if (mIjkView != null && !mIsOnlyFullScreen) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mIsPortrait = false;
                    int heightPixels = mActivity.getResources().getDisplayMetrics().heightPixels;
                    int widthPixels = mActivity.getResources().getDisplayMetrics().widthPixels;
                    mLayoutQuery.id(R.id.app_video_box).height(Math.min(heightPixels, widthPixels), false);
                }
            });
        }
    }

    private void doOnNoAllScreen() {
        setFullScreen(false);
        if (mIjkView != null && !mIsOnlyFullScreen) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mIsPortrait = true;
                    mLayoutQuery.id(R.id.app_video_box).height(mPlayerViewInitHeight, false);
                }
            });
        }
    }

    /**
     * 设置界面方向
     */
    private void setFullScreen(boolean fullScreen) {
        if (mActivity != null) {
            WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes();
            if (fullScreen) {
                attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
                mActivity.getWindow().setAttributes(attrs);
                mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
            } else {
                attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
                mActivity.getWindow().setAttributes(attrs);
                mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
            }
            toggleProcessDurationOrientation();
        }
    }

    /**
     * 设置界面方向带隐藏actionbar
     */
    private void tryFullScreen(boolean fullScreen) {
        if (mActivity instanceof AppCompatActivity) {
            ActionBar supportActionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
            if (supportActionBar != null) {
                if (fullScreen) {
                    supportActionBar.hide();
                } else {
                    supportActionBar.show();
                }
            }
        }
        setFullScreen(fullScreen);
    }

    /**
     * 隐藏状态界面
     */
    private void hideStatusUI() {
        mCenterPlayerImage.setVisibility(View.GONE);
        mLayoutQuery.id(R.id.app_video_replay).gone();
        mLayoutQuery.id(R.id.app_video_netTie).gone();
        mLayoutQuery.id(R.id.app_video_freeTie).gone();
        mLayoutQuery.id(R.id.app_video_loading).gone();
        if (mOnControlVisibilityChangeListener != null) {
            mOnControlVisibilityChangeListener.change(false);
        }
    }

    /**
     * 手势结束
     */
    private void endGesture() {
        mCurrVolume = -1;
        mCurrBrightness = -1f;
        if (mNewPosition >= 0) {
            mHandler.removeMessages(MESSAGE_SEEK_NEW_POSITION);
            mHandler.sendEmptyMessage(MESSAGE_SEEK_NEW_POSITION);
        }
        mHandler.removeMessages(MESSAGE_HIDE_CENTER_BOX);
        mHandler.sendEmptyMessageDelayed(MESSAGE_HIDE_CENTER_BOX, 500);
        if (mAutoPlayRunnable != null) {
            mAutoPlayRunnable.start();
        }
    }

    /**
     * 同步进度
     */
    private long syncProgress() {
        if (mIsDragging) {
            return 0;
        }
        long position = mIjkView.getCurrentPosition();
        long duration = mIjkView.getDuration();
        if (mProgressSeekBar != null) {
            if (duration > 0) {
                long pos = 1000L * position / duration;
                mProgressSeekBar.setProgress((int) pos);
            }
            int percent = mIjkView.getBufferPercentage();
            mProgressSeekBar.setSecondaryProgress(percent * 10);
        }

        if (mIsCharge && mMaxPlaytime + 1000 < getCurrPlayPosition()) {
            mLayoutQuery.id(R.id.app_video_freeTie).visible();
            pausePlay();
        } else {
            mLayoutQuery.id(R.id.app_video_currentTime).text(generateTime(position));
            mLayoutQuery.id(R.id.app_video_currentTime_full).text(generateTime(position));
            mLayoutQuery.id(R.id.app_video_currentTime_left).text(generateTime(position));
            mLayoutQuery.id(R.id.app_video_endTime).text(generateTime(duration));
            mLayoutQuery.id(R.id.app_video_endTime_full).text(generateTime(duration));
            mLayoutQuery.id(R.id.app_video_endTime_left).text(generateTime(duration));
        }
        return position;
    }

    /**
     * 更新播放、暂停和停止按钮
     */
    private void updatePausePlay() {
        if (mIjkView.isPlaying()) {
            if (mIsLive) {
                mBottomBarPlayerImage.setImageResource(R.drawable.simple_player_stop_white_24dp);
            } else {
                mBottomBarPlayerImage.setImageResource(R.drawable.simple_player_icon_media_pause);
                mCenterPlayerImage.setImageResource(R.drawable.simple_player_center_pause);
            }
        } else {
            mBottomBarPlayerImage.setImageResource(R.drawable.simple_player_arrow_white_24dp);
            mCenterPlayerImage.setImageResource(R.drawable.simple_player_center_play);
        }
    }

    /**
     * 更新全屏和半屏按钮
     */
    private void updateFullScreenButton() {
        if (getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
            mFullScreenImage.setImageResource(R.drawable.simple_player_icon_fullscreen_shrink);
        } else {
            mFullScreenImage.setImageResource(R.drawable.simple_player_icon_fullscreen_stretch);
        }
    }

    /**
     * 滑动改变声音大小
     */
    private void onVolumeSlide(float percent) {
        if (mCurrVolume == -1) {
            mCurrVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
            if (mCurrVolume < 0) {
                mCurrVolume = 0;
            }
        }
        int index = (int) (percent * mMaxVolume) + mCurrVolume;
        if (index > mMaxVolume) {
            index = mMaxVolume;
        } else if (index < 0) {
            index = 0;
        }
        // 变更声音
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);
        // 变更进度条
        int i = (int) (index * 1.0 / mMaxVolume * 100);
        String s = i + "%";
        if (i == 0) {
            s = "off";
        }
        // 显示
        mLayoutQuery.id(R.id.app_video_volume_icon).image(i == 0
                ? R.drawable.simple_player_volume_off_white_36dp : R.drawable.simple_player_volume_up_white_36dp);
        mLayoutQuery.id(R.id.app_video_brightness_box).gone();
        mLayoutQuery.id(R.id.app_video_volume_box).visible();
        mLayoutQuery.id(R.id.app_video_volume_box).visible();
        mLayoutQuery.id(R.id.app_video_volume).text(s).visible();
    }

    /**
     * 快进或者快退滑动改变进度
     */
    private void onProgressSlide(float percent) {
        int position = mIjkView.getCurrentPosition();
        long duration = mIjkView.getDuration();
        long deltaMax = Math.min(100 * 1000, duration - position);
        long delta = (long) (deltaMax * percent);
        mNewPosition = delta + position;
        if (mNewPosition > duration) {
            mNewPosition = duration;
        } else if (mNewPosition <= 0) {
            mNewPosition = 0;
            delta = -position;
        }
        int showDelta = (int) delta / 1000;
        if (showDelta != 0) {
            mLayoutQuery.id(R.id.app_video_fastForward_box).visible();
            String text = showDelta > 0 ? ("+" + showDelta) : "" + showDelta;
            mLayoutQuery.id(R.id.app_video_fastForward).text(text + "s");
            mLayoutQuery.id(R.id.app_video_fastForward_target).text(generateTime(mNewPosition) + "/");
            mLayoutQuery.id(R.id.app_video_fastForward_all).text(generateTime(duration));
        }
    }

    /**
     * 亮度滑动改变亮度
     */
    private void onBrightnessSlide(float percent) {
        if (mCurrBrightness < 0) {
            mCurrBrightness = mActivity.getWindow().getAttributes().screenBrightness;
            if (mCurrBrightness <= 0.00f) {
                mCurrBrightness = 0.50f;
            } else if (mCurrBrightness < 0.01f) {
                mCurrBrightness = 0.01f;
            }
        }
        Log.d(this.getClass().getSimpleName(), "mCurrBrightness:" + mCurrBrightness + ",percent:" + percent);
        mLayoutQuery.id(R.id.app_video_brightness_box).visible();
        WindowManager.LayoutParams lpa = mActivity.getWindow().getAttributes();
        lpa.screenBrightness = mCurrBrightness + percent;
        if (lpa.screenBrightness > 1.0f) {
            lpa.screenBrightness = 1.0f;
        } else if (lpa.screenBrightness < 0.01f) {
            lpa.screenBrightness = 0.01f;
        }
        mLayoutQuery.id(R.id.app_video_brightness).text(((int) (lpa.screenBrightness * 100)) + "%");
        mActivity.getWindow().setAttributes(lpa);
    }

    /**
     * 时长格式化显示
     */
    @SuppressLint("DefaultLocale")
    private String generateTime(long time) {
        int totalSeconds = (int) (time / 1000);
        int seconds = totalSeconds % 60;
        int minutes = (totalSeconds / 60) % 60;
        int hours = totalSeconds / 3600;
        return hours > 0 ? String.format("%02d:%02d:%02d", hours, minutes, seconds) : String.format("%02d:%02d", minutes, seconds);
    }

    /**
     * 下载速度格式化显示
     */
    private String getFormatSize(int size) {
        long fileSize = (long) size;
        String showSize = "";
        if (fileSize >= 0 && fileSize < 1024) {
            showSize = fileSize + "Kb/s";
        } else if (fileSize >= 1024 && fileSize < (1024 * 1024)) {
            showSize = Long.toString(fileSize / 1024) + "KB/s";
        } else if (fileSize >= (1024 * 1024) && fileSize < (1024 * 1024 * 1024)) {
            showSize = Long.toString(fileSize / (1024 * 1024)) + "MB/s";
        }
        return showSize;
    }

    // ========================================== 内部类 ========================================== //

    @SuppressLint("HandlerLeak")
    private class CusUiHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                // 滑动完成,隐藏滑动提示的box
                case MESSAGE_HIDE_CENTER_BOX:
                    mLayoutQuery.id(R.id.app_video_volume_box).gone();
                    mLayoutQuery.id(R.id.app_video_brightness_box).gone();
                    mLayoutQuery.id(R.id.app_video_fastForward_box).gone();
                    break;

                // 滑动完成,设置播放进度
                case MESSAGE_SEEK_NEW_POSITION:
                    if (!mIsLive && mNewPosition >= 0) {
                        mIjkView.seekTo((int) mNewPosition);
                        mNewPosition = -1;
                    }
                    break;

                // 滑动中,同步播放进度
                case MESSAGE_SHOW_PROGRESS:
                    long pos = syncProgress();
                    if (!mIsDragging && mIsShowControlPanel) {
                        msg = obtainMessage(MESSAGE_SHOW_PROGRESS);
                        sendMessageDelayed(msg, 1000 - (pos % 1000));
                        updatePausePlay();
                    }
                    break;

                // 重新去播放
                case MESSAGE_RESTART_PLAY:
                    mCurrStatus = PlayStateParams.STATE_ERROR;
                    startPlay();
                    updatePausePlay();
                    break;
            }
        }
    }

    /**
     * 收起控制面板轮询,默认5秒无操作,收起控制面板
     */
    private class AutoPlayRunnable implements Runnable {
        private int AUTO_PLAY_INTERVAL = 5000;
        private boolean mShouldAutoPlay;

        AutoPlayRunnable() {
            mShouldAutoPlay = false;
        }

        void start() {
            if (!mShouldAutoPlay) {
                mShouldAutoPlay = true;
                mHandler.removeCallbacks(this);
                mHandler.postDelayed(this, AUTO_PLAY_INTERVAL);
            }
        }

        void stop() {
            if (mShouldAutoPlay) {
                mHandler.removeCallbacks(this);
                mShouldAutoPlay = false;
            }
        }

        @Override
        public void run() {
            if (mShouldAutoPlay) {
                mHandler.removeCallbacks(this);
                if (!mIsForbidTouch) {
                    operatorPanel();
                }
            }
        }
    }

    /**
     * 播放器的手势监听
     */
    public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener {
        private boolean isDownTouch; // 是否是按下的标识,默认为其他动作,true为按下标识,false为其他动作
        private boolean isVolume; // 是否声音控制,默认为亮度控制,true为声音控制,false为亮度控制
        private boolean isLandscape; // 是否横向滑动,默认为纵向滑动,true为横向滑动,false为纵向滑动

        /**
         * 双击,视频视窗双击事件
         */
        @Override
        public boolean onDoubleTap(MotionEvent e) {
//            if (!mIsForbidTouch && !mIsOnlyFullScreen && !mIsForbidDoubleUp) {
//                toggleFullScreen();
//            }
            return true;
        }

        /**
         * 按下
         */
        @Override
        public boolean onDown(MotionEvent e) {
            isDownTouch = true;
            return super.onDown(e);
        }

        /**
         * 滑动
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (!mIsForbidTouch) {
                float mOldX = e1.getX(), mOldY = e1.getY();
                float deltaY = mOldY - e2.getY();
                float deltaX = mOldX - e2.getX();
                if (isDownTouch) {
                    isLandscape = Math.abs(distanceX) >= Math.abs(distanceY);
                    isVolume = mOldX > mScreenWidthPix * 0.5f;
                    isDownTouch = false;
                }

                if (isLandscape) {
                    if (!mIsLive) {
                        // 进度设置
                        onProgressSlide(-deltaX / mIjkView.getWidth());
                    }
                } else {
                    float percent = deltaY / mIjkView.getHeight();
                    if (isVolume) {
                        // 声音设置
                        onVolumeSlide(percent);
                    } else {
                        // 亮度设置
                        onBrightnessSlide(percent);
                    }
                }
            }
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        /**
         * 单击,视频视窗单击事件
         */
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            if (!mIsForbidTouch) {
                operatorPanel();
            }
            return true;
        }
    }

3.具体的使用:

在你实现播放器的activity使用:

1)首先初始化播放器:

2)对视频进行网络判断

3)吊起播放:

项目地址:

https://download.csdn.net/download/wk_beicai/11177930

发布了96 篇原创文章 · 获赞 370 · 访问量 42万+

猜你喜欢

转载自blog.csdn.net/wk_beicai/article/details/90209660