Browse Source

接口分离法则

yangchong 5 years ago
parent
commit
ab555caa8f

+ 0 - 3
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/constant/ConstantKeys.java

@@ -46,7 +46,6 @@ public final class ConstantKeys {
     @Retention(RetentionPolicy.SOURCE)
     public @interface PlayerType{}
 
-
     /**
      * 控制器上的视频顶部View点击事件
      *                  在竖屏模式下,默认是不显示,需要显示设置controller.setTopVisibility(true);
@@ -109,8 +108,6 @@ public final class ConstantKeys {
         int MODE_TINY_WINDOW = 1003;
     }
 
-
-
     /**
      * 通过注解限定类型
      * 加载loading的类型

+ 13 - 165
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/controller/AbsVideoPlayerController.java

@@ -17,15 +17,15 @@ limitations under the License.
 package org.yczbj.ycvideoplayerlib.controller;
 
 import android.content.Context;
-import android.support.annotation.DrawableRes;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
+
+import org.yczbj.ycvideoplayerlib.inter.player.InterVideoController;
+import org.yczbj.ycvideoplayerlib.inter.player.VideoControllerView;
+import org.yczbj.ycvideoplayerlib.player.VideoPlayer;
 import org.yczbj.ycvideoplayerlib.utils.VideoPlayerUtils;
 import org.yczbj.ycvideoplayerlib.constant.ConstantKeys;
-import org.yczbj.ycvideoplayerlib.inter.player.InterVideoPlayer;
 
 import java.util.Timer;
 import java.util.TimerTask;
@@ -39,10 +39,12 @@ import java.util.TimerTask;
  *     revise:
  * </pre>
  */
-public abstract class AbsVideoPlayerController extends FrameLayout implements View.OnTouchListener {
+public abstract class AbsVideoPlayerController extends VideoControllerView implements
+        View.OnTouchListener, InterVideoController {
 
     private Context mContext;
-    protected InterVideoPlayer mVideoPlayer;
+    protected VideoPlayer mVideoPlayer;
+    //protected InterPropertyVideoPlayer mVideoPlayer;
     private Timer mUpdateProgressTimer;
     private TimerTask mUpdateProgressTimerTask;
     private Timer mUpdateNetSpeedTimer;
@@ -74,113 +76,13 @@ public abstract class AbsVideoPlayerController extends FrameLayout implements Vi
         this.setOnTouchListener(this);
     }
 
-    public void setVideoPlayer(InterVideoPlayer videoPlayer) {
-        mVideoPlayer = videoPlayer;
-    }
-
-    /**
-     * 获取是否是锁屏模式
-     * @return                      true表示锁屏
-     */
-    public abstract boolean getLock();
-
-    /**
-     * 设置是否显示视频头部的下载,分享布局控件
-     * @param isVisibility          是否可见
-     */
-    public abstract void setTopVisibility(boolean isVisibility);
-
-    /**
-     * 设置top到顶部的距离
-     * @param top                   top距离
-     */
-    public abstract void setTopPadding(float top);
-
-    /**
-     * 设置横屏播放时,tv和audio图标是否显示
-     * @param isVisibility1                 tv图标是否显示
-     * @param isVisibility2                 audio图标是否显示
-     */
-    public abstract void setTvAndAudioVisibility(boolean isVisibility1 , boolean isVisibility2);
-
-    /**
-     * 设置不操作后,多久自动隐藏头部和底部布局
-     * @param time                  时间
-     */
-    public abstract void setHideTime(long time);
-
-
-    /**
-     * 设置加载loading类型
-     *
-     * @param type 加载loading的类型
-     *             目前1,是仿腾讯加载loading
-     *             2,是转圈加载loading
-     */
-    public abstract void setLoadingType(@ConstantKeys.LoadingType int type);
-
-    /**
-     * 设置播放的视频的标题
-     *
-     * @param title 视频标题
-     */
-    public abstract void setTitle(String title);
-
-    /**
-     * 视频底图
-     *
-     * @param resId 视频底图资源
-     */
-    public abstract void setImage(@DrawableRes int resId);
-
-    /**
-     * 视频底图ImageView控件,提供给外部用图片加载工具来加载网络图片
-     *
-     * @return 底图ImageView
-     */
-    public abstract ImageView imageView();
-
-    /**
-     * 设置总时长
-     */
-    public abstract void setLength(long length);
-
-    /**
-     * 设置总时长
-     */
-    public abstract void setLength(String length);
-
-    /**
-     * 当播放器的播放状态发生变化,在此方法中国你更新不同的播放状态的UI
-     *
-     * @param playState 播放状态:
-     */
-    public abstract void onPlayStateChanged(int playState);
-
-    /**
-     * 当播放器的播放模式发生变化,在此方法中更新不同模式下的控制器界面。
-     *
-     * @param playMode 播放器的模式:
-     */
-    public abstract void onPlayModeChanged(int playMode);
-
-    /**
-     * 重置控制器,将控制器恢复到初始状态。
-     */
-    public abstract void reset();
-
-    /**
-     * 控制器意外销毁,比如手动退出,意外崩溃等等
-     */
-    public abstract void destroy();
-
-
     /**
-     * 当电量发生变化的时候,在此方法中国你更新不同的电量状态的UI
-     *
-     * @param batterState 电量状态
+     * 设置VideoPlayer
+     * @param videoPlayer            VideoPlayer对象
      */
-    public abstract void onBatterStateChanged(int batterState);
+    public void setVideoPlayer(VideoPlayer videoPlayer) {
+        mVideoPlayer = videoPlayer;
+    }
 
     /**
      * 当正在缓冲或者播放准备中状态时,开启缓冲时更新网络加载速度
@@ -260,60 +162,6 @@ public abstract class AbsVideoPlayerController extends FrameLayout implements Vi
         }
     }
 
-    /**
-     * 更新进度,包括更新网络加载速度
-     */
-    protected abstract void updateNetSpeedProgress();
-
-    /**
-     * 更新进度,包括进度条进度,展示的当前播放位置时长,总时长等。
-     */
-    protected abstract void updateProgress();
-
-    /**
-     * 手势左右滑动改变播放位置时,显示控制器中间的播放位置变化视图,
-     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
-     *
-     * @param duration            视频总时长ms
-     * @param newPositionProgress 新的位置进度,取值0到100。
-     */
-    protected abstract void showChangePosition(long duration, int newPositionProgress);
-
-    /**
-     * 手势左右滑动改变播放位置后,手势up或者cancel时,隐藏控制器中间的播放位置变化视图,
-     * 在手势ACTION_UP或ACTION_CANCEL时调用。
-     */
-    protected abstract void hideChangePosition();
-
-
-    /**
-     * 手势在右侧上下滑动改变音量时,显示控制器中间的音量变化视图,
-     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
-     *
-     * @param newVolumeProgress 新的音量进度,取值1到100。
-     */
-    protected abstract void showChangeVolume(int newVolumeProgress);
-
-    /**
-     * 手势在左侧上下滑动改变音量后,手势up或者cancel时,隐藏控制器中间的音量变化视图,
-     * 在手势ACTION_UP或ACTION_CANCEL时调用。
-     */
-    protected abstract void hideChangeVolume();
-
-    /**
-     * 手势在左侧上下滑动改变亮度时,显示控制器中间的亮度变化视图,
-     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
-     *
-     * @param newBrightnessProgress 新的亮度进度,取值1到100。
-     */
-    protected abstract void showChangeBrightness(int newBrightnessProgress);
-
-    /**
-     * 手势在左侧上下滑动改变亮度后,手势up或者cancel时,隐藏控制器中间的亮度变化视图,
-     * 在手势ACTION_UP或ACTION_CANCEL时调用。
-     */
-    protected abstract void hideChangeBrightness();
-
     /**
      * 滑动处理调节声音和亮度的逻辑
      * @param v                         v

+ 7 - 10
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/controller/VideoPlayerController.java

@@ -20,14 +20,10 @@ import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.BatteryManager;
 import android.os.Build;
 import android.os.CountDownTimer;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -37,18 +33,17 @@ import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.SeekBar;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import org.yczbj.ycvideoplayerlib.dialog.ChangeClarityDialog;
 import org.yczbj.ycvideoplayerlib.R;
 import org.yczbj.ycvideoplayerlib.dialog.VideoClarity;
 import org.yczbj.ycvideoplayerlib.inter.listener.OnPlayerTypeListener;
+import org.yczbj.ycvideoplayerlib.player.VideoPlayer;
 import org.yczbj.ycvideoplayerlib.receiver.BatterReceiver;
 import org.yczbj.ycvideoplayerlib.receiver.NetChangedReceiver;
 import org.yczbj.ycvideoplayerlib.utils.VideoLogUtil;
 import org.yczbj.ycvideoplayerlib.utils.VideoPlayerUtils;
 import org.yczbj.ycvideoplayerlib.constant.ConstantKeys;
-import org.yczbj.ycvideoplayerlib.inter.player.InterVideoPlayer;
 import org.yczbj.ycvideoplayerlib.inter.listener.OnClarityChangedListener;
 import org.yczbj.ycvideoplayerlib.inter.listener.OnCompletedListener;
 import org.yczbj.ycvideoplayerlib.inter.listener.OnPlayOrPauseListener;
@@ -546,7 +541,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
      * @param videoPlayer   播放器
      */
     @Override
-    public void setVideoPlayer(InterVideoPlayer videoPlayer) {
+    public void setVideoPlayer(VideoPlayer videoPlayer) {
         super.setVideoPlayer(videoPlayer);
         // 给播放器配置视频链接地址
         if (clarities != null && clarities.size() > 1 && clarities.size()>defaultClarityIndex) {
@@ -643,7 +638,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
      */
     @SuppressLint("SetTextI18n")
     @Override
-    public void onPlayStateChanged(int playState) {
+    public void onPlayStateChanged(@ConstantKeys.CurrentState int playState) {
         switch (playState) {
             case ConstantKeys.CurrentState.STATE_IDLE:
                 break;
@@ -760,6 +755,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
      * 播放错误
      */
     private void stateError() {
+        mLoading.setVisibility(View.GONE);
         setTopBottomVisible(false);
         mError.setVisibility(View.VISIBLE);
         cancelUpdateProgressTimer();
@@ -778,6 +774,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
         cancelUpdateProgressTimer();
         cancelUpdateNetSpeedTimer();
         setTopBottomVisible(false);
+        mLoading.setVisibility(View.GONE);
         mImage.setVisibility(View.VISIBLE);
         mCompleted.setVisibility(View.VISIBLE);
         //设置播放完成的监听事件
@@ -794,7 +791,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
      * @param playMode 播放器的模式:
      */
     @Override
-    public void onPlayModeChanged(int playMode) {
+    public void onPlayModeChanged(@ConstantKeys.PlayMode int playMode) {
         switch (playMode) {
             //普通模式
             case ConstantKeys.PlayMode.MODE_NORMAL:
@@ -1029,7 +1026,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
     /**
      * 开始播放
      */
-    public void startVideo() {
+    private void startVideo() {
         //开始播放
         if (mVideoPlayer.isIdle()) {
             mVideoPlayer.start();

+ 114 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/inter/player/InterPropertyVideoPlayer.java

@@ -0,0 +1,114 @@
+/*
+Copyright 2017 yangchong211(github.com/yangchong211)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package org.yczbj.ycvideoplayerlib.inter.player;
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/21
+ *     desc  : VideoPlayer抽象接口
+ *     revise: 播放器基础属性获取和设置属性接口
+ * </pre>
+ */
+public interface InterPropertyVideoPlayer {
+
+    /**
+     * seek到制定的位置继续播放
+     *
+     * @param pos 播放位置
+     */
+    void seekTo(long pos);
+
+    /**
+     * 设置音量
+     *
+     * @param volume 音量值
+     */
+    void setVolume(int volume);
+
+    /**
+     * 设置播放速度,目前只有IjkPlayer有效果,原生MediaPlayer暂不支持
+     *
+     * @param speed 播放速度
+     */
+    void setSpeed(float speed);
+
+    /**
+     * 开始播放时,是否从上一次的位置继续播放
+     *
+     * @param continueFromLastPosition true 接着上次的位置继续播放,false从头开始播放
+     */
+    void continueFromLastPosition(boolean continueFromLastPosition);
+
+    /**
+     * 获取最大音量
+     *
+     * @return 最大音量值
+     */
+    int getMaxVolume();
+
+    /**
+     * 获取当前播放状态
+     *
+     * @return  播放状态
+     */
+    int getPlayType();
+
+    /**
+     * 获取当前音量
+     *
+     * @return 当前音量值
+     */
+    int getVolume();
+
+    /**
+     * 获取办法给总时长,毫秒
+     *
+     * @return 视频总时长ms
+     */
+    long getDuration();
+
+    /**
+     * 获取当前播放的位置,毫秒
+     *
+     * @return 当前播放位置,ms
+     */
+    long getCurrentPosition();
+
+    /**
+     * 获取视频缓冲百分比
+     *
+     * @return 缓冲白百分比
+     */
+    int getBufferPercentage();
+
+    /**
+     * 获取播放速度
+     *
+     * @param speed 播放速度
+     * @return      播放速度
+     */
+    float getSpeed(float speed);
+
+    /**
+     * 获取网络加载速度
+     *
+     * @return 网络加载速度
+     */
+    long getTcpSpeed();
+
+}

+ 92 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/inter/player/InterScreenVideoPlayer.java

@@ -0,0 +1,92 @@
+/*
+Copyright 2017 yangchong211(github.com/yangchong211)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package org.yczbj.ycvideoplayerlib.inter.player;
+
+import java.util.Map;
+
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/21
+ *     desc  : VideoPlayer抽象接口
+ *     revise: 负责播放模式切换和销毁逻辑的接口
+ * </pre>
+ */
+public interface InterScreenVideoPlayer {
+
+    /**------------------以下3个方法是播放器的模式----------------------------*/
+    /**
+     * 是否是全屏播放
+     */
+    boolean isFullScreen();
+    /**
+     * 是否是小窗口播放
+     */
+    boolean isTinyWindow();
+    /**
+     * 是否是正常播放
+     */
+    boolean isNormal();
+
+    /**------------------以下方法是切换播放器的模式----------------------------*/
+
+    /**
+     * 进入全屏模式
+     * 这个是横屏模式
+     */
+    void enterVerticalScreenScreen();
+
+    /**
+     * 进入全屏模式
+     */
+    void enterFullScreen();
+
+    /**
+     * 退出全屏模式
+     *
+     * @return true 退出
+     */
+    boolean exitFullScreen();
+
+    /**
+     * 进入小窗口模式
+     */
+    void enterTinyWindow();
+
+    /**
+     * 退出小窗口模式
+     *
+     * @return true 退出小窗口
+     */
+    boolean exitTinyWindow();
+
+    /**------------------以下方法是销毁视频播放器资源----------------------------*/
+
+    /**
+     * 此处只释放播放器(如果要释放播放器并恢复控制器状态需要调用{@link #release()}方法)
+     * 不管是全屏、小窗口还是Normal状态下控制器的UI都不恢复初始状态
+     * 这样以便在当前播放器状态下可以方便的切换不同的清晰度的视频地址
+     */
+    void releasePlayer();
+
+    /**
+     * 释放INiceVideoPlayer,释放后,内部的播放器被释放掉,同时如果在全屏、小窗口模式下都会退出
+     * 并且控制器的UI也应该恢复到最初始的状态.
+     */
+    void release();
+}

+ 73 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/inter/player/InterStateVideoPlayer.java

@@ -0,0 +1,73 @@
+/*
+Copyright 2017 yangchong211(github.com/yangchong211)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package org.yczbj.ycvideoplayerlib.inter.player;
+
+import java.util.Map;
+
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/21
+ *     desc  : VideoPlayer抽象接口
+ *     revise: 控制播放状态和获取播放状态的接口
+ * </pre>
+ */
+public interface InterStateVideoPlayer {
+
+    /**
+     * 设置视频Url,以及headers
+     *
+     * @param url           视频地址,可以是本地,也可以是网络视频
+     * @param headers       请求header.
+     */
+    void setUp(String url, Map<String, String> headers);
+
+    /**
+     * 开始播放
+     */
+    void start();
+
+    /**
+     * 从指定的位置开始播放
+     *
+     * @param position      播放位置
+     */
+    void start(long position);
+
+    /**
+     * 重新播放,播放器被暂停、播放错误、播放完成后,需要调用此方法重新播放
+     */
+    void restart();
+
+    /**
+     * 暂停播放
+     */
+    void pause();
+
+    /**------------------以下9个方法是播放器在当前的播放状态----------------------------*/
+    boolean isIdle();
+    boolean isPreparing();
+    boolean isPrepared();
+    boolean isBufferingPlaying();
+    boolean isBufferingPaused();
+    boolean isPlaying();
+    boolean isPaused();
+    boolean isError();
+    boolean isCompleted();
+
+}

+ 114 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/inter/player/InterVideoController.java

@@ -0,0 +1,114 @@
+package org.yczbj.ycvideoplayerlib.inter.player;
+
+import android.support.annotation.DrawableRes;
+import android.widget.ImageView;
+
+import org.yczbj.ycvideoplayerlib.constant.ConstantKeys;
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/21
+ *     desc  : 视频控制器接口
+ *     revise: 定义一些设置视图属性接口
+ * </pre>
+ */
+public interface InterVideoController {
+
+
+    /**
+     * 设置top到顶部的距离
+     * @param top                   top距离
+     */
+    void setTopPadding(float top);
+
+    /**
+     * 设置横屏播放时,tv和audio图标是否显示
+     * @param isVisibility1                 tv图标是否显示
+     * @param isVisibility2                 audio图标是否显示
+     */
+    void setTvAndAudioVisibility(boolean isVisibility1 , boolean isVisibility2);
+
+    /**
+     * 视频底图
+     *
+     * @param resId 视频底图资源
+     */
+    void setImage(@DrawableRes int resId);
+
+    /**
+     * 设置总时长
+     */
+    void setLength(long length);
+
+    /**
+     * 设置总时长
+     */
+    void setLength(String length);
+
+    /**
+     * 视频底图ImageView控件,提供给外部用图片加载工具来加载网络图片
+     *
+     * @return 底图ImageView
+     */
+    ImageView imageView();
+
+    /**
+     * 获取是否是锁屏模式
+     * @return                      true表示锁屏
+     */
+    boolean getLock();
+
+    /**
+     * 设置是否显示视频头部的下载,分享布局控件
+     * @param isVisibility          是否可见
+     */
+    void setTopVisibility(boolean isVisibility);
+
+    /**
+     * 设置不操作后,多久自动隐藏头部和底部布局
+     * @param time                  时间
+     */
+    void setHideTime(long time);
+
+    /**
+     * 设置加载loading类型
+     *
+     * @param type 加载loading的类型
+     *             目前1,是仿腾讯加载loading
+     *             2,是转圈加载loading
+     */
+    void setLoadingType(@ConstantKeys.LoadingType int type);
+
+    /**
+     * 设置播放的视频的标题
+     *
+     * @param title 视频标题
+     */
+    void setTitle(String title);
+
+    /**
+     * 当播放器的播放状态发生变化,在此方法中国你更新不同的播放状态的UI
+     *
+     * @param playState 播放状态:
+     */
+    void onPlayStateChanged(@ConstantKeys.CurrentState int playState);
+
+    /**
+     * 当播放器的播放模式发生变化,在此方法中更新不同模式下的控制器界面。
+     *
+     * @param playMode 播放器的模式:
+     */
+    void onPlayModeChanged(@ConstantKeys.PlayMode int playMode);
+
+    /**
+     * 重置控制器,将控制器恢复到初始状态。
+     */
+    void reset();
+
+    /**
+     * 控制器意外销毁,比如手动退出,意外崩溃等等
+     */
+    void destroy();
+}

+ 0 - 215
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/inter/player/InterVideoPlayer.java

@@ -1,215 +0,0 @@
-/*
-Copyright 2017 yangchong211(github.com/yangchong211)
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-package org.yczbj.ycvideoplayerlib.inter.player;
-
-import java.util.Map;
-
-
-/**
- * <pre>
- *     @author yangchong
- *     blog  : https://github.com/yangchong211
- *     time  : 2017/11/21
- *     desc  : VideoPlayer抽象接口
- *     revise:
- * </pre>
- */
-public interface InterVideoPlayer {
-
-    /**
-     * 设置视频Url,以及headers
-     *
-     * @param url           视频地址,可以是本地,也可以是网络视频
-     * @param headers       请求header.
-     */
-    void setUp(String url, Map<String, String> headers);
-
-    /**
-     * 开始播放
-     */
-    void start();
-
-    /**
-     * 从指定的位置开始播放
-     *
-     * @param position      播放位置
-     */
-    void start(long position);
-
-    /**
-     * 重新播放,播放器被暂停、播放错误、播放完成后,需要调用此方法重新播放
-     */
-    void restart();
-
-    /**
-     * 暂停播放
-     */
-    void pause();
-
-    /**
-     * seek到制定的位置继续播放
-     *
-     * @param pos 播放位置
-     */
-    void seekTo(long pos);
-
-    /**
-     * 设置音量
-     *
-     * @param volume 音量值
-     */
-    void setVolume(int volume);
-
-    /**
-     * 设置播放速度,目前只有IjkPlayer有效果,原生MediaPlayer暂不支持
-     *
-     * @param speed 播放速度
-     */
-    void setSpeed(float speed);
-
-    /**
-     * 开始播放时,是否从上一次的位置继续播放
-     *
-     * @param continueFromLastPosition true 接着上次的位置继续播放,false从头开始播放
-     */
-    void continueFromLastPosition(boolean continueFromLastPosition);
-
-
-    /**------------------以下9个方法是播放器在当前的播放状态----------------------------*/
-    boolean isIdle();
-    boolean isPreparing();
-    boolean isPrepared();
-    boolean isBufferingPlaying();
-    boolean isBufferingPaused();
-    boolean isPlaying();
-    boolean isPaused();
-    boolean isError();
-    boolean isCompleted();
-
-    /**------------------以下3个方法是播放器的模式----------------------------*/
-
-    /**
-     * 是否是全屏播放
-     */
-    boolean isFullScreen();
-    /**
-     * 是否是小窗口播放
-     */
-    boolean isTinyWindow();
-    /**
-     * 是否是正常播放
-     */
-    boolean isNormal();
-
-    /**
-     * 获取最大音量
-     *
-     * @return 最大音量值
-     */
-    int getMaxVolume();
-
-    /**
-     * 获取当前播放状态
-     *
-     * @return  播放状态
-     */
-    int getPlayType();
-
-    /**
-     * 获取当前音量
-     *
-     * @return 当前音量值
-     */
-    int getVolume();
-
-    /**
-     * 获取办法给总时长,毫秒
-     *
-     * @return 视频总时长ms
-     */
-    long getDuration();
-
-    /**
-     * 获取当前播放的位置,毫秒
-     *
-     * @return 当前播放位置,ms
-     */
-    long getCurrentPosition();
-
-    /**
-     * 获取视频缓冲百分比
-     *
-     * @return 缓冲白百分比
-     */
-    int getBufferPercentage();
-
-    /**
-     * 获取播放速度
-     *
-     * @param speed 播放速度
-     * @return      播放速度
-     */
-    float getSpeed(float speed);
-
-    /**
-     * 获取网络加载速度
-     *
-     * @return 网络加载速度
-     */
-    long getTcpSpeed();
-    /**
-     * 进入全屏模式
-     * 这个是横屏模式
-     */
-    void enterVerticalScreenScreen();
-
-    /**
-     * 进入全屏模式
-     */
-    void enterFullScreen();
-
-    /**
-     * 退出全屏模式
-     *
-     * @return true 退出
-     */
-    boolean exitFullScreen();
-
-    /**
-     * 进入小窗口模式
-     */
-    void enterTinyWindow();
-
-    /**
-     * 退出小窗口模式
-     *
-     * @return true 退出小窗口
-     */
-    boolean exitTinyWindow();
-
-    /**
-     * 此处只释放播放器(如果要释放播放器并恢复控制器状态需要调用{@link #release()}方法)
-     * 不管是全屏、小窗口还是Normal状态下控制器的UI都不恢复初始状态
-     * 这样以便在当前播放器状态下可以方便的切换不同的清晰度的视频地址
-     */
-    void releasePlayer();
-
-    /**
-     * 释放INiceVideoPlayer,释放后,内部的播放器被释放掉,同时如果在全屏、小窗口模式下都会退出
-     * 并且控制器的UI也应该恢复到最初始的状态.
-     */
-    void release();
-}

+ 82 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/inter/player/VideoControllerView.java

@@ -0,0 +1,82 @@
+package org.yczbj.ycvideoplayerlib.inter.player;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.widget.FrameLayout;
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/21
+ *     desc  : 视频控制器抽象视图
+ *     revise: 定义一些滑动改变属性的抽象方法
+ * </pre>
+ */
+public abstract class VideoControllerView extends FrameLayout {
+
+    public VideoControllerView(@NonNull Context context) {
+        super(context);
+    }
+
+    /**
+     * 更新进度,包括更新网络加载速度
+     */
+    protected abstract void updateNetSpeedProgress();
+
+    /**
+     * 更新进度,包括进度条进度,展示的当前播放位置时长,总时长等。
+     */
+    protected abstract void updateProgress();
+
+    /**
+     * 手势左右滑动改变播放位置时,显示控制器中间的播放位置变化视图,
+     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
+     *
+     * @param duration            视频总时长ms
+     * @param newPositionProgress 新的位置进度,取值0到100。
+     */
+    protected abstract void showChangePosition(long duration, int newPositionProgress);
+
+    /**
+     * 手势左右滑动改变播放位置后,手势up或者cancel时,隐藏控制器中间的播放位置变化视图,
+     * 在手势ACTION_UP或ACTION_CANCEL时调用。
+     */
+    protected abstract void hideChangePosition();
+
+    /**
+     * 手势在右侧上下滑动改变音量时,显示控制器中间的音量变化视图,
+     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
+     *
+     * @param newVolumeProgress 新的音量进度,取值1到100。
+     */
+    protected abstract void showChangeVolume(int newVolumeProgress);
+
+    /**
+     * 手势在左侧上下滑动改变音量后,手势up或者cancel时,隐藏控制器中间的音量变化视图,
+     * 在手势ACTION_UP或ACTION_CANCEL时调用。
+     */
+    protected abstract void hideChangeVolume();
+
+    /**
+     * 手势在左侧上下滑动改变亮度时,显示控制器中间的亮度变化视图,
+     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
+     *
+     * @param newBrightnessProgress 新的亮度进度,取值1到100。
+     */
+    protected abstract void showChangeBrightness(int newBrightnessProgress);
+
+    /**
+     * 手势在左侧上下滑动改变亮度后,手势up或者cancel时,隐藏控制器中间的亮度变化视图,
+     * 在手势ACTION_UP或ACTION_CANCEL时调用。
+     */
+    protected abstract void hideChangeBrightness();
+
+    /**
+     * 当电量发生变化的时候,在此方法中国你更新不同的电量状态的UI
+     *
+     * @param batterState 电量状态
+     */
+    public abstract void onBatterStateChanged(int batterState);
+
+}

+ 463 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/player/VideoMediaPlayer.java

@@ -0,0 +1,463 @@
+package org.yczbj.ycvideoplayerlib.player;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.view.Surface;
+import android.widget.Toast;
+
+import org.yczbj.ycvideoplayerlib.constant.ConstantKeys;
+import org.yczbj.ycvideoplayerlib.inter.listener.OnTextureListener;
+import org.yczbj.ycvideoplayerlib.utils.VideoLogUtil;
+import org.yczbj.ycvideoplayerlib.utils.VideoPlayerUtils;
+import org.yczbj.ycvideoplayerlib.view.BaseToast;
+import org.yczbj.ycvideoplayerlib.view.VideoTextureView;
+
+import java.io.IOException;
+
+import tv.danmaku.ijk.media.player.AndroidMediaPlayer;
+import tv.danmaku.ijk.media.player.IMediaPlayer;
+import tv.danmaku.ijk.media.player.IjkMediaPlayer;
+import tv.danmaku.ijk.media.player.IjkTimedText;
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/11/21
+ *     desc  : MediaPlayer帮助累
+ *     revise: 主要处理音视频player初始化操作
+ * </pre>
+ */
+public class VideoMediaPlayer {
+
+    private VideoPlayer videoPlayer;
+    private IMediaPlayer mMediaPlayer;
+    private AudioManager mAudioManager;
+    private Surface mSurface;
+    private VideoTextureView mTextureView;
+    private SurfaceTexture mSurfaceTexture;
+
+    public VideoMediaPlayer(VideoPlayer videoPlayer) {
+        this.videoPlayer = videoPlayer;
+    }
+
+    /**
+     * 避免直接初始化
+     */
+    private VideoMediaPlayer(){}
+
+    /**
+     * 初始化音频管理器
+     */
+    @RequiresApi(api = Build.VERSION_CODES.FROYO)
+    public AudioManager initAudioManager() {
+        if (mAudioManager == null) {
+            mAudioManager  = (AudioManager) videoPlayer.getContext().getSystemService(Context.AUDIO_SERVICE);
+            mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
+                    AudioManager.AUDIOFOCUS_GAIN);
+        }
+        return mAudioManager;
+    }
+
+    public IMediaPlayer getMediaPlayer() {
+        initMediaPlayer();
+        return mMediaPlayer;
+    }
+
+    public void setMediaPlayerNull(){
+        if (mMediaPlayer!=null){
+            mMediaPlayer = null;
+        }
+    }
+
+    public AudioManager getAudioManager() {
+        initAudioManager();
+        return mAudioManager;
+    }
+
+    public void setAudioManagerNull(){
+        if (mAudioManager!=null){
+            //放弃音频焦点。使以前的焦点所有者(如果有的话)接收焦点。
+            mAudioManager.abandonAudioFocus(null);
+            //置空
+            mAudioManager = null;
+        }
+    }
+
+    public Surface getSurface() {
+        return mSurface;
+    }
+
+    /**
+     *
+     */
+    public void releaseSurface(){
+        if (mSurface != null) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                mSurface.release();
+            }
+            mSurface = null;
+        }
+    }
+
+    public VideoTextureView getTextureView() {
+        return mTextureView;
+    }
+
+    /**
+     * 如果SurfaceTexture不为null,则释放
+     */
+    public void releaseSurfaceTexture(){
+        if (mSurfaceTexture != null) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                mSurfaceTexture.release();
+            }
+            mSurfaceTexture = null;
+        }
+    }
+
+    /**
+     * 初始化视频管理器
+     */
+    public void initMediaPlayer() {
+        if (mMediaPlayer == null) {
+            switch (videoPlayer.mPlayerType) {
+                //AndroidMediaPlayer和IjkMediaPlayer都是实现AbstractMediaPlayer
+                //MediaPlayer
+                case ConstantKeys.IjkPlayerType.TYPE_NATIVE:
+                    mMediaPlayer = new AndroidMediaPlayer();
+                    break;
+                //IjkMediaPlayer    基于Ijk
+                case ConstantKeys.IjkPlayerType.TYPE_IJK:
+                default:
+                    createIjkMediaPlayer();
+                    break;
+            }
+            //设置音频流类型
+            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+        }
+    }
+
+    /**
+     * 打开MediaPlayer播放器
+     */
+    private void createIjkMediaPlayer() {
+        //创建IjkMediaPlayer对象
+        mMediaPlayer = new IjkMediaPlayer();
+        int player = IjkMediaPlayer.OPT_CATEGORY_PLAYER;
+        int codec = IjkMediaPlayer.OPT_CATEGORY_CODEC;
+        int format = IjkMediaPlayer.OPT_CATEGORY_FORMAT;
+
+        //设置ijkPlayer播放器的硬件解码相关参数
+        //设置播放前的最大探测时间
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "analyzemaxduration", 100L);
+        //设置播放前的探测时间 1,达到首屏秒开效果
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "analyzeduration", 1L);
+        //播放前的探测Size,默认是1M, 改小一点会出画面更快
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "probesize", 10240L);
+        //设置是否开启变调isModifyTone?0:1
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player,"soundtouch",0);
+        //每处理一个packet之后刷新io上下文
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "flush_packets", 1L);
+        //是否开启预缓冲,一般直播项目会开启,达到秒开的效果,不过带来了播放丢帧卡顿的体验
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "packet-buffering", 0L);
+        //播放重连次数
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "reconnect", 5);
+        //最大缓冲大小,单位kb
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "max-buffer-size", 10240L);
+        //跳帧处理,放CPU处理较慢时,进行跳帧处理,保证播放流程,画面和声音同步
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "framedrop", 1L);
+        //最大fps
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "max-fps", 30L);
+        //SeekTo设置优化
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "enable-accurate-seek", 1L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "opensles", 0);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "overlay-format",
+                IjkMediaPlayer.SDL_FCC_RV32);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "framedrop", 1);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "start-on-prepared", 0);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "http-detect-range-support", 0);
+        //设置是否开启环路过滤: 0开启,画面质量高,解码开销大,48关闭,画面质量差点,解码开销小
+        ((IjkMediaPlayer)mMediaPlayer).setOption(codec, "skip_loop_filter", 48);
+
+        //jkPlayer支持硬解码和软解码。
+        //软解码时不会旋转视频角度这时需要你通过onInfo的what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED去获取角度,自己旋转画面。
+        //或者开启硬解硬解码,不过硬解码容易造成黑屏无声(硬件兼容问题),下面是设置硬解码相关的代码
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec", 0);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec-auto-rotate", 1);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec-handle-resolution-change", 1);
+    }
+
+
+    /**
+     * 打开MediaPlayer播放器
+     */
+    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+    public void openMediaPlayer() {
+        // 屏幕常亮,这个很重要,如果不设置,则看视频一会儿,屏幕会变暗
+        videoPlayer.getContainer().setKeepScreenOn(true);
+        // 设置监听,可以查看ijk中的IMediaPlayer源码监听事件
+        // 设置准备视频播放监听事件
+        mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
+        // 设置视频播放完成监听事件
+        mMediaPlayer.setOnCompletionListener(mOnCompletionListener);
+        // 设置视频缓冲更新监听事件
+        mMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
+        // 设置视频seek完成监听事件
+        mMediaPlayer.setOnSeekCompleteListener(mOnSeekCompleteListener);
+        // 设置视频大小更改监听器
+        mMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
+        // 设置视频错误监听器
+        mMediaPlayer.setOnErrorListener(mOnErrorListener);
+        // 设置视频信息监听器
+        mMediaPlayer.setOnInfoListener(mOnInfoListener);
+        // 设置时间文本监听器
+        mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);
+        // 设置dataSource
+        if(videoPlayer.getUrl()==null || videoPlayer.getUrl().length()==0){
+            BaseToast.showRoundRectToast("视频链接不能为空");
+            return;
+        }
+        Uri path = Uri.parse(videoPlayer.getUrl());
+        try {
+            mMediaPlayer.setDataSource(videoPlayer.getContext().getApplicationContext(), path, videoPlayer.getHeaders());
+            if (mSurface == null) {
+                mSurface = new Surface(mSurfaceTexture);
+            }
+            // 设置surface
+            mMediaPlayer.setSurface(mSurface);
+            // 设置播放时常亮
+            mMediaPlayer.setScreenOnWhilePlaying(true);
+            // 开始加载
+            mMediaPlayer.prepareAsync();
+            // 播放准备中
+            videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_PREPARING);
+            // 控制器,更新不同的播放状态的UI
+            videoPlayer.getController().onPlayStateChanged(videoPlayer.getCurrentState());
+            VideoLogUtil.d("STATE_PREPARING");
+        } catch (IOException e) {
+            e.printStackTrace();
+            VideoLogUtil.e("打开播放器发生错误", e);
+        }
+    }
+
+
+    /**
+     * 初始化TextureView
+     * 这个主要是用作视频的
+     */
+    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+    public void initTextureView() {
+        if (mTextureView == null) {
+            mTextureView = new VideoTextureView(videoPlayer.getContext());
+            mTextureView.setOnTextureListener(new OnTextureListener() {
+                @Override
+                public void onSurfaceAvailable(SurfaceTexture surface) {
+                    if (mSurfaceTexture == null) {
+                        mSurfaceTexture = surface;
+                        openMediaPlayer();
+                    } else {
+                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                            mTextureView.setSurfaceTexture(mSurfaceTexture);
+                        }
+                    }
+                }
+
+                @Override
+                public void onSurfaceSizeChanged(SurfaceTexture surface, int width, int height) {
+                    VideoLogUtil.i("OnTextureListener----"+"onSurfaceSizeChanged");
+                }
+
+                @Override
+                public boolean onSurfaceDestroyed(SurfaceTexture surface) {
+                    VideoLogUtil.i("OnTextureListener----"+"onSurfaceDestroyed");
+                    return mSurfaceTexture == null;
+                }
+
+                @Override
+                public void onSurfaceUpdated(SurfaceTexture surface) {
+                    VideoLogUtil.i("OnTextureListener----"+"onSurfaceUpdated");
+                }
+            });
+        }
+        mTextureView.addTextureView(videoPlayer.getContainer(),mTextureView);
+    }
+
+
+
+    /**
+     * 设置视频播放完成监听事件
+     */
+    private IMediaPlayer.OnCompletionListener mOnCompletionListener =
+            new IMediaPlayer.OnCompletionListener() {
+                @Override
+                public void onCompletion(IMediaPlayer mp) {
+                    videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_COMPLETED);
+                    videoPlayer.getController().onPlayStateChanged(videoPlayer.getCurrentState());
+                    VideoLogUtil.d("listener---------onCompletion ——> STATE_COMPLETED");
+                    // 清除屏幕常亮
+                    videoPlayer.getContainer().setKeepScreenOn(false);
+                }
+            };
+
+
+    /**
+     * 设置准备视频播放监听事件
+     */
+    private IMediaPlayer.OnPreparedListener mOnPreparedListener = new IMediaPlayer.OnPreparedListener() {
+        @Override
+        public void onPrepared(IMediaPlayer mp) {
+            videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_PREPARED);
+            videoPlayer.getController().onPlayStateChanged(videoPlayer.getCurrentState());
+            VideoLogUtil.d("listener---------onPrepared ——> STATE_PREPARED");
+            mp.start();
+            // 从上次的保存位置播放
+            if (videoPlayer.getContinueFromLastPosition()) {
+                long savedPlayPosition = VideoPlayerUtils.getSavedPlayPosition(
+                        videoPlayer.getContext(), videoPlayer.getUrl());
+                mp.seekTo(savedPlayPosition);
+            }
+            // 跳到指定位置播放
+            if (videoPlayer.getSkipToPosition() != 0) {
+                mp.seekTo(videoPlayer.getSkipToPosition());
+            }
+        }
+    };
+
+
+    /**
+     * 设置视频缓冲更新监听事件
+     */
+    private IMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener =
+            new IMediaPlayer.OnBufferingUpdateListener() {
+                final int MAX_PERCENT = 97;
+                @Override
+                public void onBufferingUpdate(IMediaPlayer mp, int percent) {
+                    videoPlayer.setBufferPercentage(percent);
+                    //播放完成后再次播放getBufferPercentage获取的值也不准确,94、95,达不到100
+                    if (percent>MAX_PERCENT){
+                        videoPlayer.setBufferPercentage(100);
+                    }
+                    VideoLogUtil.d("listener---------onBufferingUpdate ——> " + percent);
+                }
+            };
+
+
+
+    /**
+     * 设置视频seek完成监听事件
+     */
+    private IMediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener =
+            new IMediaPlayer.OnSeekCompleteListener() {
+                @Override
+                public void onSeekComplete(IMediaPlayer iMediaPlayer) {
+
+                }
+            };
+
+
+
+    /**
+     * 设置视频大小更改监听器
+     */
+    private IMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener =
+            new IMediaPlayer.OnVideoSizeChangedListener() {
+                @Override
+                public void onVideoSizeChanged(IMediaPlayer mp, int width, int height,
+                                               int sar_num, int sar_den) {
+                    mTextureView.adaptVideoSize(width, height);
+                    VideoLogUtil.d("listener---------onVideoSizeChanged ——> width:" + width + ", height:" + height);
+                }
+            };
+
+    /**
+     * 设置视频错误监听器
+     * int MEDIA_INFO_VIDEO_RENDERING_START = 3;//视频准备渲染
+     * int MEDIA_INFO_BUFFERING_START = 701;//开始缓冲
+     * int MEDIA_INFO_BUFFERING_END = 702;//缓冲结束
+     * int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//视频选择信息
+     * int MEDIA_ERROR_SERVER_DIED = 100;//视频中断,一般是视频源异常或者不支持的视频类型。
+     * int MEDIA_ERROR_IJK_PLAYER = -10000,//一般是视频源有问题或者数据格式不支持,比如音频不是AAC之类的
+     * int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//数据错误没有有效的回收
+     */
+    private IMediaPlayer.OnErrorListener mOnErrorListener = new IMediaPlayer.OnErrorListener() {
+        @Override
+        public boolean onError(IMediaPlayer mp, int what, int extra) {
+            // 直播流播放时去调用mediaPlayer.getDuration会导致-38和-2147483648错误,忽略该错误
+            if (what != -38 && what != -2147483648 && extra != -38 && extra != -2147483648) {
+                videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_ERROR);
+                videoPlayer.getController().onPlayStateChanged(videoPlayer.getCurrentState());
+            }
+            VideoLogUtil.d("listener---------onError ——> STATE_ERROR ———— what:" + what + ", extra: " + extra);
+            return true;
+        }
+    };
+
+
+
+    /**
+     * 设置视频信息监听器
+     */
+    private IMediaPlayer.OnInfoListener mOnInfoListener = new IMediaPlayer.OnInfoListener() {
+        @Override
+        public boolean onInfo(IMediaPlayer mp, int what, int extra) {
+            if (what == IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
+                // 播放器开始渲染
+                videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_PLAYING);
+                videoPlayer.getController().onPlayStateChanged(videoPlayer.getCurrentState());
+                VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_VIDEO_RENDERING_START:STATE_PLAYING");
+            } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_START) {
+                // MediaPlayer暂时不播放,以缓冲更多的数据
+                if (videoPlayer.getCurrentState() == ConstantKeys.CurrentState.STATE_PAUSED ||
+                        videoPlayer.getCurrentState() == ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED) {
+                    videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED);
+                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PAUSED");
+                } else {
+                    videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING);
+                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PLAYING");
+                }
+                videoPlayer.getController().onPlayStateChanged(videoPlayer.getCurrentState());
+            } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
+                // 填充缓冲区后,MediaPlayer恢复播放/暂停
+                if (videoPlayer.getCurrentState() == ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING) {
+                    videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_PLAYING);
+                    videoPlayer.getController().onPlayStateChanged(videoPlayer.getCurrentState());
+                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PLAYING");
+                }
+                if (videoPlayer.getCurrentState() == ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED) {
+                    videoPlayer.setCurrentState(ConstantKeys.CurrentState.STATE_PAUSED);
+                    videoPlayer.getController().onPlayStateChanged(videoPlayer.getCurrentState());
+                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PAUSED");
+                }
+            } else if (what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED) {
+                // 视频旋转了extra度,需要恢复
+                if (mTextureView != null) {
+                    mTextureView.setRotation(extra);
+                    VideoLogUtil.d("listener---------视频旋转角度:" + extra);
+                }
+            } else if (what == IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
+                VideoLogUtil.d("listener---------视频不能seekTo,为直播视频");
+            } else {
+                VideoLogUtil.d("listener---------onInfo ——> what:" + what);
+            }
+            return true;
+        }
+    };
+
+
+    /**
+     * 设置时间文本监听器
+     */
+    private IMediaPlayer.OnTimedTextListener mOnTimedTextListener = new
+            IMediaPlayer.OnTimedTextListener() {
+                @Override
+                public void onTimedText(IMediaPlayer iMediaPlayer, IjkTimedText ijkTimedText) {
+
+                }
+            };
+
+}

+ 76 - 404
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/player/VideoPlayer.java

@@ -36,7 +36,9 @@ import android.widget.Toast;
 import org.yczbj.ycvideoplayerlib.constant.ConstantKeys;
 import org.yczbj.ycvideoplayerlib.controller.AbsVideoPlayerController;
 import org.yczbj.ycvideoplayerlib.inter.listener.OnTextureListener;
-import org.yczbj.ycvideoplayerlib.inter.player.InterVideoPlayer;
+import org.yczbj.ycvideoplayerlib.inter.player.InterScreenVideoPlayer;
+import org.yczbj.ycvideoplayerlib.inter.player.InterStateVideoPlayer;
+import org.yczbj.ycvideoplayerlib.inter.player.InterPropertyVideoPlayer;
 import org.yczbj.ycvideoplayerlib.manager.VideoPlayerManager;
 import org.yczbj.ycvideoplayerlib.utils.VideoLogUtil;
 import org.yczbj.ycvideoplayerlib.utils.VideoPlayerUtils;
@@ -61,15 +63,15 @@ import tv.danmaku.ijk.media.player.IjkTimedText;
  *             android:screenOrientation="portrait"
  * </pre>
  */
-public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
-
+public class VideoPlayer extends FrameLayout implements InterPropertyVideoPlayer,
+        InterScreenVideoPlayer ,InterStateVideoPlayer {
 
     /**
      * 播放类型
      * TYPE_IJK             基于IjkPlayer封装播放器
      * TYPE_NATIVE          基于原生自带的播放器控件
      **/
-    private int mPlayerType = ConstantKeys.IjkPlayerType.TYPE_IJK;
+    public int mPlayerType = ConstantKeys.IjkPlayerType.TYPE_IJK;
     /**
      * 播放状态,错误,开始播放,暂停播放,缓存中等等状态
      **/
@@ -82,13 +84,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
 
 
     private Context mContext;
-    private AudioManager mAudioManager;
-    private IMediaPlayer mMediaPlayer;
     private FrameLayout mContainer;
-    private VideoTextureView mTextureView;
     private AbsVideoPlayerController mController;
-    private SurfaceTexture mSurfaceTexture;
-    private Surface mSurface;
     private String mUrl;
     private Map<String, String> mHeaders;
     private int mBufferPercentage;
@@ -96,7 +93,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      * 是否从上一次位置播放,默认是false
      */
     private boolean continueFromLastPosition = false;
-    private long skipToPosition;
+    public long skipToPosition;
+    private VideoMediaPlayer videoMediaPlayer;
 
     public VideoPlayer(Context context) {
         this(context, null);
@@ -122,7 +120,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         mContainer.setBackgroundColor(Color.BLACK);
         LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT);
-
+        videoMediaPlayer = new VideoMediaPlayer(this);
         //将布局添加到该视图中
         this.addView(mContainer, params);
     }
@@ -191,8 +189,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         mController.reset();
         mController.setVideoPlayer(this);
         LayoutParams params = new LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT);
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
         mContainer.addView(mController, params);
     }
 
@@ -200,6 +197,18 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         return mController;
     }
 
+    public FrameLayout getContainer() {
+        return mContainer;
+    }
+
+    public String getUrl(){
+        return mUrl;
+    }
+
+    public Map<String, String> getHeaders(){
+        return mHeaders;
+    }
+
     /**
      * 设置播放器类型,必须设置
      * 注意:感谢某人建议,这里限定了传入值类型
@@ -223,6 +232,13 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         this.continueFromLastPosition = continueFromLastPosition;
     }
 
+    public boolean getContinueFromLastPosition(){
+        return continueFromLastPosition;
+    }
+
+    public long getSkipToPosition() {
+        return skipToPosition;
+    }
 
     /**
      * 注意:MediaPlayer没有这个方法
@@ -234,13 +250,13 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         if (speed<0){
             VideoLogUtil.d("设置参数-------设置的视频播放速度不能小于0");
         }
-        if (mMediaPlayer instanceof IjkMediaPlayer) {
-            ((IjkMediaPlayer) mMediaPlayer).setSpeed(speed);
-        } else if (mMediaPlayer instanceof AndroidMediaPlayer){
-            //((AndroidMediaPlayer) mMediaPlayer).setSpeed(speed);
+        if (videoMediaPlayer.getMediaPlayer() instanceof IjkMediaPlayer) {
+            ((IjkMediaPlayer) videoMediaPlayer.getMediaPlayer()).setSpeed(speed);
+        } else if (videoMediaPlayer.getMediaPlayer() instanceof AndroidMediaPlayer){
+            //((AndroidMediaPlayer) videoMediaPlayer.getMediaPlayer()).setSpeed(speed);
             VideoLogUtil.d("设置参数-------只有IjkPlayer才能设置播放速度");
-        }else if(mMediaPlayer instanceof MediaPlayer){
-            //((MediaPlayer) mMediaPlayer).setSpeed(speed);
+        }else if(videoMediaPlayer.getMediaPlayer() instanceof MediaPlayer){
+            //((MediaPlayer) videoMediaPlayer.getMediaPlayer()).setSpeed(speed);
             VideoLogUtil.d("设置参数-------只有IjkPlayer才能设置播放速度");
         } else {
             VideoLogUtil.d("设置参数-------只有IjkPlayer才能设置播放速度");
@@ -259,9 +275,9 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         }
         if (mCurrentState == ConstantKeys.CurrentState.STATE_IDLE) {
             VideoPlayerManager.instance().setCurrentVideoPlayer(this);
-            initAudioManager();
-            initMediaPlayer();
-            initTextureView();
+            videoMediaPlayer.initAudioManager();
+            videoMediaPlayer.initMediaPlayer();
+            videoMediaPlayer.initTextureView();
         } else {
             VideoLogUtil.d("播放状态--------VideoPlayer只有在mCurrentState == STATE_IDLE时才能调用start方法.");
         }
@@ -289,21 +305,21 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     public void restart() {
         if (mCurrentState == ConstantKeys.CurrentState.STATE_PAUSED) {
             //如果是暂停状态,那么则继续播放
-            mMediaPlayer.start();
+            videoMediaPlayer.getMediaPlayer().start();
             mCurrentState = ConstantKeys.CurrentState.STATE_PLAYING;
             mController.onPlayStateChanged(mCurrentState);
             VideoLogUtil.d("播放状态--------STATE_PLAYING");
         } else if (mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED) {
             //如果是缓存暂停状态,那么则继续播放
-            mMediaPlayer.start();
+            videoMediaPlayer.getMediaPlayer().start();
             mCurrentState = ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING;
             mController.onPlayStateChanged(mCurrentState);
             VideoLogUtil.d("播放状态--------STATE_BUFFERING_PLAYING");
         } else if (mCurrentState == ConstantKeys.CurrentState.STATE_COMPLETED
                 || mCurrentState == ConstantKeys.CurrentState.STATE_ERROR) {
             //如果是完成播放或者播放错误,则重新播放
-            mMediaPlayer.reset();
-            openMediaPlayer();
+            videoMediaPlayer.getMediaPlayer().reset();
+            videoMediaPlayer.openMediaPlayer();
             VideoLogUtil.d("播放状态--------完成播放或者播放错误,则重新播放");
         } else {
             VideoLogUtil.d("VideoPlayer在mCurrentState == " + mCurrentState + "时不能调用restart()方法.");
@@ -318,13 +334,13 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     public void pause() {
         if (mCurrentState == ConstantKeys.CurrentState.STATE_PLAYING) {
             //如果是播放状态,那么则暂停播放
-            mMediaPlayer.pause();
+            videoMediaPlayer.getMediaPlayer().pause();
             mCurrentState = ConstantKeys.CurrentState.STATE_PAUSED;
             mController.onPlayStateChanged(mCurrentState);
             VideoLogUtil.d("播放状态--------STATE_PAUSED");
         } else if (mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING) {
             //如果是正在缓冲状态,那么则暂停暂停缓冲
-            mMediaPlayer.pause();
+            videoMediaPlayer.getMediaPlayer().pause();
             mCurrentState = ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED;
             mController.onPlayStateChanged(mCurrentState);
             VideoLogUtil.d("播放状态--------STATE_BUFFERING_PAUSED");
@@ -341,8 +357,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         if (pos<0){
             VideoLogUtil.d("设置参数-------设置开始跳转播放位置不能小于0");
         }
-        if (mMediaPlayer != null) {
-            mMediaPlayer.seekTo(pos);
+        if (videoMediaPlayer.getMediaPlayer() != null) {
+            videoMediaPlayer.getMediaPlayer().seekTo(pos);
         }
     }
 
@@ -353,8 +369,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @Override
     public void setVolume(int volume) {
-        if (mAudioManager != null) {
-            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        if (videoMediaPlayer.getAudioManager() != null) {
+            videoMediaPlayer.getAudioManager().setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
         }
     }
 
@@ -485,8 +501,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @Override
     public int getMaxVolume() {
-        if (mAudioManager != null) {
-            return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        if (videoMediaPlayer.getAudioManager() != null) {
+            return videoMediaPlayer.getAudioManager().getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         }
         return 0;
     }
@@ -508,8 +524,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @Override
     public int getVolume() {
-        if (mAudioManager != null) {
-            return mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+        if (videoMediaPlayer.getAudioManager() != null) {
+            return videoMediaPlayer.getAudioManager().getStreamVolume(AudioManager.STREAM_MUSIC);
         }
         return 0;
     }
@@ -521,7 +537,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @Override
     public long getDuration() {
-        return mMediaPlayer != null ? mMediaPlayer.getDuration() : 0;
+        return videoMediaPlayer.getMediaPlayer() != null ? videoMediaPlayer.getMediaPlayer().getDuration() : 0;
     }
 
 
@@ -531,7 +547,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @Override
     public long getCurrentPosition() {
-        return mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : 0;
+        return videoMediaPlayer.getMediaPlayer() != null ? videoMediaPlayer.getMediaPlayer().getCurrentPosition() : 0;
     }
 
 
@@ -544,6 +560,13 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         return mBufferPercentage;
     }
 
+    /**
+     * 设置缓冲区百分比
+     * @param bufferPercentage
+     */
+    public void setBufferPercentage(int bufferPercentage) {
+        this.mBufferPercentage = bufferPercentage;
+    }
 
     /**
      * 获取播放速度
@@ -552,8 +575,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @Override
     public float getSpeed(float speed) {
-        if (mMediaPlayer instanceof IjkMediaPlayer) {
-            return ((IjkMediaPlayer) mMediaPlayer).getSpeed(speed);
+        if (videoMediaPlayer.getMediaPlayer() instanceof IjkMediaPlayer) {
+            return ((IjkMediaPlayer) videoMediaPlayer.getMediaPlayer()).getSpeed(speed);
         }
         return 0;
     }
@@ -565,8 +588,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @Override
     public long getTcpSpeed() {
-        if (mMediaPlayer instanceof IjkMediaPlayer) {
-            return ((IjkMediaPlayer) mMediaPlayer).getTcpSpeed();
+        if (videoMediaPlayer.getMediaPlayer() instanceof IjkMediaPlayer) {
+            return ((IjkMediaPlayer) videoMediaPlayer.getMediaPlayer()).getTcpSpeed();
         }
         return 0;
     }
@@ -580,347 +603,13 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     }
 
     /**
-     * 初始化音频管理器
-     */
-    @RequiresApi(api = Build.VERSION_CODES.FROYO)
-    private void initAudioManager() {
-        if (mAudioManager == null) {
-            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
-            if (mAudioManager != null) {
-                mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
-                        AudioManager.AUDIOFOCUS_GAIN);
-            }
-        }
-    }
-
-
-    /**
-     * 初始化视频管理器
+     * 设置当前播放模式
+     * @param state             当前播放模式
      */
-    private void initMediaPlayer() {
-        if (mMediaPlayer == null) {
-            switch (mPlayerType) {
-                //AndroidMediaPlayer和IjkMediaPlayer都是实现AbstractMediaPlayer
-                //MediaPlayer
-                case ConstantKeys.IjkPlayerType.TYPE_NATIVE:
-                    mMediaPlayer = new AndroidMediaPlayer();
-                    break;
-                //IjkMediaPlayer    基于Ijk
-                case ConstantKeys.IjkPlayerType.TYPE_IJK:
-                default:
-                    createIjkMediaPlayer();
-                    break;
-            }
-            //设置音频流类型
-            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
-        }
+    public void setCurrentState(@ConstantKeys.CurrentState int state){
+        mCurrentState = state;
     }
 
-    private void createIjkMediaPlayer() {
-        //创建IjkMediaPlayer对象
-        mMediaPlayer = new IjkMediaPlayer();
-        int player = IjkMediaPlayer.OPT_CATEGORY_PLAYER;
-        int codec = IjkMediaPlayer.OPT_CATEGORY_CODEC;
-        int format = IjkMediaPlayer.OPT_CATEGORY_FORMAT;
-
-        //设置ijkPlayer播放器的硬件解码相关参数
-        //设置播放前的最大探测时间
-        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "analyzemaxduration", 100L);
-        //设置播放前的探测时间 1,达到首屏秒开效果
-        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "analyzeduration", 1L);
-        //播放前的探测Size,默认是1M, 改小一点会出画面更快
-        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "probesize", 10240L);
-        //设置是否开启变调isModifyTone?0:1
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player,"soundtouch",0);
-        //每处理一个packet之后刷新io上下文
-        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "flush_packets", 1L);
-        //是否开启预缓冲,一般直播项目会开启,达到秒开的效果,不过带来了播放丢帧卡顿的体验
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "packet-buffering", 0L);
-        //播放重连次数
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "reconnect", 5);
-        //最大缓冲大小,单位kb
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "max-buffer-size", 10240L);
-        //跳帧处理,放CPU处理较慢时,进行跳帧处理,保证播放流程,画面和声音同步
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "framedrop", 1L);
-        //最大fps
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "max-fps", 30L);
-        //SeekTo设置优化
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "enable-accurate-seek", 1L);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "opensles", 0);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "overlay-format",
-                IjkMediaPlayer.SDL_FCC_RV32);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "framedrop", 1);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "start-on-prepared", 0);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "http-detect-range-support", 0);
-        //设置是否开启环路过滤: 0开启,画面质量高,解码开销大,48关闭,画面质量差点,解码开销小
-        ((IjkMediaPlayer)mMediaPlayer).setOption(codec, "skip_loop_filter", 48);
-
-        //jkPlayer支持硬解码和软解码。
-        //软解码时不会旋转视频角度这时需要你通过onInfo的what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED去获取角度,自己旋转画面。
-        //或者开启硬解硬解码,不过硬解码容易造成黑屏无声(硬件兼容问题),下面是设置硬解码相关的代码
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec", 0);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec-auto-rotate", 1);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec-handle-resolution-change", 1);
-    }
-
-
-    /**
-     * 初始化TextureView
-     * 这个主要是用作视频的
-     */
-    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
-    private void initTextureView() {
-        if (mTextureView == null) {
-            mTextureView = new VideoTextureView(mContext);
-            mTextureView.setOnTextureListener(new OnTextureListener() {
-                @Override
-                public void onSurfaceAvailable(SurfaceTexture surface) {
-                    if (mSurfaceTexture == null) {
-                        mSurfaceTexture = surface;
-                        openMediaPlayer();
-                    } else {
-                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-                            mTextureView.setSurfaceTexture(mSurfaceTexture);
-                        }
-                    }
-                }
-
-                @Override
-                public void onSurfaceSizeChanged(SurfaceTexture surface, int width, int height) {
-                    VideoLogUtil.i("OnTextureListener----"+"onSurfaceSizeChanged");
-                }
-
-                @Override
-                public boolean onSurfaceDestroyed(SurfaceTexture surface) {
-                    VideoLogUtil.i("OnTextureListener----"+"onSurfaceDestroyed");
-                    return mSurfaceTexture == null;
-                }
-
-                @Override
-                public void onSurfaceUpdated(SurfaceTexture surface) {
-                    VideoLogUtil.i("OnTextureListener----"+"onSurfaceUpdated");
-                }
-            });
-        }
-        mTextureView.addTextureView(mContainer,mTextureView);
-    }
-
-
-    /**
-     * 打开MediaPlayer播放器
-     */
-    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
-    private void openMediaPlayer() {
-        // 屏幕常亮,这个很重要,如果不设置,则看视频一会儿,屏幕会变暗
-        mContainer.setKeepScreenOn(true);
-        // 设置监听,可以查看ijk中的IMediaPlayer源码监听事件
-        // 设置准备视频播放监听事件
-        mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
-        // 设置视频播放完成监听事件
-        mMediaPlayer.setOnCompletionListener(mOnCompletionListener);
-        // 设置视频缓冲更新监听事件
-        mMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
-        // 设置视频seek完成监听事件
-        mMediaPlayer.setOnSeekCompleteListener(mOnSeekCompleteListener);
-        // 设置视频大小更改监听器
-        mMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
-        // 设置视频错误监听器
-        mMediaPlayer.setOnErrorListener(mOnErrorListener);
-        // 设置视频信息监听器
-        mMediaPlayer.setOnInfoListener(mOnInfoListener);
-        // 设置时间文本监听器
-        mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);
-        // 设置dataSource
-        if(mUrl==null || mUrl.length()==0){
-            Toast.makeText(mContext,"视频链接不能为空",Toast.LENGTH_SHORT).show();
-            return;
-        }
-        Uri path = Uri.parse(mUrl);
-        try {
-            mMediaPlayer.setDataSource(mContext.getApplicationContext(), path, mHeaders);
-            if (mSurface == null) {
-                mSurface = new Surface(mSurfaceTexture);
-            }
-            // 设置surface
-            mMediaPlayer.setSurface(mSurface);
-            // 设置播放时常亮
-            mMediaPlayer.setScreenOnWhilePlaying(true);
-            // 开始加载
-            mMediaPlayer.prepareAsync();
-            // 播放准备中
-            mCurrentState = ConstantKeys.CurrentState.STATE_PREPARING;
-            // 控制器,更新不同的播放状态的UI
-            mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("STATE_PREPARING");
-        } catch (IOException e) {
-            e.printStackTrace();
-            VideoLogUtil.e("打开播放器发生错误", e);
-        }
-    }
-
-    /**
-     * 设置准备视频播放监听事件
-     */
-    private IMediaPlayer.OnPreparedListener mOnPreparedListener = new IMediaPlayer.OnPreparedListener() {
-        @Override
-        public void onPrepared(IMediaPlayer mp) {
-            mCurrentState = ConstantKeys.CurrentState.STATE_PREPARED;
-            mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("listener---------onPrepared ——> STATE_PREPARED");
-            mp.start();
-            // 从上次的保存位置播放
-            if (continueFromLastPosition) {
-                long savedPlayPosition = VideoPlayerUtils.getSavedPlayPosition(mContext, mUrl);
-                mp.seekTo(savedPlayPosition);
-            }
-            // 跳到指定位置播放
-            if (skipToPosition != 0) {
-                mp.seekTo(skipToPosition);
-            }
-        }
-    };
-
-
-    /**
-     * 设置视频播放完成监听事件
-     */
-    private IMediaPlayer.OnCompletionListener mOnCompletionListener =
-            new IMediaPlayer.OnCompletionListener() {
-        @Override
-        public void onCompletion(IMediaPlayer mp) {
-            mCurrentState = ConstantKeys.CurrentState.STATE_COMPLETED;
-            mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("listener---------onCompletion ——> STATE_COMPLETED");
-            // 清除屏幕常亮
-            mContainer.setKeepScreenOn(false);
-        }
-    };
-
-    /**
-     * 设置视频缓冲更新监听事件
-     */
-    private IMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener =
-            new IMediaPlayer.OnBufferingUpdateListener() {
-        final int MAX_PERCENT = 97;
-        @Override
-        public void onBufferingUpdate(IMediaPlayer mp, int percent) {
-            mBufferPercentage = percent;
-            //播放完成后再次播放getBufferPercentage获取的值也不准确,94、95,达不到100
-            if (percent>MAX_PERCENT){
-                mBufferPercentage = 100;
-            }
-            VideoLogUtil.d("listener---------onBufferingUpdate ——> " + percent);
-        }
-    };
-
-    /**
-     * 设置视频seek完成监听事件
-     */
-    private IMediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener =
-            new IMediaPlayer.OnSeekCompleteListener() {
-        @Override
-        public void onSeekComplete(IMediaPlayer iMediaPlayer) {
-
-        }
-    };
-
-    /**
-     * 设置视频大小更改监听器
-     */
-    private IMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener =
-            new IMediaPlayer.OnVideoSizeChangedListener() {
-        @Override
-        public void onVideoSizeChanged(IMediaPlayer mp, int width, int height,
-                                       int sar_num, int sar_den) {
-            mTextureView.adaptVideoSize(width, height);
-            VideoLogUtil.d("listener---------onVideoSizeChanged ——> width:" + width + ", height:" + height);
-        }
-    };
-
-    /**
-     * 设置视频错误监听器
-     * int MEDIA_INFO_VIDEO_RENDERING_START = 3;//视频准备渲染
-     * int MEDIA_INFO_BUFFERING_START = 701;//开始缓冲
-     * int MEDIA_INFO_BUFFERING_END = 702;//缓冲结束
-     * int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//视频选择信息
-     * int MEDIA_ERROR_SERVER_DIED = 100;//视频中断,一般是视频源异常或者不支持的视频类型。
-     * int MEDIA_ERROR_IJK_PLAYER = -10000,//一般是视频源有问题或者数据格式不支持,比如音频不是AAC之类的
-     * int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//数据错误没有有效的回收
-     */
-    private IMediaPlayer.OnErrorListener mOnErrorListener = new IMediaPlayer.OnErrorListener() {
-        @Override
-        public boolean onError(IMediaPlayer mp, int what, int extra) {
-            // 直播流播放时去调用mediaPlayer.getDuration会导致-38和-2147483648错误,忽略该错误
-            if (what != -38 && what != -2147483648 && extra != -38 && extra != -2147483648) {
-                mCurrentState = ConstantKeys.CurrentState.STATE_ERROR;
-                mController.onPlayStateChanged(mCurrentState);
-            }
-            VideoLogUtil.d("listener---------onError ——> STATE_ERROR ———— what:" + what + ", extra: " + extra);
-            return true;
-        }
-    };
-
-    /**
-     * 设置视频信息监听器
-     */
-    private IMediaPlayer.OnInfoListener mOnInfoListener = new IMediaPlayer.OnInfoListener() {
-        @Override
-        public boolean onInfo(IMediaPlayer mp, int what, int extra) {
-            if (what == IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
-                // 播放器开始渲染
-                mCurrentState = ConstantKeys.CurrentState.STATE_PLAYING;
-                mController.onPlayStateChanged(mCurrentState);
-                VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_VIDEO_RENDERING_START:STATE_PLAYING");
-            } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_START) {
-                // MediaPlayer暂时不播放,以缓冲更多的数据
-                if (mCurrentState == ConstantKeys.CurrentState.STATE_PAUSED ||
-                        mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED) {
-                    mCurrentState = ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED;
-                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PAUSED");
-                } else {
-                    mCurrentState = ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING;
-                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PLAYING");
-                }
-                mController.onPlayStateChanged(mCurrentState);
-            } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
-                // 填充缓冲区后,MediaPlayer恢复播放/暂停
-                if (mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING) {
-                    mCurrentState = ConstantKeys.CurrentState.STATE_PLAYING;
-                    mController.onPlayStateChanged(mCurrentState);
-                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PLAYING");
-                }
-                if (mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED) {
-                    mCurrentState = ConstantKeys.CurrentState.STATE_PAUSED;
-                    mController.onPlayStateChanged(mCurrentState);
-                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PAUSED");
-                }
-            } else if (what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED) {
-                // 视频旋转了extra度,需要恢复
-                if (mTextureView != null) {
-                    mTextureView.setRotation(extra);
-                    VideoLogUtil.d("listener---------视频旋转角度:" + extra);
-                }
-            } else if (what == IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
-                VideoLogUtil.d("listener---------视频不能seekTo,为直播视频");
-            } else {
-                VideoLogUtil.d("listener---------onInfo ——> what:" + what);
-            }
-            return true;
-        }
-    };
-
-
-    /**
-     * 设置时间文本监听器
-     */
-    private IMediaPlayer.OnTimedTextListener mOnTimedTextListener = new
-            IMediaPlayer.OnTimedTextListener() {
-        @Override
-        public void onTimedText(IMediaPlayer iMediaPlayer, IjkTimedText ijkTimedText) {
-
-        }
-    };
-
 
     /**
      * 进入全屏模式
@@ -985,8 +674,6 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     }
 
 
-
-
     /**
      * 退出全屏模式
      * 退出全屏,移除mTextureView和mController,并添加到非全屏的容器中。
@@ -1111,34 +798,19 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @Override
     public void releasePlayer() {
-        if (mAudioManager != null) {
-            //放弃音频焦点。使以前的焦点所有者(如果有的话)接收焦点。
-            mAudioManager.abandonAudioFocus(null);
-            //置空
-            mAudioManager = null;
-        }
-        if (mMediaPlayer != null) {
+        videoMediaPlayer.setAudioManagerNull();
+        if (videoMediaPlayer.getMediaPlayer() != null) {
             //释放视频焦点
-            mMediaPlayer.release();
-            mMediaPlayer = null;
+            videoMediaPlayer.getMediaPlayer().release();
+            videoMediaPlayer.setMediaPlayerNull();
         }
         if (mContainer!=null){
             //从视图中移除TextureView
-            mContainer.removeView(mTextureView);
-        }
-        if (mSurface != null) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-                mSurface.release();
-            }
-            mSurface = null;
+            mContainer.removeView(videoMediaPlayer.getTextureView());
         }
+        videoMediaPlayer.releaseSurface();
         //如果SurfaceTexture不为null,则释放
-        if (mSurfaceTexture != null) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-                mSurfaceTexture.release();
-            }
-            mSurfaceTexture = null;
-        }
+        videoMediaPlayer.releaseSurfaceTexture();
         mCurrentState = ConstantKeys.CurrentState.STATE_IDLE;
     }
 

+ 1 - 0
app/src/main/java/org/yczbj/ycvideoplayer/TestFullActivity.java

@@ -76,6 +76,7 @@ public class TestFullActivity extends BaseActivity implements View.OnClickListen
         //设置中间播放按钮是否显示
         controller.setTopPadding(24.0f);
         controller.setTopVisibility(true);
+        controller.destroy();
         controller.setOnVideoControlListener(new OnVideoControlListener() {
             @Override
             public void onVideoControlClick(int type) {

+ 112 - 4
read/wiki5.md

@@ -3,10 +3,35 @@
 - 01.视频全屏播放崩溃
 - 02.视频播放解析异常
 - 03.视频
-
-
-
-#### 01.视频全屏播放崩溃
+- 10.如何实现视频的自动播放
+- 11.怎么获取网络视频的第一帧的截图
+- 14.拖动进度条后,加载中的转圈动画怎么才能显示出来
+- 15.怎样监听视频的播放进度和视频的播放状态
+- 16.滑动进度条的时候,如何显示当前开始时间
+- 17.如何监听视频播放自动判断横竖屏问题
+- 21.极少部分机型出现水平方向为充满的情况
+- 22.播几分钟后都会显示视频加载失败
+- 23.暂停播放的时候,没有释放音频焦点
+- 24.当视频在加载中,切换页面,后台仍会播放
+- 25.全屏播放按返回键退出全屏的判断
+- 26.如何取消每次进入的时候都会接着上次的继续播放
+- 28.mediaPlayer的setDataSource为什么要用反射的方式获取
+- 29.视频播放的AB循环怎么实现呢
+- 30.播放视频时添加headers或者cookie
+- 32.全屏播放完,重播的时候不能保持全屏播放
+- 33.TextureView会被销毁,导致视频有声音,没有图像
+- 34.倍速播放完成后重播应该继续之前的倍速
+- 36.关闭了硬件加速后,点击播放一直在加载状态转圈
+- 37.如何实现小窗口视频跟随手指在窗口移动
+- 41.recyclerView滑动到屏幕之外,视频无法停止播放
+- 44.列表滑动自动播放,条目滑出屏幕自动停止
+- 45.切换播放源,能否无感知的切换,只刷新播放的url
+- 46.SeekTo()方法定位到指定的毫秒数播放会跳帧的问题
+- 47.有的时候会出现视频影像不出现但是有声音的情况
+- 60.横屏播放视频,全屏后点击返回,Activity被修改为竖屏
+
+
+#### 01.视频切换到全屏播放崩溃,报错
 - 解决办法
     - android:configChanges 保证了在全屏的时候横竖屏切换不会执行Activity的相关生命周期,打断视频的播放
     - android:screenOrientation 固定了屏幕的初始方向
@@ -26,23 +51,106 @@
 
 
 
+#### 10.如何实现视频的自动播放
+
+
+#### 11.怎么获取网络视频的第一帧的截图
+
+
+#### 14.拖动进度条后,加载中的转圈动画怎么才能显示出来
+
+
+#### 15.怎样监听视频的播放进度和视频的播放状态
+
+#### 16.滑动进度条的时候,如何显示当前开始时间
+
+
+#### 17.如何监听视频播放自动判断横竖屏问题
+
+
+#### 21.极少部分机型出现水平方向为充满的情况
+- 复写onVideoSizeChanged函数,看返回的宽度是否是屏幕宽度
+- 出现原因:播放器设置的高度不够,导致视频按比例缩放时水平方向无法撑满,建议设置视频为16:9,避免黑边
+
+
+
+#### 22.播几分钟后都会显示视频加载失败
+- 问题描述
+    - 播几分钟后都会显示视频加载失败 是怎么回事呢 日志输出是 onError 1 - -1004 [216283790]
+    - 播放几分钟就显示视频加载失败,点击重新播放一直在那里转圈圈不会重新播放,除非退出当前界面重新进来才能正常播放。
+- 方案,有待验证
+可能是因为服务器没设置断点续传功能,在服务器端配置,尽量使用阿里云七牛等现成的视频点播服务。
+也可以在手机端配置,如果视频体积不大可以设置header,让服务器一口气把所有视频都传给你。
+header.put("Content-Type","video/mp4");
+header.put("Accept-Ranges","bytes");
+header.put("Status","206");
+header.put("Cache-control","no-cache");
+
+
+
+#### 23.暂停播放的时候,没有释放音频焦点
+- 暂停播放的时候,没有释放音频焦点,导致其他app因为获取不到音频焦点无法播放
+
+
+
+#### 24.当视频在加载中,切换页面,后台仍会播放
+
+
+
+#### 25.全屏播放按返回键退出全屏的判断
+
+
+
+#### 26.如何取消每次进入的时候都会接着上次的继续播放
+
+
+#### 28.mediaPlayer的setDataSource为什么要用反射的方式获取
+
+
+
+#### 29.视频播放的AB循环怎么实现呢
+
+
+#### 30.播放视频时添加headers或者cookie
+
+
+#### 32.全屏播放完,重播的时候不能保持全屏播放
+
+
+
+#### 33.TextureView会被销毁,导致视频有声音,没有图像
+- https://github.com/lipangit/JiaoZiVideoPlayer/issues/2208
+
 
 
+#### 34.倍速播放完成后重播应该继续之前的倍速
 
 
+#### 36.关闭了硬件加速后,点击播放一直在加载状态转圈
+- 硬件加速不能关闭,否则textureView不工作
 
 
+#### 41.recyclerView滑动到屏幕之外,视频无法停止播放
+- https://github.com/lipangit/JiaoZiVideoPlayer/issues/2130
 
 
+#### 44.列表滑动自动播放,条目滑出屏幕自动停止
 
 
 
+#### 45.切换播放源,能否无感知的切换,只刷新播放的url
+- https://github.com/lipangit/JiaoZiVideoPlayer/issues/1962
 
 
+#### 46.SeekTo()方法定位到指定的毫秒数播放会跳帧的问题
+- https://github.com/lipangit/JiaoZiVideoPlayer/issues/1906
 
 
+#### 47.有的时候会出现视频影像不出现但是有声音的情况
 
 
+#### 60.横屏播放视频,全屏后点击返回,Activity被修改为竖屏
+- https://github.com/lipangit/JiaoZiVideoPlayer/issues/1691