饺子 视频GitHub:
入门文档 1:
入门文档 2:
常见问题:
主要特点
即便是自定义UI,或者对Library有过修改,也是这五步骤来使用播放器。
//饺子视频播放器
implementation 'cn.jzvd:jiaozivideoplayer:7.0.5'
<cn.jzvd.CustJzvdStd
android:id="@+id/videoplayer"
android:layout_width="match_parent"
android:layout_height="200dp"/>
自定义的CustJzvdStd布局 View
/**
* 这里可以监听到视频播放的生命周期和播放状态
* 所有关于视频的逻辑都应该写在这里
* Created by Nathen on 2017/7/2.
*/
public class CustJzvdStd extends JzvdStd {
private CommonInterface.OnVideoCompletion onVideoCompletion;
public CustJzvdStd(Context context) {
super(context);
}
public CustJzvdStd(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void init(Context context) {
super.init(context);
}
@Override
public void setUp(JZDataSource jzDataSource, int screen) {
super.setUp(jzDataSource, screen);
if (this.screen == SCREEN_FULLSCREEN) {
titleTextView.setVisibility(View.VISIBLE);
} else {
titleTextView.setVisibility(View.INVISIBLE);
}
}
@Override
public void onClick(View v) {
super.onClick(v);
int i = v.getId();
if (i == cn.jzvd.R.id.fullscreen) {
Log.i(TAG, "onClick: fullscreen button");
} else if (i == R.id.start) {
Log.i(TAG, "onClick: start button");
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
super.onTouch(v, event);
int id = v.getId();
if (id == cn.jzvd.R.id.surface_container) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (mChangePosition) {
Log.i(TAG, "Touch screen seek position");
}
if (mChangeVolume) {
Log.i(TAG, "Touch screen change volume");
}
break;
}
}
return false;
}
@Override
public int getLayoutId() {
return R.layout.jz_layout_std;
}
@Override
public void startVideo() {
super.startVideo();
Log.i(TAG, "startVideo");
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
super.onStopTrackingTouch(seekBar);
Log.i(TAG, "Seek position ");
}
@Override
public void gotoScreenFullscreen() {
super.gotoScreenFullscreen();
Log.i(TAG, "goto Fullscreen");
titleTextView.setVisibility(View.VISIBLE);
}
@Override
public void gotoScreenNormal() {
super.gotoScreenNormal();
Log.i(TAG, "quit Fullscreen");
titleTextView.setVisibility(View.INVISIBLE);
}
@Override
public void autoFullscreen(float x) {
super.autoFullscreen(x);
Log.i(TAG, "auto Fullscreen");
}
@Override
public void onClickUiToggle() {
super.onClickUiToggle();
Log.i(TAG, "click blank");
}
//onState 代表了播放器引擎的回调,播放视频各个过程的状态的回调
@Override
public void onStateNormal() {
super.onStateNormal();
}
@Override
public void onStatePreparing() {
super.onStatePreparing();
}
@Override
public void onStatePlaying() {
super.onStatePlaying();
}
@Override
public void onStatePause() {
super.onStatePause();
}
@Override
public void onStateError() {
super.onStateError();
}
@Override
public void onStateAutoComplete() {
super.onStateAutoComplete();
Log.i(TAG, "Auto complete");
}
//changeUiTo 真能能修改ui的方法
@Override
public void changeUiToNormal() {
super.changeUiToNormal();
}
@Override
public void changeUiToPreparing() {
super.changeUiToPreparing();
}
@Override
public void changeUiToPlayingShow() {
super.changeUiToPlayingShow();
}
@Override
public void changeUiToPlayingClear() {
super.changeUiToPlayingClear();
}
@Override
public void changeUiToPauseShow() {
super.changeUiToPauseShow();
}
@Override
public void changeUiToPauseClear() {
super.changeUiToPauseClear();
}
@Override
public void changeUiToComplete() {
super.changeUiToComplete();
}
@Override
public void changeUiToError() {
super.changeUiToError();
}
@Override
public void onInfo(int what, int extra) {
super.onInfo(what, extra);
}
@Override
public void onError(int what, int extra) {
super.onError(what, extra);
}
/**
* 播放完成
*/
@Override
public void onAutoCompletion() {
super.onAutoCompletion();
//播完完,回调这个方法
onVideoCompletion.onVideoCompletion();
}
public void setOnVideoCompletion(CommonInterface.OnVideoCompletion onVideoCompletion){
this.onVideoCompletion = onVideoCompletion;
}
}
TRTCActivity 使用
我们可能遇到一个问题,视频不能充满整个布局,周围都是黑边,因此我们需要自定义布局大小。
代码如下:
/**
* 视频播放和直播展示界面
*/
public class TRTCActivity extends AppCompatActivity {
@BindView(R.id.tv_tip)
TextView tvTip;
private static String TAG = "LUO";
@BindView(R.id.videoplayer)
CustJzvdStd videoplayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 应用运行时,保持不锁屏、全屏化
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_trtc);
ButterKnife.bind(this);
//播放视频
videoPlay();
}
/**
* 播放视频
*/
private void videoPlay() {
//设置视频大小
setImageSize();
//设置播放视频的 URL
videoplayer.setUp("https://sumansoul.oss-cn-shanghai.aliyuncs.com/public/video/6732627438732659604.MP4"
, "", JzvdStd.SYSTEM_UI_FLAG_VISIBLE);
//设置图片大小
videoplayer.thumbImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
//设置视频裁剪方式
Jzvd.setVideoImageDisplayType(Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_FILL_SCROP);
Glide.with(this).load("http://jzvd-pic.nathen.cn/jzvd-pic/1bb2ebbe-140d-4e2e-abd2-9e7e564f71ac.png").into(videoplayer.thumbImageView);
//只有开始时播放时间
videoplayer.seekToInAdvance = 10000;
//自动播放
//myJzvdStd.startVideo();
//倒计时播放
countDown();
}
/**
* 倒计时显示
*/
private void countDown() {
CountDownTimer timer = new CountDownTimer(5000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
tvTip.setText("视频正在加载中" + millisUntilFinished / 1000 + "s");
}
@Override
public void onFinish() {
tvTip.setVisibility(View.GONE);
//自动播放
videoplayer.startVideo();
}
}.start();
}
/**
* 视频设置控件大小
*/
private void setImageSize() {
//控件大小
videoplayer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) videoplayer.getLayoutParams();
// -DensityUtils.dp2px(context,14*2) params.getMarginStart()
int width = ScreenUtils.getScreenWidth();
//int h=(int)(width*9/16+0.5);//16:9
int h = (int) (width + 2);
params.height = h;
//将设置好的布局参数应用到控件中
videoplayer.setLayoutParams(params);
//设置容器内播放器高
Jzvd.setVideoImageDisplayType(Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_FILL_PARENT);
//Jzvd.setVideoImageDisplayType(Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_FILL_SCROP);
}
});
}
@Override
protected void onPause() {
super.onPause();
Jzvd.releaseAllVideos();
}
@Override
public void onBackPressed() {
if (Jzvd.backPress()) {
return;
}
super.onBackPressed();
}
}
MyJzvdStd myJzvdStd= findViewById(R.id.videoplayer);
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);
@Override
protected void onPause() {
super.onPause();
Jzvd.releaseAllVideos();
}
@Override
public void onBackPressed() {
if (Jzvd.backPress()) {
return;
}
super.onBackPressed();
}
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" /> <!-- or android:screenOrientation="landscape"-->
Glide.with(this).load(Url).into(myJzvdStd.thumbImageView); //推荐使用Glide
- myJzvdStd.startButton.performClick();
- myJzvdStd.startVideo();
//这里只有开始播放时才生效
mJzvdStd.seekToInAdvance = 20000;
//跳转制定位置播放
JZMediaManager.seekTo(30000)
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, );
这里很多人问为什么播不了,请认真怒url,播不了就是url没怒对
复制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();
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);
}
}
}
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);
}
}
@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循环标志
Jzvd.FULLSCREEN_ORIENTATION=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
Jzvd.NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
两个变量控制全屏前后的屏幕方向
Jzvd.SAVE_PROGRESS = false;
Jzvd.WIFI_TIP_DIALOG_SHOWED=true;
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后,通过mCurrentScreen变量,取得当前屏幕类型
根据自己项目的实际情况来 ,这里只是简单的测试
public class TryToSeeVideo extends JzvdStd {
RelativeLayout mRelativeLayout;
TextView mExit, mPay, mTryToSee;
boolean isNoPay;
public TryToSeeVideo(Context context) {
super(context);
}
public TryToSeeVideo(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void init(Context context) {
super.init(context);
mRelativeLayout = findViewById(R.id.try_to_see_tip);
mExit = findViewById(R.id.exit); //退出按钮
mPay = findViewById(R.id.pay); //支付按钮
mTryToSee = findViewById(R.id.try_see); //重新试看按钮
mExit.setOnClickListener(this);
mPay.setOnClickListener(this);
mTryToSee.setOnClickListener(this);
}
@Override
public int getLayoutId() {
return R.layout.try_to_see_video_layout;
}
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.exit:
//finish界面 建议回调出当前事件
break;
case R.id.pay:
//进入支付界面 支付成功后 Jzvd.goOnPlayOnResume();
getContext().startActivity(new Intent(getContext(), ActivityMain.class)); //模拟跳转支付界面
break;
case R.id.try_see:
JZMediaManager.seekTo(0);//回到0秒
Jzvd.goOnPlayOnResume();
progressBar.setProgress(0);
mRelativeLayout.setVisibility(GONE);
break;
}
}
/**
* @param progress 百分比
* @param position 当前时间
* @param duration 总时长
*/
@Override
public void onProgress(int progress, long position, long duration) {
super.onProgress(progress, position, duration);
long totalSeconds = position / 1000;
if (true) { //这里是从服务器拿到特定字段判断是否付费 这里模拟未付费
if (totalSeconds >= 30) { //考虑未付费情况下拖动进度条超过试看时间
if (!isNoPay) { //加个标记 因为此函数一直在回调
JZMediaManager.seekTo(30000); //回到30秒
progressBar.setProgress(30);
mRelativeLayout.setVisibility(VISIBLE); //在适当的时候隐藏
Jzvd.goOnPlayOnPause(); //在适当的时候(支付成功后)播放
startButton.setEnabled(false); //在适当的时候取消
isNoPay = true;
}
}
}
}
@Override
public void onStatePlaying() {
super.onStatePlaying();
isNoPay = false;
startButton.setEnabled(true);
}
}
2.列表页到详情页无时差播放
3.列表自动播放
4.自动播放下一集剧集
public class AutoPlayNextVideo extends JzvdStd {
int UrlIndex = 0; //剧集标识
public AutoPlayNextVideo(Context context) {
super(context);
}
public AutoPlayNextVideo(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 自动播放下一集
* 若果需要手动选集 自定义Ui定义出剧集列表 调用相关changeUrl
*/
@Override
public void onAutoCompletion() {
super.onAutoCompletion();
if (UrlIndex<videoUrlList.length){
UrlIndex++;
changeUrl(videoUrlList[UrlIndex], "各剧集的标题", 0);
}
}
}
public class JzvdStdSpeed extends JzvdStd {
TextView tvSpeed;
int currentSpeedIndex = 2;
public JzvdStdSpeed(Context context) {
super(context);
}
public JzvdStdSpeed(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void init(Context context) {
super.init(context);
tvSpeed = findViewById(R.id.tv_speed);
tvSpeed.setOnClickListener(this);
}
@Override
public void setUp(JZDataSource jzDataSource, int screen) {
super.setUp(jzDataSource, screen);
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
tvSpeed.setVisibility(View.VISIBLE);
} else {
tvSpeed.setVisibility(View.GONE);
}
if (jzDataSource.objects == null) {
Object[] object = {2};
jzDataSource.objects = object;
currentSpeedIndex = 2;
} else {
currentSpeedIndex = (int) jzDataSource.objects[0];
}
if (currentSpeedIndex == 2) {
tvSpeed.setText("倍速");
} else {
tvSpeed.setText(getSpeedFromIndex(currentSpeedIndex) + "X");
}
}
@Override
public void onClick(View v) {
super.onClick(v);
if (v.getId() == R.id.tv_speed) {//0.5 0.75 1.0 1.25 1.5 1.75 2.0
if (currentSpeedIndex == 6) {
currentSpeedIndex = 0;
} else {
currentSpeedIndex += 1;
}
JZMediaManager.setSpeed(getSpeedFromIndex(currentSpeedIndex));
tvSpeed.setText(getSpeedFromIndex(currentSpeedIndex) + "X");
jzDataSource.objects[0] = currentSpeedIndex;
}
}
@Override
public int getLayoutId() {
return R.layout.layout_std_speed;
}
private float getSpeedFromIndex(int index) {
float ret = 0f;
if (index == 0) {
ret = 0.5f;
} else if (index == 1) {
ret = 0.75f;
} else if (index == 2) {
ret = 1.0f;
} else if (index == 3) {
ret = 1.25f;
} else if (index == 4) {
ret = 1.5f;
} else if (index == 5) {
ret = 1.75f;
} else if (index == 6) {
ret = 2.0f;
}
return ret;
}
/**
* context 上下文
* uri 视频地址
* imageView 设置image
* frameTimeMicros 获取某一时间帧
*/
public static void loadVideoScreenshot(final Context context, String uri, ImageView imageView, long frameTimeMicros) {
RequestOptions requestOptions = RequestOptions.frameOf(frameTimeMicros);
requestOptions.set(FRAME_OPTION, MediaMetadataRetriever.OPTION_CLOSEST);
requestOptions.transform(new BitmapTransformation() {
@Override
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
return toTransform;
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
try {
messageDigest.update((context.getPackageName() + "RotateTransform").getBytes("utf-8"));
} catch (Exception e) {
e.printStackTrace();
}
}
});
Glide.with(context).load(uri).apply(requestOptions).into(imageView);
}
ViewOutlineProvider (注:该类是5.0的特性,低于5.0没效果,如果要适配5.0以下这里给出一个思路.9图遮罩)
创建一个类继承ViewOutLineProvider 实现改该方法
public class JzViewOutlineProvider extends ViewOutlineProvider {
private float mRadius;
public JzViewOutlineProvider(float radius) {
this.mRadius = radius;
}
@Override
public void getOutline(View view, Outline outline) {
Rect rect = new Rect();
view.getGlobalVisibleRect(rect);
Rect selfRect = new Rect(0, 0,
view.getWeight(),view.getHeight());
outline.setRoundRect(selfRect,mRadius);
}
}
mJzvdStd.setOutlineProvider(new JzViewOutlineProvider(radius));
mJzvdStd.setClipToOutline(true);
点击全屏按钮闪退,报错空指针
<activity
android:name=".xxxxxxxActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" />
视屏宽高不填充屏幕,有黑边
Jzvd.setTextureViewRotation(90); //视频旋转90度
根据自己情况选择一个 填充
Jzvd.setVideoImageDisplayType(Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_FILL_PARENT);
Jzvd.setVideoImageDisplayType(Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_FILL_SCROP);
Jzvd.setVideoImageDisplayType(Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_ORIGINAL); //原始大小
背景高斯模糊
<FrameLayout
android:id="@+id/surface_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cn.jzvd.ResizableImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
这里我为了方便重写了Imageview 使他宽填充屏幕宽,这里怎么简单怎么来想进一切办法让他填充满宽度
在JzvdStd类下的init 方法里面获取上面的Imageview控件,好了到此就完了,然后在设置缩略图的下面用能高斯模糊的方法设置就OK,下面是我的做法你可以根据你自己来。
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());
Glide.with(ActivityMain.this)
.load("http://t2.hddhhn.com/uploads/tu/201810/9999/9139710e12.jpg")
.dontAnimate()
// 设置高斯模糊
.bitmapTransform(new BlurTransformation(this, 14, 5))
.into(myJzvdStd.mFrameLayout);
参考作者:TrueloveSomeGIRl
链接:https://juejin.im/post/5cb837f1518825329f6cf300