餃子播放器詳細說明記錄


1.上地址 https://github.com/lipangit/JiaoZiVideoPlayer

2.JiaoZiVideo主要特點

  • 可以完全自定義UI和任何功能
  • 可以完全自定義UI和任何功能
  • 一行代碼切換播放引擎,支持的視頻格式和協議取決於播放引擎,android.media.MediaPlayer ijkplayer
  • 完美檢測列表滑動
  • 可實現全屏播放,小窗播放
  • 能在ListView、ViewPager和ListView、ViewPager和Fragment等多重嵌套模式下全屏工作
  • 可以在加載、暫停、播放等各種狀態中正常進入全屏和退出全屏
  • 多種視頻適配屏幕的方式,可鋪滿全屏,可以全屏剪裁
  • 重力感應自動進入全屏
  • 全屏后手勢修改進度和音量
  • Home鍵退出界面暫停播放,返回界面繼續播放

3.開始使用

引入

implementation 'cn.jzvd:jiaozivideoplayer:7.0.3'

xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="200dp">
    <cn.jzvd.demo.CustomJzvd.MyJzvdStd
        android:id="@+id/jz_video"
        android:layout_width="match_parent"
        android:layout_height="200dp" />
</LinearLayout>

java

MyJzvdStd jzvdStd = (MyJzvdStd) findViewById(R.id.jz_video);
jzvdStd.setUp("http://jzvd.nathen.cn/c6e3dc12a1154626b3476d9bf3bd7266/6b56c5f0dc31428083757a45764763b0-5287d2089db37e62345123a1be272f8b.mp4"
                            , "視頻標題");
jzvdStd.thumbImageView.setImage("http://p.qpic.cn/videoyun/0/2449_43b6f696980311e59ed467f22794e792_1/640");
@Override
public void onBackPressed() {
    if (Jzvd.backPress()) {
        return;
    }
    super.onBackPressed();
}
@Override
protected void onPause() {
    super.onPause();
    Jzvd.releaseAllVideos();
}

AndroidManifest.xml

<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden"
    android:screenOrientation="portrait" /> <!-- or android:screenOrientation="landscape"-->

自動播放

      自動播放有兩種 這里隨便選擇添加一個,
    1. myJzvdStd.startButton.performClick();
    2. myJzvdStd.startVideo();

跳轉制定位置播放

    //這里只有開始播放時才生效
    mJzvdStd.seekToInAdvance = 20000;
    //跳轉制定位置播放
    JZMediaManager.seekTo(30000);

   2.播放sd卡下視頻

    public void cpAssertVideoToLocalPath() {
            try {
                InputStream myInput;
                OutputStream myOutput = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera/local_video.mp4");
                myInput = this.getAssets().open("local_video.mp4");
                byte[] buffer = new byte[1024];
                int length = myInput.read(buffer);
                while (length > 0) {
                    myOutput.write(buffer, 0, length);
                    length = myInput.read(buffer);
                }
     
                myOutput.flush();
                myInput.close();
                myOutput.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    myJzvdStd.setUp(Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera/local_video.mp4", "視頻標題",Jzvd.SCREEN_WINDOW_NORMAL, );

播放assets目錄下的視頻

           復制Demo中CustomMediaPlayerAssertFolder類到你的項目下
            ----------------------------------------------------------------------------
            JZDataSource jzDataSource = null;
            try {
                jzDataSource = new JZDataSource(getAssets().openFd("local_video.mp4"));
                jzDataSource.title = "餃子快長大";
            } catch (IOException e) {
                e.printStackTrace();
            }
            jzvdStd.setUp(jzDataSource, JzvdStd.SCREEN_WINDOW_NORMAL);
            Glide.with(this)
                    .load("http://jzvd-pic.nathen.cn/jzvd-pic/1bb2ebbe-140d-4e2e-abd2-9e7e564f71ac.png")
                    .into(jzvdStd.thumbImageView);
     
            Jzvd.setMediaInterface(new CustomMediaPlayerAssertFolder());//進入此頁面修改MediaInterface,讓此頁面的jzvd正常工作

直接全屏播放

JzvdStd.startFullscreen(this, JzvdStd.class, VideoConstant.videoUrlList[6], "視頻標題");

開啟小窗播放

mJzvdStd.startWindowTiny();

列表Item划出開啟小窗播放

    1.Listview
       listView.setOnScrollListener(new AbsListView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) { 
     
                }
                @Override
                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                    Jzvd.onScrollAutoTiny(view, firstVisibleItem, visibleItemCount, totalItemCount);
                  // Jzvd.onScrollReleaseAllVideos(view, firstVisibleItem, visibleItemCount, totalItemCount);  這是不開啟列表划出小窗 同時也是畫出屏幕釋放JZ 划出暫停
                }
            });
    2. RecyclerView  划出列表開啟小窗
       recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
                @Override
                public void onChildViewAttachedToWindow(View view) {
                    Jzvd.onChildViewAttachedToWindow(view, R.id.videoplayer);
                }
     
                @Override
                public void onChildViewDetachedFromWindow(View view) {
                    Jzvd.onChildViewDetachedFromWindow(view);
                }
            });
    2.1 RecyclerView划出屏幕釋放JZ,同時也是不開啟列表划出顯示小窗
        recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
                @Override
                public void onChildViewAttachedToWindow(View view) {
     
                }
     
                @Override
                public void onChildViewDetachedFromWindow(View view) {
                    Jzvd jzvd = view.findViewById(R.id.videoplayer);
                    if (jzvd != null && jzvd.jzDataSource.containsTheUrl(JZMediaManager.getCurrentUrl())) {
                        Jzvd currentJzvd = JzvdMgr.getCurrentJzvd();
                        if (currentJzvd != null && currentJzvd.currentScreen != Jzvd.SCREEN_WINDOW_FULLSCREEN) {
                            Jzvd.releaseAllVideos();
                        }
                    }
                }
            });

小屏播放無聲音,全屏有聲音

    創建一個類繼承JzvdStd並在XML設置
    public class JzvdStdVolumeAfterFullscreen extends JzvdStd {
        public JzvdStdVolumeAfterFullscreen(Context context) {
            super(context);
        }
     
        public JzvdStdVolumeAfterFullscreen(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        @Override
        public void onPrepared() {
            super.onPrepared();
            if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
                JZMediaManager.instance().jzMediaInterface.setVolume(1f, 1f);
            } else {
                JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f);
            }
        }
     
        /**
         * 進入全屏模式的時候關閉靜音模式
         */
        @Override
        public void startWindowFullscreen() {
            super.startWindowFullscreen();
            JZMediaManager.instance().jzMediaInterface.setVolume(1f, 1f);
        }
     
        /**
         * 退出全屏模式的時候開啟靜音模式
         */
        @Override
        public void playOnThisJzvd() {
            super.playOnThisJzvd();
            JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f);
        }
    }

全屏狀態播放完成,不退出全屏

    創建一個類繼承JzvdStd並在XML設置
    public class JzvdStdAutoCompleteAfterFullscreen extends JzvdStd {
        public JzvdStdAutoCompleteAfterFullscreen(Context context) {
            super(context);
        }
     
        public JzvdStdAutoCompleteAfterFullscreen(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        @Override
        public void startVideo() {
            if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
                Log.d(TAG, "startVideo [" + this.hashCode() + "] ");
                initTextureView();
                addTextureView();
                AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
                mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
                JZUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
     
                JZMediaManager.setDataSource(jzDataSource);
                JZMediaManager.instance().positionInList = positionInList;
                onStatePreparing();
            } else {
                super.startVideo();
            }
        }
     
        @Override
        public void onAutoCompletion() {
            if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
                onStateAutoComplete();
            } else {
                super.onAutoCompletion();
            }
     
        }
    }

全屏模式下顯示分享按鈕

    復制DEMO下的layout文件在 layout_top 布局下 添加你的分享按鈕
    public class JzvdStdShowShareButtonAfterFullscreen extends JzvdStd {
     
        public ImageView shareButton;
     
        public JzvdStdShowShareButtonAfterFullscreen(Context context) {
            super(context);
        }
     
        public JzvdStdShowShareButtonAfterFullscreen(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        @Override
        public void init(Context context) {
            super.init(context);
            shareButton = findViewById(R.id.share);
            shareButton.setOnClickListener(this);
     
        }
     
        @Override
        public int getLayoutId() {
            return R.layout.layout_standard_with_share_button;
        }
     
        @Override
        public void onClick(View v) {
            super.onClick(v);
            if (v.getId() == R.id.share) {
                Toast.makeText(getContext(), "Whatever the icon means", Toast.LENGTH_SHORT).show();
            }
        }
     
        @Override
        public void setUp(JZDataSource jzDataSource, int screen) {
            super.setUp(jzDataSource, screen);
            if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
                shareButton.setVisibility(View.VISIBLE);
            } else {
                shareButton.setVisibility(View.INVISIBLE);
            }
        }
    }

小屏狀態下不顯示標題,全屏模式下顯示標題

    public class JzvdStdShowTitleAfterFullscreen extends JzvdStd {
        public JzvdStdShowTitleAfterFullscreen(Context context) {
            super(context);
        }
     
        public JzvdStdShowTitleAfterFullscreen(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        @Override
        public void setUp(JZDataSource jzDataSource, int screen) {
            super.setUp(jzDataSource, screen);
            if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
                titleTextView.setVisibility(View.VISIBLE);
            } else {
                titleTextView.setVisibility(View.INVISIBLE);
            }
        }
    }

播放MP3

    public class JzvdStdMp3 extends JzvdStd {
     
        public JzvdStdMp3(Context context) {
            super(context);
        }
     
        public JzvdStdMp3(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        @Override
        public int getLayoutId() {
            return R.layout.jz_layout_standard_mp3;
        }
     
        @Override
        public void onClick(View v) {
            if (v.getId() == cn.jzvd.R.id.thumb &&
                    (currentState == CURRENT_STATE_PLAYING ||
                            currentState == CURRENT_STATE_PAUSE)) {
                onClickUiToggle();
            } else if (v.getId() == R.id.fullscreen) {
     
            } else {
                super.onClick(v);
            }
        }
     
        //changeUiTo 真能能修改ui的方法
        @Override
        public void changeUiToNormal() {
            super.changeUiToNormal();
        }
     
        @Override
        public void changeUiToPreparing() {
            super.changeUiToPreparing();
        }
     
        @Override
        public void changeUiToPlayingShow() {
            super.changeUiToPlayingShow();
            thumbImageView.setVisibility(View.VISIBLE);
     
        }
     
        @Override
        public void changeUiToPlayingClear() {
            super.changeUiToPlayingClear();
            thumbImageView.setVisibility(View.VISIBLE);
     
        }
     
        @Override
        public void changeUiToPauseShow() {
            super.changeUiToPauseShow();
            thumbImageView.setVisibility(View.VISIBLE);
     
        }
     
        @Override
        public void changeUiToPauseClear() {
            super.changeUiToPauseClear();
            thumbImageView.setVisibility(View.VISIBLE);
     
        }
     
        @Override
        public void changeUiToComplete() {
            super.changeUiToComplete();
        }
     
        @Override
        public void changeUiToError() {
            super.changeUiToError();
        }
    }
     
            jzvdStdMp3 = findViewById(R.id.jz_videoplayer_mp3);
            jzvdStdMp3.setUp(URL, "餃子搖擺", Jzvd.SCREEN_WINDOW_NORMAL);
            Glide.with(this)
                    .load(VideoConstant.videoThumbs[0][1])
                    .into(jzvdStdMp3.thumbImageView);

播放完成不顯示預覽圖

    public class JzvdStdShowTextureViewAfterAutoComplete extends JzvdStd {
        public JzvdStdShowTextureViewAfterAutoComplete(Context context) {
            super(context);
        }
     
        public JzvdStdShowTextureViewAfterAutoComplete(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        @Override
        public void onAutoCompletion() {
            super.onAutoCompletion();
            thumbImageView.setVisibility(View.GONE);
        }
     
    }

Home鍵退出界面暫停播放,返回界面繼續播放

      @Override
        protected void onResume() {
            super.onResume();
            //home back
            JzvdStd.goOnPlayOnResume();
        }
     
        @Override
        protected void onPause() {
            super.onPause();
       //     Jzvd.clearSavedProgress(this, null);
            //home back
            JzvdStd.goOnPlayOnPause();
        }

邊播邊緩存和清晰度切換

    1. 集成videocache implementation 'com.danikula:videocache:2.7.0',並初始化
    public class ApplicationDemo extends Application {
     
        @Override
        public void onCreate() {
            super.onCreate();
    //        LeakCanary.install(this);
        }
     
        private HttpProxyCacheServer proxy;
     
        public static HttpProxyCacheServer getProxy(Context context) {
            ApplicationDemo app = (ApplicationDemo) context.getApplicationContext();
            return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
        }
     
        private HttpProxyCacheServer newProxy() {
            return new HttpProxyCacheServer(this);
        }
    }
    2.引用
            LinkedHashMap map = new LinkedHashMap();
     
            String proxyUrl = ApplicationDemo.getProxy(this).getProxyUrl(VideoConstant.videoUrls[0][9]);
     
            map.put("高清", proxyUrl);
            map.put("標清", VideoConstant.videoUrls[0][6]);
            map.put("普清", VideoConstant.videoUrlList[0]);
            JZDataSource jzDataSource = new JZDataSource(map, "餃子不信");
            jzDataSource.looping = true;
            jzDataSource.currentUrlIndex = 2;
            jzDataSource.headerMap.put("key", "value");//header
            mJzvdStd.setUp(jzDataSource
                    , JzvdStd.SCREEN_WINDOW_NORMAL);
            Glide.with(this).load(VideoConstant.videoThumbList[0]).into(mJzvdStd.thumbImageView);

重復播放

    創建一個類集成JzvdStd並在XML設置
    public class JZVideoPlayerStandardLoopVideo extends JzvdStd{
        public JZVideoPlayerStandardLoopVideo (Context context) {
            super(context);
        }
     
        public JZVideoPlayerStandardLoopVideo (Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        @Override
        public void onAutoCompletion() {
            super.onAutoCompletion();
            startVideo();
        }
    }
    還有一種方法就是上面清晰度切換loop循環標志

重力感應自動進入全屏

        SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        Jzvd.JZAutoFullscreenListener mSensorEventListener = new Jzvd.JZAutoFullscreenListener();
        @Override
        protected void onResume() {
            super.onResume();
            Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            mSensorManager.registerListener(mSensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
     
        @Override
        protected void onPause() {
            super.onPause();
            mSensorManager.unregisterListener(mSensorEventListener);
       }
     

重力感應

    Jzvd.FULLSCREEN_ORIENTATION=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
    Jzvd.NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
    兩個變量控制全屏前后的屏幕方向

不保存播放進度

Jzvd.SAVE_PROGRESS = false;

取消播放時在非WIFIDialog提示

Jzvd.WIFI_TIP_DIALOG_SHOWED=true;

清除某個URL進度

Jzvd.clearSavedProgress(this, "url");

切換播放內核

ijk
復制Demo中JZMediaIjkplayer類到你的項目下 
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
Jzvd.setMediaInterface(new JZMediaIjkplayer()); // ijkMediaPlayer
Mediaplayer
Jzvd.setMediaInterface(new JZMediaSystem()); // 
exo
復制Demo中JZExoPlayer類到你的項目下 
implementation 'com.google.android.exoplayer:exoplayer:2.7.1' Jzvd.setMediaInterface(new JZExoPlayer()); //exo

 



用戶埋點統計

Jzvd.setJzUserAction(new MyUserActionStd());
/**
* 這只是給埋點統計用戶數據用的,不能寫和播放相關的邏輯,監聽事件請參考MyJzvdStd,復寫函數取得相應事件
*/
class MyUserActionStd implements JZUserActionStd {

@Override
public void onEvent(int type, Object url, int screen, Object... objects) {
switch (type) {
case JZUserAction.ON_CLICK_START_ICON:
Log.i("USER_EVENT", "ON_CLICK_START_ICON" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_CLICK_START_ERROR:
Log.i("USER_EVENT", "ON_CLICK_START_ERROR" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_CLICK_START_AUTO_COMPLETE:
Log.i("USER_EVENT", "ON_CLICK_START_AUTO_COMPLETE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_CLICK_PAUSE:
Log.i("USER_EVENT", "ON_CLICK_PAUSE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_CLICK_RESUME:
Log.i("USER_EVENT", "ON_CLICK_RESUME" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_SEEK_POSITION:
Log.i("USER_EVENT", "ON_SEEK_POSITION" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_AUTO_COMPLETE:
Log.i("USER_EVENT", "ON_AUTO_COMPLETE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_ENTER_FULLSCREEN:
Log.i("USER_EVENT", "ON_ENTER_FULLSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_QUIT_FULLSCREEN:
Log.i("USER_EVENT", "ON_QUIT_FULLSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_ENTER_TINYSCREEN:
Log.i("USER_EVENT", "ON_ENTER_TINYSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_QUIT_TINYSCREEN:
Log.i("USER_EVENT", "ON_QUIT_TINYSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_TOUCH_SCREEN_SEEK_VOLUME:
Log.i("USER_EVENT", "ON_TOUCH_SCREEN_SEEK_VOLUME" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_TOUCH_SCREEN_SEEK_POSITION:
Log.i("USER_EVENT", "ON_TOUCH_SCREEN_SEEK_POSITION" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;

case JZUserActionStd.ON_CLICK_START_THUMB:
Log.i("USER_EVENT", "ON_CLICK_START_THUMB" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserActionStd.ON_CLICK_BLANK:
Log.i("USER_EVENT", "ON_CLICK_BLANK" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
default:
Log.i("USER_EVENT", "unknow");
break;
}
}
}

 



相關函數回調,屏幕狀態,播放器狀態,事件
在繼承JzvdStd之后,可以通過父類的mCurrentState,取得當前的播放狀態。

  • CURRENT_STATE_IDLE 未知狀態,指控件被new出來之后什么都沒做
  • CURRENT_STATE_NORMAL 普通狀態
  • CURRENT_STATE_PREPARING 視頻准備狀態
  • CURRENT_STATE_PREPARING_CHANGING_URL 播放中切換url的准備狀態
  • CURRENT_STATE_PLAYING 播放中狀態
  • CURRENT_STATE_PAUSE 暫停狀態
  • CURRENT_STATE_AUTO_COMPLETE 自動播放完成狀態
  • CURRENT_STATE_ERROR 錯誤狀態

復寫進入播放狀態的函數,取得播放狀態的回調

  • onStateNormal 進入普通狀態,通常指setUp之后
  • onStatePreparing 進入准備中狀態,就是loading狀態
  • onStatePlaying 進入播放狀態
  • onStatePause 進入暫停狀態
  • onStateError 進入錯誤狀態
  • onStateAutoComplete 進入自動播放完成狀態

全屏、小窗、非全屏分別是不同的實例,在繼承JzvdStd后,通過mCurrentScreen變量,取得當前屏幕類型

  • SCREEN_WINDOW_NORMAL 普通窗口(進入全屏之前的)
  • SCREEN_WINDOW_LIST 列表窗口(進入全屏之前)
  • SCREEN_WINDOW_FULLSCREEN 全屏
  • SCREEN_WINDOW_TINY 小窗

事件
復寫onProgress函數,取得每次播放器設置底部seekBar的進度回調
調用changeUrl函數,切換url
復寫onClick函數,取得各種按鈕的點擊事件
復寫onTouch函數,取得全屏之后的手勢操作


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM