androdi視頻播放器之餃子播放器!


視頻開發----之餃子播放器!
GitHub代碼地址: https://github.com/lipangit/JiaoZiVideoPlayer

一. 簡介:
JZVedioPlayer 是目前發現的集成和使用起來最簡單,也是穩定度很高的一個庫JZVedioPlayer 封裝了 UI 層和播放器層,讓我們可以簡簡單單的一鍵集成.

二. 集成以及使用:
compile 'cn.jzvd:jiaozivideoplayer:6.2.12' 或 jiaozivideoplayer.jar依賴庫(不推薦)
JiaoZiVideoPlayer主要功能使用:

可以完全自定義UI和任何功能
多種視頻適配屏幕的方式,可鋪滿全屏,可以全屏剪裁
完美檢測列表滑動
可以加載,暫停,播放和其他正常狀態進入全屏並退出全屏
切換播放引擎,支持的視頻格式和協議的一行代碼取決於播放引擎,如: android.media.MediaPlayer,IJKplayer,ExoPlayer。
全屏適用於多種嵌套模式,如ListView,ViewPager和ListView,ViewPager和Fragment
提供全屏和小窗口選項
Home鍵退出界面暫停播放,返回界面繼續播放
WebView嵌套本地視頻控件
全屏后手勢修改進度和音量
VideoCache在演示中

 


三. 接下來我們從三步來實現簡單視頻播放
1) 首先設置你的布局文件

<cn.jzvd.demo.CustomView.MyJzvdStd
android:id="@+id/jz_video"
android:layout_width="match_parent"
android:layout_height="300dp" />
2) ActivityMain中設置視頻初始化操作

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
myJzvdStd = findViewById(R.id.jz_video);
/**
* 參數說明
* 視頻播放地址
* 設置視頻標題
*/
myJzvdStd.setUp("http://jzvd.nathen.cn/342a5f7ef6124a4a8faf00e738b8bee4/cf6d9db0bd4d41f59d09ea0a81e918fd-5287d2089db37e62345123a1be272f8b.mp4"
, "餃子快長大", JzvdStd.SCREEN_WINDOW_NORMAL);
//設置視頻封面
Glide.with(this).load("http://jzvd-pic.nathen.cn/jzvd-pic/1bb2ebbe-140d-4e2e-abd2-9e7e564f71ac.png").into(myJzvdStd.thumbImageView);
Jzvd.setJzUserAction(new MyUserActionStd());

}

@Override
protected void onPause() {
super.onPause();
Jzvd.releaseAllVideos();
}

@Override
public void onBackPressed() {
if (Jzvd.backPress()) {
return;
}
super.onBackPressed();
}


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

@Override
public void onEvent(int type, Object url, int screen, Object... objects) {
switch (type) {
//繼承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 錯誤狀態

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;
}
}
}
3) 在清單文件中AndroidManifest.xml中添加 "android:configChanges="orientation|screenSize|keyboardHidden"

<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" />
四. JiaoZiVideoPlayer 基本使用
1) 自動播放(兩種方法選其一)

myJzvdStd.startButton.performClick();
myJzvdStd.startVideo();

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

public void getAssertVideoToLocalPath() {
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, );
3) 播放assets目錄下的視頻

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());
4) 切換成全屏模式以及小窗口模式

//切換全屏
JzvdStd.startFullscreen(this, JzvdStd.class, VideoConstant.videoUrlList[6], "視頻的標題");
//設置小窗口模式
mJzvdStd.startWindowTiny();

5) 列表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();
}
}
}
});
6) 小屏播放無聲音,全屏有聲音

創建一個類繼承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);
}
}
7) 全屏狀態播放完成,不退出全屏

創建一個類繼承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();
}

}
}
8) 全屏模式下顯示分享按鈕

復制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);
}
}
}

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

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);
}
}
}
10) 播放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);
11) 播放完成不顯示預覽圖

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

}
12) 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();
}
13) 邊播邊緩存和清晰度切換

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);
14) 重復播放

創建一個類集成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循環標志
15) 重力感應自動進入全屏

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

16) 重力感應

Jzvd.FULLSCREEN_ORIENTATION=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
Jzvd.NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
兩個變量控制全屏前后的屏幕方向
17) 不保存播放進度

Jzvd.SAVE_PROGRESS = false;
18) 取消播放時在非WIFIDialog提示

Jzvd.WIFI_TIP_DIALOG_SHOWED=true;
19) 清除某個URL進度

Jzvd.clearSavedProgress(this, "url");


免責聲明!

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



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