JiaoZiVideoPlayer
程序员文章站
2022-06-03 11:51:38
...
https://github.com/lipangit/JiaoZiVideoPlayer/blob/develop/README-ZH.md
主要特点
- 可以完全自定义UI和任何功能
- 一行代码切换播放引擎,支持的视频格式和协议取决于播放引擎,android.media.MediaPlayer ijkplayer
- 完美检测列表滑动
- 可实现全屏播放,小窗播放
- 能在ListView、ViewPager和ListView、ViewPager和Fragment等多重嵌套模式下全屏工作
- 可以在加载、暂停、播放等各种状态中正常进入全屏和退出全屏
- 多种视频适配屏幕的方式,可铺满全屏,可以全屏剪裁
- 重力感应自动进入全屏
- 全屏后手势修改进度和音量
- Home键退出界面暂停播放,返回界面继续播放
- WebView嵌套本地视频控件
- demo中添加视频缓存的例子
集成使用
即便是自定义UI,或者对Library有过修改,也是这五步骤来使用播放器。
1.添加类库
compile 'cn.jzvd:jiaozivideoplayer:6.2.12'
2.添加布局
<cn.jzvd.JZVideoPlayerStandard
android:id="@+id/videoplayer"
android:layout_width="match_parent"
android:layout_height="200dp"/>
3.设置视频地址、缩略图地址、标题
JZVideoPlayerStandard jzVideoPlayerStandard = (JZVideoPlayerStandard) findViewById(R.id.videoplayer);
jzVideoPlayerStandard.setUp("http://jzvd.nathen.cn/c6e3dc12a1154626b3476d9bf3bd7266/6b56c5f0dc31428083757a45764763b0-5287d2089db37e62345123a1be272f8b.mp4"
, JZVideoPlayerStandard.SCREEN_WINDOW_NORMAL, "饺子闭眼睛");
jzVideoPlayerStandard.thumbImageView.setImage("http://p.qpic.cn/videoyun/0/2449_43b6f696980311e59ed467f22794e792_1/640
这里只是告诉你缩略图该怎么设置,库中没有该方法,推荐使用Glide
4.在Activity中
@Override
public void onBackPressed() {
if (JZVideoPlayer.backPress()) {
return;
}
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
JZVideoPlayer.releaseAllVideos();
}
在AndroidManifest.xml中
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" /> <!-- or android:screenOrientation="landscape"-->
image
基本使用
- 加缩略载图
Glide.with(this).load(Url).into(myJZVideoPlayerStandard.thumbImageView); //推荐使用Glide
- 自动播放
1. mJZVideoPlayerStandard.startButton.performClick();
2. myJZVideoPlayerStandard.startVideo();
2.播放sd卡下视频
public void cpAssertVideoToLocalPath() {
try {
InputStream myInput;
OutputStream myOutput = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "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();
}
}
mJzVideoPlayerStandard.setUp(Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera/local_video.mp4", JZVideoPlayerStandard.SCREEN_WINDOW_NORMAL, "饺子不信");
这里很多人问为什么播不了,请认真怒url,播不了就是url没怒对
播放assets目录下的视频
复制Demo中CustomMediaPlayerAssertFolder类到你的项目下
----------------------------------------------------------------------------
LinkedHashMap map = new LinkedHashMap();
try {
map.put(JZVideoPlayer.URL_KEY_DEFAULT, getAssets().openFd("local_video.mp4"));
} catch (IOException e) {
e.printStackTrace();
}
Object[] dataSourceObjects = new Object[2];
dataSourceObjects[0] = map;
dataSourceObjects[1] = this;
JZVideoPlayerStandard.startFullscreen(this, JZVideoPlayerStandard.class, dataSourceObjects, 0, "")
JZVideoPlayer.setMediaInterface(new CustomMediaPlayerAssertFolder());
直接全屏播放
JZVideoPlayerStandard.startFullscreen(this, JZVideoPlayerStandard.class, "url", "饺子辛苦了");
开启小窗播放
mJzVideoPlayerStandard.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) {
JZVideoPlayer.onScrollAutoTiny(view, firstVisibleItem, visibleItemCount, totalItemCount);
// JZVideoPlayer.onScrollReleaseAllVideos(view, firstVisibleItem, visibleItemCount, totalItemCount); 这是不开启列表划出小窗 同时也是画出屏幕释放JZ
}
});
2. RecyclerView
recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
JZVideoPlayer.onChildViewAttachedToWindow(view, R.id.videoplayer);
}
@Override
public void onChildViewDetachedFromWindow(View view) {
JZVideoPlayer.onChildViewDetachedFromWindow(view);
}
});
2.1 RecyclerView划出屏幕释放JZ,同时也是不开启列表划出显示小窗
recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
}
@Override
public void onChildViewDetachedFromWindow(View view) {
JZVideoPlayer jzvd = view.findViewById(R.id.videoplayer);
if (jzvd != null && JZUtils.dataSourceObjectsContainsUri(jzvd.dataSourceObjects, JZMediaManager.getCurrentDataSource())) {
JZVideoPlayer currentJzvd = JZVideoPlayerManager.getCurrentJzvd();
if (currentJzvd != null && currentJzvd.currentScreen != JZVideoPlayer.SCREEN_WINDOW_FULLSCREEN) {
JZVideoPlayer.releaseAllVideos();
}
}
}
});
小屏播放无声音,全屏有声音
创建一个类集成JZVideoPlayerStandard 并在XML设置
public class JZVideoPlayerStandardVolumeAfterFullscreen extends JZVideoPlayerStandard {
public JZVideoPlayerStandardVolumeAfterFullscreen(Context context) {
super(context);
}
public JZVideoPlayerStandardVolumeAfterFullscreen(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);
}
}
全屏状态播放完成,不退出全屏
创建一个类集成JZVideoPlayerStandard 并在XML设置
public class JZVideoPlayerStandardAutoCompleteAfterFullscreen extends JZVideoPlayerStandard {
public JZVideoPlayerStandardAutoCompleteAfterFullscreen(Context context) {
super(context);
}
public JZVideoPlayerStandardAutoCompleteAfterFullscreen(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(dataSourceObjects);
JZMediaManager.setCurrentDataSource(JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex));
JZMediaManager.instance().positionInList = positionInList;
onStatePreparing();
} else {
super.startVideo();
}
}
@Override
public void onAutoCompletion() {
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
onStateAutoComplete();
} else {
super.onAutoCompletion();
}
}
}
Home键退出界面暂停播放,返回界面继续播放
@Override
protected void onResume() {
super.onResume();
//home back
JZVideoPlayer.goOnPlayOnResume();
}
@Override
protected void onPause() {
super.onPause();
JZVideoPlayer.clearSavedProgress(this, null);
//home back
JZVideoPlayer.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]);
// 这是各个清晰度URL
map.put("高清", proxyUrl); //这里是边播边缓存
map.put("标清", VideoConstant.videoUrls[0][6]);
map.put("普清", VideoConstant.videoUrlList[0]);
Object[] objects = new Object[3];
objects[0] = map;
objects[1] = false;//looping //这里是重复播放的标志
objects[2] = new HashMap<>();
// ((HashMap) objects[2]).put("key", "value");//header
mJzVideoPlayerStandard.setUp(objects, 2
, JZVideoPlayerStandard.SCREEN_WINDOW_NORMAL, "饺子不信");
重复播放
创建一个类集成JZVideoPlayerStandard 并在XML设置
public class JZVideoPlayerStandardLoopVideo extends JZVideoPlayerStandard {
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);
JZVideoPlayer.JZAutoFullscreenListener mSensorEventListener = new JZVideoPlayer.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);
}
重力感应
JZVideoPlayer.FULLSCREEN_ORIENTATION=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
JZVideoPlayer.NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
两个变量控制全屏前后的屏幕方向
不保存播放进度
JZVideoPlayer.SAVE_PROGRESS = false;
取消播放时4GDialog提示
JZVideoPlayer.WIFI_TIP_DIALOG_SHOWED=true;
清除某个URL进度
JZVideoPlayer.clearSavedProgress(this, "url");
获取视频某一帧
/**
* [@param](https://github.com/param) context 上下文
* [@param](https://github.com/param) uri 视频地址
* [@param](https://github.com/param) imageView 设置image
* [@param](https://github.com/param) 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);
}
切换播放内核
ijk
复制Demo中JZMediaIjkplayer类到你的项目下
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
MediaPlayer
JZVideoPlayer.setMediaInterface(new JZMediaIjkplayer()); // ijk
JZVideoPlayer.setMediaInterface(new JZMediaSystem()); //
exo
复制Demo中JZExoPlayer类到你的项目下
implementation 'com.google.android.exoplayer:exoplayer:2.7.1'
JZVideoPlayer.setMediaInterface(new JZExoPlayer()); //exo
上一篇: DM8数据库运维常用基础SQL
下一篇: 怎样进行vue-cli打包上线