diff --git a/.travis.yml b/.travis.yml index 2fbbeaf78..85ccab7bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ android: components: - platform-tools - tools - - build-tools-23.0.1 + - build-tools-26.0.2 - android-22 - extra-android-support - extra-android-m2repository diff --git a/01.gif b/01.gif deleted file mode 100644 index 2be922404..000000000 Binary files a/01.gif and /dev/null differ diff --git a/01.jpg b/01.jpg deleted file mode 100644 index f5b5c3130..000000000 Binary files a/01.jpg and /dev/null differ diff --git a/02.gif b/02.gif deleted file mode 100644 index aed60f7a3..000000000 Binary files a/02.gif and /dev/null differ diff --git a/02.jpg b/02.jpg deleted file mode 100644 index 9dc318ce1..000000000 Binary files a/02.jpg and /dev/null differ diff --git a/03.gif b/03.gif deleted file mode 100644 index be6c14d95..000000000 Binary files a/03.gif and /dev/null differ diff --git a/03.jpg b/03.jpg deleted file mode 100644 index d134ec584..000000000 Binary files a/03.jpg and /dev/null differ diff --git a/04.gif b/04.gif deleted file mode 100644 index 554de9831..000000000 Binary files a/04.gif and /dev/null differ diff --git a/04.jpg b/04.jpg deleted file mode 100644 index feb7b8a8e..000000000 Binary files a/04.jpg and /dev/null differ diff --git a/05.gif b/05.gif deleted file mode 100644 index dbd4af180..000000000 Binary files a/05.gif and /dev/null differ diff --git a/09.gif b/09.gif index 094334329..29c9942e4 100644 Binary files a/09.gif and b/09.gif differ diff --git a/11.gif b/11.gif new file mode 100755 index 000000000..cbdb5e486 Binary files /dev/null and b/11.gif differ diff --git a/22.gif b/22.gif new file mode 100755 index 000000000..e99145907 Binary files /dev/null and b/22.gif differ diff --git a/33.gif b/33.gif new file mode 100755 index 000000000..a9c4bff39 Binary files /dev/null and b/33.gif differ diff --git a/44.gif b/44.gif new file mode 100755 index 000000000..0efc09824 Binary files /dev/null and b/44.gif differ diff --git a/55.gif b/55.gif new file mode 100755 index 000000000..8b6552167 Binary files /dev/null and b/55.gif differ diff --git a/99.png b/99.png new file mode 100644 index 000000000..29e619bc4 Binary files /dev/null and b/99.png differ diff --git a/DECODERS.md b/DECODERS.md index 7c9267daf..314d7bd24 100644 --- a/DECODERS.md +++ b/DECODERS.md @@ -3,7 +3,7 @@ --------- -#### 出于so大小考虑,编译so只支持了常用的视频编码,如果需要支持额外类型,可重新编译ijkplayer源码,配置module.sh然后编译so,替换现在项目中的so,注意so的版本要和ijk的java版本一致。编译流程可参考首页编译https的so流程。 +#### 出于so大小考虑,普通编译so只支持了常用的视频编码,如果需要支持额外类型,可依赖ex_so,如果依旧不满足,可重新编译ijkplayer源码,配置module.sh然后编译so,替换现在项目中的so,注意so的版本要和ijk的java版本一致。编译流程可参考首页编译https的so流程。 --------- @@ -14,21 +14,11 @@ 对于视频相关的,推荐雷宵骅的视频基础:[视音频编解码技术零基础学习方法](http://blog.csdn.net/leixiaohua1020/article/details/18893769),这里你可以了解到视频和音频相关编码和协议的东西。 -项目默认支持的视频编码和音频编码有如下,更多详细配置可查看[编译配置文件](https://github.com/CarGuo/GSYVideoPlayer/blob/master/module-lite-hevc.sh)。 +项目普通so默认支持的视频编码和音频编码配置可查看[编译配置文件](https://github.com/CarGuo/GSYVideoPlayer/blob/master/module-lite-hevc.sh)。 + +ex_so支持的视频编码和音频编码配置可查看[编译配置文件](https://github.com/CarGuo/GSYVideoPlayer/blob/master/module-lite-more.sh)。 + +ex_so多支持了mepg、concat协议,crypto协议。 -``` - --enable-decoder=aac" - --enable-decoder=aac_latm" - --enable-decoder=flv" - --enable-decoder=h263" - --enable-decoder=h263i" - --enable-decoder=h263p" - --enable-decoder=h264" - --enable-decoder=mp3*" - --enable-decoder=vp6" - --enable-decoder=vp6a" - --enable-decoder=vp6f" - --enable-decoder=hevc" -``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/QUESTION.md b/QUESTION.md index 39edeefdc..052c8f746 100644 --- a/QUESTION.md +++ b/QUESTION.md @@ -71,7 +71,7 @@ sourceSets {  是否监听了列表滑动了,在监听里更新了列表之类的。 -#### 4、目前不支持3gp或者mepg。 +#### 4、普通模式不支持3gp或者mepg,mepg可使用ex-so依赖。 如果拍摄的视频播放不了,可以尝试用使用系统录制的项目:[VideoRecord](https://github.com/CarGuo/VideoRecord) 或者使用JAVACV录制的项目:[FFmpegRecorder](https://github.com/CrazyOrr/FFmpegRecorder ),测试视频是否可以播放。 @@ -90,7 +90,14 @@ setUp(String url, boolean cacheWithPlay····) ``` -#### 6、为什么拖动视屏会弹回来,因为ijk的FFMPEG对关键帧问题,目前无解。 +#### 6、为什么拖动视屏会弹回来,因为ijk的FFMPEG对关键帧问题。 +可以尝试以下设置 +``` +VideoOptionModel videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1); +List list = new ArrayList<>(); +list.add(videoOptionModel); +GSYVideoManager.instance().setOptionModelList(list); +``` #### 7、视频旋转后重新开始,配置AndroidManifest.xml。 ``` @@ -156,4 +163,86 @@ https://github.com/Bilibili/ijkplayer/issues/2874 https://github.com/CarGuo/GSYVideoPlayer/issues/252 +#### 16、播放本地m3u8有问题 + +``` +VideoOptionModel videoOptionModel = + new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "protocol_whitelist", crypto,file,http,https,tcp,tls,udp); +List list = new ArrayList<>(); +list.add(videoOptionModel); +GSYVideoManager.instance().setOptionModelList(list); +``` +#### 17、rtsp连接有问题 + +``` +VideoOptionModel videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp"); +List list = new ArrayList<>(); +list.add(videoOphtionModel); +GSYVideoManager.instance().setOptionModelList(list); +``` + +#### 18、url切换400(http与https域名共用) + +``` +VideoOptionModel videoOptionModel = + new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1); + List list = new ArrayList<>(); + list.add(videoOptionModel); + GSYVideoManager.instance().setOptionModelList(list); +``` + +#### 19、全屏与非全屏的同步问题 + +有一些自定义操作,需要全屏与非全屏切换之间做同步处理,具体操作是重载下面两个方法,实现自己的自定义操作,详细可参考demo。 +外部获取当前播放器,推荐使用`play.getCurPlay().xxxxxx` +``` +/** + * 全屏时将对应处理参数逻辑赋给全屏播放器 + * + * @param context + * @param actionBar + * @param statusBar + * @return + */ +@Override +public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionBar, boolean statusBar) { + SmartPickVideo sampleVideo = (SmartPickVideo) super.startWindowFullscreen(context, actionBar, statusBar); + sampleVideo.mSourcePosition = mSourcePosition; + sampleVideo.mType = mType; + sampleVideo.mUrlList = mUrlList; + sampleVideo.mTypeText = mTypeText; + sampleVideo.mSwitchSize.setText(mTypeText); + return sampleVideo; +} +/** + * 推出全屏时将对应处理参数逻辑返回给非播放器 + * + * @param oldF + * @param vp + * @param gsyVideoPlayer + */ +@Override +protected void resolveNormalVideoShow(View oldF, ViewGroup vp, GSYVideoPlayer gsyVideoPlayer) { + super.resolveNormalVideoShow(oldF, vp, gsyVideoPlayer); + if (gsyVideoPlayer != null) { + SmartPickVideo sampleVideo = (SmartPickVideo) gsyVideoPlayer; + mSourcePosition = sampleVideo.mSourcePosition; + mType = sampleVideo.mType; + mTypeText = sampleVideo.mTypeText; + mSwitchSize.setText(mTypeText); + setUp(mUrlList, mCache, mCachePath, mTitle); + } +} +``` + +#### 20、精准的某个时间开始播放 + +注意,这个是全局地设置,设置之后如果不需要需要清除这个item。 +``` +VideoOptionModel videoOptionModel = + new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "seek-at-start", startPosition); + List list = new ArrayList<>(); + list.add(videoOptionModel); + GSYVideoManager.instance().setOptionModelList(list); +``` diff --git a/README.md b/README.md index 09eae9c05..6d342ccc5 100644 --- a/README.md +++ b/README.md @@ -1,136 +1,188 @@ ![](https://github.com/CarGuo/GSYVideoPlayer/blob/master/home_logo.png) -## 基于[IJKPlayer](https://github.com/Bilibili/ijkplayer),实现了多功能的视频播放器。 (请仔细阅读下方各项说明,大多数问题可在下方找到解答)。 - -* **支持基本的拖动,声音、亮度调节。** -* **支持边播边缓存,使用了[AndroidVideoCache](https://github.com/danikula/AndroidVideoCache)。** -* **支持视频本身自带rotation的旋转。** -* **增加了重力旋转与手动旋转的同步支持。** -* **支持列表播放。** -* **直接添加控件为封面。** -* **全屏和播放等的动画效果。** -* **列表的全屏效果优化,多种配置模式。** -* **列表的小窗口播放,可拖动。** -* **网络视频加载速度。** -* **锁定/解锁全屏点击功能。** -* **支持快播和慢播。** -* **调整显示比例:默认、16:9、4:3。** -* **暂停时前后台切换不黑屏** -* **调整不同清晰度的支持。** -* **支持IJKPlayer和EXOPlayer切换。** -* **进度条小窗口预览(测试)。** -* **Https支持。** -* **支持播放时旋转画面角度(0,90,180,270)。** -* **连续播放一个列表的视频。** -* **支持全屏与非全屏两套布局切换** -* **弹幕支持** -* **镜像旋转** +## 基于[IJKPlayer](https://github.com/Bilibili/ijkplayer)(兼容系统MediaPlayer与EXOPlayer2),实现了多功能的视频播放器。 (请仔细阅读下方各项说明,大多数问题可在下方找到解答)。 + +状态 | 功能 +-------- | --- +**支持**|**边播边缓存,使用了[AndroidVideoCache](https://github.com/danikula/AndroidVideoCache)。** +**支持**|**其他协议和编码concat、rtsp、hls、rtmp、crypto、mpeg等。** +**支持**|**DEMO演示获取视频第一帧等实现。** +**支持**|**简单滤镜(马赛克、黑白、色彩过滤、高斯、模糊、模糊等等20多种)。** +**支持**|**GL效果动画,(xyz轴旋转,放大)。** +**支持**|**视频帧截图功能,视频生成gif功能** +**支持**|**视频播放效果(水印、画面多重播放等)** +**支持**|**列表播放;列表连续播放;重力旋转与手动旋转;视频本身rotation旋转属性。** +**支持**|**全屏切换动画效果;小窗口播放,可拖动。** +**支持**|**快播和慢播;网络视频加载速度。** +**支持**|**调整显示比例:默认、16:9、4:3、填充。** +**支持**|**播放时旋转画面角度(0,90,180,270);镜像旋转。** +**支持**|**暂停前后台切换不黑屏;调整不同清晰度的支持;无缝切换支持。** +**支持**|**Https;IJKPlayer、EXOPlayer、系统播放器切换。** +**支持**|**锁定/解锁全屏点击功能;进度条小窗口预览(测试)。** +**支持**|**全屏与非全屏两套布局切换;弹幕功能。** +**支持**|**没有任何操作控件的纯播放支持。** +**支持**|**Demo带有RecyclerView列表滑动自动播放。** +**支持**|**多窗体下(包括桌面)的小窗口播放。** +**支持**|**同时播放多个视频** +**支持**|**片头广告、跳过广告支持。** +**支持**|**中简插入广告功能。** +**支持**|**可自定义渲染层、自定义管理层、自定义播放层。** + [![](https://jitpack.io/v/CarGuo/GSYVideoPlayer.svg)](https://jitpack.io/#CarGuo/GSYVideoPlayer) [ ![Download](https://api.bintray.com/packages/carguo/GSYVideoPlayer/gsyVideoPlayer/images/download.svg) ](https://bintray.com/carguo/GSYVideoPlayer/gsyVideoPlayer/_latestVersion) [![Build Status](https://travis-ci.org/CarGuo/GSYVideoPlayer.svg?branch=master)](https://travis-ci.org/CarGuo/GSYVideoPlayer) -## 使用依赖(支持jcenter和jitpack) +[]() +[![GitHub stars](https://img.shields.io/github/stars/CarGuo/GSYVideoPlayer.svg)](https://github.com/CarGuo/GSYVideoPlayer/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/CarGuo/GSYVideoPlayer.svg)](https://github.com/CarGuo/GSYVideoPlayer/network) +[![GitHub issues](https://img.shields.io/github/issues/CarGuo/GSYVideoPlayer.svg)](https://github.com/CarGuo/GSYVideoPlayer/issues) +[![GitHub license](https://img.shields.io/github/license/CarGuo/GSYVideoPlayer.svg)](https://github.com/CarGuo/GSYVideoPlayer/blob/master/LICENSE) -### 1、JCenter 引入方法 +### [微信赞赏链接](https://github.com/CarGuo/GSYVideoPlayer/blob/master/thanks.jpg) -#### 直接在module下的build.gradle添加 -``` -compile 'com.shuyu:GSYVideoPlayer:1.6.9' +## 一、使用依赖 -``` +##### 新版本调整了代码结构,如更新后显示类路径错误,参考demo调整包路径即可。 + +### 1、JCenter 引入方法(推荐) --------------------------------------------------------------------------------- +**你可以选择下面三种的其中一种,在module下的build.gradle添加。** -### 2、JitPack引入方法 -#### 在project下的build.gradle添加 +#### A、直接引入 ``` -allprojects { - repositories { - ... - maven { url 'https://jitpack.io' } - } -} +//完整版引入 +compile 'com.shuyu:GSYVideoPlayer:4.1.0' + ``` -#### 在module下的build.gradle添加 +#### B、添加java和你想要的so支持: ``` -dependencies { - compile 'com.github.CarGuo:GSYVideoPlayer:v1.6.9' -} +compile 'com.shuyu:gsyVideoPlayer-java:4.1.0' + +//根据你的需求 +compile 'com.shuyu:gsyVideoPlayer-armv5:4.1.0' +compile 'com.shuyu:gsyVideoPlayer-armv7a:4.1.0' +compile 'com.shuyu:gsyVideoPlayer-arm64:4.1.0' +compile 'com.shuyu:gsyVideoPlayer-x64:4.1.0' +compile 'com.shuyu:gsyVideoPlayer-x86:4.1.0' + ``` --------------------------------------------------------------------------------- +#### C、支持其他格式协议的(mpeg,rtsp, concat、crypto协议) -* ### 下方文档以及问题集锦,你想要知道的大部分都在里面。 +A、B普通版本支持263/264/265等,对于mpeg编码会有声音无画面情况。 +C 引入的so支持mpeg编码和其他补充协议,但是so包相对变大。 + +``` +compile 'com.shuyu:gsyVideoPlayer-java:4.1.0' -* ### 有问题请先下面问题集锦中查阅(如依赖不成功,播放不成功等等)。 +compile 'com.shuyu:gsyVideoPlayer-ex_so:4.1.0' -* ### QQ群,有兴趣的可以进来(群里平时可能比较吵):174815284 。 +``` --------------------------------------------------------------------------------- +### [--- 更多依赖方式请点击 - ](https://github.com/CarGuo/GSYVideoPlayer/blob/master/dependencies.md) -## 文档Wiki +## 二、其他推荐 -### [--- 使用说明、接口文档 - 入口](https://github.com/CarGuo/GSYVideoPlayer/wiki) +### * QQ群,有兴趣的欢迎(平时吹水吐槽多,因为人数饱和,目前开启付费入群):174815284 。 +### * [GSYGithubAPP 跨平台github客户端](https://github.com/CarGuo/GSYGithubAPP) +### * [RickText](https://github.com/CarGuo/RickText) +### * [LazyRecyclerAdapter](https://github.com/CarGuo/LazyRecyclerAdapter) -## 其他 +## 三、文档Wiki -### [--- 版本更新说明 - 入口](https://github.com/CarGuo/GSYVideoPlayer/blob/master/UPDATE_VERSION.md) -### [--- 问题集锦 - 入口 ](https://github.com/CarGuo/GSYVideoPlayer/blob/master/QUESTION.md) +### [--- 使用说明、接口文档 - 入口](https://github.com/CarGuo/GSYVideoPlayer/wiki) +### [--- 问题集锦 - 入口(大部分你遇到的问题都在这里解决) ](https://github.com/CarGuo/GSYVideoPlayer/blob/master/QUESTION.md) +### [--- 项目支持视频格式(如果遇上黑屏,没声音)](https://github.com/CarGuo/GSYVideoPlayer/blob/master/DECODERS.md) ### [--- IJKPlayer问题 - 入口](http://www.jianshu.com/p/220b00d00deb)  ### [--- IJKPlayer编译自定义SO - 入口](http://www.jianshu.com/p/bd289e25d272)  ### [--- 简书详解 (项目的基础)- 入口](http://www.jianshu.com/p/9fe377dd9750) -### [--- 项目支持视频格式(如果遇上黑屏,没声音)](https://github.com/CarGuo/GSYVideoPlayer/blob/master/DECODERS.md) +### [--- 版本更新说明 - 入口](https://github.com/CarGuo/GSYVideoPlayer/blob/master/UPDATE_VERSION.md) -  -## 运行效果 +## 四、运行效果 -* ### 1、打开一个播放 - +* ### 1、打开一个播放(旋转、镜像、填充) + -* ### 2、列表/详情模式 +* ### 2、列表/详情模式(动画、旋转、小窗体)
- - - + + +
* ### 3、弹幕 - + + +* ### 4、滤镜和GL动画 + +* ### 6、背景铺满模糊播放 -* ### 4、进度条小窗口预览 - + +* ### 7、进度条小窗口预览 + -## 近期版本 +## 五、近期版本 + +### 4.1.0 (2018-02-26) +* 1、update to ijk 0.8.8 +* 2、去除cache模块的log库依赖 +* 3、去除exo模块的无用依赖 +* 4、增加恢复播放方法参数 +``` + XXXXManager相关 +/** + * 恢复暂停状态 + * + * @param seek 是否产生seek动作,直播设置为false + */ + public static void onResume(String key, boolean seek) + + Video相关 + /** + * 恢复暂停状态 + * + * @param seek 是否产生seek动作 + */ + @Override + public void onVideoResume(boolean seek) +``` -### 1.6.9(2017-07-08) >>>> [片头广告功能推迟到1.7.0] -* 修改setup的设置参数。 -* 升级修改所有回调接口,回调接口中返回当前播放器。 -* 修正播放本地文件错误,会错删文件问题。 -* 兼容Appbar中使用,感谢[@loveRose](https://github.com/loveRose) -* 非全屏播放器可获取全屏播放器对象。 +### 4.0.0-beat1(2018-02-06) +* 1、新增简单片头广告支持。 +`GSYSampleADVideoPlayer 与 DetailADPlayer` +* 2、优化了ListGSYVideoPlayer、增加`playNext()`接口。 +* 3、优化代码结构,调整部分API接口(稍微调整下,偶尔有和旧版本不兼容的,参考源码和demo修改下方法名即可)。 +* 4、增加GSYVideoHelper视频帮助类,更加节省资源。 +* 5、增加GSYSampleCallBack节省继承,优化GSYVideoProgressListener的回调。 +* 6、增加GSYVideoViewBridge、重载`getGSYVideoManager()`方法实现自己的Manager。 +* 7、支持自定义渲染层,demo中`CustomRenderVideoPlayer`演示如何设置自定义渲染层。 +* 8、`ListMultiVideoActivity`和`MultiSampleVideo`演示如何同时播放多个视频。 +* 9、`DetailADPlayer2`和`ListADVideoActivity`演示广告与中间插入广告支持。 +* 10、增加音频焦点方法。 ``` /** - * 获取全屏播放器对象 - * - * @return GSYVideoPlayer 如果没有则返回空。 - */ -public GSYVideoPlayer getFullWindowPlayer() + * 长时间失去音频焦点,暂停播放器 + * + * @param releaseWhenLossAudio 默认true,false的时候只会暂停 + */ + public void setReleaseWhenLossAudio(boolean releaseWhenLossAudio) + ``` -### 更多版本请查阅:[版本更新说明](https://github.com/CarGuo/GSYVideoPlayer/blob/master/UPDATE_VERSION.md) -------------------- -## 关于Issues +### 更多版本请查阅:[版本更新说明](https://github.com/CarGuo/GSYVideoPlayer/blob/master/UPDATE_VERSION.md) + +## 六、关于Issues ``` 提问题前可先查阅上方文档和说明,请在Demo中复现问题。 @@ -143,13 +195,41 @@ public GSYVideoPlayer getFullWindowPlayer() 4、补充问题的机型,android版本。 ``` -## 混淆 +## 七、混淆 ``` +-keep class com.shuyu.gsyvideoplayer.video.** { *; } +-dontwarn com.shuyu.gsyvideoplayer.video.** +-keep class com.shuyu.gsyvideoplayer.video.base.** { *; } +-dontwarn com.shuyu.gsyvideoplayer.video.base.** +-keep class com.shuyu.gsyvideoplayer.utils.** { *; } +-dontwarn com.shuyu.gsyvideoplayer.utils.** -keep class tv.danmaku.ijk.** { *; } -dontwarn tv.danmaku.ijk.** --keep class com.shuyu.gsyvideoplayer.** { *; } --dontwarn com.shuyu.gsyvideoplayer.** + +-keep public class * extends android.view.View{ + *** get*(); + void set*(***); + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); +} +``` + +## 温馨提示 + +``` +关于自定义和出现问题的请先看问题集锦、demo、issue。 + +多了解一些音视频的基础常识,对容器,音视频编码,ffmpeg先做一些了解,以及mediacodec等的不同。 +尽量少出现为什么别的能播的问题哟。 + +播放器的可自定义还是挺高的,定制请参考demo,多看源码。现在的功能有些多,demo也在不断的更新。 + +一些新功能和项目结构也在不断的调整。 + +欢迎提出问题,谢谢。 + ``` ## 依赖大小参考 @@ -157,9 +237,19 @@ public GSYVideoPlayer getFullWindowPlayer() ![](https://ooo.0o0.ooo/2017/06/15/5941f343a39f5.png) +## 非常感谢您的支持 + +#### 撸码不易,如果对你有所帮助,欢迎您的赞赏 + +##### 微信赞赏码 + + + + ## License ``` 请参看IJKPlayer和AndroidVideoCache相关协议。 -项目最开始是从jiecao过来的,只是后来方向不同,所以慢慢的也异化了。 +项目最开始是从jiecao过来的,改着改着直接重构了。 +偶尔有一变量和方法名可能还有点jiaozi的影子,但是基本是一个新项目。 ``` diff --git a/UPDATE_VERSION.md b/UPDATE_VERSION.md index da0d77851..5dc3cd68a 100644 --- a/UPDATE_VERSION.md +++ b/UPDATE_VERSION.md @@ -1,5 +1,238 @@ ## 下方个版本说明,可以当做简单的wiki使用~,效果可参考DEMO。 +### 4.1.0 (2018-02-26) +* 1、update to ijk 0.8.8 +* 2、去除cache模块的log库依赖 +* 3、去除exo模块的无用依赖 +* 4、增加恢复播放方法参数 +``` + XXXXManager相关 +/** + * 恢复暂停状态 + * + * @param seek 是否产生seek动作,直播设置为false + */ + public static void onResume(String key, boolean seek) + + Video相关 + /** + * 恢复暂停状态 + * + * @param seek 是否产生seek动作 + */ + @Override + public void onVideoResume(boolean seek) + +``` + +### 4.0.0-beat1(2018-02-06) +* 1、新增简单片头广告支持。 +`GSYSampleADVideoPlayer 与 DetailADPlayer` +* 2、优化了ListGSYVideoPlayer、增加`playNext()`接口。 +* 3、优化代码结构,调整部分API接口(稍微调整下,偶尔有和旧版本不兼容的,参考源码和demo修改下方法名即可)。 +* 4、增加GSYVideoHelper视频帮助类,更加节省资源。 +* 5、增加GSYSampleCallBack节省继承,优化GSYVideoProgressListener的回调。 +* 6、增加GSYVideoViewBridge、重载`getGSYVideoManager()`方法实现自己的Manager。 +* 7、支持自定义渲染层,demo中`CustomRenderVideoPlayer`演示如何设置自定义渲染层。 +* 8、`ListMultiVideoActivity`和`MultiSampleVideo`演示如何同时播放多个视频。 +* 9、`DetailADPlayer2`和`ListADVideoActivity`演示广告与中间插入广告支持。 +* 10、增加音频焦点方法。 +``` +/** + * 长时间失去音频焦点,暂停播放器 + * + * @param releaseWhenLossAudio 默认true,false的时候只会暂停 + */ + public void setReleaseWhenLossAudio(boolean releaseWhenLossAudio) + +``` + + +### 3.0.0(2018-01-14) + +1、增肌PlayerManager,更新为ExoPlayer2,优化对ExoPlayer2的支持。 + +2、增加系统播放器AndroidMediaPlayer支持 + +3、增对列表增加setUpLazy方法,优化列表中可能的滑动卡顿 +``` + /** + * 在点击播放的时候才进行真正setup + */ + public boolean setUpLazy(String url, boolean cacheWithPlay, File cachePath, Map mapHeadData, String title) + +``` +4、优化GL渲染和处理切换渲染效果崩溃。 + + + +5、DEMO增加SamllVideoHelper实现小窗口逻辑,更新demo + + + +6、优化触摸的音量、亮度、进度的弹出框,优化可自定义程度 +``` + /** + * 触摸进度dialog的layoutId + * 继承后重写可返回自定义 + * 有自定义的实现逻辑可重载showProgressDialog方法 + */ + protected int getProgressDialogLayoutId() + /** + * 触摸进度dialog的进度条id + * 继承后重写可返回自定义,如果没有可返回空 + * 有自定义的实现逻辑可重载showProgressDialog方法 + */ + protected int getProgressDialogProgressId() + + /** + * 触摸进度dialog的当前时间文本 + * 继承后重写可返回自定义,如果没有可返回空 + * 有自定义的实现逻辑可重载showProgressDialog方法 + */ + protected int getProgressDialogCurrentDurationTextId() + + /** + * 触摸进度dialog全部时间文本 + * 继承后重写可返回自定义,如果没有可返回空 + * 有自定义的实现逻辑可重载showProgressDialog方法 + */ + protected int getProgressDialogAllDurationTextId() + + /** + * 触摸进度dialog的图片id + * 继承后重写可返回自定义,如果没有可返回空 + * 有自定义的实现逻辑可重载showProgressDialog方法 + */ + protected int getProgressDialogImageId() + + /** + * 音量dialog的layoutId + * 继承后重写可返回自定义 + * 有自定义的实现逻辑可重载showVolumeDialog方法 + */ + protected int getVolumeLayoutId() + /** + * 音量dialog的百分比进度条 id + * 继承后重写可返回自定义,如果没有可返回空 + * 有自定义的实现逻辑可重载showVolumeDialog方法 + */ + protected int getVolumeProgressId() + + /** + * 亮度dialog的layoutId + * 继承后重写可返回自定义 + * 有自定义的实现逻辑可重载showBrightnessDialog方法 + */ + protected int getBrightnessLayoutId() + + /** + * 亮度dialog的百分比text id + * 继承后重写可返回自定义,如果没有可返回空 + * 有自定义的实现逻辑可重载showBrightnessDialog方法 + */ + protected int getBrightnessTextId() + +``` + + +### 2.1.3(2017-12-24) +* update demo gradle to 4.1 +* 增加对CollapsingToolbarLayout的支持与demo +* 多窗体下(包括桌面)的小窗口播放(WindowActivity)。 +* 增加播放进度回调 +``` +/** + * 进度回调 + */ +public void setGSYVideoProgressListener(GSYVideoProgressListener videoProgressListener) +``` + +### 2.1.2(2017-12-08) +* 增加针对Prepared之前调用OnVideoPause的处理 +* 背景视频模糊铺满,前方视频正常播放 +``` +DetailFilterActivity中注释的 +//高斯拉伸视频铺满背景,替换黑色,前台正常比例播放 +``` + + +### 2.1.1(2017-10-29) +* videoCache模式支持增加header +* 增加无缝切换视频DEMO SmartPickVideo +* 调整部分代码路径,优化代码 +* log输入等级接口 +``` +GSYVideoManager.instance().setLogLevel(IjkMediaPlayer.IJK_LOG_SILENT); +``` + +### 2.1.0(2017-10-10) +* 增加了视频帧合成gif功能(DEMO DetailControlActivity中)。 +* update ijkplayer 0.84 + +### 2.0.9(2017-10-02) +* 增加顶层效果渲染的动画效果。 +* 增加截图功能。 +* 增加自定义render支持。 +* 增加水印、多重播放等。 + + +### 2.0.8(2017-09-17) +* 增加GSYBaseActivityDetail抽象类,方便detail模式集成。 +* 内部增加一些优化。 +* 增加简单滤镜功能支持。 +``` +1、全局设置 +GSYVideoType.setRenderType(GSYVideoType.GLSURFACE); +2、设置滤镜 +player.setEffectFilter(new BarrelBlurEffect()); +``` + + +### 2.0.7(2017-09-13) + +* 优化增加了断网自动续连,需要为http前加上 "ijkhttphook:http://ssss" +* update ijk to 0.8.3 +* 增加了demo中seekto精准定位,解决某些视频seek之后从头播放 + +### 2.0.6(2017-08-31) +* 调整了返回按键显示的问题。 +* 修改了全屏可能出现缓冲不消失问题。 +* 优化了双击问题。 + +### 2.0.5(2017-08-26) +* 增加双击暂停开始。 +* 增加了SurfaceView的支持:GSYVideoType.setRenderType(GSYVideoType.SUFRACE)。 +* 优化了触摸问题、内存问题、dismisstime问题。 + +### 2.0.4(2017-08-08) +* 增加了空播放ui支持。 +* 调整了GSYVideoOptionBuilder。 +* 修改了已知问题。 +* 增加了播放中调整播放速度接口。 +``` +public void setSpeedPlaying(float speed, boolean soundTouch) +``` + +### 2.0.3(2017-08-06) +* update ijk to 0.8.2 +* fix rtsp 播放问题 +* fix 小窗口播放问题 +* 调整了部分代码逻辑与结构。 + +### 2.0.2(2017-07-16) +* 完美实现播放、暂停、前后台切换、画面调整等情况不黑屏不突变,删除coverImageView类。 +* 增加了6.0下变调不变速接口 +* update ijkPlayer to 0.8.1 + +### 2.0.1(2017-07-11) +* 优化了TextureView显示 +* 修复SampleView的暂停问题 + + +### 2.0.0(2017-07-10) +* 项目结构调整,增加了新的so支持。 + ### 1.6.9(2017-07-08) * 修改setup的设置参数。 diff --git a/app/11.gif b/app/11.gif new file mode 100644 index 000000000..d918576a3 Binary files /dev/null and b/app/11.gif differ diff --git a/app/22.gif b/app/22.gif new file mode 100644 index 000000000..6671ea70c Binary files /dev/null and b/app/22.gif differ diff --git a/app/33.gif b/app/33.gif new file mode 100644 index 000000000..ee109696b Binary files /dev/null and b/app/33.gif differ diff --git a/app/44.gif b/app/44.gif new file mode 100644 index 000000000..6f759a2fe Binary files /dev/null and b/app/44.gif differ diff --git a/app/55.gif b/app/55.gif new file mode 100644 index 000000000..fc6253ef9 Binary files /dev/null and b/app/55.gif differ diff --git a/app/build.gradle b/app/build.gradle index 6eb40c7fa..ce3bb535d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,5 @@ apply plugin: 'com.android.application' -apply plugin: 'com.neenbedankt.android-apt' + android { @@ -13,10 +13,12 @@ android { minSdkVersion globalConfiguration.androidMinSdkVersion targetSdkVersion globalConfiguration.androidTargetSdkVersion - versionCode 3 - versionName "1.4.9" - + versionCode 5 + versionName "4.0.0" + javaCompileOptions { + annotationProcessorOptions.includeCompileClasspath = true + } ndk { //设置支持的SO库架构 abiFilters 'armeabi', 'armeabi-v7a', 'x86' @@ -45,18 +47,35 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(dir: 'libs', include: ['*.jar']) def viewDependencies = rootProject.ext.viewDependencies def androidDependencies = rootProject.ext.androidDependencies def dataDependencies = rootProject.ext.dataDependencies - apt viewDependencies.apt_butterKnife - compile viewDependencies.butterKnife - compile androidDependencies.recyclerView - compile viewDependencies.DanmakuFlameMaster - compile viewDependencies.ndkbitmap_armv7a - compile viewDependencies.ndkbitmap_armv5 - compile viewDependencies.ndkbitmap_x86 - compile androidDependencies.support_v4 + annotationProcessor viewDependencies.apt_butterKnife //debugCompile dataDependencies.leakcanary - compile project(':gsyVideoPlayer') + implementation viewDependencies.butterKnife + implementation androidDependencies.recyclerView + implementation viewDependencies.DanmakuFlameMaster + implementation viewDependencies.ndkbitmap_armv7a + implementation viewDependencies.ndkbitmap_armv5 + implementation viewDependencies.ndkbitmap_x86 + implementation viewDependencies.glide + implementation viewDependencies.glideProcessor + implementation androidDependencies.support_v4 + implementation androidDependencies.design + + implementation project(':gsyVideoPlayer') + //jcenter + //implementation "com.shuyu:GSYVideoPlayer:$gsyVideoVersion" + + //implementation "com.shuyu:gsyVideoPlayer-java:$gsyVideoVersion' + + //implementation "com.shuyu:gsyVideoPlayer-armv5:$gsyVideoVersion" + //implementation "com.shuyu:gsyVideoPlayer-armv7a:$gsyVideoVersion" + //implementation "com.shuyu:gsyVideoPlayer-arm64:$gsyVideoVersion" + //implementation "com.shuyu:gsyVideoPlayer-x64:$gsyVideoVersion" + //implementation "com.shuyu:gsyVideoPlayer-x86:$gsyVideoVersion" + + //implementation "com.shuyu:gsyVideoPlayer-ex_so:$gsyVideoVersion" + } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 39b7c73b0..31101cb63 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -40,12 +40,6 @@ native ; } - --keepclassmembers class fqcn.of.javascript.interface.for.webview { - public *; -} - - -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; @@ -77,7 +71,53 @@ public static ** valueOf(java.lang.String); } --keep class com.shuyu.gsyvideoplayer.** { *; } --dontwarn com.shuyu.gsyvideoplayer.** +# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆 +-keepclassmembers class * { + void *(**On*Event); + void *(**On*Listener); +} + +-keepclassmembers class * extends android.webkit.webViewClient { + public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); + public boolean *(android.webkit.WebView, java.lang.String); +} +-keepclassmembers class * extends android.webkit.webViewClient { + public void *(android.webkit.webView, jav.lang.String); +} + + +# ButterKnife +-keep class butterknife.** { *; } +-dontwarn butterknife.internal.** +-keep class **$$ViewBinder { *; } +-keepclasseswithmembernames class * { + @butterknife.* ; +} +-keepclasseswithmembernames class * { + @butterknife.* ; +} + +# Glide +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { + **[] $VALUES; + public *; +} + + +# 保留我们自定义控件(继承自View)不被混淆 +-keep public class * extends android.view.View{ + *** get*(); + void set*(***); + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); +} +-keep class com.shuyu.gsyvideoplayer.video.** { *; } +-dontwarn com.shuyu.gsyvideoplayer.video.** +-keep class com.shuyu.gsyvideoplayer.video.base.** { *; } +-dontwarn com.shuyu.gsyvideoplayer.video.base.** +-keep class com.shuyu.gsyvideoplayer.utils.** { *; } +-dontwarn com.shuyu.gsyvideoplayer.utils.** -keep class tv.danmaku.ijk.** { *; } -dontwarn tv.danmaku.ijk.** \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 66a5dc411..30de99fb4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -8,7 +9,7 @@ -   + - + + + + + + + + + + + + + android:theme="@style/Theme.AppCompat.Translucent" /> + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/gsyvideoplayer/AutoPlayRecyclerViewActivity.java b/app/src/main/java/com/example/gsyvideoplayer/AutoPlayRecyclerViewActivity.java new file mode 100644 index 000000000..5f22bc3ad --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/AutoPlayRecyclerViewActivity.java @@ -0,0 +1,144 @@ +package com.example.gsyvideoplayer; + + +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.os.Build; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.transition.Explode; +import android.view.Window; + +import com.example.gsyvideoplayer.adapter.RecyclerBaseAdapter; +import com.example.gsyvideoplayer.adapter.RecyclerNormalAdapter; +import com.example.gsyvideoplayer.model.VideoModel; +import com.example.gsyvideoplayer.utils.ScrollCalculatorHelper; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.utils.CommonUtil; +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * 类似微博视频,滑动到具体位置自动播放 + */ +public class AutoPlayRecyclerViewActivity extends AppCompatActivity { + + + @BindView(R.id.list_item_recycler) + RecyclerView videoList; + + LinearLayoutManager linearLayoutManager; + + RecyclerBaseAdapter recyclerBaseAdapter; + + List dataList = new ArrayList<>(); + + boolean mFull = false; + + ScrollCalculatorHelper scrollCalculatorHelper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + // 设置一个exit transition + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + getWindow().setEnterTransition(new Explode()); + getWindow().setExitTransition(new Explode()); + } + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_recycler_view); + ButterKnife.bind(this); + + resolveData(); + + + //限定范围为屏幕一半的上下偏移180 + int playTop = CommonUtil.getScreenHeight(this) / 2 - CommonUtil.dip2px(this, 180); + int playBottom = CommonUtil.getScreenHeight(this) / 2 + CommonUtil.dip2px(this, 180); + //自定播放帮助类 + scrollCalculatorHelper = new ScrollCalculatorHelper(R.id.video_item_player, playTop, playBottom); + + final RecyclerNormalAdapter recyclerNormalAdapter = new RecyclerNormalAdapter(this, dataList); + linearLayoutManager = new LinearLayoutManager(this); + videoList.setLayoutManager(linearLayoutManager); + videoList.setAdapter(recyclerNormalAdapter); + + videoList.addOnScrollListener(new RecyclerView.OnScrollListener() { + + int firstVisibleItem, lastVisibleItem; + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + scrollCalculatorHelper.onScrollStateChanged(recyclerView, newState); + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition(); + lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); + + //这是滑动自动播放的代码 + if (!mFull) { + scrollCalculatorHelper.onScroll(recyclerView, firstVisibleItem, lastVisibleItem, lastVisibleItem - firstVisibleItem); + } + } + }); + + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + //如果旋转了就全屏 + if (newConfig.orientation != ActivityInfo.SCREEN_ORIENTATION_USER) { + mFull = false; + } else { + mFull = true; + } + + } + + @Override + public void onBackPressed() { + if (GSYVideoManager.backFromWindowFull(this)) { + return; + } + super.onBackPressed(); + } + + @Override + protected void onPause() { + super.onPause(); + GSYVideoManager.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + GSYVideoManager.onResume(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + GSYVideoManager.releaseAllVideos(); + } + + + private void resolveData() { + for (int i = 0; i < 19; i++) { + VideoModel videoModel = new VideoModel(); + dataList.add(videoModel); + } + if (recyclerBaseAdapter != null) + recyclerBaseAdapter.notifyDataSetChanged(); + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/DanmkuVideoActivity.java b/app/src/main/java/com/example/gsyvideoplayer/DanmkuVideoActivity.java index 07a91513c..971551bee 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/DanmkuVideoActivity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/DanmkuVideoActivity.java @@ -9,10 +9,10 @@ import android.widget.ImageView; import android.widget.RelativeLayout; -import com.example.gsyvideoplayer.listener.SampleListener; import com.example.gsyvideoplayer.video.DanmakuVideoPlayer; -import com.shuyu.gsyvideoplayer.GSYPreViewManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; import com.shuyu.gsyvideoplayer.listener.LockClickListener; import com.shuyu.gsyvideoplayer.utils.OrientationUtils; import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; @@ -54,7 +54,8 @@ protected void onCreate(Bundle savedInstanceState) { danmakuVideoPlayer.setShrinkImageRes(R.drawable.custom_shrink); danmakuVideoPlayer.setEnlargeImageRes(R.drawable.custom_enlarge); - String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; + //String url = "https://res.exexm.com/cw_145225549855002"; + String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; //String url = "https://res.exexm.com/cw_145225549855002"; danmakuVideoPlayer.setUp(url, true, null, "测试视频"); @@ -90,7 +91,7 @@ public void onClick(View v) { } }); - danmakuVideoPlayer.setStandardVideoAllCallBack(new SampleListener() { + danmakuVideoPlayer.setVideoAllCallBack(new GSYSampleCallBack() { @Override public void onPrepared(String url, Object... objects) { super.onPrepared(url, objects); @@ -137,7 +138,7 @@ public void onBackPressed() { orientationUtils.backToProtVideo(); } - if (StandardGSYVideoPlayer.backFromWindowFull(this)) { + if (GSYVideoManager.backFromWindowFull(this)) { return; } super.onBackPressed(); @@ -146,12 +147,14 @@ public void onBackPressed() { @Override protected void onPause() { + getCurPlay().onVideoPause(); super.onPause(); isPause = true; } @Override protected void onResume() { + getCurPlay().onVideoResume(); super.onResume(); isPause = false; } @@ -159,29 +162,21 @@ protected void onResume() { @Override protected void onDestroy() { super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); + if (isPlay) { + getCurPlay().release(); + } + //GSYPreViewManager.instance().releaseMediaPlayer(); if (orientationUtils != null) orientationUtils.releaseListener(); } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //如果旋转了就全屏 if (isPlay && !isPause) { - if (newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_USER) { - if (!danmakuVideoPlayer.isIfCurrentIsFullscreen()) { - danmakuVideoPlayer.startWindowFullscreen(DanmkuVideoActivity.this, true, true); - } - } else { - //新版本isIfCurrentIsFullscreen的标志位内部提前设置了,所以不会和手动点击冲突 - if (danmakuVideoPlayer.isIfCurrentIsFullscreen()) { - StandardGSYVideoPlayer.backFromWindowFull(this); - } - if (orientationUtils != null) { - orientationUtils.setEnable(true); - } - } + danmakuVideoPlayer.onConfigurationChanged(this, newConfig, orientationUtils, true, true); } } @@ -189,8 +184,14 @@ public void onConfigurationChanged(Configuration newConfig) { private void resolveNormalVideoUI() { //增加title danmakuVideoPlayer.getTitleTextView().setVisibility(View.GONE); - danmakuVideoPlayer.getTitleTextView().setText("测试视频"); danmakuVideoPlayer.getBackButton().setVisibility(View.GONE); } + private GSYVideoPlayer getCurPlay() { + if (danmakuVideoPlayer.getFullWindowPlayer() != null) { + return danmakuVideoPlayer.getFullWindowPlayer(); + } + return danmakuVideoPlayer; + } + } \ No newline at end of file diff --git a/app/src/main/java/com/example/gsyvideoplayer/DetailADPlayer.java b/app/src/main/java/com/example/gsyvideoplayer/DetailADPlayer.java new file mode 100644 index 000000000..a63288adf --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/DetailADPlayer.java @@ -0,0 +1,128 @@ +package com.example.gsyvideoplayer; + +import android.os.Bundle; +import android.support.v4.widget.NestedScrollView; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; + + +import com.shuyu.gsyvideoplayer.GSYBaseActivityDetail; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.listener.LockClickListener; +import com.shuyu.gsyvideoplayer.video.GSYSampleADVideoPlayer; +import com.shuyu.gsyvideoplayer.video.ListGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; + + +public class DetailADPlayer extends GSYBaseActivityDetail { + + + @BindView(R.id.post_detail_nested_scroll) + NestedScrollView postDetailNestedScroll; + @BindView(R.id.ad_player) + GSYSampleADVideoPlayer detailPlayer; + @BindView(R.id.activity_detail_player) + RelativeLayout activityDetailPlayer; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_detail_ad_player); + ButterKnife.bind(this); + + //普通模式 + initVideo(); + + ArrayList urls = new ArrayList<>(); + //广告1 + urls.add(new GSYSampleADVideoPlayer.GSYADVideoModel("http://video.7k.cn/app_video/20171202/6c8cf3ea/v.m3u8.mp4", + "", GSYSampleADVideoPlayer.GSYADVideoModel.TYPE_AD)); + //正式内容1 + urls.add(new GSYSampleADVideoPlayer.GSYADVideoModel("http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4", + "正文1标题", GSYSampleADVideoPlayer.GSYADVideoModel.TYPE_NORMAL)); + //广告2 + urls.add(new GSYSampleADVideoPlayer.GSYADVideoModel("http://video.7k.cn/app_video/20171202/6c8cf3ea/v.m3u8.mp4", + "", GSYSampleADVideoPlayer.GSYADVideoModel.TYPE_AD, true)); + //正式内容2 + urls.add(new GSYSampleADVideoPlayer.GSYADVideoModel("http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f30.mp4", + "正文2标题", GSYSampleADVideoPlayer.GSYADVideoModel.TYPE_NORMAL)); + + detailPlayer.setAdUp(urls, true, 0); + + //增加封面 + ImageView imageView = new ImageView(this); + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setImageResource(R.mipmap.xxx1); + detailPlayer.setThumbImageView(imageView); + + resolveNormalVideoUI(); + + detailPlayer.setIsTouchWiget(true); + //关闭自动旋转 + detailPlayer.setRotateViewAuto(false); + detailPlayer.setLockLand(false); + detailPlayer.setShowFullAnimation(false); + detailPlayer.setNeedLockFull(true); + + detailPlayer.setVideoAllCallBack(this); + + detailPlayer.setLockClickListener(new LockClickListener() { + @Override + public void onClick(View view, boolean lock) { + if (orientationUtils != null) { + //配合下方的onConfigurationChanged + orientationUtils.setEnable(!lock); + } + } + }); + + } + + @Override + public ListGSYVideoPlayer getGSYVideoPlayer() { + return detailPlayer; + } + + @Override + public GSYVideoOptionBuilder getGSYVideoOptionBuilder() { + //不需要builder的 + return null; + } + + @Override + public void clickForFullScreen() { + + } + + /** + * 是否启动旋转横屏,true表示启动 + * + * @return true + */ + @Override + public boolean getDetailOrientationRotateAuto() { + return true; + } + + @Override + public void onEnterFullscreen(String url, Object... objects) { + super.onEnterFullscreen(url, objects); + //隐藏调全屏对象的返回按键 + GSYVideoPlayer gsyVideoPlayer = (GSYVideoPlayer) objects[1]; + gsyVideoPlayer.getBackButton().setVisibility(View.GONE); + } + + + private void resolveNormalVideoUI() { + //增加title + detailPlayer.getTitleTextView().setVisibility(View.VISIBLE); + detailPlayer.getBackButton().setVisibility(View.VISIBLE); + } +} + diff --git a/app/src/main/java/com/example/gsyvideoplayer/DetailADPlayer2.java b/app/src/main/java/com/example/gsyvideoplayer/DetailADPlayer2.java new file mode 100644 index 000000000..0e128cd10 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/DetailADPlayer2.java @@ -0,0 +1,153 @@ +package com.example.gsyvideoplayer; + +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; + +import com.shuyu.gsyvideoplayer.GSYBaseADActivityDetail; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.listener.GSYVideoProgressListener; +import com.shuyu.gsyvideoplayer.listener.LockClickListener; +import com.shuyu.gsyvideoplayer.video.NormalGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.GSYADVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; + +/** + * 带广告播放,支持中间插入广告模式 + */ +public class DetailADPlayer2 extends GSYBaseADActivityDetail { + + private NormalGSYVideoPlayer detailPlayer; + + private GSYADVideoPlayer adPlayer; + + private String urlAd = "http://video.7k.cn/app_video/20171202/6c8cf3ea/v.m3u8.mp4"; + + private String urlAd2 = "http://video.7k.cn/app_video/20171202/6c8cf3ea/v.m3u8.mp4"; + + private String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_detail_ad_player2); + + detailPlayer = (NormalGSYVideoPlayer) findViewById(R.id.detail_player); + adPlayer = (GSYADVideoPlayer) findViewById(R.id.ad_player); + + //普通模式 + resolveNormalVideoUI(); + + initVideoBuilderMode(); + + detailPlayer.setLockClickListener(new LockClickListener() { + @Override + public void onClick(View view, boolean lock) { + if (orientationUtils != null) { + //配合下方的onConfigurationChanged + orientationUtils.setEnable(!lock); + } + } + }); + detailPlayer.setStartAfterPrepared(false); + detailPlayer.setReleaseWhenLossAudio(false); + + detailPlayer.setGSYVideoProgressListener(new GSYVideoProgressListener() { + private int preSecond = 0; + @Override + public void onProgress(int progress, int secProgress, int currentPosition, int duration) { + //在5秒的时候弹出中间广告 + int currentSecond = currentPosition / 1000; + if (currentSecond == 5 && currentSecond != preSecond) { + detailPlayer.getCurrentPlayer().onVideoPause(); + getGSYADVideoOptionBuilder().setUrl(urlAd2).build(adPlayer); + startAdPlay(); + } + preSecond = currentSecond; + } + }); + + } + + @Override + public NormalGSYVideoPlayer getGSYVideoPlayer() { + return detailPlayer; + } + + @Override + public GSYADVideoPlayer getGSYADVideoPlayer() { + return adPlayer; + } + + @Override + public GSYVideoOptionBuilder getGSYVideoOptionBuilder() { + //不需要builder的 + ImageView imageView = new ImageView(this); + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setImageResource(R.mipmap.xxx1); + return getCommonBuilder() + .setUrl(url) + .setThumbImageView(imageView); + } + + @Override + public GSYVideoOptionBuilder getGSYADVideoOptionBuilder() { + return getCommonBuilder() + .setUrl(urlAd); + } + + @Override + public void clickForFullScreen() { + + } + + /** + * 需要片头广告 + */ + @Override + public boolean isNeedAdOnStart() { + return true; + } + + /** + * 是否启动旋转横屏,true表示启动 + * + * @return true + */ + @Override + public boolean getDetailOrientationRotateAuto() { + return true; + } + + @Override + public void onEnterFullscreen(String url, Object... objects) { + super.onEnterFullscreen(url, objects); + //隐藏调全屏对象的返回按键 + GSYVideoPlayer gsyVideoPlayer = (GSYVideoPlayer) objects[1]; + gsyVideoPlayer.getBackButton().setVisibility(View.GONE); + } + + /** + * 公用的视频配置 + */ + private GSYVideoOptionBuilder getCommonBuilder() { + return new GSYVideoOptionBuilder() + .setCacheWithPlay(true) + .setVideoTitle(" ") + .setFullHideActionBar(true) + .setFullHideStatusBar(true) + .setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setShowFullAnimation(false)//打开动画 + .setNeedLockFull(true) + .setSeekRatio(1); + } + + private void resolveNormalVideoUI() { + //增加title + detailPlayer.getTitleTextView().setVisibility(View.VISIBLE); + detailPlayer.getBackButton().setVisibility(View.VISIBLE); + } +} + diff --git a/app/src/main/java/com/example/gsyvideoplayer/DetailControlActivity.java b/app/src/main/java/com/example/gsyvideoplayer/DetailControlActivity.java new file mode 100644 index 000000000..011d68a03 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/DetailControlActivity.java @@ -0,0 +1,358 @@ +package com.example.gsyvideoplayer; + +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.v4.widget.NestedScrollView; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.Toast; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.example.gsyvideoplayer.utils.CommonUtil; +import com.example.gsyvideoplayer.utils.JumpUtils; +import com.example.gsyvideoplayer.video.SampleControlVideo; +import com.shuyu.gsyvideoplayer.GSYBaseActivityDetail; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.listener.GSYVideoGifSaveListener; +import com.shuyu.gsyvideoplayer.listener.GSYVideoShotListener; +import com.shuyu.gsyvideoplayer.listener.LockClickListener; +import com.shuyu.gsyvideoplayer.model.VideoOptionModel; +import com.shuyu.gsyvideoplayer.utils.Debuger; +import com.shuyu.gsyvideoplayer.utils.FileUtils; +import com.shuyu.gsyvideoplayer.utils.GifCreateHelper; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import tv.danmaku.ijk.media.player.IjkMediaPlayer; + +/** + * sampleVideo支持全屏与非全屏切换的清晰度,旋转,镜像等功能. + * Activity可以继承GSYBaseActivityDetail实现详情模式的页面 + * 或者参考DetailPlayer、DetailListPlayer实现 + *

+ * Created by guoshuyu on 2017/6/18. + */ + +public class DetailControlActivity extends GSYBaseActivityDetail { + + @BindView(R.id.post_detail_nested_scroll) + NestedScrollView postDetailNestedScroll; + + @BindView(R.id.detail_player) + SampleControlVideo detailPlayer; + + @BindView(R.id.activity_detail_player) + RelativeLayout activityDetailPlayer; + + @BindView(R.id.change_speed) + Button changeSpeed; + + + @BindView(R.id.jump) + Button jump; + + @BindView(R.id.shot) + Button shot; + + @BindView(R.id.start_gif) + Button startGif; + + @BindView(R.id.stop_gif) + Button stopGif; + + @BindView(R.id.loadingView) + View loadingView; + + private String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + //private String url = "https://ruigongkao.oss-cn-shenzhen.aliyuncs.com/transcode/video/source/video/8908d124aa839d0d3fa9593855ef5957.m3u8"; + //private String url2 = "http://ruigongkao.oss-cn-shenzhen.aliyuncs.com/transcode/video/source/video/3aca1a0db8db9418dcbc765848c8903e.m3u8"; + + + private GifCreateHelper mGifCreateHelper; + + private float speed = 1; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_detail_control); + ButterKnife.bind(this); + + resolveNormalVideoUI(); + + initVideoBuilderMode(); + + initGifHelper(); + + detailPlayer.setLockClickListener(new LockClickListener() { + @Override + public void onClick(View view, boolean lock) { + //if (orientationUtils != null) { + //配合下方的onConfigurationChanged + //orientationUtils.setEnable(!lock); + //} + } + }); + + changeSpeed.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + resolveTypeUI(); + } + }); + + /*VideoOptionModel videoOptionModel = + new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1); + List list = new ArrayList<>(); + list.add(videoOptionModel); + videoOptionModel = + new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp"); + list.add(videoOptionModel); + GSYVideoManager.instance().setOptionModelList(list);*/ + + jump.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + JumpUtils.gotoControl(DetailControlActivity.this); + //startActivity(new Intent(DetailControlActivity.this, MainActivity.class)); + } + }); + + shot.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + shotImage(v); + } + }); + + + startGif.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startGif(); + } + }); + + stopGif.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + stopGif(); + } + }); + + loadingView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //do nothing + } + }); + } + + @Override + public StandardGSYVideoPlayer getGSYVideoPlayer() { + return detailPlayer; + } + + @Override + public GSYVideoOptionBuilder getGSYVideoOptionBuilder() { + //内置封面可参考SampleCoverVideo + ImageView imageView = new ImageView(this); + loadCover(imageView, url); + return new GSYVideoOptionBuilder() + .setThumbImageView(imageView) + .setUrl(url) + .setCacheWithPlay(true) + .setVideoTitle(" ") + .setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setShowFullAnimation(true)//打开动画 + .setNeedLockFull(true) + .setSeekRatio(1); + } + + @Override + public void clickForFullScreen() { + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mGifCreateHelper.cancelTask(); + } + + + /*******************************竖屏全屏开始************************************/ + + @Override + public void initVideo() { + super.initVideo(); + //重载后实现点击,不横屏 + if (getGSYVideoPlayer().getFullscreenButton() != null) { + getGSYVideoPlayer().getFullscreenButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //第一个true是否需要隐藏actionbar,第二个true是否需要隐藏statusbar + getGSYVideoPlayer().startWindowFullscreen(DetailControlActivity.this, true, true); + } + }); + } + } + + + /** + * 是否启动旋转横屏,true表示启动 + * + * @return true + */ + @Override + public boolean getDetailOrientationRotateAuto() { + return false; + } + + //重载后关闭重力旋转 + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + orientationUtils.setEnable(false); + } + + //重载后不做任何事情,实现竖屏全屏 + @Override + public void onQuitFullscreen(String url, Object... objects) { + super.onQuitFullscreen(url, objects); + } + + /*******************************竖屏全屏结束************************************/ + + private void initGifHelper() { + mGifCreateHelper = new GifCreateHelper(detailPlayer, new GSYVideoGifSaveListener() { + @Override + public void result(boolean success, File file) { + detailPlayer.post(new Runnable() { + @Override + public void run() { + loadingView.setVisibility(View.GONE); + Toast.makeText(detailPlayer.getContext(), "创建成功", Toast.LENGTH_LONG).show(); + } + }); + } + + @Override + public void process(int curPosition, int total) { + Debuger.printfError(" current " + curPosition + " total " + total); + } + }); + } + + + /** + * 开始gif截图 + */ + private void startGif() { + //开始缓存各个帧 + mGifCreateHelper.startGif(new File(FileUtils.getPath())); + + } + + /** + * 生成gif + */ + private void stopGif() { + loadingView.setVisibility(View.VISIBLE); + mGifCreateHelper.stopGif(new File(FileUtils.getPath(), "GSY-Z-" + System.currentTimeMillis() + ".gif")); + } + + + /** + * 视频截图 + */ + private void shotImage(final View v) { + //获取截图 + detailPlayer.taskShotPic(new GSYVideoShotListener() { + @Override + public void getBitmap(Bitmap bitmap) { + if (bitmap != null) { + try { + CommonUtil.saveBitmap(bitmap); + } catch (FileNotFoundException e) { + showToast("save fail "); + e.printStackTrace(); + return; + } + showToast("save success "); + } else { + showToast("get bitmap fail "); + } + } + }); + + } + + + private void loadCover(ImageView imageView, String url) { + + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setImageResource(R.mipmap.xxx1); + + Glide.with(this.getApplicationContext()) + .setDefaultRequestOptions( + new RequestOptions() + .frame(3000000) + .centerCrop() + .error(R.mipmap.xxx2) + .placeholder(R.mipmap.xxx1)) + .load(url) + .into(imageView); + } + + private void resolveNormalVideoUI() { + //增加title + detailPlayer.getTitleTextView().setVisibility(View.GONE); + detailPlayer.getBackButton().setVisibility(View.GONE); + } + + /** + * 显示比例 + * 注意,GSYVideoType.setShowType是全局静态生效,除非重启APP。 + */ + private void resolveTypeUI() { + if (speed == 1) { + speed = 1.5f; + } else if (speed == 1.5f) { + speed = 2f; + } else if (speed == 2) { + speed = 0.5f; + } else if (speed == 0.5f) { + speed = 0.25f; + } else if (speed == 0.25f) { + speed = 1; + } + changeSpeed.setText("播放速度:" + speed); + detailPlayer.setSpeedPlaying(speed, true); + } + + + private void showToast(final String tip) { + detailPlayer.post(new Runnable() { + @Override + public void run() { + Toast.makeText(DetailControlActivity.this, tip, Toast.LENGTH_LONG).show(); + } + }); + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/DetailFilterActivity.java b/app/src/main/java/com/example/gsyvideoplayer/DetailFilterActivity.java new file mode 100644 index 000000000..969aceacd --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/DetailFilterActivity.java @@ -0,0 +1,575 @@ +package com.example.gsyvideoplayer; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.opengl.Matrix; +import android.os.Bundle; +import android.support.v4.widget.NestedScrollView; +import android.util.TypedValue; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.Toast; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.example.gsyvideoplayer.effect.BitmapIconEffect; +import com.example.gsyvideoplayer.effect.GSYVideoGLViewCustomRender; +import com.example.gsyvideoplayer.effect.GSYVideoGLViewCustomRender2; +import com.example.gsyvideoplayer.effect.GSYVideoGLViewCustomRender4; +import com.example.gsyvideoplayer.effect.PixelationEffect; +import com.example.gsyvideoplayer.utils.CommonUtil; +import com.example.gsyvideoplayer.video.SampleControlVideo; +import com.shuyu.gsyvideoplayer.GSYBaseActivityDetail; +import com.shuyu.gsyvideoplayer.listener.GSYVideoGifSaveListener; +import com.shuyu.gsyvideoplayer.render.view.GSYVideoGLView; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.render.effect.AutoFixEffect; +import com.shuyu.gsyvideoplayer.render.effect.BarrelBlurEffect; +import com.shuyu.gsyvideoplayer.render.effect.BlackAndWhiteEffect; +import com.shuyu.gsyvideoplayer.render.effect.BrightnessEffect; +import com.shuyu.gsyvideoplayer.render.effect.ContrastEffect; +import com.shuyu.gsyvideoplayer.render.effect.CrossProcessEffect; +import com.shuyu.gsyvideoplayer.render.effect.DocumentaryEffect; +import com.shuyu.gsyvideoplayer.render.effect.DuotoneEffect; +import com.shuyu.gsyvideoplayer.render.effect.FillLightEffect; +import com.shuyu.gsyvideoplayer.render.effect.GammaEffect; +import com.shuyu.gsyvideoplayer.render.effect.GaussianBlurEffect; +import com.shuyu.gsyvideoplayer.render.effect.GrainEffect; +import com.shuyu.gsyvideoplayer.render.effect.HueEffect; +import com.shuyu.gsyvideoplayer.render.effect.InvertColorsEffect; +import com.shuyu.gsyvideoplayer.render.effect.LamoishEffect; +import com.shuyu.gsyvideoplayer.render.effect.NoEffect; +import com.shuyu.gsyvideoplayer.render.effect.OverlayEffect; +import com.shuyu.gsyvideoplayer.render.effect.PosterizeEffect; +import com.shuyu.gsyvideoplayer.render.effect.SampleBlurEffect; +import com.shuyu.gsyvideoplayer.render.effect.SaturationEffect; +import com.shuyu.gsyvideoplayer.render.effect.SepiaEffect; +import com.shuyu.gsyvideoplayer.render.effect.SharpnessEffect; +import com.shuyu.gsyvideoplayer.render.effect.TemperatureEffect; +import com.shuyu.gsyvideoplayer.render.effect.TintEffect; +import com.shuyu.gsyvideoplayer.render.effect.VignetteEffect; +import com.shuyu.gsyvideoplayer.listener.GSYVideoShotListener; +import com.shuyu.gsyvideoplayer.listener.LockClickListener; +import com.shuyu.gsyvideoplayer.utils.Debuger; +import com.shuyu.gsyvideoplayer.utils.FileUtils; +import com.shuyu.gsyvideoplayer.utils.GSYVideoType; +import com.shuyu.gsyvideoplayer.utils.GifCreateHelper; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Timer; +import java.util.TimerTask; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * 滤镜 + * Activity可以继承GSYBaseActivityDetail实现详情模式的页面 + * 或者参考DetailPlayer、DetailListPlayer实现 + * Created by guoshuyu on 2017/6/18. + */ + +public class DetailFilterActivity extends GSYBaseActivityDetail { + + @BindView(R.id.post_detail_nested_scroll) + NestedScrollView postDetailNestedScroll; + + @BindView(R.id.detail_player) + SampleControlVideo detailPlayer; + + @BindView(R.id.activity_detail_player) + RelativeLayout activityDetailPlayer; + + @BindView(R.id.change_filter) + Button changeFilter; + + + @BindView(R.id.jump) + Button jump; + + @BindView(R.id.change_anima) + Button anima; + + @BindView(R.id.start_gif) + Button startGif; + + @BindView(R.id.stop_gif) + Button stopGif; + + @BindView(R.id.loadingView) + View loadingView; + + private int type = 0; + + private int backupRendType; + + private float deep = 0.8f; + + private String url = "https://res.exexm.com/cw_145225549855002"; + //private String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + + private Timer timer = new Timer(); + + private TaskLocal mTimerTask; + + private TaskLocal2 mTimerTask2; + + private GSYVideoGLViewCustomRender mGSYVideoGLViewCustomRender; + + private BitmapIconEffect mCustomBitmapIconEffect; + + private int percentage = 1; + + private int percentageType = 1; + + private boolean moveBitmap = false; + + private GifCreateHelper mGifCreateHelper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_detail_filter); + ButterKnife.bind(this); + + backupRendType = GSYVideoType.getRenderType(); + + //设置为GL播放模式,才能支持滤镜,注意此设置是全局的 + GSYVideoType.setRenderType(GSYVideoType.GLSURFACE); + + resolveNormalVideoUI(); + + initVideoBuilderMode(); + + initGifHelper(); + + detailPlayer.setLockClickListener(new LockClickListener() { + @Override + public void onClick(View view, boolean lock) { + if (orientationUtils != null) { + //配合下方的onConfigurationChanged + orientationUtils.setEnable(!lock); + } + } + }); + + + //自定义render需要在播放器开始播放之前,播放过程中不允许切换render + + //水印图效果 + /*Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); + mGSYVideoGLViewCustomRender = new GSYVideoGLViewCustomRender(); + mCustomBitmapIconEffect = new BitmapIconEffect(bitmap, dp2px(50), dp2px(50), 0.6f); + mGSYVideoGLViewCustomRender.setBitmapEffect(mCustomBitmapIconEffect); + detailPlayer.setCustomGLRenderer(mGSYVideoGLViewCustomRender); + detailPlayer.setGLRenderMode(GSYVideoGLView.MODE_RENDER_SIZE);*/ + + //多窗口播放效果 + //detailPlayer.setEffectFilter(new GammaEffect(0.8f)); + //detailPlayer.setCustomGLRenderer(new GSYVideoGLViewCustomRender2()); + + //图片穿孔透视播放 + //detailPlayer.setCustomGLRenderer(new GSYVideoGLViewCustomRender3()); + + //高斯拉伸视频铺满背景,替换黑色,前台正常比例播放 + //detailPlayer.setEffectFilter(new GaussianBlurEffect(6.0f, GaussianBlurEffect.TYPEXY)); + //detailPlayer.setCustomGLRenderer(new GSYVideoGLViewCustomRender4()); + //detailPlayer.setGLRenderMode(GSYVideoGLView.MODE_RENDER_SIZE); + + changeFilter.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + resolveTypeUI(); + } + }); + + //使用GL播放的话,用这种方式可以解决退出全屏黑屏的问题 + detailPlayer.setBackFromFullScreenListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + DetailFilterActivity.this.onBackPressed(); + } + }); + + + jump.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + shotImage(v); + //JumpUtils.gotoControl(DetailFilterActivity.this); + //startActivity(new Intent(DetailControlActivity.this, MainActivity.class)); + } + }); + + anima.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //画面旋转 + cancelTask(); + mTimerTask = new TaskLocal(); + timer.schedule(mTimerTask, 0, 50); + percentageType++; + if (percentageType > 4) { + percentageType = 1; + } + //水印图动起来 + //cancelTask2(); + //mTimerTask2 = new TaskLocal2(); + //timer.schedule(mTimerTask2, 0, 400); + + //moveBitmap = !moveBitmap; + } + }); + + + startGif.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startGif(); + } + }); + + stopGif.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + stopGif(); + } + }); + + loadingView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //do nothing + } + }); + } + + @Override + public StandardGSYVideoPlayer getGSYVideoPlayer() { + return detailPlayer; + } + + @Override + public GSYVideoOptionBuilder getGSYVideoOptionBuilder() { + //内置封面可参考SampleCoverVideo + ImageView imageView = new ImageView(this); + loadCover(imageView, url); + return new GSYVideoOptionBuilder() + .setThumbImageView(imageView) + .setUrl(url) + .setCacheWithPlay(true) + .setVideoTitle(" ") + .setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setShowFullAnimation(false) + .setNeedLockFull(true) + .setSeekRatio(1); + } + + @Override + public void clickForFullScreen() { + + } + + /** + * 是否启动旋转横屏,true表示启动 + * @return true + */ + @Override + public boolean getDetailOrientationRotateAuto() { + return true; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + //恢复到原本的绘制模式 + GSYVideoType.setRenderType(backupRendType); + cancelTask(); + } + + /** + * 视频截图 + */ + private void shotImage(final View v) { + //获取截图 + detailPlayer.taskShotPic(new GSYVideoShotListener() { + @Override + public void getBitmap(Bitmap bitmap) { + if (bitmap != null) { + try { + CommonUtil.saveBitmap(bitmap); + } catch (FileNotFoundException e) { + showToast("save fail "); + e.printStackTrace(); + return; + } + showToast("save success "); + } else { + showToast("get bitmap fail "); + } + } + }); + + } + + + + private void initGifHelper() { + mGifCreateHelper = new GifCreateHelper(detailPlayer, new GSYVideoGifSaveListener() { + @Override + public void result(boolean success, File file) { + detailPlayer.post(new Runnable() { + @Override + public void run() { + loadingView.setVisibility(View.GONE); + Toast.makeText(detailPlayer.getContext(), "创建成功", Toast.LENGTH_LONG).show(); + } + }); + } + + @Override + public void process(int curPosition, int total) { + Debuger.printfError(" current " + curPosition + " total " + total); + } + }); + } + + + /** + * 开始gif截图 + */ + private void startGif() { + //开始缓存各个帧 + mGifCreateHelper.startGif(new File(FileUtils.getPath())); + + } + + /** + * 生成gif + */ + private void stopGif() { + loadingView.setVisibility(View.VISIBLE); + mGifCreateHelper.stopGif(new File(FileUtils.getPath(), "GSY-Z-" + System.currentTimeMillis() + ".gif")); + } + + /** + * 加载第三秒的帧数作为封面 + */ + private void loadCover(ImageView imageView, String url) { + + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setImageResource(R.mipmap.xxx1); + + Glide.with(this.getApplicationContext()) + .setDefaultRequestOptions( + new RequestOptions() + .frame(3000000) + .centerCrop() + .error(R.mipmap.xxx2) + .placeholder(R.mipmap.xxx1)) + .load(url) + .into(imageView); + } + + private void resolveNormalVideoUI() { + //增加title + detailPlayer.getTitleTextView().setVisibility(View.GONE); + detailPlayer.getBackButton().setVisibility(View.GONE); + } + + /** + * 切换滤镜 + */ + private void resolveTypeUI() { + GSYVideoGLView.ShaderInterface effect = new NoEffect(); + switch (type) { + case 0: + effect = new AutoFixEffect(deep); + break; + case 1: + effect = new PixelationEffect(); + break; + case 2: + effect = new BlackAndWhiteEffect(); + break; + case 3: + effect = new ContrastEffect(deep); + break; + case 4: + effect = new CrossProcessEffect(); + break; + case 5: + effect = new DocumentaryEffect(); + break; + case 6: + effect = new DuotoneEffect(Color.BLUE, Color.YELLOW); + break; + case 7: + effect = new FillLightEffect(deep); + break; + case 8: + effect = new GammaEffect(deep); + break; + case 9: + effect = new GrainEffect(deep); + break; + case 10: + effect = new GrainEffect(deep); + break; + case 11: + effect = new HueEffect(deep); + break; + case 12: + effect = new InvertColorsEffect(); + break; + case 13: + effect = new LamoishEffect(); + break; + case 14: + effect = new PosterizeEffect(); + break; + case 15: + effect = new BarrelBlurEffect(); + break; + case 16: + effect = new SaturationEffect(deep); + break; + case 17: + effect = new SepiaEffect(); + break; + case 18: + effect = new SharpnessEffect(deep); + break; + case 19: + effect = new TemperatureEffect(deep); + break; + case 20: + effect = new TintEffect(Color.GREEN); + break; + case 21: + effect = new VignetteEffect(deep); + break; + case 22: + effect = new NoEffect(); + break; + case 23: + effect = new OverlayEffect(); + break; + case 24: + effect = new SampleBlurEffect(4.0f); + break; + case 25: + effect = new GaussianBlurEffect(6.0f, GaussianBlurEffect.TYPEXY); + break; + case 26: + effect = new BrightnessEffect(deep); + break; + } + detailPlayer.setEffectFilter(effect); + type++; + if (type > 25) { + type = 0; + } + } + + + private void cancelTask2() { + if (mTimerTask2 != null) { + mTimerTask2.cancel(); + mTimerTask2 = null; + } + } + + private void cancelTask() { + if (mTimerTask != null) { + mTimerTask.cancel(); + mTimerTask = null; + } + } + + + /** + * 水印图动起来,播放前开始会崩溃哟 + */ + private class TaskLocal2 extends TimerTask { + @Override + public void run() { + float[] transform = new float[16]; + //旋转到正常角度 + Matrix.setRotateM(transform, 0, 180f, 0.0f, 0, 1.0f); + //调整大小比例 + Matrix.scaleM(transform, 0, mCustomBitmapIconEffect.getScaleW(), mCustomBitmapIconEffect.getScaleH(), 1); + if (moveBitmap) { + //调整位置 + Matrix.translateM(transform, 0, mCustomBitmapIconEffect.getPositionX(), mCustomBitmapIconEffect.getPositionY(), 0f); + } else { + float maxX = mCustomBitmapIconEffect.getMaxPositionX(); + float minX = mCustomBitmapIconEffect.getMinPositionX(); + float maxY = mCustomBitmapIconEffect.getMaxPositionY(); + float minY = mCustomBitmapIconEffect.getMinPositionY(); + float x = (float) Math.random() * (maxX - minX) + minX; + float y = (float) Math.random() * (maxY - minY) + minY; + //调整位置 + Matrix.translateM(transform, 0, x, y, 0f); + mGSYVideoGLViewCustomRender.setCurrentMVPMatrix(transform); + } + } + } + + + /** + * 设置GLRender的VertexShader的transformMatrix + * 注意,这是android.opengl.Matrix + */ + private class TaskLocal extends TimerTask { + @Override + public void run() { + float[] transform = new float[16]; + switch (percentageType) { + case 1: + //给予x变化 + Matrix.setRotateM(transform, 0, 360 * percentage / 100, 1.0f, 0, 0.0f); + break; + case 2: + //给予y变化 + Matrix.setRotateM(transform, 0, 360 * percentage / 100, 0.0f, 1.0f, 0.0f); + break; + case 3: + //给予z变化 + Matrix.setRotateM(transform, 0, 360 * percentage / 100, 0.0f, 0, 1.0f); + break; + case 4: + Matrix.setRotateM(transform, 0, 360, 0.0f, 0, 1.0f); + break; + } + //设置渲染transform + detailPlayer.setMatrixGL(transform); + percentage++; + if (percentage > 100) { + percentage = 1; + } + } + } + + private int dp2px(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, + getResources().getDisplayMetrics()); + } + + private void showToast(final String tip) { + detailPlayer.post(new Runnable() { + @Override + public void run() { + Toast.makeText(DetailFilterActivity.this, tip, Toast.LENGTH_LONG).show(); + } + }); + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/DetailListPlayer.java b/app/src/main/java/com/example/gsyvideoplayer/DetailListPlayer.java index 93a44c76e..2c3faf9e2 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/DetailListPlayer.java +++ b/app/src/main/java/com/example/gsyvideoplayer/DetailListPlayer.java @@ -1,23 +1,19 @@ package com.example.gsyvideoplayer; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; import android.os.Bundle; -import android.support.annotation.Nullable; import android.support.v4.widget.NestedScrollView; -import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; -import com.example.gsyvideoplayer.listener.SampleListener; -import com.shuyu.gsyvideoplayer.GSYPreViewManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.GSYBaseActivityDetail; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; import com.shuyu.gsyvideoplayer.listener.LockClickListener; import com.shuyu.gsyvideoplayer.model.GSYVideoModel; -import com.shuyu.gsyvideoplayer.utils.OrientationUtils; import com.shuyu.gsyvideoplayer.video.ListGSYVideoPlayer; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; import java.util.ArrayList; import java.util.List; @@ -26,10 +22,12 @@ import butterknife.ButterKnife; /** + * Activity可以继承GSYBaseActivityDetail实现详情模式的页面 + * 或者参考DetailPlayer、DetailListPlayer实现 * Created by shuyu on 2016/12/20. */ -public class DetailListPlayer extends AppCompatActivity { +public class DetailListPlayer extends GSYBaseActivityDetail { @BindView(R.id.post_detail_nested_scroll) @@ -38,11 +36,8 @@ public class DetailListPlayer extends AppCompatActivity { ListGSYVideoPlayer detailPlayer; @BindView(R.id.activity_detail_player) RelativeLayout activityDetailPlayer; - - private boolean isPlay; - private boolean isPause; - - private OrientationUtils orientationUtils; + @BindView(R.id.next) + View next; @Override protected void onCreate(Bundle savedInstanceState) { @@ -50,11 +45,14 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_deatil_list_player); ButterKnife.bind(this); + //普通模式 + initVideo(); + //String url = "http://baobab.wd jcdn.com/14564977406580.mp4"; List urls = new ArrayList<>(); - urls.add(new GSYVideoModel("http://baobab.wdjcdn.com/14564977406580.mp4", "标题1")); + urls.add(new GSYVideoModel("http://7xse1z.com1.z0.glb.clouddn.com/1491813192", "标题1")); urls.add(new GSYVideoModel("http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4", "标题2")); - urls.add(new GSYVideoModel("http://baobab.wdjcdn.com/14564977406580.mp4", "标题3")); + urls.add(new GSYVideoModel("https://res.exexm.com/cw_145225549855002", "标题3")); urls.add(new GSYVideoModel("http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4", "标题4")); detailPlayer.setUp(urls, true, 0); @@ -66,11 +64,6 @@ protected void onCreate(Bundle savedInstanceState) { resolveNormalVideoUI(); - //外部辅助的旋转,帮助全屏 - orientationUtils = new OrientationUtils(this, detailPlayer); - //初始化不打开外部的旋转 - orientationUtils.setEnable(false); - detailPlayer.setIsTouchWiget(true); //关闭自动旋转 detailPlayer.setRotateViewAuto(false); @@ -78,44 +71,7 @@ protected void onCreate(Bundle savedInstanceState) { detailPlayer.setShowFullAnimation(false); detailPlayer.setNeedLockFull(true); - detailPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - //直接横屏 - orientationUtils.resolveByClick(); - - //第一个true是否需要隐藏actionbar,第二个true是否需要隐藏statusbar - detailPlayer.startWindowFullscreen(DetailListPlayer.this, true, true); - } - }); - - detailPlayer.setStandardVideoAllCallBack(new SampleListener() { - @Override - public void onPrepared(String url, Object... objects) { - super.onPrepared(url, objects); - //开始播放了才能旋转和全屏 - orientationUtils.setEnable(true); - isPlay = true; - } - - @Override - public void onAutoComplete(String url, Object... objects) { - super.onAutoComplete(url, objects); - } - - @Override - public void onClickStartError(String url, Object... objects) { - super.onClickStartError(url, objects); - } - - @Override - public void onQuitFullscreen(String url, Object... objects) { - super.onQuitFullscreen(url, objects); - if (orientationUtils != null) { - orientationUtils.backToProtVideo(); - } - } - }); + detailPlayer.setVideoAllCallBack(this); detailPlayer.setLockClickListener(new LockClickListener() { @Override @@ -127,69 +83,62 @@ public void onClick(View view, boolean lock) { } }); + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ((ListGSYVideoPlayer)detailPlayer.getCurrentPlayer()).playNext(); + } + }); + } @Override - public void onBackPressed() { - - if (orientationUtils != null) { - orientationUtils.backToProtVideo(); - } - - if (StandardGSYVideoPlayer.backFromWindowFull(this)) { - return; - } - super.onBackPressed(); + public ListGSYVideoPlayer getGSYVideoPlayer() { + return detailPlayer; } - @Override - protected void onPause() { - super.onPause(); - isPause = true; + public GSYVideoOptionBuilder getGSYVideoOptionBuilder() { + //不需要builder的 + return null; } @Override - protected void onResume() { - super.onResume(); - isPause = false; + public void clickForFullScreen() { + } + /** + * 是否启动旋转横屏,true表示启动 + * @return true + */ @Override - protected void onDestroy() { - super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); - if (orientationUtils != null) - orientationUtils.releaseListener(); + public boolean getDetailOrientationRotateAuto() { + return true; } @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - //如果旋转了就全屏 - if (isPlay && !isPause) { - if (newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_USER) { - if (!detailPlayer.isIfCurrentIsFullscreen()) { - detailPlayer.startWindowFullscreen(DetailListPlayer.this, true, true); - } - } else { - //新版本isIfCurrentIsFullscreen的标志位内部提前设置了,所以不会和手动点击冲突 - if (detailPlayer.isIfCurrentIsFullscreen()) { - StandardGSYVideoPlayer.backFromWindowFull(this); - } - if (orientationUtils != null) { - orientationUtils.setEnable(true); - } - } - } + public void onEnterFullscreen(String url, Object... objects) { + super.onEnterFullscreen(url, objects); + //隐藏调全屏对象的返回按键 + GSYVideoPlayer gsyVideoPlayer = (GSYVideoPlayer)objects[1]; + gsyVideoPlayer.getBackButton().setVisibility(View.GONE); } + private void resolveNormalVideoUI() { //增加title - detailPlayer.getTitleTextView().setVisibility(View.GONE); - detailPlayer.getTitleTextView().setText("测试视频"); - detailPlayer.getBackButton().setVisibility(View.GONE); + detailPlayer.getTitleTextView().setVisibility(View.VISIBLE); + detailPlayer.getBackButton().setVisibility(View.VISIBLE); + } + + private GSYVideoPlayer getCurPlay() { + if (detailPlayer.getFullWindowPlayer() != null) { + return detailPlayer.getFullWindowPlayer(); + } + return detailPlayer; } + } diff --git a/app/src/main/java/com/example/gsyvideoplayer/DetailMoreTypeActivity.java b/app/src/main/java/com/example/gsyvideoplayer/DetailMoreTypeActivity.java index 7002e1165..9f70813f3 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/DetailMoreTypeActivity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/DetailMoreTypeActivity.java @@ -2,6 +2,8 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.media.MediaMetadataRetriever; import android.os.Bundle; import android.support.v4.widget.NestedScrollView; import android.support.v7.app.AppCompatActivity; @@ -9,15 +11,18 @@ import android.widget.ImageView; import android.widget.RelativeLayout; -import com.example.gsyvideoplayer.listener.SampleListener; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; import com.example.gsyvideoplayer.model.SwitchVideoModel; import com.example.gsyvideoplayer.video.SampleVideo; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; import com.shuyu.gsyvideoplayer.listener.LockClickListener; import com.shuyu.gsyvideoplayer.utils.OrientationUtils; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import butterknife.BindView; @@ -25,10 +30,10 @@ /** * Created by guoshuyu on 2017/6/18. - * ampleVideo支持全屏与非全屏切换的清晰度,旋转,镜像等功能. + * sampleVideo支持全屏与非全屏切换的清晰度,旋转,镜像等功能. */ -public class DetailMoreTypeActivity extends AppCompatActivity{ +public class DetailMoreTypeActivity extends AppCompatActivity { @BindView(R.id.post_detail_nested_scroll) NestedScrollView postDetailNestedScroll; @@ -42,9 +47,14 @@ public class DetailMoreTypeActivity extends AppCompatActivity{ private boolean isPlay; private boolean isPause; + private boolean isRelease; private OrientationUtils orientationUtils; + private MediaMetadataRetriever mCoverMedia; + + private ImageView coverImageView; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -52,7 +62,7 @@ protected void onCreate(Bundle savedInstanceState) { ButterKnife.bind(this); String source1 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; - //String source1 = "http://baobab.wdjcdn.com/14564977406580.mp4"; + //String source1 = "https://res.exexm.com/cw_145225549855002"; String name = "普通"; SwitchVideoModel switchVideoModel = new SwitchVideoModel(name, source1); @@ -67,10 +77,10 @@ protected void onCreate(Bundle savedInstanceState) { detailPlayer.setUp(list, true, ""); //增加封面 - ImageView imageView = new ImageView(this); - imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); - imageView.setImageResource(R.mipmap.xxx1); - detailPlayer.setThumbImageView(imageView); + coverImageView = new ImageView(this); + coverImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + //coverImageView.setImageResource(R.mipmap.xxx1); + detailPlayer.setThumbImageView(coverImageView); resolveNormalVideoUI(); @@ -84,27 +94,31 @@ protected void onCreate(Bundle savedInstanceState) { //关闭自动旋转 detailPlayer.setRotateViewAuto(false); detailPlayer.setLockLand(false); - detailPlayer.setShowFullAnimation(false); + + //打开 实现竖屏全屏动画 + detailPlayer.setShowFullAnimation(true); + detailPlayer.setNeedLockFull(true); detailPlayer.setSeekRatio(1); //detailPlayer.setOpenPreView(false); detailPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - //直接横屏 - orientationUtils.resolveByClick(); + //屏蔽,实现竖屏全屏 + //orientationUtils.resolveByClick(); //第一个true是否需要隐藏actionbar,第二个true是否需要隐藏statusbar detailPlayer.startWindowFullscreen(DetailMoreTypeActivity.this, true, true); } }); - detailPlayer.setStandardVideoAllCallBack(new SampleListener() { + detailPlayer.setVideoAllCallBack(new GSYSampleCallBack() { @Override public void onPrepared(String url, Object... objects) { super.onPrepared(url, objects); //开始播放了才能旋转和全屏 - orientationUtils.setEnable(true); + //orientationUtils.setEnable(true); + orientationUtils.setEnable(false); isPlay = true; } @@ -121,22 +135,25 @@ public void onClickStartError(String url, Object... objects) { @Override public void onQuitFullscreen(String url, Object... objects) { super.onQuitFullscreen(url, objects); - if (orientationUtils != null) { - orientationUtils.backToProtVideo(); - } + //屏蔽,实现竖屏全屏 + //if (orientationUtils != null) { + //orientationUtils.backToProtVideo(); + //} } }); detailPlayer.setLockClickListener(new LockClickListener() { @Override public void onClick(View view, boolean lock) { - if (orientationUtils != null) { + //屏蔽,实现竖屏全屏 + //if (orientationUtils != null) { //配合下方的onConfigurationChanged - orientationUtils.setEnable(!lock); - } + //orientationUtils.setEnable(!lock); + //} } }); + loadFirstFrameCover(source1); } @Override @@ -146,7 +163,7 @@ public void onBackPressed() { orientationUtils.backToProtVideo(); } - if (StandardGSYVideoPlayer.backFromWindowFull(this)) { + if (GSYVideoManager.backFromWindowFull(this)) { return; } super.onBackPressed(); @@ -155,12 +172,14 @@ public void onBackPressed() { @Override protected void onPause() { + getCurPlay().onVideoPause(); super.onPause(); isPause = true; } @Override protected void onResume() { + getCurPlay().onVideoResume(); super.onResume(); isPause = false; } @@ -168,10 +187,17 @@ protected void onResume() { @Override protected void onDestroy() { super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); + isRelease = true; + if (isPlay) { + getCurPlay().release(); + } //GSYPreViewManager.instance().releaseMediaPlayer(); if (orientationUtils != null) orientationUtils.releaseListener(); + if (mCoverMedia != null) { + mCoverMedia.release(); + mCoverMedia = null; + } } @Override @@ -179,27 +205,79 @@ public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //如果旋转了就全屏 if (isPlay && !isPause) { - if (newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_USER) { - if (!detailPlayer.isIfCurrentIsFullscreen()) { - detailPlayer.startWindowFullscreen(DetailMoreTypeActivity.this, true, true); - } - } else { - //新版本isIfCurrentIsFullscreen的标志位内部提前设置了,所以不会和手动点击冲突 - if (detailPlayer.isIfCurrentIsFullscreen()) { - StandardGSYVideoPlayer.backFromWindowFull(this); - } - if (orientationUtils != null) { - orientationUtils.setEnable(true); - } - } + detailPlayer.onConfigurationChanged(this, newConfig, orientationUtils, true, true); } + //竖屏全屏 + orientationUtils.setEnable(false); + } + + + + private GSYVideoPlayer getCurPlay() { + if (detailPlayer.getFullWindowPlayer() != null) { + return detailPlayer.getFullWindowPlayer(); + } + return detailPlayer; } private void resolveNormalVideoUI() { //增加title detailPlayer.getTitleTextView().setVisibility(View.GONE); - detailPlayer.getTitleTextView().setText("测试视频"); detailPlayer.getBackButton().setVisibility(View.GONE); } + + + /** + * 这里只是演示,并不建议直接这么做 + * MediaMetadataRetriever最好做一个独立的管理器 + * 使用缓存 + * 注意资源的开销和异步等 + * + * @param url + */ + public void loadFirstFrameCover(String url) { + + //原始方法 + /*final MediaMetadataRetriever mediaMetadataRetriever = getMediaMetadataRetriever(url); + //获取帧图片 + if (getMediaMetadataRetriever(url) != null) { + new Thread(new Runnable() { + @Override + public void run() { + final Bitmap bitmap = mediaMetadataRetriever + .getFrameAtTime(1000, MediaMetadataRetriever.OPTION_CLOSEST); + runOnUiThread(new Runnable() { + @Override + public void run() { + if (bitmap != null && !isRelease) { + Debuger.printfLog("time " + System.currentTimeMillis()); + //显示 + coverImageView.setImageBitmap(bitmap); + } + } + }); + } + }).start(); + }*/ + + //可以参考Glide,内部也是封装了MediaMetadataRetriever + Glide.with(this.getApplicationContext()) + .setDefaultRequestOptions( + new RequestOptions() + .frame(1000000) + .centerCrop() + .error(R.mipmap.xxx2) + .placeholder(R.mipmap.xxx1)) + .load(url) + .into(coverImageView); + } + + public MediaMetadataRetriever getMediaMetadataRetriever(String url) { + if (mCoverMedia == null) { + mCoverMedia = new MediaMetadataRetriever(); + } + mCoverMedia.setDataSource(url, new HashMap()); + return mCoverMedia; + } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/DetailPlayer.java b/app/src/main/java/com/example/gsyvideoplayer/DetailPlayer.java index fb0670299..839d1cee2 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/DetailPlayer.java +++ b/app/src/main/java/com/example/gsyvideoplayer/DetailPlayer.java @@ -1,6 +1,5 @@ package com.example.gsyvideoplayer; -import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.widget.NestedScrollView; @@ -9,26 +8,20 @@ import android.widget.ImageView; import android.widget.RelativeLayout; -import com.example.gsyvideoplayer.listener.SampleListener; import com.example.gsyvideoplayer.video.LandLayoutVideo; -import com.shuyu.gsyvideoplayer.GSYPreViewManager; import com.shuyu.gsyvideoplayer.GSYVideoManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.listener.GSYVideoProgressListener; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; -import com.shuyu.gsyvideoplayer.builder.GSYVideoBuilder; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; import com.shuyu.gsyvideoplayer.listener.LockClickListener; -import com.shuyu.gsyvideoplayer.model.VideoOptionModel; import com.shuyu.gsyvideoplayer.utils.Debuger; import com.shuyu.gsyvideoplayer.utils.OrientationUtils; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; -import java.util.ArrayList; -import java.util.List; - import butterknife.BindView; import butterknife.ButterKnife; -import tv.danmaku.ijk.media.player.IjkMediaPlayer; public class DetailPlayer extends AppCompatActivity { @@ -55,7 +48,23 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_detail_player); ButterKnife.bind(this); - String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; + //断网自动重新链接,url前接上ijkhttphook: + //String url = "ijkhttphook:https://res.exexm.com/cw_145225549855002"; + + //String url = "http://7xjmzj.com1.z0.glb.clouddn.com/20171026175005_JObCxCE2.mp4"; + + //String url = "http://video.7k.cn/app_video/20171202/6c8cf3ea/v.m3u8.mp4"; + String url = "http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8"; + + //String url = "rtsp://ajj:12345678@218.21.217.122:65523/h264/ch40/sub/av_stream"; + //String url = "rtsp://ajj:ajj12345678@218.21.217.122:65522/h264/ch15/sub/av_stream";//String url = "rtsp://cloud.easydarwin.org:554/stream0.sdp"; + //String url = "http://s.swao.cn/o_1c4gm8o1nniu1had13bk1t0l1rq64m.mov"; + //String url = "http://api.ciguang.tv/avideo/play?num=02-041-0491&type=flv&v=1&client=android"; + //String url = "http://video.7k.cn/app_video/20171213/276d8195/v.m3u8.mp4"; + //String url = "http://103.233.191.21/riak/riak-bucket/6469ac502e813a4c1df7c99f364e70c1.mp4"; + //String url = "http://7xjmzj.com1.z0.glb.clouddn.com/20171026175005_JObCxCE2.mp4"; + //String url = "https://media6.smartstudy.com/ae/07/3997/2/dest.m3u8"; + //String url = "http://cdn.tiaobatiaoba.com/Upload/square/2017-11-02/1509585140_1279.mp4"; //String url = "http://hcjs2ra2rytd8v8np1q.exp.bcevod.com/mda-hegtjx8n5e8jt9zv/mda-hegtjx8n5e8jt9zv.m3u8"; //String url = "http://7xse1z.com1.z0.glb.clouddn.com/1491813192"; @@ -65,14 +74,19 @@ protected void onCreate(Bundle savedInstanceState) { //String url = "http://pl-ali.youku.com/playlist/m3u8?type=mp4&ts=1490185963&keyframe=0&vid=XMjYxOTQ1Mzg2MA==&ep=ciadGkiFU8cF4SvajD8bYyuwJiYHXJZ3rHbN%2FrYDAcZuH%2BrC6DPcqJ21TPs%3D&sid=04901859548541247bba8&token=0524&ctype=12&ev=1&oip=976319194"; //String url = "http://hls.ciguang.tv/hdtv/video.m3u8"; //String url = "https://res.exexm.com/cw_145225549855002"; + //String url = "http://storage.gzstv.net/uploads/media/huangmeiyan/jr05-09.mp4";//mepg + //detailPlayer.setUp(url, false, null, "测试视频"); //detailPlayer.setLooping(true); //detailPlayer.setShowPauseCover(false); - /*VideoOptionModel videoOptionModel = - new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 5); - List list = new ArrayList<>(); - list.add(videoOptionModel); - GSYVideoManager.instance().setOptionModelList(list);*/ + + //如果视频帧数太高导致卡画面不同步 + //VideoOptionModel videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 5); + //如果视频seek之后从头播放 + //VideoOptionModel videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1); + //List list = new ArrayList<>(); + //list.add(videoOptionModel); + //GSYVideoManager.instance().setOptionModelList(list); //GSYVideoManager.instance().setTimeOut(4000, true); @@ -90,8 +104,8 @@ protected void onCreate(Bundle savedInstanceState) { //初始化不打开外部的旋转 orientationUtils.setEnable(false); - GSYVideoBuilder gsyVideoBuilder = new GSYVideoBuilder(); - gsyVideoBuilder.setThumbImageView(imageView) + GSYVideoOptionBuilder gsyVideoOption = new GSYVideoOptionBuilder(); + gsyVideoOption.setThumbImageView(imageView) .setIsTouchWiget(true) .setRotateViewAuto(false) .setLockLand(false) @@ -101,7 +115,7 @@ protected void onCreate(Bundle savedInstanceState) { .setUrl(url) .setCacheWithPlay(false) .setVideoTitle("测试视频") - .setStandardVideoAllCallBack(new SampleListener() { + .setVideoAllCallBack(new GSYSampleCallBack() { @Override public void onPrepared(String url, Object... objects) { Debuger.printfError("***** onPrepared **** " + objects[0]); @@ -147,7 +161,14 @@ public void onClick(View view, boolean lock) { orientationUtils.setEnable(!lock); } } - }).build(detailPlayer); + }) + .setGSYVideoProgressListener(new GSYVideoProgressListener() { + @Override + public void onProgress(int progress, int secProgress, int currentPosition, int duration) { + Debuger.printfLog(" progress " + progress + " secProgress " + secProgress + " currentPosition " + currentPosition + " duration " + duration); + } + }) + .build(detailPlayer); detailPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { @Override @@ -159,7 +180,6 @@ public void onClick(View v) { detailPlayer.startWindowFullscreen(DetailPlayer.this, true, true); } }); - } @Override @@ -169,7 +189,7 @@ public void onBackPressed() { orientationUtils.backToProtVideo(); } - if (StandardGSYVideoPlayer.backFromWindowFull(this)) { + if (GSYVideoManager.backFromWindowFull(this)) { return; } super.onBackPressed(); @@ -178,12 +198,14 @@ public void onBackPressed() { @Override protected void onPause() { + getCurPlay().onVideoPause(); super.onPause(); isPause = true; } @Override protected void onResume() { + getCurPlay().onVideoResume(false); super.onResume(); isPause = false; } @@ -191,30 +213,22 @@ protected void onResume() { @Override protected void onDestroy() { super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); + if (isPlay) { + getCurPlay().release(); + } //GSYPreViewManager.instance().releaseMediaPlayer(); if (orientationUtils != null) orientationUtils.releaseListener(); } + + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //如果旋转了就全屏 if (isPlay && !isPause) { - if (newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_USER) { - if (!detailPlayer.isIfCurrentIsFullscreen()) { - detailPlayer.startWindowFullscreen(DetailPlayer.this, true, true); - } - } else { - //新版本isIfCurrentIsFullscreen的标志位内部提前设置了,所以不会和手动点击冲突 - if (detailPlayer.isIfCurrentIsFullscreen()) { - StandardGSYVideoPlayer.backFromWindowFull(this); - } - if (orientationUtils != null) { - orientationUtils.setEnable(true); - } - } + detailPlayer.onConfigurationChanged(this, newConfig, orientationUtils, true, true); } } @@ -222,8 +236,13 @@ public void onConfigurationChanged(Configuration newConfig) { private void resolveNormalVideoUI() { //增加title detailPlayer.getTitleTextView().setVisibility(View.GONE); - detailPlayer.getTitleTextView().setText("测试视频"); detailPlayer.getBackButton().setVisibility(View.GONE); } + private GSYVideoPlayer getCurPlay() { + if (detailPlayer.getFullWindowPlayer() != null) { + return detailPlayer.getFullWindowPlayer(); + } + return detailPlayer; + } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/EmptyActivity.java b/app/src/main/java/com/example/gsyvideoplayer/EmptyActivity.java new file mode 100644 index 000000000..a96a4ecb0 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/EmptyActivity.java @@ -0,0 +1,28 @@ +package com.example.gsyvideoplayer; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.widget.Button; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +public class EmptyActivity extends AppCompatActivity { + + @BindView(R.id.jump_other) + Button jumpOther; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_empty); + ButterKnife.bind(this); + } + + @OnClick(R.id.jump_other) + public void onViewClicked() { + startActivity(new Intent(this, EmptyActivity.class)); + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/GSYApplication.java b/app/src/main/java/com/example/gsyvideoplayer/GSYApplication.java index 03992995d..9ef955ed8 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/GSYApplication.java +++ b/app/src/main/java/com/example/gsyvideoplayer/GSYApplication.java @@ -5,6 +5,8 @@ import com.shuyu.gsyvideoplayer.GSYVideoManager; import com.shuyu.gsyvideoplayer.utils.GSYVideoType; +import tv.danmaku.ijk.media.player.IjkMediaPlayer; + //import com.squareup.leakcanary.LeakCanary; /** @@ -22,9 +24,21 @@ public void onCreate() { //return; //} //LeakCanary.install(this); + + //GSYVideoType.enableMediaCodec(); - //GSYVideoManager.instance().setVideoType(this, GSYVideoType.IJKEXOPLAYER); + //GSYVideoType.enableMediaCodecTexture(); + + //GSYVideoManager.instance().setVideoType(this, GSYVideoType.IJKEXOPLAYER); //EXO 1 播放内核,弃用 + //GSYVideoManager.instance().setVideoType(this, GSYVideoType.IJKEXOPLAYER2); //EXO 2 播放内核 + //GSYVideoManager.instance().setVideoType(this, GSYVideoType.SYSTEMPLAYER); //系统播放器 + //GSYVideoType.setShowType(GSYVideoType.SCREEN_MATCH_FULL); //GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_FULL); + + //GSYVideoType.setRenderType(GSYVideoType.SUFRACE); + //GSYVideoType.setRenderType(GSYVideoType.GLSURFACE); + + //GSYVideoManager.instance().setLogLevel(IjkMediaPlayer.IJK_LOG_SILENT); } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/InputUrlDetailActivity.java b/app/src/main/java/com/example/gsyvideoplayer/InputUrlDetailActivity.java index 4ab75aa33..d23075c89 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/InputUrlDetailActivity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/InputUrlDetailActivity.java @@ -1,6 +1,5 @@ package com.example.gsyvideoplayer; -import android.app.Activity; import android.content.DialogInterface; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -12,18 +11,14 @@ import android.widget.ImageView; import android.widget.RelativeLayout; -import com.example.gsyvideoplayer.listener.SampleListener; -import com.example.gsyvideoplayer.model.SwitchVideoModel; import com.example.gsyvideoplayer.video.LandLayoutVideo; -import com.example.gsyvideoplayer.video.SampleVideo; import com.example.gsyvideoplayer.view.CustomInputDialog; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; import com.shuyu.gsyvideoplayer.listener.LockClickListener; import com.shuyu.gsyvideoplayer.utils.OrientationUtils; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; - -import java.util.ArrayList; -import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; @@ -52,21 +47,20 @@ public class InputUrlDetailActivity extends AppCompatActivity { private OrientationUtils orientationUtils; + private GSYVideoOptionBuilder gsyVideoOptionBuilder; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_input_url_detail); ButterKnife.bind(this); - url = "http://baobab.wdjcdn.com/14564977406580.mp4"; - detailPlayer.setUp(url, cache, null, "测试视频"); - + url = "https://res.exexm.com/cw_145225549855002"; //增加封面 ImageView imageView = new ImageView(this); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setImageResource(R.mipmap.xxx1); - detailPlayer.setThumbImageView(imageView); resolveNormalVideoUI(); @@ -75,15 +69,36 @@ protected void onCreate(Bundle savedInstanceState) { //初始化不打开外部的旋转 orientationUtils.setEnable(false); - detailPlayer.setIsTouchWiget(true); - //detailPlayer.setIsTouchWigetFull(false); - //关闭自动旋转 - detailPlayer.setRotateViewAuto(false); - detailPlayer.setLockLand(false); - detailPlayer.setShowFullAnimation(false); - detailPlayer.setNeedLockFull(true); - detailPlayer.setSeekRatio(1); - //detailPlayer.setOpenPreView(false); + gsyVideoOptionBuilder = new GSYVideoOptionBuilder() + .setThumbImageView(imageView) + .setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setShowFullAnimation(false) + .setNeedLockFull(true) + .setSeekRatio(1) + .setUrl(url) + .setCacheWithPlay(cache) + .setVideoTitle("测试视频") + .setVideoAllCallBack(new GSYSampleCallBack() { + @Override + public void onPrepared(String url, Object... objects) { + super.onPrepared(url, objects); + //开始播放了才能旋转和全屏 + orientationUtils.setEnable(true); + isPlay = true; + } + + @Override + public void onQuitFullscreen(String url, Object... objects) { + super.onQuitFullscreen(url, objects); + if (orientationUtils != null) { + orientationUtils.backToProtVideo(); + } + } + }); + gsyVideoOptionBuilder.build(detailPlayer); + detailPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -95,34 +110,6 @@ public void onClick(View v) { } }); - detailPlayer.setStandardVideoAllCallBack(new SampleListener() { - @Override - public void onPrepared(String url, Object... objects) { - super.onPrepared(url, objects); - //开始播放了才能旋转和全屏 - orientationUtils.setEnable(true); - isPlay = true; - } - - @Override - public void onAutoComplete(String url, Object... objects) { - super.onAutoComplete(url, objects); - } - - @Override - public void onClickStartError(String url, Object... objects) { - super.onClickStartError(url, objects); - } - - @Override - public void onQuitFullscreen(String url, Object... objects) { - super.onQuitFullscreen(url, objects); - if (orientationUtils != null) { - orientationUtils.backToProtVideo(); - } - } - }); - detailPlayer.setLockClickListener(new LockClickListener() { @Override public void onClick(View view, boolean lock) { @@ -149,7 +136,7 @@ public void onBackPressed() { orientationUtils.backToProtVideo(); } - if (StandardGSYVideoPlayer.backFromWindowFull(this)) { + if (GSYVideoManager.backFromWindowFull(this)) { return; } super.onBackPressed(); @@ -158,12 +145,14 @@ public void onBackPressed() { @Override protected void onPause() { + getCurPlay().onVideoPause(); super.onPause(); isPause = true; } @Override protected void onResume() { + getCurPlay().onVideoResume(); super.onResume(); isPause = false; } @@ -171,7 +160,9 @@ protected void onResume() { @Override protected void onDestroy() { super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); + if (isPlay) { + getCurPlay().release(); + } //GSYPreViewManager.instance().releaseMediaPlayer(); if (orientationUtils != null) orientationUtils.releaseListener(); @@ -182,25 +173,24 @@ public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //如果旋转了就全屏 if (isPlay && !isPause) { - if (newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_USER) { - if (!detailPlayer.isIfCurrentIsFullscreen()) { - detailPlayer.startWindowFullscreen(InputUrlDetailActivity.this, true, true); - } - } else { - //新版本isIfCurrentIsFullscreen的标志位内部提前设置了,所以不会和手动点击冲突 - if (detailPlayer.isIfCurrentIsFullscreen()) { - StandardGSYVideoPlayer.backFromWindowFull(this); - } - if (orientationUtils != null) { - orientationUtils.setEnable(true); - } - } + detailPlayer.onConfigurationChanged(this, newConfig, orientationUtils, true, true); + } + } + + private GSYVideoPlayer getCurPlay() { + if (detailPlayer.getFullWindowPlayer() != null) { + return detailPlayer.getFullWindowPlayer(); } + return detailPlayer; } private void playVideo() { detailPlayer.release(); - detailPlayer.setUp(url, cache, null, "测试视频"); + gsyVideoOptionBuilder.setUrl(url) + .setCacheWithPlay(cache) + .setVideoTitle("测试视频") + .build(detailPlayer); + gsyVideoOptionBuilder.build(detailPlayer); detailPlayer.postDelayed(new Runnable() { @Override public void run() { @@ -212,7 +202,6 @@ public void run() { private void resolveNormalVideoUI() { //增加title detailPlayer.getTitleTextView().setVisibility(View.GONE); - detailPlayer.getTitleTextView().setText("测试视频"); detailPlayer.getBackButton().setVisibility(View.GONE); } diff --git a/app/src/main/java/com/example/gsyvideoplayer/ListADVideoActivity.java b/app/src/main/java/com/example/gsyvideoplayer/ListADVideoActivity.java new file mode 100644 index 000000000..b9a538126 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/ListADVideoActivity.java @@ -0,0 +1,319 @@ +package com.example.gsyvideoplayer; + +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.transition.Explode; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.AbsListView; +import android.widget.BaseAdapter; +import android.widget.ListView; + +import com.example.gsyvideoplayer.model.VideoModel; +import com.example.gsyvideoplayer.video.SampleCoverVideo; +import com.shuyu.gsyvideoplayer.GSYVideoADManager; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.video.GSYADVideoPlayer; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * 带广告播放列表,支持中间插入广告模式 + */ +public class ListADVideoActivity extends AppCompatActivity { + + @BindView(R.id.video_list) + ListView videoList; + + ListADNormalAdapter listADNormalAdapter; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + // 设置一个exit transition + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + getWindow().setEnterTransition(new Explode()); + getWindow().setExitTransition(new Explode()); + } + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list_video); + ButterKnife.bind(this); + + listADNormalAdapter = new ListADNormalAdapter(this); + videoList.setAdapter(listADNormalAdapter); + + videoList.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + int lastVisibleItem = firstVisibleItem + visibleItemCount; + //大于0说明有播放 + if (GSYVideoManager.instance().getPlayPosition() >= 0) { + //当前播放的位置 + int position = GSYVideoManager.instance().getPlayPosition(); + //对应的播放列表TAG + if (GSYVideoManager.instance().getPlayTag().equals(ListADNormalAdapter.TAG) + && (position < firstVisibleItem || position > lastVisibleItem)) { + //如果滑出去了上面和下面就是否,和今日头条一样 + //释放广告和视频 + if (GSYVideoADManager.instance().listener() != null) { + GSYVideoADManager.instance().listener().onAutoCompletion(); + } + GSYVideoADManager.releaseAllVideos(); + GSYVideoManager.releaseAllVideos(); + listADNormalAdapter.notifyDataSetChanged(); + } + } + } + }); + + } + + @Override + public void onBackPressed() { + if (GSYVideoADManager.backFromWindowFull(this)) { + return; + } + if (GSYVideoManager.backFromWindowFull(this)) { + return; + } + super.onBackPressed(); + } + + @Override + protected void onPause() { + super.onPause(); + GSYVideoManager.onPause(); + GSYVideoADManager.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + GSYVideoManager.onResume(); + GSYVideoADManager.onResume(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + GSYVideoManager.releaseAllVideos(); + GSYVideoADManager.releaseAllVideos(); + } + + + public class ListADNormalAdapter extends BaseAdapter { + + public static final String TAG = "ListADNormalAdapter"; + + private List list = new ArrayList<>(); + private LayoutInflater inflater = null; + private Context context; + + public ListADNormalAdapter(Context context) { + super(); + this.context = context; + inflater = LayoutInflater.from(context); + for (int i = 0; i < 40; i++) { + list.add(new VideoModel()); + } + + } + + @Override + public int getCount() { + return list.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + final ViewHolder holder; + if (convertView == null) { + holder = new ViewHolder(); + convertView = inflater.inflate(R.layout.list_video_item_ad, null); + holder.gsyVideoPlayer = (SampleCoverVideo) convertView.findViewById(R.id.video_item_player); + holder.adVideoPlayer = (GSYADVideoPlayer) convertView.findViewById(R.id.video_ad_player); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + + final String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + final String urlAD = "http://video.7k.cn/app_video/20171202/6c8cf3ea/v.m3u8.mp4"; + + //多个播放时必须在setUpLazy、setUp和getGSYVideoManager()等前面设置 + holder.gsyVideoPlayer.setPlayTag(TAG); + holder.gsyVideoPlayer.setPlayPosition(position); + + boolean isPlaying = holder.gsyVideoPlayer.getCurrentPlayer().isInPlayingState(); + + if (!isPlaying) { + holder.gsyVideoPlayer.setUpLazy(url, false, null, null, "这是title"); + } + + boolean isADPlaying = holder.adVideoPlayer.getCurrentPlayer().isInPlayingState(); + if (!isADPlaying) { + holder.adVideoPlayer.setUpLazy(urlAD, false, null, null, "这是title"); + } + + + //增加title + holder.gsyVideoPlayer.getTitleTextView().setVisibility(View.GONE); + + //设置返回键 + holder.gsyVideoPlayer.getBackButton().setVisibility(View.GONE); + + + //设置全屏按键功能 + holder.gsyVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + resolveFullBtn(holder.gsyVideoPlayer); + } + }); + holder.adVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + resolveFullBtn(holder.adVideoPlayer); + } + }); + holder.gsyVideoPlayer.setRotateViewAuto(false); + holder.adVideoPlayer.setRotateViewAuto(false); + holder.gsyVideoPlayer.setLockLand(true); + holder.adVideoPlayer.setLockLand(true); + holder.gsyVideoPlayer.setReleaseWhenLossAudio(false); + holder.adVideoPlayer.setReleaseWhenLossAudio(false); + holder.gsyVideoPlayer.setShowFullAnimation(false); + holder.adVideoPlayer.setShowFullAnimation(false); + holder.gsyVideoPlayer.setIsTouchWiget(false); + holder.adVideoPlayer.setIsTouchWiget(false); + + holder.gsyVideoPlayer.setNeedLockFull(true); + + if (position % 2 == 0) { + holder.gsyVideoPlayer.loadCoverImage(url, R.mipmap.xxx1); + } else { + holder.gsyVideoPlayer.loadCoverImage(url, R.mipmap.xxx2); + } + + holder.gsyVideoPlayer.setVideoAllCallBack(new GSYSampleCallBack() { + + + @Override + public void onPrepared(String url, Object... objects) { + super.onPrepared(url, objects); + if (isNeedAdOnStart()) + startAdPlay(holder.adVideoPlayer, holder.gsyVideoPlayer); + } + + @Override + public void onQuitFullscreen(String url, Object... objects) { + super.onQuitFullscreen(url, objects); + } + + @Override + public void onEnterFullscreen(String url, Object... objects) { + super.onEnterFullscreen(url, objects); + holder.gsyVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String) objects[0]); + } + + @Override + public void onAutoComplete(String url, Object... objects) { + super.onAutoComplete(url, objects); + } + }); + + holder.adVideoPlayer.setVideoAllCallBack(new GSYSampleCallBack() { + + + @Override + public void onAutoComplete(String url, Object... objects) { + //广告结束,释放 + holder.adVideoPlayer.getCurrentPlayer().release(); + holder.adVideoPlayer.onVideoReset(); + holder.adVideoPlayer.setVisibility(View.GONE); + //开始播放原视频,根据是否处于全屏状态判断 + holder.gsyVideoPlayer.getCurrentPlayer().startAfterPrepared(); + if (holder.adVideoPlayer.getCurrentPlayer().isIfCurrentIsFullscreen()) { + holder.adVideoPlayer.removeFullWindowViewOnly(); + if (!holder.gsyVideoPlayer.getCurrentPlayer().isIfCurrentIsFullscreen()) { + resolveFullBtn(holder.gsyVideoPlayer); + holder.gsyVideoPlayer.setSaveBeforeFullSystemUiVisibility(holder.adVideoPlayer.getSaveBeforeFullSystemUiVisibility()); + } + } + } + + @Override + public void onQuitFullscreen(String url, Object... objects) { + //退出全屏逻辑 + if (holder.gsyVideoPlayer.isIfCurrentIsFullscreen()) { + holder.gsyVideoPlayer.onBackFullscreen(); + } + } + + }); + + + return convertView; + } + + /** + * 全屏幕按键处理 + */ + private void resolveFullBtn(final StandardGSYVideoPlayer standardGSYVideoPlayer) { + standardGSYVideoPlayer.startWindowFullscreen(context, false, true); + } + + + /** + * 显示播放广告 + */ + public void startAdPlay(GSYADVideoPlayer gsyadVideoPlayer, StandardGSYVideoPlayer normalPlayer) { + gsyadVideoPlayer.setVisibility(View.VISIBLE); + gsyadVideoPlayer.startPlayLogic(); + if (normalPlayer.getCurrentPlayer().isIfCurrentIsFullscreen()) { + resolveFullBtn(gsyadVideoPlayer); + gsyadVideoPlayer.setSaveBeforeFullSystemUiVisibility(normalPlayer.getSaveBeforeFullSystemUiVisibility()); + } + } + + class ViewHolder { + SampleCoverVideo gsyVideoPlayer; + GSYADVideoPlayer adVideoPlayer; + } + } + + + /** + * 需要片头广告 + */ + public boolean isNeedAdOnStart() { + return true; + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/ListMultiVideoActivity.java b/app/src/main/java/com/example/gsyvideoplayer/ListMultiVideoActivity.java new file mode 100644 index 000000000..7d96dfa94 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/ListMultiVideoActivity.java @@ -0,0 +1,112 @@ +package com.example.gsyvideoplayer; + +import android.os.Build; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.transition.Explode; +import android.view.Window; +import android.widget.AbsListView; +import android.widget.ListView; + +import com.example.gsyvideoplayer.adapter.ListMultiNormalAdapter; +import com.example.gsyvideoplayer.video.manager.CustomManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * 多个同时播放的demo + */ +public class ListMultiVideoActivity extends AppCompatActivity { + + @BindView(R.id.video_list) + ListView videoList; + + ListMultiNormalAdapter listMultiNormalAdapter; + + private boolean isPause; + + @Override + protected void onCreate(Bundle savedInstanceState) { + // 设置一个exit transition + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + getWindow().setEnterTransition(new Explode()); + getWindow().setExitTransition(new Explode()); + } + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list_video); + ButterKnife.bind(this); + + listMultiNormalAdapter = new ListMultiNormalAdapter(this); + videoList.setAdapter(listMultiNormalAdapter); + + videoList.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + int lastVisibleItem = firstVisibleItem + visibleItemCount; + //大于0说明有播放 + if (CustomManager.instance().size() >= 0) { + Map map = CustomManager.instance(); + List removeKey = new ArrayList<>(); + for (Map.Entry customManagerEntry : map.entrySet()) { + CustomManager customManager = customManagerEntry.getValue(); + //当前播放的位置 + int position = customManager.getPlayPosition(); + //对应的播放列表TAG + if (customManager.getPlayTag().equals(ListMultiNormalAdapter.TAG) + && (position < firstVisibleItem || position > lastVisibleItem)) { + CustomManager.releaseAllVideos(customManagerEntry.getKey()); + removeKey.add(customManagerEntry.getKey()); + } + } + if(removeKey.size() > 0) { + for (String key : removeKey) { + map.remove(key); + } + listMultiNormalAdapter.notifyDataSetChanged(); + } + } + } + + }); + + } + + @Override + public void onBackPressed() { + if (CustomManager.backFromWindowFull(this, listMultiNormalAdapter.getFullKey())) { + return; + } + super.onBackPressed(); + } + + @Override + protected void onPause() { + super.onPause(); + CustomManager.onPauseAll(); + isPause = true; + } + + @Override + protected void onResume() { + super.onResume(); + CustomManager.onResumeAll(); + isPause = false; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + CustomManager.clearAllVideo(); + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/ListVideo2Activity.java b/app/src/main/java/com/example/gsyvideoplayer/ListVideo2Activity.java index e9230ad68..2a0a3eb46 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/ListVideo2Activity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/ListVideo2Activity.java @@ -12,27 +12,37 @@ import android.widget.RelativeLayout; import com.example.gsyvideoplayer.adapter.ListVideoAdapter; -import com.example.gsyvideoplayer.listener.SampleListener; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.utils.GSYVideoHelper; import com.shuyu.gsyvideoplayer.utils.CommonUtil; import com.shuyu.gsyvideoplayer.utils.Debuger; -import com.shuyu.gsyvideoplayer.utils.ListVideoUtil; import butterknife.BindView; import butterknife.ButterKnife; +/** + * 列表小窗口 + */ public class ListVideo2Activity extends AppCompatActivity { @BindView(R.id.video_list) ListView videoList; + @BindView(R.id.video_full_container) FrameLayout videoFullContainer; + @BindView(R.id.activity_list_video) RelativeLayout activityListVideo; - ListVideoUtil listVideoUtil; + GSYVideoHelper smallVideoHelper; + ListVideoAdapter listVideoAdapter; + + GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder; + int lastVisibleItem; + int firstVisibleItem; @Override @@ -47,20 +57,51 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_list_video2); ButterKnife.bind(this); - listVideoUtil = new ListVideoUtil(this); - listVideoUtil.setFullViewContainer(videoFullContainer); - listVideoUtil.setHideStatusBar(true); - //listVideoUtil.setHideActionBar(true); - listVideoUtil.setNeedLockFull(true); + //创建小窗口帮助类 + smallVideoHelper = new GSYVideoHelper(this); + + //如果不设置即使用默认的 windowViewContainer + //smallVideoHelper.setFullViewContainer(videoFullContainer); + + //配置 + gsySmallVideoHelperBuilder = new GSYVideoHelper.GSYVideoHelperBuilder(); + gsySmallVideoHelperBuilder + .setHideStatusBar(true) + .setNeedLockFull(true) + .setCacheWithPlay(true) + .setShowFullAnimation(false) + .setRotateViewAuto(false) + .setLockLand(true) + .setVideoAllCallBack(new GSYSampleCallBack(){ + @Override + public void onPrepared(String url, Object... objects) { + super.onPrepared(url, objects); + Debuger.printfLog("Duration " + smallVideoHelper.getGsyVideoPlayer().getDuration() + " CurrentPosition " + smallVideoHelper.getGsyVideoPlayer().getCurrentPositionWhenPlaying()); + } - listVideoAdapter = new ListVideoAdapter(this, listVideoUtil); - listVideoAdapter.setRootView(activityListVideo); - videoList.setAdapter(listVideoAdapter); + @Override + public void onQuitSmallWidget(String url, Object... objects) { + super.onQuitSmallWidget(url, objects); + //大于0说明有播放,//对应的播放列表TAG + if (smallVideoHelper.getPlayPosition() >= 0 && smallVideoHelper.getPlayTAG().equals(ListVideoAdapter.TAG)) { + //当前播放的位置 + int position = smallVideoHelper.getPlayPosition(); + //不可视的是时候 + if ((position < firstVisibleItem || position > lastVisibleItem)) { + //释放掉视频 + smallVideoHelper.releaseVideoPlayer(); + listVideoAdapter.notifyDataSetChanged(); + } + } + + } + }); - //listVideoUtil.setShowFullAnimation(true); - //listVideoUtil.setAutoRotation(true); - //listVideoUtil.setFullLandFrist(true); + smallVideoHelper.setGsyVideoOptionBuilder(gsySmallVideoHelperBuilder); + listVideoAdapter = new ListVideoAdapter(this, smallVideoHelper, gsySmallVideoHelperBuilder); + listVideoAdapter.setRootView(activityListVideo); + videoList.setAdapter(listVideoAdapter); videoList.setOnScrollListener(new AbsListView.OnScrollListener() { @Override @@ -72,60 +113,32 @@ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCoun ListVideo2Activity.this.firstVisibleItem = firstVisibleItem; lastVisibleItem = firstVisibleItem + visibleItemCount; //大于0说明有播放,//对应的播放列表TAG - if (listVideoUtil.getPlayPosition() >= 0 && listVideoUtil.getPlayTAG().equals(ListVideoAdapter.TAG)) { + if (smallVideoHelper.getPlayPosition() >= 0 && smallVideoHelper.getPlayTAG().equals(ListVideoAdapter.TAG)) { //当前播放的位置 - int position = listVideoUtil.getPlayPosition(); + int position = smallVideoHelper.getPlayPosition(); //不可视的是时候 if ((position < firstVisibleItem || position > lastVisibleItem)) { //如果是小窗口就不需要处理 - if (!listVideoUtil.isSmall()) { + if (!smallVideoHelper.isSmall()) { //小窗口 int size = CommonUtil.dip2px(ListVideo2Activity.this, 150); - listVideoUtil.showSmallVideo(new Point(size, size), false, true); + smallVideoHelper.showSmallVideo(new Point(size, size), false, true); } } else { - if (listVideoUtil.isSmall()) { - listVideoUtil.smallVideoToNormal(); + if (smallVideoHelper.isSmall()) { + smallVideoHelper.smallVideoToNormal(); } } } } }); - - //小窗口关闭被点击的时候回调处理回复页面 - listVideoUtil.setVideoAllCallBack(new SampleListener(){ - @Override - public void onPrepared(String url, Object... objects) { - super.onPrepared(url, objects); - Debuger.printfLog("Duration " + listVideoUtil.getDuration() + " CurrentPosition " + listVideoUtil.getCurrentPositionWhenPlaying()); - } - - @Override - public void onQuitSmallWidget(String url, Object... objects) { - super.onQuitSmallWidget(url, objects); - //大于0说明有播放,//对应的播放列表TAG - if (listVideoUtil.getPlayPosition() >= 0 && listVideoUtil.getPlayTAG().equals(ListVideoAdapter.TAG)) { - //当前播放的位置 - int position = listVideoUtil.getPlayPosition(); - //不可视的是时候 - if ((position < firstVisibleItem || position > lastVisibleItem)) { - //释放掉视频 - listVideoUtil.releaseVideoPlayer(); - listVideoAdapter.notifyDataSetChanged(); - } - } - - } - }); - - } @Override public void onBackPressed() { - if (listVideoUtil.backFromFull()) { + if (smallVideoHelper.backFromFull()) { return; } super.onBackPressed(); @@ -135,8 +148,8 @@ public void onBackPressed() { @Override protected void onDestroy() { super.onDestroy(); - listVideoUtil.releaseVideoPlayer(); - GSYVideoPlayer.releaseAllVideos(); + smallVideoHelper.releaseVideoPlayer(); + GSYVideoManager.releaseAllVideos(); } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/ListVideoActivity.java b/app/src/main/java/com/example/gsyvideoplayer/ListVideoActivity.java index 8bc5c64f5..7fda9d43c 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/ListVideoActivity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/ListVideoActivity.java @@ -1,11 +1,10 @@ package com.example.gsyvideoplayer; +import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; -import android.os.Debug; import android.support.v7.app.AppCompatActivity; import android.transition.Explode; -import android.util.Log; import android.view.Window; import android.widget.AbsListView; import android.widget.ListView; @@ -13,12 +12,9 @@ import com.example.gsyvideoplayer.adapter.ListNormalAdapter; import com.shuyu.gsyvideoplayer.GSYVideoManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; import butterknife.BindView; import butterknife.ButterKnife; -import tv.danmaku.ijk.media.player.IjkMediaPlayer; public class ListVideoActivity extends AppCompatActivity { @@ -27,6 +23,10 @@ public class ListVideoActivity extends AppCompatActivity { @BindView(R.id.activity_list_video) RelativeLayout activityListVideo; + ListNormalAdapter listNormalAdapter; + + private boolean isPause; + @Override protected void onCreate(Bundle savedInstanceState) { // 设置一个exit transition @@ -39,7 +39,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_list_video); ButterKnife.bind(this); - final ListNormalAdapter listNormalAdapter = new ListNormalAdapter(this); + listNormalAdapter = new ListNormalAdapter(this); videoList.setAdapter(listNormalAdapter); videoList.setOnScrollListener(new AbsListView.OnScrollListener() { @@ -58,7 +58,7 @@ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCoun if (GSYVideoManager.instance().getPlayTag().equals(ListNormalAdapter.TAG) && (position < firstVisibleItem || position > lastVisibleItem)) { //如果滑出去了上面和下面就是否,和今日头条一样 - GSYVideoPlayer.releaseAllVideos(); + GSYVideoManager.releaseAllVideos(); listNormalAdapter.notifyDataSetChanged(); } } @@ -69,7 +69,10 @@ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCoun @Override public void onBackPressed() { - if (StandardGSYVideoPlayer.backFromWindowFull(this)) { + //为了支持重力旋转 + onBackPressAdapter(); + + if (GSYVideoManager.backFromWindowFull(this)) { return; } super.onBackPressed(); @@ -79,17 +82,38 @@ public void onBackPressed() { protected void onPause() { super.onPause(); GSYVideoManager.onPause(); + isPause = true; } @Override protected void onResume() { super.onResume(); GSYVideoManager.onResume(); + isPause = false; } @Override protected void onDestroy() { super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); + GSYVideoManager.releaseAllVideos(); + if (listNormalAdapter != null) { + listNormalAdapter.onDestroy(); + } + } + + /********************************为了支持重力旋转********************************/ + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (listNormalAdapter != null && listNormalAdapter.getListNeedAutoLand() && !isPause) { + listNormalAdapter.onConfigurationChanged(this, newConfig); + } + } + + private void onBackPressAdapter() { + //为了支持重力旋转 + if (listNormalAdapter != null && listNormalAdapter.getListNeedAutoLand()) { + listNormalAdapter.onBackPressed(); + } } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/MainActivity.java b/app/src/main/java/com/example/gsyvideoplayer/MainActivity.java index b5f8a6ac8..234c9a787 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/MainActivity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/MainActivity.java @@ -1,6 +1,5 @@ package com.example.gsyvideoplayer; -import android.app.Activity; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; @@ -19,6 +18,9 @@ public class MainActivity extends AppCompatActivity { @BindView(R.id.open_btn) Button openBtn; + @BindView(R.id.open_btn_empty) + Button openBtn2; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -27,7 +29,9 @@ protected void onCreate(Bundle savedInstanceState) { ButterKnife.bind(this); } - @OnClick({R.id.open_btn, R.id.list_btn, R.id.list_btn_2, R.id.list_detail, R.id.clear_cache, R.id.recycler, R.id.recycler_2, R.id.list_detail_list, R.id.web_detail, R.id.danmaku_video, R.id.fragment_video, R.id.more_type, R.id.input_type}) + @OnClick({R.id.open_btn, R.id.list_btn, R.id.list_btn_2, R.id.list_detail, R.id.clear_cache, R.id.recycler, R.id.recycler_2, R.id.list_detail_list, R.id.web_detail, R.id.danmaku_video, R.id.fragment_video, + R.id.more_type, R.id.input_type, R.id.open_btn_empty, R.id.open_control, R.id.open_filter, R.id.open_btn_pick, R.id.open_btn_auto, R.id.open_scroll, R.id.open_window, R.id.open_btn_ad, + R.id.open_btn_multi, R.id.open_btn_ad2, R.id.open_list_ad}) public void onClick(View view) { switch (view.getId()) { case R.id.open_btn: @@ -59,7 +63,7 @@ public void onClick(View view) { JumpUtils.goToDetailListPlayer(this); break; case R.id.web_detail: - //播放一个连续列表 + //正常播放,带preview JumpUtils.gotoWebDetail(this); break; case R.id.danmaku_video: @@ -77,10 +81,51 @@ public void onClick(View view) { case R.id.input_type: JumpUtils.gotoInput(this); break; + case R.id.open_btn_empty: + JumpUtils.goToPlayEmptyControlActivity(this, openBtn2); + break; + case R.id.open_control: + JumpUtils.gotoControl(this); + break; + case R.id.open_filter: + JumpUtils.gotoFilter(this); + break; + case R.id.open_btn_pick: + //无缝切换 + JumpUtils.goToVideoPickPlayer(this, openBtn); + break; + case R.id.open_btn_auto: + //列表自动播放 + JumpUtils.goToAutoVideoPlayer(this); + break; + case R.id.open_scroll: + //列表自动播放 + JumpUtils.goToScrollDetailPlayer(this); + break; + case R.id.open_window: + //多窗体下的悬浮窗 + JumpUtils.goToScrollWindow(this); + break; + case R.id.open_btn_ad: + //广告 + JumpUtils.goToVideoADPlayer(this); + break; + case R.id.open_btn_multi: + //多个同时播放 + JumpUtils.goToMultiVideoPlayer(this); + break; + case R.id.open_btn_ad2: + //多个同时播放 + JumpUtils.goToVideoADPlayer2(this); + break; + case R.id.open_list_ad: + //多个同时播放 + JumpUtils.goToADListVideoPlayer(this); + break; case R.id.clear_cache: //清理缓存 GSYVideoManager.clearAllDefaultCache(MainActivity.this); - //String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; + //String url = "https://res.exexm.com/cw_145225549855002"; //GSYVideoManager.clearDefaultCache(MainActivity.this, url); break; } diff --git a/app/src/main/java/com/example/gsyvideoplayer/PlayActivity.java b/app/src/main/java/com/example/gsyvideoplayer/PlayActivity.java index 02fc4c62a..88fc00c30 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/PlayActivity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/PlayActivity.java @@ -15,12 +15,9 @@ import com.example.gsyvideoplayer.listener.OnTransitionListener; import com.example.gsyvideoplayer.model.SwitchVideoModel; import com.example.gsyvideoplayer.video.SampleVideo; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; -import com.shuyu.gsyvideoplayer.utils.FileUtils; +import com.shuyu.gsyvideoplayer.GSYVideoManager; import com.shuyu.gsyvideoplayer.utils.OrientationUtils; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; -import java.io.File; import java.util.ArrayList; import java.util.List; @@ -55,7 +52,7 @@ protected void onCreate(Bundle savedInstanceState) { } private void init() { - String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; + String url = "https://res.exexm.com/cw_145225549855002"; //String url = "http://7xse1z.com1.z0.glb.clouddn.com/1491813192"; //需要路径的 @@ -74,7 +71,7 @@ private void init() { list.add(switchVideoModel); list.add(switchVideoModel2); - videoPlayer.setUp(list, true, ""); + videoPlayer.setUp(list, true, "测试视频"); //增加封面 ImageView imageView = new ImageView(this); @@ -84,7 +81,6 @@ private void init() { //增加title videoPlayer.getTitleTextView().setVisibility(View.VISIBLE); - videoPlayer.getTitleTextView().setText("测试视频"); //videoPlayer.setShowPauseCover(false); //videoPlayer.setSpeed(2f); @@ -135,6 +131,7 @@ protected void onPause() { @Override protected void onResume() { super.onResume(); + videoPlayer.onVideoResume(); } @TargetApi(Build.VERSION_CODES.KITKAT) @@ -153,8 +150,8 @@ public void onBackPressed() { return; } //释放所有 - videoPlayer.setStandardVideoAllCallBack(null); - GSYVideoPlayer.releaseAllVideos(); + videoPlayer.setVideoAllCallBack(null); + GSYVideoManager.releaseAllVideos(); if (isTransition && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { super.onBackPressed(); } else { diff --git a/app/src/main/java/com/example/gsyvideoplayer/PlayEmptyControlActivity.java b/app/src/main/java/com/example/gsyvideoplayer/PlayEmptyControlActivity.java new file mode 100644 index 000000000..ae0cb9d92 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/PlayEmptyControlActivity.java @@ -0,0 +1,122 @@ +package com.example.gsyvideoplayer; + +import android.annotation.TargetApi; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.view.ViewCompat; +import android.support.v7.app.AppCompatActivity; +import android.transition.Transition; + +import com.example.gsyvideoplayer.listener.OnTransitionListener; +import com.example.gsyvideoplayer.video.EmptyControlVideo; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.utils.OrientationUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * 单独的视频播放页面 + * Created by shuyu on 2016/11/11. + */ +public class PlayEmptyControlActivity extends AppCompatActivity { + + public final static String IMG_TRANSITION = "IMG_TRANSITION"; + public final static String TRANSITION = "TRANSITION"; + + @BindView(R.id.video_player) + EmptyControlVideo videoPlayer; + + OrientationUtils orientationUtils; + + private boolean isTransition; + + private Transition transition; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_play_empty_control); + ButterKnife.bind(this); + isTransition = getIntent().getBooleanExtra(TRANSITION, false); + init(); + } + + private void init() { + String url = "https://res.exexm.com/cw_145225549855002"; + + videoPlayer.setUp(url, true, ""); + + //过渡动画 + initTransition(); + } + + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + @Override + protected void onDestroy() { + super.onDestroy(); + videoPlayer.release(); + if (orientationUtils != null) + orientationUtils.releaseListener(); + } + + @Override + public void onBackPressed() { + //释放所有 + videoPlayer.setVideoAllCallBack(null); + GSYVideoManager.releaseAllVideos(); + if (isTransition && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + super.onBackPressed(); + } else { + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + finish(); + overridePendingTransition(R.anim.abc_fade_in, R.anim.abc_fade_out); + } + }, 500); + } + } + + + private void initTransition() { + if (isTransition && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + postponeEnterTransition(); + ViewCompat.setTransitionName(videoPlayer, IMG_TRANSITION); + addTransitionListener(); + startPostponedEnterTransition(); + } else { + videoPlayer.startPlayLogic(); + } + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private boolean addTransitionListener() { + transition = getWindow().getSharedElementEnterTransition(); + if (transition != null) { + transition.addListener(new OnTransitionListener(){ + @Override + public void onTransitionEnd(Transition transition) { + super.onTransitionEnd(transition); + videoPlayer.startPlayLogic(); + transition.removeListener(this); + } + }); + return true; + } + return false; + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/PlayPickActivity.java b/app/src/main/java/com/example/gsyvideoplayer/PlayPickActivity.java new file mode 100644 index 000000000..9b3615015 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/PlayPickActivity.java @@ -0,0 +1,180 @@ +package com.example.gsyvideoplayer; + +import android.annotation.TargetApi; +import android.content.pm.ActivityInfo; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.view.ViewCompat; +import android.support.v7.app.AppCompatActivity; +import android.transition.Transition; +import android.view.View; +import android.widget.ImageView; + +import com.example.gsyvideoplayer.listener.OnTransitionListener; +import com.example.gsyvideoplayer.model.SwitchVideoModel; +import com.example.gsyvideoplayer.video.SmartPickVideo; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.utils.OrientationUtils; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * 单独的视频播放页面 + * Created by shuyu on 2016/11/11. + */ +public class PlayPickActivity extends AppCompatActivity { + + public final static String IMG_TRANSITION = "IMG_TRANSITION"; + public final static String TRANSITION = "TRANSITION"; + + @BindView(R.id.video_player) + SmartPickVideo videoPlayer; + + OrientationUtils orientationUtils; + + private boolean isTransition; + + private Transition transition; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_play_pick); + ButterKnife.bind(this); + isTransition = getIntent().getBooleanExtra(TRANSITION, false); + init(); + } + + private void init() { + //借用了jjdxm_ijkplayer的URL + String source1 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + String name = "普通"; + SwitchVideoModel switchVideoModel = new SwitchVideoModel(name, source1); + + String source2 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f30.mp4"; + String name2 = "清晰"; + SwitchVideoModel switchVideoModel2 = new SwitchVideoModel(name2, source2); + + List list = new ArrayList<>(); + list.add(switchVideoModel); + list.add(switchVideoModel2); + + videoPlayer.setUp(list, false, "测试视频"); + + //增加封面 + ImageView imageView = new ImageView(this); + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setImageResource(R.mipmap.xxx1); + videoPlayer.setThumbImageView(imageView); + + //增加title + videoPlayer.getTitleTextView().setVisibility(View.VISIBLE); + + //设置返回键 + videoPlayer.getBackButton().setVisibility(View.VISIBLE); + + //设置旋转 + orientationUtils = new OrientationUtils(this, videoPlayer); + + //设置全屏按键功能,这是使用的是选择屏幕,而不是全屏 + videoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + orientationUtils.resolveByClick(); + } + }); + + //是否可以滑动调整 + videoPlayer.setIsTouchWiget(true); + + //设置返回按键功能 + videoPlayer.getBackButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); + } + }); + + //过渡动画 + initTransition(); + } + + + @Override + protected void onPause() { + super.onPause(); + videoPlayer.onVideoPause(); + } + + @Override + protected void onResume() { + super.onResume(); + videoPlayer.onVideoResume(); + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + @Override + protected void onDestroy() { + super.onDestroy(); + if (orientationUtils != null) + orientationUtils.releaseListener(); + } + + @Override + public void onBackPressed() { + //先返回正常状态 + if (orientationUtils.getScreenType() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { + videoPlayer.getFullscreenButton().performClick(); + return; + } + //释放所有 + videoPlayer.setVideoAllCallBack(null); + GSYVideoManager.releaseAllVideos(); + if (isTransition && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + super.onBackPressed(); + } else { + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + finish(); + overridePendingTransition(R.anim.abc_fade_in, R.anim.abc_fade_out); + } + }, 500); + } + } + + + private void initTransition() { + if (isTransition && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + postponeEnterTransition(); + ViewCompat.setTransitionName(videoPlayer, IMG_TRANSITION); + addTransitionListener(); + startPostponedEnterTransition(); + } else { + videoPlayer.startPlayLogic(); + } + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private boolean addTransitionListener() { + transition = getWindow().getSharedElementEnterTransition(); + if (transition != null) { + transition.addListener(new OnTransitionListener(){ + @Override + public void onTransitionEnd(Transition transition) { + super.onTransitionEnd(transition); + videoPlayer.startPlayLogic(); + transition.removeListener(this); + } + }); + return true; + } + return false; + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/RecyclerView2Activity.java b/app/src/main/java/com/example/gsyvideoplayer/RecyclerView2Activity.java index 515b5f763..4d163ee4f 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/RecyclerView2Activity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/RecyclerView2Activity.java @@ -7,20 +7,18 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.transition.Explode; -import android.view.View; import android.view.Window; -import android.widget.AbsListView; import android.widget.FrameLayout; -import com.example.gsyvideoplayer.adapter.ListVideoAdapter; import com.example.gsyvideoplayer.adapter.RecyclerBaseAdapter; import com.example.gsyvideoplayer.holder.RecyclerItemViewHolder; -import com.example.gsyvideoplayer.listener.SampleListener; import com.example.gsyvideoplayer.model.VideoModel; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.utils.GSYVideoHelper; +import com.shuyu.gsyvideoplayer.video.NormalGSYVideoPlayer; import com.shuyu.gsyvideoplayer.utils.CommonUtil; import com.shuyu.gsyvideoplayer.utils.Debuger; -import com.shuyu.gsyvideoplayer.utils.ListVideoUtil; import java.util.ArrayList; import java.util.List; @@ -28,10 +26,14 @@ import butterknife.BindView; import butterknife.ButterKnife; +/** + * 小窗口 + */ public class RecyclerView2Activity extends AppCompatActivity { @BindView(R.id.list_item_recycler) RecyclerView listItemRecycler; + @BindView(R.id.video_full_container) FrameLayout videoFullContainer; @@ -41,8 +43,12 @@ public class RecyclerView2Activity extends AppCompatActivity { List dataList = new ArrayList<>(); - ListVideoUtil listVideoUtil; + GSYVideoHelper smallVideoHelper; + + GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder; + int lastVisibleItem; + int firstVisibleItem; @Override @@ -60,13 +66,6 @@ protected void onCreate(Bundle savedInstanceState) { initView(); - listVideoUtil.setHideActionBar(true); - - //listVideoUtil.setShowFullAnimation(true); - //listVideoUtil.setAutoRotation(true); - //listVideoUtil.setFullLandFrist(true); - - listItemRecycler.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { @@ -80,59 +79,31 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); Debuger.printfLog("firstVisibleItem " + firstVisibleItem +" lastVisibleItem " + lastVisibleItem); //大于0说明有播放,//对应的播放列表TAG - if (listVideoUtil.getPlayPosition() >= 0 && listVideoUtil.getPlayTAG().equals(RecyclerItemViewHolder.TAG)) { + if (smallVideoHelper.getPlayPosition() >= 0 && smallVideoHelper.getPlayTAG().equals(RecyclerItemViewHolder.TAG)) { //当前播放的位置 - int position = listVideoUtil.getPlayPosition(); + int position = smallVideoHelper.getPlayPosition(); //不可视的是时候 if ((position < firstVisibleItem || position > lastVisibleItem)) { //如果是小窗口就不需要处理 - if (!listVideoUtil.isSmall() && !listVideoUtil.isFull()) { + if (!smallVideoHelper.isSmall() && !smallVideoHelper.isFull()) { //小窗口 int size = CommonUtil.dip2px(RecyclerView2Activity.this, 150); //actionbar为true才不会掉下面去 - listVideoUtil.showSmallVideo(new Point(size, size), true, true); + smallVideoHelper.showSmallVideo(new Point(size, size), true, true); } } else { - if (listVideoUtil.isSmall()) { - listVideoUtil.smallVideoToNormal(); + if (smallVideoHelper.isSmall()) { + smallVideoHelper.smallVideoToNormal(); } } } } }); - - //小窗口关闭被点击的时候回调处理回复页面 - listVideoUtil.setVideoAllCallBack(new SampleListener() { - @Override - public void onPrepared(String url, Object... objects) { - super.onPrepared(url, objects); - Debuger.printfLog("Duration " + listVideoUtil.getDuration() + " CurrentPosition " + listVideoUtil.getCurrentPositionWhenPlaying()); - } - - @Override - public void onQuitSmallWidget(String url, Object... objects) { - super.onQuitSmallWidget(url, objects); - //大于0说明有播放,//对应的播放列表TAG - if (listVideoUtil.getPlayPosition() >= 0 && listVideoUtil.getPlayTAG().equals(RecyclerItemViewHolder.TAG)) { - //当前播放的位置 - int position = listVideoUtil.getPlayPosition(); - //不可视的是时候 - if ((position < firstVisibleItem || position > lastVisibleItem)) { - //释放掉视频 - listVideoUtil.releaseVideoPlayer(); - recyclerBaseAdapter.notifyDataSetChanged(); - } - } - - } - }); - - } @Override public void onBackPressed() { - if (listVideoUtil.backFromFull()) { + if (smallVideoHelper.backFromFull()) { return; } super.onBackPressed(); @@ -142,8 +113,8 @@ public void onBackPressed() { @Override protected void onDestroy() { super.onDestroy(); - listVideoUtil.releaseVideoPlayer(); - GSYVideoPlayer.releaseAllVideos(); + smallVideoHelper.releaseVideoPlayer(); + GSYVideoManager.releaseAllVideos(); } private void initView() { @@ -156,10 +127,45 @@ private void initView() { listItemRecycler.setAdapter(recyclerBaseAdapter); - listVideoUtil = new ListVideoUtil(this); - listVideoUtil.setFullViewContainer(videoFullContainer); - listVideoUtil.setHideStatusBar(true); - recyclerBaseAdapter.setListVideoUtil(listVideoUtil); + smallVideoHelper = new GSYVideoHelper(this, new NormalGSYVideoPlayer(this)); + smallVideoHelper.setFullViewContainer(videoFullContainer); + + //配置 + gsySmallVideoHelperBuilder = new GSYVideoHelper.GSYVideoHelperBuilder(); + gsySmallVideoHelperBuilder + .setHideActionBar(true) + .setHideStatusBar(true) + .setNeedLockFull(true) + .setCacheWithPlay(true) + .setShowFullAnimation(true) + .setLockLand(true).setVideoAllCallBack(new GSYSampleCallBack() { + @Override + public void onPrepared(String url, Object... objects) { + super.onPrepared(url, objects); + Debuger.printfLog("Duration " + smallVideoHelper.getGsyVideoPlayer().getDuration() + " CurrentPosition " + smallVideoHelper.getGsyVideoPlayer().getCurrentPositionWhenPlaying()); + } + + @Override + public void onQuitSmallWidget(String url, Object... objects) { + super.onQuitSmallWidget(url, objects); + //大于0说明有播放,//对应的播放列表TAG + if (smallVideoHelper.getPlayPosition() >= 0 && smallVideoHelper.getPlayTAG().equals(RecyclerItemViewHolder.TAG)) { + //当前播放的位置 + int position = smallVideoHelper.getPlayPosition(); + //不可视的是时候 + if ((position < firstVisibleItem || position > lastVisibleItem)) { + //释放掉视频 + smallVideoHelper.releaseVideoPlayer(); + recyclerBaseAdapter.notifyDataSetChanged(); + } + } + + } + }); + + smallVideoHelper.setGsyVideoOptionBuilder(gsySmallVideoHelperBuilder); + + recyclerBaseAdapter.setVideoHelper(smallVideoHelper, gsySmallVideoHelperBuilder); } diff --git a/app/src/main/java/com/example/gsyvideoplayer/RecyclerViewActivity.java b/app/src/main/java/com/example/gsyvideoplayer/RecyclerViewActivity.java index d6c35ad95..89e5cb4a3 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/RecyclerViewActivity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/RecyclerViewActivity.java @@ -11,16 +11,12 @@ import android.transition.Explode; import android.view.Window; -import com.example.gsyvideoplayer.adapter.ListNormalAdapter; import com.example.gsyvideoplayer.adapter.RecyclerBaseAdapter; import com.example.gsyvideoplayer.adapter.RecyclerNormalAdapter; import com.example.gsyvideoplayer.holder.RecyclerItemNormalHolder; import com.example.gsyvideoplayer.model.VideoModel; import com.shuyu.gsyvideoplayer.GSYVideoManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; -import com.shuyu.gsyvideoplayer.utils.Debuger; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; import java.util.ArrayList; import java.util.List; @@ -86,7 +82,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { //如果滑出去了上面和下面就是否,和今日头条一样 //是否全屏 if(!mFull) { - GSYVideoPlayer.releaseAllVideos(); + GSYVideoManager.releaseAllVideos(); recyclerNormalAdapter.notifyDataSetChanged(); } } @@ -110,7 +106,7 @@ public void onConfigurationChanged(Configuration newConfig) { @Override public void onBackPressed() { - if (StandardGSYVideoPlayer.backFromWindowFull(this)) { + if (GSYVideoManager.backFromWindowFull(this)) { return; } super.onBackPressed(); @@ -131,7 +127,7 @@ protected void onResume() { @Override protected void onDestroy() { super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); + GSYVideoManager.releaseAllVideos(); } diff --git a/app/src/main/java/com/example/gsyvideoplayer/ScrollingActivity.java b/app/src/main/java/com/example/gsyvideoplayer/ScrollingActivity.java new file mode 100644 index 000000000..4b7b8888f --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/ScrollingActivity.java @@ -0,0 +1,273 @@ +package com.example.gsyvideoplayer; + +import android.content.res.Configuration; +import android.graphics.Point; +import android.os.Bundle; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CollapsingToolbarLayout; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.ImageView; + +import com.example.gsyvideoplayer.listener.AppBarStateChangeListener; +import com.example.gsyvideoplayer.video.LandLayoutVideo; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.listener.GSYVideoProgressListener; +import com.shuyu.gsyvideoplayer.listener.LockClickListener; +import com.shuyu.gsyvideoplayer.utils.CommonUtil; +import com.shuyu.gsyvideoplayer.utils.Debuger; +import com.shuyu.gsyvideoplayer.utils.OrientationUtils; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; + +/** + * CollapsingToolbarLayout的播放页面 + * 额,有点懒,细节上没处理 + */ +public class ScrollingActivity extends AppCompatActivity { + + private boolean isPlay; + private boolean isPause; + private boolean isSamll; + + private OrientationUtils orientationUtils; + private LandLayoutVideo detailPlayer; + private AppBarLayout appBar; + private FloatingActionButton fab; + private CoordinatorLayout root; + private CollapsingToolbarLayout toolBarLayout; + + private AppBarStateChangeListener.State curState; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_scrolling); + + initView(); + + String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + + //增加封面 + ImageView imageView = new ImageView(this); + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setImageResource(R.mipmap.xxx1); + + resolveNormalVideoUI(); + + //外部辅助的旋转,帮助全屏 + orientationUtils = new OrientationUtils(this, detailPlayer); + //初始化不打开外部的旋转 + orientationUtils.setEnable(false); + + GSYVideoOptionBuilder gsyVideoOption = new GSYVideoOptionBuilder(); + gsyVideoOption.setThumbImageView(imageView) + .setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setShowFullAnimation(false) + .setNeedLockFull(true) + .setSeekRatio(1) + .setUrl(url) + .setCacheWithPlay(false) + .setVideoTitle("测试视频") + .setVideoAllCallBack(new GSYSampleCallBack() { + + @Override + public void onPrepared(String url, Object... objects) { + Debuger.printfError("***** onPrepared **** " + objects[0]); + Debuger.printfError("***** onPrepared **** " + objects[1]); + super.onPrepared(url, objects); + //开始播放了才能旋转和全屏 + orientationUtils.setEnable(true); + isPlay = true; + root.removeView(fab); + } + + @Override + public void onEnterFullscreen(String url, Object... objects) { + super.onEnterFullscreen(url, objects); + Debuger.printfError("***** onEnterFullscreen **** " + objects[0]);//title + Debuger.printfError("***** onEnterFullscreen **** " + objects[1]);//当前全屏player + } + + @Override + public void onAutoComplete(String url, Object... objects) { + super.onAutoComplete(url, objects); + } + + @Override + public void onClickStartError(String url, Object... objects) { + super.onClickStartError(url, objects); + } + + @Override + public void onQuitFullscreen(String url, Object... objects) { + super.onQuitFullscreen(url, objects); + Debuger.printfError("***** onQuitFullscreen **** " + objects[0]);//title + Debuger.printfError("***** onQuitFullscreen **** " + objects[1]);//当前非全屏player + if (orientationUtils != null) { + orientationUtils.backToProtVideo(); + } + } + }) + .setLockClickListener(new LockClickListener() { + @Override + public void onClick(View view, boolean lock) { + if (orientationUtils != null) { + //配合下方的onConfigurationChanged + orientationUtils.setEnable(!lock); + } + } + }) + .setGSYVideoProgressListener(new GSYVideoProgressListener() { + @Override + public void onProgress(int progress, int secProgress, int currentPosition, int duration) { + Debuger.printfLog(" progress " + progress + " secProgress " + secProgress + " currentPosition " + currentPosition + " duration " + duration); + } + }) + .build(detailPlayer); + + detailPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //直接横屏 + orientationUtils.resolveByClick(); + + //第一个true是否需要隐藏actionbar,第二个true是否需要隐藏statusbar + detailPlayer.startWindowFullscreen(ScrollingActivity.this, true, true); + } + }); + + } + + @Override + public void onBackPressed() { + + if (orientationUtils != null) { + orientationUtils.backToProtVideo(); + } + + if (GSYVideoManager.backFromWindowFull(this)) { + return; + } + super.onBackPressed(); + } + + + @Override + protected void onPause() { + getCurPlay().onVideoPause(); + super.onPause(); + isPause = true; + } + + @Override + protected void onResume() { + getCurPlay().onVideoResume(); + appBar.addOnOffsetChangedListener(appBarStateChangeListener); + super.onResume(); + isPause = false; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (isPlay) { + getCurPlay().release(); + } + if (orientationUtils != null) + orientationUtils.releaseListener(); + } + + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + //如果旋转了就全屏 + if (isPlay && !isPause) { + detailPlayer.onConfigurationChanged(this, newConfig, orientationUtils, true, true); + } + } + + private void initView() { + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + detailPlayer = (LandLayoutVideo) findViewById(R.id.detail_player); + root = (CoordinatorLayout) findViewById(R.id.root_layout); + + setSupportActionBar(toolbar); + toolBarLayout = (CollapsingToolbarLayout) findViewById(R.id.toolbar_layout); + toolBarLayout.setTitle(getTitle()); + + fab = (FloatingActionButton) findViewById(R.id.fab); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + detailPlayer.startPlayLogic(); + root.removeView(fab); + } + }); + + appBar = (AppBarLayout) findViewById(R.id.app_bar); + appBar.addOnOffsetChangedListener(appBarStateChangeListener); + } + + private void resolveNormalVideoUI() { + //增加title + detailPlayer.getTitleTextView().setVisibility(View.GONE); + detailPlayer.getBackButton().setVisibility(View.GONE); + } + + private GSYVideoPlayer getCurPlay() { + if (detailPlayer.getFullWindowPlayer() != null) { + return detailPlayer.getFullWindowPlayer(); + } + return detailPlayer; + } + + AppBarStateChangeListener appBarStateChangeListener = new AppBarStateChangeListener() { + @Override + public void onStateChanged(AppBarLayout appBarLayout, AppBarStateChangeListener.State + state) { + if (state == AppBarStateChangeListener.State.EXPANDED) { + //展开状态 + curState = state; + toolBarLayout.setTitle(""); + } else if (state == AppBarStateChangeListener.State.COLLAPSED) { + //折叠状态 + //如果是小窗口就不需要处理 + toolBarLayout.setTitle("Title"); + if (!isSamll && isPlay) { + isSamll = true; + int size = CommonUtil.dip2px(ScrollingActivity.this, 150); + detailPlayer.showSmallVideo(new Point(size, size), true, true); + orientationUtils.setEnable(false); + } + curState = state; + } else { + if (curState == AppBarStateChangeListener.State.COLLAPSED) { + //由折叠变为中间状态 + toolBarLayout.setTitle(""); + if (isSamll) { + isSamll = false; + orientationUtils.setEnable(true); + //必须 + detailPlayer.postDelayed(new Runnable() { + @Override + public void run() { + detailPlayer.hideSmallVideo(); + } + }, 50); + } + } + curState = state; + //中间状态 + } + } + }; + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/WebDetailActivity.java b/app/src/main/java/com/example/gsyvideoplayer/WebDetailActivity.java index 652933ec1..d423da2f0 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/WebDetailActivity.java +++ b/app/src/main/java/com/example/gsyvideoplayer/WebDetailActivity.java @@ -1,24 +1,24 @@ package com.example.gsyvideoplayer; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; import android.graphics.Point; import android.os.Bundle; import android.support.v4.widget.NestedScrollView; -import android.support.v7.app.AppCompatActivity; import android.view.View; import android.webkit.WebSettings; import android.widget.ImageView; import android.widget.RelativeLayout; -import com.example.gsyvideoplayer.listener.SampleListener; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.example.gsyvideoplayer.video.PreViewGSYVideoPlayer; import com.example.gsyvideoplayer.view.ScrollWebView; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.GSYBaseActivityDetail; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.utils.GSYVideoType; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; import com.shuyu.gsyvideoplayer.listener.LockClickListener; import com.shuyu.gsyvideoplayer.utils.CommonUtil; -import com.shuyu.gsyvideoplayer.utils.OrientationUtils; -import com.shuyu.gsyvideoplayer.video.NormalGSYVideoPlayer; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; import butterknife.BindView; import butterknife.ButterKnife; @@ -27,22 +27,20 @@ * Created by shuyu on 2016/12/26. */ -public class WebDetailActivity extends AppCompatActivity { +public class WebDetailActivity extends GSYBaseActivityDetail { @BindView(R.id.scroll_webView) ScrollWebView webView; @BindView(R.id.web_player) - NormalGSYVideoPlayer webPlayer; + PreViewGSYVideoPlayer webPlayer; @BindView(R.id.web_top_layout) NestedScrollView webTopLayout; @BindView(R.id.web_top_layout_video) RelativeLayout webTopLayoutVideo; - private boolean isPlay; - private boolean isPause; - private boolean isSamll; + private boolean isSmall; - private OrientationUtils orientationUtils; + private int backupRendType; @Override protected void onCreate(Bundle savedInstanceState) { @@ -50,68 +48,15 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_web_detail); ButterKnife.bind(this); - String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; - //String url = "https://d131x7vzzf85jg.cloudfront.net/upload/documents/paper/b2/61/00/00/20160420_115018_b544.mp4"; - webPlayer.setUp(url, false, null, "测试视频"); + backupRendType = GSYVideoType.getRenderType(); - //增加封面 - ImageView imageView = new ImageView(this); - imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); - imageView.setImageResource(R.mipmap.xxx1); - webPlayer.setThumbImageView(imageView); + //设置为Surface播放模式,注意此设置是全局的 + GSYVideoType.setRenderType(GSYVideoType.SUFRACE); resolveNormalVideoUI(); - //外部辅助的旋转,帮助全屏 - orientationUtils = new OrientationUtils(this, webPlayer); - //初始化不打开外部的旋转 - orientationUtils.setEnable(false); - - webPlayer.setIsTouchWiget(true); - //关闭自动旋转 - webPlayer.setRotateViewAuto(false); - webPlayer.setLockLand(false); - webPlayer.setShowFullAnimation(false); - webPlayer.setNeedLockFull(true); - //detailPlayer.setOpenPreView(true); - webPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - //直接横屏 - orientationUtils.resolveByClick(); - - //第一个true是否需要隐藏actionbar,第二个true是否需要隐藏statusbar - webPlayer.startWindowFullscreen(WebDetailActivity.this, true, true); - } - }); - - webPlayer.setStandardVideoAllCallBack(new SampleListener() { - @Override - public void onPrepared(String url, Object... objects) { - super.onPrepared(url, objects); - //开始播放了才能旋转和全屏 - orientationUtils.setEnable(true); - isPlay = true; - } - - @Override - public void onAutoComplete(String url, Object... objects) { - super.onAutoComplete(url, objects); - } - - @Override - public void onClickStartError(String url, Object... objects) { - super.onClickStartError(url, objects); - } + initVideoBuilderMode(); - @Override - public void onQuitFullscreen(String url, Object... objects) { - super.onQuitFullscreen(url, objects); - if (orientationUtils != null) { - orientationUtils.backToProtVideo(); - } - } - }); webPlayer.setLockClickListener(new LockClickListener() { @Override @@ -119,6 +64,7 @@ public void onClick(View view, boolean lock) { if (orientationUtils != null) { //配合下方的onConfigurationChanged orientationUtils.setEnable(!lock); + webPlayer.getCurrentPlayer().setRotateViewAuto(!lock); } } }); @@ -128,21 +74,24 @@ public void onClick(View view, boolean lock) { settings.setJavaScriptEnabled(true); webView.loadUrl("https://www.baidu.com"); + + orientationUtils.setRotateWithSystem(false); + webTopLayout.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { @Override public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { if (!webPlayer.isIfCurrentIsFullscreen() && scrollY >= 0 && isPlay) { if (scrollY > webPlayer.getHeight()) { //如果是小窗口就不需要处理 - if (!isSamll) { - isSamll = true; + if (!isSmall) { + isSmall = true; int size = CommonUtil.dip2px(WebDetailActivity.this, 150); webPlayer.showSmallVideo(new Point(size, size), true, true); orientationUtils.setEnable(false); } } else { - if (isSamll) { - isSamll = false; + if (isSmall) { + isSmall = false; orientationUtils.setEnable(true); //必须 webTopLayoutVideo.postDelayed(new Runnable() { @@ -161,65 +110,71 @@ public void run() { } @Override - public void onBackPressed() { - - if (orientationUtils != null) { - orientationUtils.backToProtVideo(); - } - - if (StandardGSYVideoPlayer.backFromWindowFull(this)) { - return; - } - super.onBackPressed(); + protected void onDestroy() { + super.onDestroy(); + //设置为GL播放模式,才能支持滤镜,注意此设置是全局的 + GSYVideoType.setRenderType(backupRendType); } - @Override - protected void onPause() { - super.onPause(); - isPause = true; + public StandardGSYVideoPlayer getGSYVideoPlayer() { + return webPlayer; } @Override - protected void onResume() { - super.onResume(); - isPause = false; + public GSYVideoOptionBuilder getGSYVideoOptionBuilder() { + String url = "https://res.exexm.com/cw_145225549855002"; + //String url = "https://d131x7vzzf85jg.cloudfront.net/upload/documents/paper/b2/61/00/00/20160420_115018_b544.mp4"; + //增加封面。内置封面可参考SampleCoverVideo + ImageView imageView = new ImageView(this); + loadCover(imageView, url); + return new GSYVideoOptionBuilder() + .setThumbImageView(imageView) + .setUrl(url) + .setCacheWithPlay(false) + .setRotateWithSystem(false) + .setVideoTitle("测试视频") + .setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setShowFullAnimation(false) + .setNeedLockFull(true); } @Override - protected void onDestroy() { - super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); - if (orientationUtils != null) - orientationUtils.releaseListener(); + public void clickForFullScreen() { + } + /** + * 是否启动旋转横屏,true表示启动 + * @return true + */ @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - //如果旋转了就全屏 - if (isPlay && !isPause && !isSamll) { - if (newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_USER) { - if (!webPlayer.isIfCurrentIsFullscreen()) { - webPlayer.startWindowFullscreen(WebDetailActivity.this, true, true); - } - } else { - //新版本isIfCurrentIsFullscreen的标志位内部提前设置了,所以不会和手动点击冲突 - if (webPlayer.isIfCurrentIsFullscreen()) { - StandardGSYVideoPlayer.backFromWindowFull(this); - } - if (orientationUtils != null) { - orientationUtils.setEnable(true); - } - } - } + public boolean getDetailOrientationRotateAuto() { + return true; + } + + private void loadCover(ImageView imageView, String url) { + + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setImageResource(R.mipmap.xxx1); + + Glide.with(this.getApplicationContext()) + .setDefaultRequestOptions( + new RequestOptions() + .frame(3000000) + .centerCrop() + .error(R.mipmap.xxx2) + .placeholder(R.mipmap.xxx1)) + .load(url) + .into(imageView); } private void resolveNormalVideoUI() { //增加title webPlayer.getTitleTextView().setVisibility(View.GONE); - webPlayer.getTitleTextView().setText("测试视频"); webPlayer.getBackButton().setVisibility(View.GONE); } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/WindowActivity.java b/app/src/main/java/com/example/gsyvideoplayer/WindowActivity.java new file mode 100644 index 000000000..5a4fafde2 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/WindowActivity.java @@ -0,0 +1,105 @@ +package com.example.gsyvideoplayer; + +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.RequiresApi; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.animation.BounceInterpolator; +import android.widget.Button; + + +import com.example.gsyvideoplayer.utils.floatUtil.FloatWindow; +import com.example.gsyvideoplayer.utils.floatUtil.MoveType; +import com.example.gsyvideoplayer.utils.floatUtil.Screen; +import com.example.gsyvideoplayer.utils.floatUtil.Util; +import com.example.gsyvideoplayer.view.FloatPlayerView; +import com.shuyu.gsyvideoplayer.GSYVideoManager; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +/** + * 多窗体下的悬浮窗页面 + */ +public class WindowActivity extends AppCompatActivity { + + @BindView(R.id.start_window) + Button startWindow; + @BindView(R.id.jump_other) + Button jumpOther; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_window); + ButterKnife.bind(this); + if (Build.VERSION.SDK_INT >= 23) { + if (!Util.hasPermission(this)) { + requestAlertWindowPermission(); + } + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + GSYVideoManager.instance().releaseMediaPlayer(); + /** + * 这里在返回主页的时候销毁了,因为不想和DEMO中其他页面冲突 + */ + FloatWindow.destroy(); + } + + @RequiresApi(api = 23) + private void requestAlertWindowPermission() { + Intent intent = new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION"); + intent.setData(Uri.parse("package:" + getPackageName())); + startActivityForResult(intent, 1); + } + + + @RequiresApi(api = 23) + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (Build.VERSION.SDK_INT >= 23){ + //todo 用23以上编译即可出现canDrawOverlays + if (Util.hasPermission(this)) { + + } else { + this.finish(); + } + } + } + + @OnClick({R.id.start_window, R.id.jump_other}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.start_window: + if (FloatWindow.get() != null) { + return; + } + FloatPlayerView floatPlayerView = new FloatPlayerView(getApplicationContext()); + FloatWindow + .with(getApplicationContext()) + .setView(floatPlayerView) + .setWidth(Screen.width, 0.4f) + .setHeight(Screen.width, 0.4f) + .setX(Screen.width, 0.8f) + .setY(Screen.height, 0.3f) + .setMoveType(MoveType.slide) + .setFilter(false) + .setMoveStyle(500, new BounceInterpolator()) + .build(); + FloatWindow.get().show(); + break; + case R.id.jump_other: + startActivity(new Intent(this, EmptyActivity.class)); + break; + } + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/adapter/ListMultiNormalAdapter.java b/app/src/main/java/com/example/gsyvideoplayer/adapter/ListMultiNormalAdapter.java new file mode 100644 index 000000000..f6ecf833b --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/adapter/ListMultiNormalAdapter.java @@ -0,0 +1,151 @@ +package com.example.gsyvideoplayer.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import com.example.gsyvideoplayer.R; +import com.example.gsyvideoplayer.model.VideoModel; +import com.example.gsyvideoplayer.video.MultiSampleVideo; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; + +import java.util.ArrayList; +import java.util.List; + +/** + * 多个播放的listview adapter + * Created by shuyu on 2016/11/12. + */ + +public class ListMultiNormalAdapter extends BaseAdapter { + + public static final String TAG = "ListMultiNormalAdapter"; + + private List list = new ArrayList<>(); + private LayoutInflater inflater = null; + private Context context; + + private String fullKey = "null"; + + public ListMultiNormalAdapter(Context context) { + super(); + this.context = context; + inflater = LayoutInflater.from(context); + for (int i = 0; i < 40; i++) { + list.add(new VideoModel()); + } + + } + + @Override + public int getCount() { + return list.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + final ViewHolder holder; + if (convertView == null) { + holder = new ViewHolder(); + convertView = inflater.inflate(R.layout.list_video_item_mutli, null); + holder.gsyVideoPlayer = (MultiSampleVideo) convertView.findViewById(R.id.video_item_player); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + + final String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + + //多个播放时必须在setUpLazy、setUp和getGSYVideoManager()等前面设置 + holder.gsyVideoPlayer.setPlayTag(TAG); + holder.gsyVideoPlayer.setPlayPosition(position); + + boolean isPlaying = holder.gsyVideoPlayer.getCurrentPlayer().isInPlayingState(); + + if (!isPlaying) { + holder.gsyVideoPlayer.setUpLazy(url, false, null, null, "这是title"); + } + + //增加title + holder.gsyVideoPlayer.getTitleTextView().setVisibility(View.GONE); + + //设置返回键 + holder.gsyVideoPlayer.getBackButton().setVisibility(View.GONE); + + //设置全屏按键功能 + holder.gsyVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + resolveFullBtn(holder.gsyVideoPlayer); + } + }); + holder.gsyVideoPlayer.setRotateViewAuto(true); + holder.gsyVideoPlayer.setLockLand(true); + holder.gsyVideoPlayer.setReleaseWhenLossAudio(false); + holder.gsyVideoPlayer.setShowFullAnimation(true); + holder.gsyVideoPlayer.setIsTouchWiget(false); + + holder.gsyVideoPlayer.setNeedLockFull(true); + + if (position % 2 == 0) { + holder.gsyVideoPlayer.loadCoverImage(url, R.mipmap.xxx1); + } else { + holder.gsyVideoPlayer.loadCoverImage(url, R.mipmap.xxx2); + } + + holder.gsyVideoPlayer.setVideoAllCallBack(new GSYSampleCallBack() { + + + @Override + public void onQuitFullscreen(String url, Object... objects) { + super.onQuitFullscreen(url, objects); + fullKey = "null"; + } + + @Override + public void onEnterFullscreen(String url, Object... objects) { + super.onEnterFullscreen(url, objects); + holder.gsyVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String) objects[0]); + fullKey = holder.gsyVideoPlayer.getKey(); + } + + @Override + public void onAutoComplete(String url, Object... objects) { + super.onAutoComplete(url, objects); + } + }); + + return convertView; + } + + /** + * 全屏幕按键处理 + */ + private void resolveFullBtn(final StandardGSYVideoPlayer standardGSYVideoPlayer) { + standardGSYVideoPlayer.startWindowFullscreen(context, false, true); + } + + class ViewHolder { + MultiSampleVideo gsyVideoPlayer; + } + + + public String getFullKey() { + return fullKey; + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/adapter/ListNormalAdapter.java b/app/src/main/java/com/example/gsyvideoplayer/adapter/ListNormalAdapter.java index 6bce2003c..e9a319713 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/adapter/ListNormalAdapter.java +++ b/app/src/main/java/com/example/gsyvideoplayer/adapter/ListNormalAdapter.java @@ -1,28 +1,25 @@ package com.example.gsyvideoplayer.adapter; +import android.app.Activity; import android.content.Context; +import android.content.res.Configuration; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import android.widget.ImageView; import com.example.gsyvideoplayer.R; -import com.example.gsyvideoplayer.listener.SampleListener; import com.example.gsyvideoplayer.model.VideoModel; +import com.example.gsyvideoplayer.video.SampleCoverVideo; import com.shuyu.gsyvideoplayer.GSYVideoManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; -import com.shuyu.gsyvideoplayer.listener.StandardVideoAllCallBack; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; import com.shuyu.gsyvideoplayer.utils.Debuger; -import com.shuyu.gsyvideoplayer.utils.FileUtils; +import com.shuyu.gsyvideoplayer.utils.OrientationUtils; import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; -import java.io.File; import java.util.ArrayList; import java.util.List; -import static com.shuyu.gsyvideoplayer.GSYVideoPlayer.CURRENT_STATE_NORMAL; - /** * Created by shuyu on 2016/11/12. */ @@ -35,7 +32,11 @@ public class ListNormalAdapter extends BaseAdapter { private LayoutInflater inflater = null; private Context context; - private boolean isFullVideo; + private StandardGSYVideoPlayer curPlayer; + + protected OrientationUtils orientationUtils; + + protected boolean isPlay; public ListNormalAdapter(Context context) { super(); @@ -68,38 +69,37 @@ public View getView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { holder = new ViewHolder(); convertView = inflater.inflate(R.layout.list_video_item_normal, null); - holder.gsyVideoPlayer = (StandardGSYVideoPlayer) convertView.findViewById(R.id.video_item_player); - holder.imageView = new ImageView(context); + holder.gsyVideoPlayer = (SampleCoverVideo) convertView.findViewById(R.id.video_item_player); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } - //增加封面 - holder.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + + //final String url = "https://res.exexm.com/cw_145225549855002"; + final String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + //final String url = "http://7xse1z.com1.z0.glb.clouddn.com/1491813192"; + //final String url = "http://111.198.24.133:83/yyy_login_server/pic/YB059284/97778276040859/1.mp4"; + + if (position % 2 == 0) { - holder.imageView.setImageResource(R.mipmap.xxx1); + holder.gsyVideoPlayer.loadCoverImage(url, R.mipmap.xxx1); } else { - holder.imageView.setImageResource(R.mipmap.xxx2); + holder.gsyVideoPlayer.loadCoverImage(url, R.mipmap.xxx2); } - if (holder.imageView.getParent() != null) { - ViewGroup viewGroup = (ViewGroup) holder.imageView.getParent(); - viewGroup.removeView(holder.imageView); - } - holder.gsyVideoPlayer.setThumbImageView(holder.imageView); - final String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; - //final String url = "http://7xse1z.com1.z0.glb.clouddn.com/1491813192"; - //final String url = "http://111.198.24.133:83/yyy_login_server/pic/YB059284/97778276040859/1.mp4"; + //防止错位,离开释放 + //holder.gsyVideoPlayer.initUIState(); //默认缓存路径 - holder.gsyVideoPlayer.setUp(url, true , null, "这是title"); + //使用lazy的set可以避免滑动卡的情况存在 + holder.gsyVideoPlayer.setUpLazy(url, true, null, null, "这是title"); //holder.gsyVideoPlayer.setNeedShowWifiTip(false); /************************下方为其他路径************************************/ //如果一个列表的缓存路劲都一一致 - //holder.gsyVideoPlayer.setUp(url, true, new File(FileUtils.getTestPath(), "")); + //holder.gsyVideoPlayer.setUp(url, true, new File(FileUtils.getTestPath()), ""); /************************下方为其他路径************************************/ //如果一个列表里的缓存路劲不一致 @@ -143,10 +143,12 @@ public void onClick(View v) { resolveFullBtn(holder.gsyVideoPlayer); } }); - holder.gsyVideoPlayer.setRotateViewAuto(true); - holder.gsyVideoPlayer.setLockLand(true); + holder.gsyVideoPlayer.setRotateViewAuto(!getListNeedAutoLand()); + holder.gsyVideoPlayer.setLockLand(!getListNeedAutoLand()); holder.gsyVideoPlayer.setPlayTag(TAG); - holder.gsyVideoPlayer.setShowFullAnimation(true); + holder.gsyVideoPlayer.setReleaseWhenLossAudio(false); + holder.gsyVideoPlayer.setShowFullAnimation(!getListNeedAutoLand()); + holder.gsyVideoPlayer.setIsTouchWiget(false); //循环 //holder.gsyVideoPlayer.setLooping(true); holder.gsyVideoPlayer.setNeedLockFull(true); @@ -155,27 +157,53 @@ public void onClick(View v) { holder.gsyVideoPlayer.setPlayPosition(position); - holder.gsyVideoPlayer.setStandardVideoAllCallBack(new SampleListener(){ + holder.gsyVideoPlayer.setVideoAllCallBack(new GSYSampleCallBack() { + @Override + public void onClickStartIcon(String url, Object... objects) { + super.onClickStartIcon(url, objects); + } + @Override public void onPrepared(String url, Object... objects) { super.onPrepared(url, objects); Debuger.printfLog("onPrepared"); - if (!holder.gsyVideoPlayer.isIfCurrentIsFullscreen()) { + boolean full = holder.gsyVideoPlayer.getCurrentPlayer().isIfCurrentIsFullscreen(); + if (!holder.gsyVideoPlayer.getCurrentPlayer().isIfCurrentIsFullscreen()) { GSYVideoManager.instance().setNeedMute(true); } - + curPlayer = (StandardGSYVideoPlayer) objects[1]; + isPlay = true; + if (getListNeedAutoLand()) { + //重力全屏工具类 + initOrientationUtils(holder.gsyVideoPlayer, full); + ListNormalAdapter.this.onPrepared(); + } } @Override public void onQuitFullscreen(String url, Object... objects) { super.onQuitFullscreen(url, objects); GSYVideoManager.instance().setNeedMute(true); + if (getListNeedAutoLand()) { + ListNormalAdapter.this.onQuitFullscreen(); + } } @Override public void onEnterFullscreen(String url, Object... objects) { super.onEnterFullscreen(url, objects); GSYVideoManager.instance().setNeedMute(false); + holder.gsyVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String) objects[0]); + } + + @Override + public void onAutoComplete(String url, Object... objects) { + super.onAutoComplete(url, objects); + curPlayer = null; + isPlay = false; + if (getListNeedAutoLand()) { + ListNormalAdapter.this.onAutoComplete(); + } } }); @@ -186,14 +214,98 @@ public void onEnterFullscreen(String url, Object... objects) { * 全屏幕按键处理 */ private void resolveFullBtn(final StandardGSYVideoPlayer standardGSYVideoPlayer) { + if (getListNeedAutoLand() && orientationUtils != null) { + resolveFull(); + } standardGSYVideoPlayer.startWindowFullscreen(context, false, true); - isFullVideo = true; } - class ViewHolder { - StandardGSYVideoPlayer gsyVideoPlayer; - ImageView imageView; + SampleCoverVideo gsyVideoPlayer; + } + + public void clearCache() { + if (curPlayer != null) { + curPlayer.getCurrentPlayer().clearCurrentCache(); + } + } + + + /**************************支持全屏重力全屏的部分**************************/ + + /** + * 列表时是否需要支持重力旋转 + * + * @return 返回true为支持列表重力全屏 + */ + public boolean getListNeedAutoLand() { + return true; + } + + private void initOrientationUtils(StandardGSYVideoPlayer standardGSYVideoPlayer, boolean full) { + orientationUtils = new OrientationUtils((Activity) context, standardGSYVideoPlayer); + //是否需要跟随系统旋转设置 + //orientationUtils.setRotateWithSystem(false); + orientationUtils.setEnable(false); + orientationUtils.setIsLand((full) ? 1 : 0); + } + + private void resolveFull() { + if (getListNeedAutoLand() && orientationUtils != null) { + //直接横屏 + orientationUtils.resolveByClick(); + } + } + + private void onQuitFullscreen() { + if (orientationUtils != null) { + orientationUtils.backToProtVideo(); + } + } + + public void onAutoComplete() { + if (orientationUtils != null) { + orientationUtils.setEnable(false); + orientationUtils.releaseListener(); + orientationUtils = null; + } + isPlay = false; + } + + public void onPrepared() { + if (orientationUtils == null) { + return; + } + //开始播放了才能旋转和全屏 + orientationUtils.setEnable(true); + } + + public void onConfigurationChanged(Activity activity, Configuration newConfig) { + //如果旋转了就全屏 + if (isPlay && curPlayer != null && orientationUtils != null) { + curPlayer.onConfigurationChanged(activity, newConfig, orientationUtils, false, true); + } + } + + public OrientationUtils getOrientationUtils() { + return orientationUtils; + } + + + public void onBackPressed() { + if (orientationUtils != null) { + orientationUtils.backToProtVideo(); + } + } + + public void onDestroy() { + if (isPlay && curPlayer != null) { + curPlayer.getCurrentPlayer().release(); + } + if (orientationUtils != null) { + orientationUtils.releaseListener(); + orientationUtils = null; + } } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/adapter/ListVideoAdapter.java b/app/src/main/java/com/example/gsyvideoplayer/adapter/ListVideoAdapter.java index 8ddd26d62..edd05c1fb 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/adapter/ListVideoAdapter.java +++ b/app/src/main/java/com/example/gsyvideoplayer/adapter/ListVideoAdapter.java @@ -10,9 +10,7 @@ import com.example.gsyvideoplayer.R; import com.example.gsyvideoplayer.model.VideoModel; -import com.shuyu.gsyvideoplayer.listener.StandardVideoAllCallBack; -import com.shuyu.gsyvideoplayer.utils.FileUtils; -import com.shuyu.gsyvideoplayer.utils.ListVideoUtil; +import com.shuyu.gsyvideoplayer.utils.GSYVideoHelper; import com.shuyu.gsyvideoplayer.utils.OrientationUtils; import java.io.File; @@ -32,16 +30,20 @@ public class ListVideoAdapter extends BaseAdapter { private Context context; private ViewGroup rootView; + private OrientationUtils orientationUtils; private boolean isFullVideo; - private ListVideoUtil listVideoUtil; + private GSYVideoHelper smallVideoHelper; + + private GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder; - public ListVideoAdapter(Context context, ListVideoUtil listVideoUtil) { + public ListVideoAdapter(Context context, GSYVideoHelper smallVideoHelper, GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder) { super(); this.context = context; - this.listVideoUtil = listVideoUtil; + this.smallVideoHelper = smallVideoHelper; + this.gsySmallVideoHelperBuilder = gsySmallVideoHelperBuilder; inflater = LayoutInflater.from(context); for (int i = 0; i < 40; i++) { @@ -82,20 +84,21 @@ public View getView(final int position, View convertView, ViewGroup parent) { //增加封面 holder.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); holder.imageView.setImageResource(R.mipmap.xxx1); - listVideoUtil.addVideoPlayer(position, holder.imageView, TAG, holder.videoContainer, holder.playerBtn); + smallVideoHelper.addVideoPlayer(position, holder.imageView, TAG, holder.videoContainer, holder.playerBtn); holder.playerBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { notifyDataSetChanged(); //listVideoUtil.setLoop(true); - listVideoUtil.setPlayPositionAndTag(position, TAG); - final String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; - listVideoUtil.setTitle("title " + position); - //listVideoUtil.setCachePath(new File(FileUtils.getPath())); - listVideoUtil.startPlay(url); + smallVideoHelper.setPlayPositionAndTag(position, TAG); + //final String url = "https://res.exexm.com/cw_145225549855002"; + final String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + gsySmallVideoHelperBuilder.setVideoTitle("title " + position) + .setUrl(url); + smallVideoHelper.startPlay(); //必须在startPlay之后设置才能生效 - //listVideoUtil.getGsyVideoPlayer().getTitleTextView().setVisibility(View.VISIBLE); + //smallVideoHelper.getGsyVideoPlayer().getTitleTextView().setVisibility(View.VISIBLE); } }); return convertView; diff --git a/app/src/main/java/com/example/gsyvideoplayer/adapter/RecyclerBaseAdapter.java b/app/src/main/java/com/example/gsyvideoplayer/adapter/RecyclerBaseAdapter.java index ed8c2e4db..314c13bd6 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/adapter/RecyclerBaseAdapter.java +++ b/app/src/main/java/com/example/gsyvideoplayer/adapter/RecyclerBaseAdapter.java @@ -9,7 +9,7 @@ import com.example.gsyvideoplayer.R; import com.example.gsyvideoplayer.holder.RecyclerItemViewHolder; import com.example.gsyvideoplayer.model.VideoModel; -import com.shuyu.gsyvideoplayer.utils.ListVideoUtil; +import com.shuyu.gsyvideoplayer.utils.GSYVideoHelper; import java.util.List; @@ -25,8 +25,12 @@ public class RecyclerBaseAdapter extends RecyclerView.Adapter { private final static String TAG = "RecyclerBaseAdapter"; private List itemDataList = null; + private Context context = null; - private ListVideoUtil listVideoUtil; + + private GSYVideoHelper smallVideoHelper; + + private GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder; public RecyclerBaseAdapter(Context context, List itemDataList) { this.itemDataList = itemDataList; @@ -45,7 +49,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, @Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { RecyclerItemViewHolder recyclerItemViewHolder = (RecyclerItemViewHolder) holder; - recyclerItemViewHolder.setListVideoUtil(listVideoUtil); + recyclerItemViewHolder.setVideoHelper(smallVideoHelper, gsySmallVideoHelperBuilder); recyclerItemViewHolder.setRecyclerBaseAdapter(this); recyclerItemViewHolder.onBind(position, itemDataList.get(position)); } @@ -66,11 +70,12 @@ public void setListData(List data) { notifyDataSetChanged(); } - public ListVideoUtil getListVideoUtil() { - return listVideoUtil; + public GSYVideoHelper getVideoHelper() { + return smallVideoHelper; } - public void setListVideoUtil(ListVideoUtil listVideoUtil) { - this.listVideoUtil = listVideoUtil; + public void setVideoHelper(GSYVideoHelper smallVideoHelper, GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder) { + this.smallVideoHelper = smallVideoHelper; + this.gsySmallVideoHelperBuilder = gsySmallVideoHelperBuilder; } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/effect/BitmapEffect.java b/app/src/main/java/com/example/gsyvideoplayer/effect/BitmapEffect.java new file mode 100644 index 000000000..e06038180 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/effect/BitmapEffect.java @@ -0,0 +1,32 @@ +package com.example.gsyvideoplayer.effect; + +import android.opengl.GLSurfaceView; + +import com.shuyu.gsyvideoplayer.render.view.GSYVideoGLView.ShaderInterface; + + +/** + * 合成两个渲染图画面 + */ +public class BitmapEffect implements ShaderInterface { + public BitmapEffect() { + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + String shader = + "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "varying vec2 vTextureCoord;\n" + + "uniform samplerExternalOES sTexture;\n" + + "uniform sampler2D sTexture2;\n" + + "void main() {\n" + + " vec4 c2 = texture2D(sTexture, vTextureCoord);\n" + + " vec4 c1 = texture2D(sTexture2, vTextureCoord);\n" + + " vec4 whiteColor = vec4(1.0);\n" + + " gl_FragColor = whiteColor - (whiteColor - c2) / c1;\n" + + "}\n"; + return shader; + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/gsyvideoplayer/effect/BitmapIconEffect.java b/app/src/main/java/com/example/gsyvideoplayer/effect/BitmapIconEffect.java new file mode 100644 index 000000000..a5bc13c82 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/effect/BitmapIconEffect.java @@ -0,0 +1,142 @@ +package com.example.gsyvideoplayer.effect; + +import android.graphics.Bitmap; +import android.opengl.GLSurfaceView; + +import com.shuyu.gsyvideoplayer.render.view.GSYVideoGLView.ShaderInterface; + + +/** + * 水印效果 + */ +public class BitmapIconEffect implements ShaderInterface { + + private final static int NEVER_SET = -5555; + + private GLSurfaceView mGlSurfaceViewl; + + private Bitmap mBitmap; + + private int mWidth = -1; + + private int mHeight = -1; + + private float mAlpha = 1.0f; + + private float mPositionOffset = 1.0f; + + private float mPositionX = NEVER_SET; + + private float mPositionY = NEVER_SET; + + public BitmapIconEffect(Bitmap bitmap) { + this(bitmap, bitmap.getWidth(), bitmap.getHeight()); + } + + public BitmapIconEffect(Bitmap bitmap, int width, int height) { + this(bitmap, width, height, 1); + } + + public BitmapIconEffect(Bitmap bitmap, int width, int height, float alpha) { + this.mBitmap = bitmap; + this.mWidth = width; + this.mHeight = height; + this.mAlpha = alpha; + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + this.mGlSurfaceViewl = mGlSurfaceView; + String shader = + "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "varying vec2 vTextureCoord;\n" + + "uniform samplerExternalOES sTexture;\n" + + "uniform sampler2D sTexture2;\n" + + "void main() {\n" + + " vec4 c1 = texture2D(sTexture2, vTextureCoord);\n" + + " gl_FragColor = vec4(c1.rgb, c1.a *" + mAlpha + ");\n" + + "}\n"; + return shader; + + } + + public void setPositionX(float positionX) { + this.mPositionX = positionX; + } + + public void setPositionY(float positionY) { + this.mPositionY = positionY; + } + + public float getAlpha() { + return mAlpha; + } + + public float getPositionOffset() { + return mPositionOffset; + } + + public float getWidth() { + return (float) mWidth; + } + + public float getHeight() { + return (float) mHeight; + } + + /** + * 水印图的默认比例 + */ + public float getScaleW() { + return getWidth() / mGlSurfaceViewl.getWidth(); + } + + /** + * 水印图的默认比例 + */ + public float getScaleH() { + return getHeight() / mGlSurfaceViewl.getHeight(); + } + + /** + * 水印图的起始位置,默认右边 + */ + public float getPositionX() { + if (mPositionX != NEVER_SET) { + return mPositionX; + } + return -(mGlSurfaceViewl.getWidth() / (getWidth()) - mPositionOffset); + } + + /** + * 水印图的起始位置,默认上 + */ + public float getPositionY() { + if (mPositionY != NEVER_SET) { + return mPositionY; + } + return -(mGlSurfaceViewl.getHeight() / (getHeight()) - mPositionOffset); + } + + + public float getMaxPositionX() { + return mGlSurfaceViewl.getWidth() / (getWidth()) - mPositionOffset; + } + + public float getMaxPositionY() { + return mGlSurfaceViewl.getHeight() / (getHeight()) - mPositionOffset; + } + + public float getMinPositionX() { + return -(mGlSurfaceViewl.getWidth() / (getWidth()) - mPositionOffset); + } + + public float getMinPositionY() { + return -(mGlSurfaceViewl.getHeight() / (getHeight()) - mPositionOffset); + } + + public Bitmap getBitmap() { + return mBitmap; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender.java b/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender.java new file mode 100644 index 000000000..6fb5f7396 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender.java @@ -0,0 +1,230 @@ +package com.example.gsyvideoplayer.effect; + +import android.annotation.SuppressLint; +import android.graphics.Bitmap; +import android.opengl.GLES20; +import android.opengl.GLUtils; +import android.opengl.Matrix; + +import com.shuyu.gsyvideoplayer.render.glrender.GSYVideoGLViewSimpleRender; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + + +/** + * 自定义渲染功能,继承原本的提供视频渲染 + * 自定义实现水印 + */ +@SuppressLint("ViewConstructor") +public class GSYVideoGLViewCustomRender extends GSYVideoGLViewSimpleRender { + + private static final int FLOAT_SIZE_BYTES = 4; + + private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; + + private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; + + private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; + + private final float[] mTriangleVerticesData = { + // X, Y, Z, U, V + -1.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, -1.0f, 0.0f, + 1.0f, 0.0f, -1.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, + 1.0f, 0.0f, 1.0f, 1.0f,}; + + private float[] mMVPMatrix = new float[16]; + + private float[] mSTMatrix = new float[16]; + + private int muMVPMatrixHandle; + + private int muSTMatrixHandle; + + private int maPositionHandle; + + private int maTextureHandle; + + private int curProgram; + + private int mTexturesBitmap[] = new int[1]; + + private FloatBuffer mTriangleVertices; + + //水印圖 + private BitmapIconEffect mBitmapEffect; + + public GSYVideoGLViewCustomRender() { + super(); + init(); + } + + public GSYVideoGLViewCustomRender(Bitmap bitmap) { + this(bitmap, bitmap.getWidth(), bitmap.getHeight()); + + } + + public GSYVideoGLViewCustomRender(Bitmap bitmap, int width, int height) { + this(bitmap, width, height, 1.0f); + } + + public GSYVideoGLViewCustomRender(Bitmap bitmap, int width, int height, float alpha) { + super(); + init(); + + mBitmapEffect = new BitmapIconEffect(bitmap, width, height, alpha); + } + + private void init() { + mTriangleVertices = ByteBuffer + .allocateDirect( + mTriangleVerticesData.length * FLOAT_SIZE_BYTES) + .order(ByteOrder.nativeOrder()).asFloatBuffer(); + mTriangleVertices.put(mTriangleVerticesData).position(0); + + Matrix.setIdentityM(mSTMatrix, 0); + Matrix.setIdentityM(mMVPMatrix, 0); + } + + @Override + public void onDrawFrame(GL10 glUnused) { + super.onDrawFrame(glUnused); + + //curProgram = createProgram(getVertexShader(), mBitmapEffect.getShader(mSurfaceView)); + + GLES20.glUseProgram(curProgram); + checkGlError("glUseProgram"); + + //绑定注入bitmap + int mFilterInputTextureUniform2 = GLES20.glGetUniformLocation(curProgram, "sTexture2"); + GLES20.glActiveTexture(GLES20.GL_TEXTURE3); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexturesBitmap[0]); + GLES20.glUniform1i(mFilterInputTextureUniform2, mTexturesBitmap[0]); + + mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); + GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, + false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, + mTriangleVertices); + checkGlError("glVertexAttribPointer maPosition"); + GLES20.glEnableVertexAttribArray(maPositionHandle); + checkGlError("glEnableVertexAttribArray maPositionHandle"); + + mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); + GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, + false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, + mTriangleVertices); + checkGlError("glVertexAttribPointer maTextureHandle"); + GLES20.glEnableVertexAttribArray(maTextureHandle); + checkGlError("glEnableVertexAttribArray maTextureHandle"); + + GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0); + + + GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0); + + //水印透明 + GLES20.glEnable(GLES20.GL_BLEND); + GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); + + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + checkGlError("glDrawArrays"); + + GLES20.glFinish(); + GLES20.glDisable(GLES20.GL_BLEND); + } + + @Override + public void onSurfaceChanged(GL10 glUnused, int width, int height) { + super.onSurfaceChanged(glUnused, width, height); + //旋转到正常角度 + Matrix.setRotateM(mMVPMatrix, 0, 180f, 0.0f, 0, 1.0f); + //调整大小比例 + Matrix.scaleM(mMVPMatrix, 0, mBitmapEffect.getScaleW(), mBitmapEffect.getScaleH(), 1); + //调整位置 + Matrix.translateM(mMVPMatrix, 0, mBitmapEffect.getPositionX(), mBitmapEffect.getPositionY(), 0f); + } + + @Override + public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { + super.onSurfaceCreated(glUnused, config); + + curProgram = createProgram(getVertexShader(), mBitmapEffect.getShader(mSurfaceView)); + + if (curProgram == 0) { + return; + } + maPositionHandle = GLES20 + .glGetAttribLocation(curProgram, "aPosition"); + checkGlError("glGetAttribLocation aPosition"); + if (maPositionHandle == -1) { + throw new RuntimeException( + "Could not get attrib location for aPosition"); + } + maTextureHandle = GLES20.glGetAttribLocation(curProgram, + "aTextureCoord"); + checkGlError("glGetAttribLocation aTextureCoord"); + if (maTextureHandle == -1) { + throw new RuntimeException( + "Could not get attrib location for aTextureCoord"); + } + + muMVPMatrixHandle = GLES20.glGetUniformLocation(curProgram, + "uMVPMatrix"); + checkGlError("glGetUniformLocation uMVPMatrix"); + if (muMVPMatrixHandle == -1) { + throw new RuntimeException( + "Could not get attrib location for uMVPMatrix"); + } + + muSTMatrixHandle = GLES20.glGetUniformLocation(curProgram, + "uSTMatrix"); + checkGlError("glGetUniformLocation uSTMatrix"); + if (muSTMatrixHandle == -1) { + throw new RuntimeException( + "Could not get attrib location for uSTMatrix"); + } + + //创建bitmap + GLES20.glGenTextures(1, mTexturesBitmap, 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexturesBitmap[0]); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmapEffect.getBitmap(), 0); + } + + + @Override + public void releaseAll() { + super.releaseAll(); + Bitmap bitmap = mBitmapEffect.getBitmap(); + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + } + + public float[] getCurrentMVPMatrix() { + return mMVPMatrix; + } + + public void setCurrentMVPMatrix(float[] mMVPMatrix) { + this.mMVPMatrix = mMVPMatrix; + } + + public void setBitmapEffect(BitmapIconEffect bitmapEffect) { + this.mBitmapEffect = bitmapEffect; + } +} + + diff --git a/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender2.java b/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender2.java new file mode 100644 index 000000000..427a8cc75 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender2.java @@ -0,0 +1,34 @@ +package com.example.gsyvideoplayer.effect; + +import android.annotation.SuppressLint; +import android.opengl.GLES20; +import android.opengl.Matrix; + +import com.shuyu.gsyvideoplayer.render.glrender.GSYVideoGLViewSimpleRender; + +import javax.microedition.khronos.opengles.GL10; + + +/** + * 双重播放效果 + */ +@SuppressLint("ViewConstructor") +public class GSYVideoGLViewCustomRender2 extends GSYVideoGLViewSimpleRender { + + public GSYVideoGLViewCustomRender2() { + super(); + } + + @Override + public void onDrawFrame(GL10 glUnused) { + super.onDrawFrame(glUnused); + float[] transform = new float[16]; + Matrix.setIdentityM(transform, 0); + Matrix.scaleM(transform, 0, 0.8f, 0.8f, 1); + GLES20.glUniformMatrix4fv(getMuMVPMatrixHandle(), 1, false, transform, 0); + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + GLES20.glFinish(); + } +} + + diff --git a/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender3.java b/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender3.java new file mode 100644 index 000000000..92fdbeb12 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender3.java @@ -0,0 +1,69 @@ +package com.example.gsyvideoplayer.effect; + +import android.annotation.SuppressLint; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.opengl.GLES20; +import android.opengl.GLUtils; + +import com.example.gsyvideoplayer.R; +import com.shuyu.gsyvideoplayer.render.glrender.GSYVideoGLViewSimpleRender; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + + +/** + * 图片穿孔透视播放 + */ +@SuppressLint("ViewConstructor") +public class GSYVideoGLViewCustomRender3 extends GSYVideoGLViewSimpleRender { + + private int mTexturesBitmap[] = new int[1]; + + private BitmapEffect mBitmapEffect = new BitmapEffect(); + + public GSYVideoGLViewCustomRender3() { + super(); + } + + @Override + protected void bindDrawFrameTexture() { + super.bindDrawFrameTexture(); + + //绑定注入bitmap + int mFilterInputTextureUniform2 = GLES20.glGetUniformLocation(getProgram(), "sTexture2"); + GLES20.glActiveTexture(GLES20.GL_TEXTURE3); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexturesBitmap[0]); + GLES20.glUniform1i(mFilterInputTextureUniform2, mTexturesBitmap[0]); + } + + @Override + public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { + super.onSurfaceCreated(glUnused, config); + + Bitmap bitmap = BitmapFactory.decodeResource(mSurfaceView.getResources(), R.drawable.video_brightness_6_white_36dp); + //创建bitmap + GLES20.glGenTextures(1, mTexturesBitmap, 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexturesBitmap[0]); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); + bitmap.recycle(); + } + + @Override + protected String getFragmentShader() { + return mBitmapEffect.getShader(mSurfaceView); + } + + +} + + diff --git a/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender4.java b/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender4.java new file mode 100644 index 000000000..066c13cc6 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/effect/GSYVideoGLViewCustomRender4.java @@ -0,0 +1,59 @@ +package com.example.gsyvideoplayer.effect; + +import android.annotation.SuppressLint; +import android.opengl.GLES20; +import android.opengl.Matrix; + +import com.shuyu.gsyvideoplayer.render.effect.NoEffect; +import com.shuyu.gsyvideoplayer.render.glrender.GSYVideoGLViewSimpleRender; +import com.shuyu.gsyvideoplayer.utils.Debuger; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + + +/** + * 铺满的双重播放 + * 配合高斯模糊,可以实现,高斯拉伸视频铺满背景,替换黑色,前台正常比例播放 + */ +@SuppressLint("ViewConstructor") +public class GSYVideoGLViewCustomRender4 extends GSYVideoGLViewSimpleRender { + + private int mProgram; + + public GSYVideoGLViewCustomRender4() { + super(); + } + + @Override + public void onDrawFrame(GL10 glUnused) { + super.onDrawFrame(glUnused); + + GLES20.glUseProgram(mProgram); + + float[] transform = new float[16]; + Matrix.setIdentityM(transform, 0); + Matrix.scaleM(transform, 0, (float) mCurrentViewWidth / mSurfaceView.getWidth(), + (float) mCurrentViewHeight / mSurfaceView.getHeight(), 1); + + GLES20.glUniformMatrix4fv(getMuSTMatrixHandle(), 1, false, mSTMatrix, 0); + + GLES20.glUniformMatrix4fv(getMuMVPMatrixHandle(), 1, false, transform, 0); + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + GLES20.glFinish(); + } + + + @Override + public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { + super.onSurfaceCreated(glUnused, config); + mProgram = createProgram(getVertexShader(), new NoEffect().getShader(mSurfaceView)); + } + + @Override + public void initRenderSize() { + Matrix.scaleM(mMVPMatrix, 0, 1f, 1f, 1); + } +} + + diff --git a/app/src/main/java/com/example/gsyvideoplayer/effect/PixelationEffect.java b/app/src/main/java/com/example/gsyvideoplayer/effect/PixelationEffect.java new file mode 100644 index 000000000..9fdc9790b --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/effect/PixelationEffect.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 CyberAgent + * + * 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 com.example.gsyvideoplayer.effect; + +import android.opengl.GLSurfaceView; + +import com.shuyu.gsyvideoplayer.render.view.GSYVideoGLView; + +/** + * 马赛克效果 + * Created by guoshuyu on 2017/09/20. + */ +public class PixelationEffect implements GSYVideoGLView.ShaderInterface { + + private float pixel = 40f; + + + public PixelationEffect() { + } + + /** + * 1 - 100 + */ + public PixelationEffect(float pixel) { + this.pixel = pixel; + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + + String shader = "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n"+ + "varying vec2 vTextureCoord;\n" + + + "float imageWidthFactor = "+ (1 / (float)mGlSurfaceView.getWidth()) +";\n" + + "float imageHeightFactor = " + ( 1 /(float)mGlSurfaceView.getHeight()) + ";\n" + + "uniform samplerExternalOES sTexture;\n" + + "float pixel = " + pixel +";\n" + + + "void main()\n" + + "{\n" + + " vec2 uv = vTextureCoord.xy;\n" + + " float dx = pixel * imageWidthFactor;\n" + + " float dy = pixel * imageHeightFactor;\n" + + " vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));\n" + + " vec3 tc = texture2D(sTexture, coord).xyz;\n" + + " gl_FragColor = vec4(tc, 1.0);\n" + + "}"; + + return shader; + + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/fragment/VideoFragment.java b/app/src/main/java/com/example/gsyvideoplayer/fragment/VideoFragment.java index a7e6bad34..cd7aef32c 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/fragment/VideoFragment.java +++ b/app/src/main/java/com/example/gsyvideoplayer/fragment/VideoFragment.java @@ -3,26 +3,20 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; -import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.transition.Explode; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.Window; import com.example.gsyvideoplayer.R; -import com.example.gsyvideoplayer.adapter.ListNormalAdapter; import com.example.gsyvideoplayer.adapter.RecyclerBaseAdapter; import com.example.gsyvideoplayer.adapter.RecyclerNormalAdapter; import com.example.gsyvideoplayer.holder.RecyclerItemNormalHolder; import com.example.gsyvideoplayer.model.VideoModel; import com.shuyu.gsyvideoplayer.GSYVideoManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; -import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; import java.util.ArrayList; import java.util.List; @@ -93,7 +87,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { && (position < firstVisibleItem || position > lastVisibleItem)) { //如果滑出去了上面和下面就是否,和今日头条一样 if(!mFull) { - GSYVideoPlayer.releaseAllVideos(); + GSYVideoManager.releaseAllVideos(); recyclerNormalAdapter.notifyDataSetChanged(); } } @@ -105,7 +99,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } public boolean onBackPressed() { - if (StandardGSYVideoPlayer.backFromWindowFull(getActivity())) { + if (GSYVideoManager.backFromWindowFull(getActivity())) { return true; } return false; @@ -138,7 +132,7 @@ public void onResume() { @Override public void onDestroy() { super.onDestroy(); - GSYVideoPlayer.releaseAllVideos(); + GSYVideoManager.releaseAllVideos(); } diff --git a/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemBaseHolder.java b/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemBaseHolder.java index b1776f44b..f5f6dfe88 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemBaseHolder.java +++ b/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemBaseHolder.java @@ -14,8 +14,6 @@ public class RecyclerItemBaseHolder extends RecyclerView.ViewHolder { RecyclerView.Adapter recyclerBaseAdapter; - ListVideoUtil listVideoUtil; - public RecyclerItemBaseHolder(View itemView) { super(itemView); } @@ -27,12 +25,4 @@ public RecyclerView.Adapter getRecyclerBaseAdapter() { public void setRecyclerBaseAdapter(RecyclerView.Adapter recyclerBaseAdapter) { this.recyclerBaseAdapter = recyclerBaseAdapter; } - - public ListVideoUtil getListVideoUtil() { - return listVideoUtil; - } - - public void setListVideoUtil(ListVideoUtil listVideoUtil) { - this.listVideoUtil = listVideoUtil; - } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemNormalHolder.java b/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemNormalHolder.java index fb9d29e23..7c67587fd 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemNormalHolder.java +++ b/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemNormalHolder.java @@ -6,10 +6,10 @@ import android.widget.ImageView; import com.example.gsyvideoplayer.R; -import com.example.gsyvideoplayer.listener.SampleListener; import com.example.gsyvideoplayer.model.VideoModel; import com.shuyu.gsyvideoplayer.GSYVideoManager; -import com.shuyu.gsyvideoplayer.utils.Debuger; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; import butterknife.BindView; @@ -24,17 +24,20 @@ public class RecyclerItemNormalHolder extends RecyclerItemBaseHolder { public final static String TAG = "RecyclerView2List"; protected Context context = null; - + @BindView(R.id.video_item_player) StandardGSYVideoPlayer gsyVideoPlayer; ImageView imageView; + GSYVideoOptionBuilder gsyVideoOptionBuilder; + public RecyclerItemNormalHolder(Context context, View v) { super(v); this.context = context; ButterKnife.bind(this, v); imageView = new ImageView(context); + gsyVideoOptionBuilder = new GSYVideoOptionBuilder(); } public void onBind(final int position, VideoModel videoModel) { @@ -47,15 +50,59 @@ public void onBind(final int position, VideoModel videoModel) { imageView.setImageResource(R.mipmap.xxx2); } if (imageView.getParent() != null) { - ViewGroup viewGroup = (ViewGroup)imageView.getParent(); + ViewGroup viewGroup = (ViewGroup) imageView.getParent(); viewGroup.removeView(imageView); } - gsyVideoPlayer.setThumbImageView(imageView); - - final String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; + String url; + String title; + if (position % 2 == 0) { + url = "https://res.exexm.com/cw_145225549855002"; + title = "这是title"; + } else { + url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + title = "哦?Title?"; + } + //防止错位,离开释放 + //gsyVideoPlayer.initUIState(); + gsyVideoOptionBuilder + .setIsTouchWiget(false) + .setThumbImageView(imageView) + .setUrl(url) + .setSetUpLazy(true)//lazy可以防止滑动卡顿 + .setVideoTitle(title) + .setCacheWithPlay(true) + .setRotateViewAuto(true) + .setLockLand(true) + .setPlayTag(TAG) + .setShowFullAnimation(true) + .setNeedLockFull(true) + .setPlayPosition(position) + .setVideoAllCallBack(new GSYSampleCallBack() { + @Override + public void onPrepared(String url, Object... objects) { + super.onPrepared(url, objects); + if (!gsyVideoPlayer.isIfCurrentIsFullscreen()) { + //静音 + GSYVideoManager.instance().setNeedMute(true); + } + + } + + @Override + public void onQuitFullscreen(String url, Object... objects) { + super.onQuitFullscreen(url, objects); + //全屏不静音 + GSYVideoManager.instance().setNeedMute(true); + } + + @Override + public void onEnterFullscreen(String url, Object... objects) { + super.onEnterFullscreen(url, objects); + GSYVideoManager.instance().setNeedMute(false); + gsyVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String)objects[0]); + } + }).build(gsyVideoPlayer); - //默认缓存路径 - gsyVideoPlayer.setUp(url, true , null, "这是title"); //增加title gsyVideoPlayer.getTitleTextView().setVisibility(View.GONE); @@ -70,42 +117,6 @@ public void onClick(View v) { resolveFullBtn(gsyVideoPlayer); } }); - gsyVideoPlayer.setRotateViewAuto(true); - gsyVideoPlayer.setLockLand(true); - gsyVideoPlayer.setPlayTag(TAG); - gsyVideoPlayer.setShowFullAnimation(true); - //循环 - //gsyVideoPlayer.setLooping(true); - gsyVideoPlayer.setNeedLockFull(true); - - //gsyVideoPlayer.setSpeed(2); - - gsyVideoPlayer.setPlayPosition(position); - - gsyVideoPlayer.setStandardVideoAllCallBack(new SampleListener(){ - @Override - public void onPrepared(String url, Object... objects) { - super.onPrepared(url, objects); - if (!gsyVideoPlayer.isIfCurrentIsFullscreen()) { - //静音 - GSYVideoManager.instance().setNeedMute(true); - } - - } - - @Override - public void onQuitFullscreen(String url, Object... objects) { - super.onQuitFullscreen(url, objects); - //全屏不静音 - GSYVideoManager.instance().setNeedMute(true); - } - - @Override - public void onEnterFullscreen(String url, Object... objects) { - super.onEnterFullscreen(url, objects); - GSYVideoManager.instance().setNeedMute(false); - } - }); } /** diff --git a/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemViewHolder.java b/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemViewHolder.java index cce91256f..8142ac5a0 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemViewHolder.java +++ b/app/src/main/java/com/example/gsyvideoplayer/holder/RecyclerItemViewHolder.java @@ -1,14 +1,13 @@ package com.example.gsyvideoplayer.holder; import android.content.Context; -import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import com.example.gsyvideoplayer.R; -import com.example.gsyvideoplayer.adapter.ListVideoAdapter; import com.example.gsyvideoplayer.model.VideoModel; +import com.shuyu.gsyvideoplayer.utils.GSYVideoHelper; import butterknife.BindView; import butterknife.ButterKnife; @@ -21,13 +20,19 @@ public class RecyclerItemViewHolder extends RecyclerItemBaseHolder { public final static String TAG = "RecyclerView2List"; protected Context context = null; + @BindView(R.id.list_item_container) FrameLayout listItemContainer; + @BindView(R.id.list_item_btn) ImageView listItemBtn; ImageView imageView; + private GSYVideoHelper smallVideoHelper; + + private GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder; + public RecyclerItemViewHolder(Context context, View v) { super(v); this.context = context; @@ -41,18 +46,25 @@ public void onBind(final int position, VideoModel videoModel) { imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setImageResource(R.mipmap.xxx1); - listVideoUtil.addVideoPlayer(position, imageView, TAG, listItemContainer, listItemBtn); + smallVideoHelper.addVideoPlayer(position, imageView, TAG, listItemContainer, listItemBtn); listItemBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getRecyclerBaseAdapter().notifyDataSetChanged(); //listVideoUtil.setLoop(true); - listVideoUtil.setPlayPositionAndTag(position, TAG); - listVideoUtil.setTitle("title " + position); - final String url = "http://baobab.wdjcdn.com/14564977406580.mp4"; + smallVideoHelper.setPlayPositionAndTag(position, TAG); + String url; + if (position % 2 == 0) { + url = "https://res.exexm.com/cw_145225549855002"; + } else { + url = "http://7xse1z.com1.z0.glb.clouddn.com/1491813192"; + } //listVideoUtil.setCachePath(new File(FileUtils.getPath())); - listVideoUtil.startPlay(url); + + gsySmallVideoHelperBuilder.setVideoTitle("title " + position).setUrl(url); + + smallVideoHelper.startPlay(); //必须在startPlay之后设置才能生效 //listVideoUtil.getGsyVideoPlayer().getTitleTextView().setVisibility(View.VISIBLE); @@ -60,6 +72,11 @@ public void onClick(View v) { }); } + + public void setVideoHelper(GSYVideoHelper smallVideoHelper, GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder) { + this.smallVideoHelper = smallVideoHelper; + this.gsySmallVideoHelperBuilder = gsySmallVideoHelperBuilder; + } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/listener/AppBarStateChangeListener.java b/app/src/main/java/com/example/gsyvideoplayer/listener/AppBarStateChangeListener.java new file mode 100644 index 000000000..acd3c22fd --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/listener/AppBarStateChangeListener.java @@ -0,0 +1,39 @@ +package com.example.gsyvideoplayer.listener; + +import android.support.design.widget.AppBarLayout; + +import com.shuyu.gsyvideoplayer.utils.Debuger; + +public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener { + + public enum State { + EXPANDED, + COLLAPSED, + IDLE + } + + private State mCurrentState = State.IDLE; + + @Override + public final void onOffsetChanged(AppBarLayout appBarLayout, int i) { + if (i == 0) { + if (mCurrentState != State.EXPANDED) { + onStateChanged(appBarLayout, State.EXPANDED); + } + mCurrentState = State.EXPANDED; + } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) { + if (mCurrentState != State.COLLAPSED) { + onStateChanged(appBarLayout, State.COLLAPSED); + } + mCurrentState = State.COLLAPSED; + } else { + if (mCurrentState != State.IDLE) { + onStateChanged(appBarLayout, State.IDLE); + } + mCurrentState = State.IDLE; + } + appBarLayout.addOnOffsetChangedListener(this); + } + + public abstract void onStateChanged(AppBarLayout appBarLayout, State state); +} \ No newline at end of file diff --git a/app/src/main/java/com/example/gsyvideoplayer/listener/SampleListener.java b/app/src/main/java/com/example/gsyvideoplayer/listener/SampleListener.java index 24a9f8623..e97bb7422 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/listener/SampleListener.java +++ b/app/src/main/java/com/example/gsyvideoplayer/listener/SampleListener.java @@ -1,12 +1,18 @@ package com.example.gsyvideoplayer.listener; -import com.shuyu.gsyvideoplayer.listener.StandardVideoAllCallBack; +import com.shuyu.gsyvideoplayer.listener.VideoAllCallBack; /** * Created by shuyu on 2016/11/23. */ -public class SampleListener implements StandardVideoAllCallBack { +public class SampleListener implements VideoAllCallBack { + + //开始加载,objects[0]是title,object[1]是当前所处播放器(全屏或非全屏) + @Override + public void onStartPrepared(String url, Object... objects) { + + } //加载成功,objects[0]是title,object[1]是当前所处播放器(全屏或非全屏) @Override diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/CommonUtil.java b/app/src/main/java/com/example/gsyvideoplayer/utils/CommonUtil.java index 98e496ee6..69eef3257 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/utils/CommonUtil.java +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/CommonUtil.java @@ -1,7 +1,17 @@ package com.example.gsyvideoplayer.utils; +import android.content.Context; +import android.graphics.Bitmap; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; + +import com.shuyu.gsyvideoplayer.utils.FileUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; /** * Created by shuyu on 2016/11/11. @@ -18,5 +28,14 @@ public static void setViewHeight(View view, int width, int height) { view.setLayoutParams(layoutParams); } + public static void saveBitmap(Bitmap bitmap) throws FileNotFoundException { + if (bitmap != null) { + File file = new File(FileUtils.getPath(), "GSY-" + System.currentTimeMillis() + ".jpg"); + OutputStream outputStream; + outputStream = new FileOutputStream(file); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); + bitmap.recycle(); + } + } } diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/JumpUtils.java b/app/src/main/java/com/example/gsyvideoplayer/utils/JumpUtils.java index d5e584d85..24609fbd9 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/utils/JumpUtils.java +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/JumpUtils.java @@ -7,19 +7,30 @@ import android.support.v4.util.Pair; import android.view.View; +import com.example.gsyvideoplayer.AutoPlayRecyclerViewActivity; import com.example.gsyvideoplayer.DanmkuVideoActivity; +import com.example.gsyvideoplayer.DetailADPlayer; +import com.example.gsyvideoplayer.DetailADPlayer2; +import com.example.gsyvideoplayer.DetailControlActivity; +import com.example.gsyvideoplayer.DetailFilterActivity; import com.example.gsyvideoplayer.DetailListPlayer; import com.example.gsyvideoplayer.DetailMoreTypeActivity; import com.example.gsyvideoplayer.DetailPlayer; import com.example.gsyvideoplayer.FragmentVideoActivity; import com.example.gsyvideoplayer.InputUrlDetailActivity; +import com.example.gsyvideoplayer.ListADVideoActivity; +import com.example.gsyvideoplayer.ListMultiVideoActivity; import com.example.gsyvideoplayer.ListVideo2Activity; import com.example.gsyvideoplayer.ListVideoActivity; import com.example.gsyvideoplayer.PlayActivity; +import com.example.gsyvideoplayer.PlayEmptyControlActivity; +import com.example.gsyvideoplayer.PlayPickActivity; import com.example.gsyvideoplayer.R; import com.example.gsyvideoplayer.RecyclerView2Activity; import com.example.gsyvideoplayer.RecyclerViewActivity; +import com.example.gsyvideoplayer.ScrollingActivity; import com.example.gsyvideoplayer.WebDetailActivity; +import com.example.gsyvideoplayer.WindowActivity; /** * Created by shuyu on 2016/11/11. @@ -47,6 +58,46 @@ public static void goToVideoPlayer(Activity activity, View view) { } } + /** + * 跳转到视频播放 + * + * @param activity + * @param view + */ + public static void goToVideoPickPlayer(Activity activity, View view) { + Intent intent = new Intent(activity, PlayPickActivity.class); + intent.putExtra(PlayActivity.TRANSITION, true); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + Pair pair = new Pair<>(view, PlayActivity.IMG_TRANSITION); + ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation( + activity, pair); + ActivityCompat.startActivity(activity, intent, activityOptions.toBundle()); + } else { + activity.startActivity(intent); + activity.overridePendingTransition(R.anim.abc_fade_in, R.anim.abc_fade_out); + } + } + + /** + * 跳转到无UI视频播放 + * + * @param activity + * @param view + */ + public static void goToPlayEmptyControlActivity(Activity activity, View view) { + Intent intent = new Intent(activity, PlayEmptyControlActivity.class); + intent.putExtra(PlayActivity.TRANSITION, true); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + Pair pair = new Pair<>(view, PlayActivity.IMG_TRANSITION); + ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation( + activity, pair); + ActivityCompat.startActivity(activity, intent, activityOptions.toBundle()); + } else { + activity.startActivity(intent); + activity.overridePendingTransition(R.anim.abc_fade_in, R.anim.abc_fade_out); + } + } + /** * 跳转到视频列表 * @@ -58,6 +109,17 @@ public static void goToVideoPlayer(Activity activity) { ActivityCompat.startActivity(activity, intent, activityOptions.toBundle()); } + /** + * 跳转到视频列表 + * + * @param activity + */ + public static void goToAutoVideoPlayer(Activity activity) { + Intent intent = new Intent(activity, AutoPlayRecyclerViewActivity.class); + ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(activity); + ActivityCompat.startActivity(activity, intent, activityOptions.toBundle()); + } + /** * 跳转到视频列表2 * @@ -101,6 +163,61 @@ public static void goToDetailPlayer(Activity activity) { activity.startActivity(intent); } + /** + * 跳转到详情播放 + * + * @param activity + */ + public static void goToScrollDetailPlayer(Activity activity) { + Intent intent = new Intent(activity, ScrollingActivity.class); + activity.startActivity(intent); + } + + /** + * 跳转到AD详情播放 + * + * @param activity + */ + public static void goToVideoADPlayer(Activity activity) { + Intent intent = new Intent(activity, DetailADPlayer.class); + activity.startActivity(intent); + } + + /** + * 跳转到多个同时播放 + * + * @param activity + */ + public static void goToMultiVideoPlayer(Activity activity) { + Intent intent = new Intent(activity, ListMultiVideoActivity.class); + ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(activity); + ActivityCompat.startActivity(activity, intent, activityOptions.toBundle()); + } + + /** + * 跳转列表带广告 + * + * @param activity + */ + public static void goToADListVideoPlayer(Activity activity) { + Intent intent = new Intent(activity, ListADVideoActivity.class); + ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(activity); + ActivityCompat.startActivity(activity, intent, activityOptions.toBundle()); + } + + + + + /** + * 跳转到详情播放 + * + * @param activity + */ + public static void goToScrollWindow(Activity activity) { + Intent intent = new Intent(activity, WindowActivity.class); + activity.startActivity(intent); + } + /** * 跳转到详情播放 * @@ -112,6 +229,19 @@ public static void goToDetailListPlayer(Activity activity) { } + /** + * 跳转到带广告的 + * + * @param activity + */ + public static void goToVideoADPlayer2(Activity activity) { + Intent intent = new Intent(activity, DetailADPlayer2.class); + activity.startActivity(intent); + } + + + + /** * 跳转到详情播放 * @@ -144,6 +274,7 @@ public static void gotoFragment(Activity activity) { /** * 跳到多类型 + * * @param activity */ public static void gotoMoreType(Activity activity) { @@ -153,10 +284,32 @@ public static void gotoMoreType(Activity activity) { /** * 跳到可输入 + * * @param activity */ public static void gotoInput(Activity activity) { Intent intent = new Intent(activity, InputUrlDetailActivity.class); activity.startActivity(intent); } + + /** + * 跳到可控制 + * + * @param activity + */ + public static void gotoControl(Activity activity) { + Intent intent = new Intent(activity, DetailControlActivity.class); + activity.startActivity(intent); + } + + /** + * 跳到滤镜 + * + * @param activity + */ + public static void gotoFilter(Activity activity) { + Intent intent = new Intent(activity, DetailFilterActivity.class); + activity.startActivity(intent); + } + } diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/ScrollCalculatorHelper.java b/app/src/main/java/com/example/gsyvideoplayer/utils/ScrollCalculatorHelper.java new file mode 100644 index 000000000..fb56cbe7e --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/ScrollCalculatorHelper.java @@ -0,0 +1,167 @@ +package com.example.gsyvideoplayer.utils; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Rect; +import android.os.Handler; +import android.support.v7.widget.RecyclerView; +import android.widget.AbsListView; +import android.widget.Toast; + +import com.shuyu.gsyvideoplayer.utils.*; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; + +/** + * 计算滑动,自动播放的帮助类 + * Created by guoshuyu on 2017/11/2. + */ + +public class ScrollCalculatorHelper { + + private int firstVisible = 0; + private int lastVisible = 0; + private int visibleCount = 0; + private int playId; + private int rangeTop; + private int rangeBottom; + private PlayRunnable runnable; + + private Handler playHandler = new Handler(); + + public ScrollCalculatorHelper(int playId, int rangeTop, int rangeBottom) { + this.playId = playId; + this.rangeTop = rangeTop; + this.rangeBottom = rangeBottom; + } + + public void onScrollStateChanged(RecyclerView view, int scrollState) { + switch (scrollState) { + case RecyclerView.SCROLL_STATE_IDLE: + playVideo(view); + break; + } + } + + public void onScroll(RecyclerView view, int firstVisibleItem, int lastVisibleItem, int visibleItemCount) { + if (firstVisible == firstVisibleItem) { + return; + } + firstVisible = firstVisibleItem; + lastVisible = lastVisibleItem; + visibleCount = visibleItemCount; + } + + + void playVideo(RecyclerView view) { + + if (view == null) { + return; + } + + RecyclerView.LayoutManager layoutManager = view.getLayoutManager(); + + GSYBaseVideoPlayer gsyBaseVideoPlayer = null; + + boolean needPlay = false; + + for (int i = 0; i < visibleCount; i++) { + if (layoutManager.getChildAt(i) != null && layoutManager.getChildAt(i).findViewById(playId) != null) { + GSYBaseVideoPlayer player = (GSYBaseVideoPlayer) layoutManager.getChildAt(i).findViewById(playId); + Rect rect = new Rect(); + player.getLocalVisibleRect(rect); + int height = player.getHeight(); + //说明第一个完全可视 + if (rect.top == 0 && rect.bottom == height) { + gsyBaseVideoPlayer = player; + if ((player.getCurrentPlayer().getCurrentState() == GSYBaseVideoPlayer.CURRENT_STATE_NORMAL + || player.getCurrentPlayer().getCurrentState() == GSYBaseVideoPlayer.CURRENT_STATE_ERROR)) { + needPlay = true; + } + break; + } + + } + } + + if (gsyBaseVideoPlayer != null && needPlay) { + if (runnable != null) { + GSYBaseVideoPlayer tmpPlayer = runnable.gsyBaseVideoPlayer; + playHandler.removeCallbacks(runnable); + runnable = null; + if (tmpPlayer == gsyBaseVideoPlayer) { + return; + } + } + runnable = new PlayRunnable(gsyBaseVideoPlayer); + //降低频率 + playHandler.postDelayed(runnable, 400); + } + + + } + + private class PlayRunnable implements Runnable { + + GSYBaseVideoPlayer gsyBaseVideoPlayer; + + public PlayRunnable(GSYBaseVideoPlayer gsyBaseVideoPlayer) { + this.gsyBaseVideoPlayer = gsyBaseVideoPlayer; + } + + @Override + public void run() { + boolean inPosition = false; + //如果未播放,需要播放 + if (gsyBaseVideoPlayer != null) { + int[] screenPosition = new int[2]; + gsyBaseVideoPlayer.getLocationOnScreen(screenPosition); + int halfHeight = gsyBaseVideoPlayer.getHeight() / 2; + int rangePosition = screenPosition[1] + halfHeight; + //中心点在播放区域内 + if (rangePosition >= rangeTop && rangePosition <= rangeBottom) { + inPosition = true; + } + if (inPosition) { + startPlayLogic(gsyBaseVideoPlayer, gsyBaseVideoPlayer.getContext()); + //gsyBaseVideoPlayer.startPlayLogic(); + } + } + } + } + + + /***************************************自动播放的点击播放确认******************************************/ + private void startPlayLogic(GSYBaseVideoPlayer gsyBaseVideoPlayer, Context context) { + if (!com.shuyu.gsyvideoplayer.utils.CommonUtil.isWifiConnected(context)) { + //这里判断是否wifi + showWifiDialog(gsyBaseVideoPlayer, context); + return; + } + gsyBaseVideoPlayer.startPlayLogic(); + } + + private void showWifiDialog(final GSYBaseVideoPlayer gsyBaseVideoPlayer, Context context) { + if (!NetworkUtils.isAvailable(context)) { + Toast.makeText(context, context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.no_net), Toast.LENGTH_LONG).show(); + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setMessage(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi)); + builder.setPositiveButton(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi_confirm), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + gsyBaseVideoPlayer.startPlayLogic(); + } + }); + builder.setNegativeButton(context.getResources().getString(com.shuyu.gsyvideoplayer.R.string.tips_not_wifi_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + builder.create().show(); + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/SmallVideoHelper.java b/app/src/main/java/com/example/gsyvideoplayer/utils/SmallVideoHelper.java new file mode 100644 index 000000000..c72021df2 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/SmallVideoHelper.java @@ -0,0 +1,742 @@ +package com.example.gsyvideoplayer.utils; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Point; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.FrameLayout; + +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; +import com.shuyu.gsyvideoplayer.listener.GSYVideoProgressListener; +import com.shuyu.gsyvideoplayer.listener.LockClickListener; +import com.shuyu.gsyvideoplayer.listener.VideoAllCallBack; +import com.shuyu.gsyvideoplayer.render.view.GSYVideoGLView; +import com.shuyu.gsyvideoplayer.utils.*; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; +import com.transitionseverywhere.TransitionManager; +import com.shuyu.gsyvideoplayer.utils.CommonUtil; + + +import java.io.File; +import java.util.Map; + +import static com.shuyu.gsyvideoplayer.utils.CommonUtil.getActionBarHeight; +import static com.shuyu.gsyvideoplayer.utils.CommonUtil.getStatusBarHeight; +import static com.shuyu.gsyvideoplayer.utils.CommonUtil.hideNavKey; +import static com.shuyu.gsyvideoplayer.utils.CommonUtil.showNavKey; + +/** + * 列表模式的小屏和全屏工具类 + * Created by guoshuyu on 2018/1/15. + */ +public class SmallVideoHelper { + + /** + * 播放的标志 + */ + private String TAG = "NULL"; + /** + * 播放器 + */ + private StandardGSYVideoPlayer gsyVideoPlayer; + /** + * 全屏承载布局 + */ + private ViewGroup fullViewContainer; + /** + * 全屏承载布局 + */ + private ViewGroup windowViewContainer; + /** + * 记录列表中item的父布局 + */ + private ViewGroup listParent; + /** + * 布局 + */ + private ViewGroup.LayoutParams listParams; + /** + * 选择工具类 + */ + private OrientationUtils orientationUtils; + /** + * 播放配置 + */ + private GSYSmallVideoHelperBuilder gsyVideoOptionBuilder; + /** + * 上下文 + */ + private Context context; + /** + * 播放的位置 + */ + private int playPosition = -1; + /** + * 可视保存 + */ + private int systemUiVisibility; + /** + * 当前是否全屏 + */ + private boolean isFull; + /** + * 当前是否小屏 + */ + private boolean isSmall; + /** + * 当前item框的屏幕位置 + */ + private int[] listItemRect; + /** + * 当前item的大小 + */ + private int[] listItemSize; + /** + * handler + */ + private Handler handler = new Handler(); + + + public SmallVideoHelper(Context context) { + this(context, new StandardGSYVideoPlayer(context)); + } + + public SmallVideoHelper(Context context, StandardGSYVideoPlayer player) { + gsyVideoPlayer = player; + this.context = context; + this.windowViewContainer = (ViewGroup) (CommonUtil.scanForActivity(context)).findViewById(Window.ID_ANDROID_CONTENT); + + } + + /** + * 处理全屏逻辑 + */ + private void resolveToFull() { + systemUiVisibility = ((Activity) context).getWindow().getDecorView().getSystemUiVisibility(); + CommonUtil.hideSupportActionBar(context, gsyVideoOptionBuilder.isHideActionBar(), gsyVideoOptionBuilder.isHideStatusBar()); + if (gsyVideoOptionBuilder.isHideKey()) { + hideNavKey(context); + } + isFull = true; + ViewGroup viewGroup = (ViewGroup) gsyVideoPlayer.getParent(); + listParams = gsyVideoPlayer.getLayoutParams(); + if (viewGroup != null) { + listParent = viewGroup; + viewGroup.removeView(gsyVideoPlayer); + } + gsyVideoPlayer.setIfCurrentIsFullscreen(true); + gsyVideoPlayer.getFullscreenButton().setImageResource(gsyVideoPlayer.getShrinkImageRes()); + gsyVideoPlayer.getBackButton().setVisibility(View.VISIBLE); + //设置旋转 + orientationUtils = new OrientationUtils((Activity) context, gsyVideoPlayer); + orientationUtils.setEnable(gsyVideoOptionBuilder.isRotateViewAuto()); + gsyVideoPlayer.getBackButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + resolveMaterialToNormal(gsyVideoPlayer); + } + }); + if (gsyVideoOptionBuilder.isShowFullAnimation()) { + if (fullViewContainer instanceof FrameLayout) { + //目前只做了frameLoayout的判断 + resolveMaterialAnimation(); + } else { + resolveFullAdd(); + } + + } else { + resolveFullAdd(); + } + } + + /** + * 添加到全屏父布局里 + */ + private void resolveFullAdd() { + if (gsyVideoOptionBuilder.isShowFullAnimation()) { + if (fullViewContainer != null) { + fullViewContainer.setBackgroundColor(Color.BLACK); + } + } + resolveChangeFirstLogic(0); + if (fullViewContainer != null) { + fullViewContainer.addView(gsyVideoPlayer); + } else { + windowViewContainer.addView(gsyVideoPlayer); + } + } + + /** + * 如果是5.0的动画开始位置 + */ + private void resolveMaterialAnimation() { + listItemRect = new int[2]; + listItemSize = new int[2]; + saveLocationStatus(context, gsyVideoOptionBuilder.isHideActionBar(), gsyVideoOptionBuilder.isHideStatusBar()); + FrameLayout.LayoutParams lpParent = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.setBackgroundColor(Color.BLACK); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(listItemSize[0], listItemSize[1]); + lp.setMargins(listItemRect[0], listItemRect[1], 0, 0); + frameLayout.addView(gsyVideoPlayer, lp); + if (fullViewContainer != null) { + fullViewContainer.addView(frameLayout, lpParent); + } else { + windowViewContainer.addView(frameLayout, lpParent); + } + handler.postDelayed(new Runnable() { + @Override + public void run() { + //开始动画 + if (fullViewContainer != null) { + TransitionManager.beginDelayedTransition(fullViewContainer); + } else { + TransitionManager.beginDelayedTransition(windowViewContainer); + } + resolveMaterialFullVideoShow(gsyVideoPlayer); + resolveChangeFirstLogic(600); + } + }, 300); + } + + /** + * 如果是5.0的,要从原位置过度到全屏位置 + */ + private void resolveMaterialFullVideoShow(GSYBaseVideoPlayer gsyVideoPlayer) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) gsyVideoPlayer.getLayoutParams(); + lp.setMargins(0, 0, 0, 0); + lp.height = ViewGroup.LayoutParams.MATCH_PARENT; + lp.width = ViewGroup.LayoutParams.MATCH_PARENT; + lp.gravity = Gravity.CENTER; + gsyVideoPlayer.setLayoutParams(lp); + gsyVideoPlayer.setIfCurrentIsFullscreen(true); + } + + + /** + * 处理正常逻辑 + */ + private void resolveToNormal() { + int delay = orientationUtils.backToProtVideo(); + if (!gsyVideoOptionBuilder.isShowFullAnimation()) { + delay = 0; + } + handler.postDelayed(new Runnable() { + @Override + public void run() { + isFull = false; + removeWindowContainer(); + if (fullViewContainer != null) { + fullViewContainer.removeAllViews(); + } + if (gsyVideoPlayer.getParent() != null) { + ((ViewGroup) gsyVideoPlayer.getParent()).removeView(gsyVideoPlayer); + } + orientationUtils.setEnable(false); + gsyVideoPlayer.setIfCurrentIsFullscreen(false); + if (fullViewContainer != null) { + fullViewContainer.setBackgroundColor(Color.TRANSPARENT); + } + listParent.addView(gsyVideoPlayer, listParams); + gsyVideoPlayer.getFullscreenButton().setImageResource(gsyVideoPlayer.getEnlargeImageRes()); + gsyVideoPlayer.getBackButton().setVisibility(View.GONE); + gsyVideoPlayer.setIfCurrentIsFullscreen(false); + if (gsyVideoOptionBuilder.getVideoAllCallBack() != null) { + Debuger.printfLog("onQuitFullscreen"); + gsyVideoOptionBuilder.getVideoAllCallBack().onQuitFullscreen(gsyVideoOptionBuilder.getUrl(), gsyVideoOptionBuilder.getVideoTitle(), gsyVideoPlayer); + } + if (gsyVideoOptionBuilder.isHideKey()) { + showNavKey(context, systemUiVisibility); + } + CommonUtil.showSupportActionBar(context, gsyVideoOptionBuilder.isHideActionBar(), gsyVideoOptionBuilder.isHideStatusBar()); + } + }, delay); + } + + + /** + * 动画回到正常效果 + */ + private void resolveMaterialToNormal(final GSYVideoPlayer gsyVideoPlayer) { + if (gsyVideoOptionBuilder.isShowFullAnimation() && fullViewContainer instanceof FrameLayout) { + int delay = orientationUtils.backToProtVideo(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + TransitionManager.beginDelayedTransition(fullViewContainer); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) gsyVideoPlayer.getLayoutParams(); + lp.setMargins(listItemRect[0], listItemRect[1], 0, 0); + lp.width = listItemSize[0]; + lp.height = listItemSize[1]; + //注意配置回来,不然动画效果会不对 + lp.gravity = Gravity.NO_GRAVITY; + gsyVideoPlayer.setLayoutParams(lp); + handler.postDelayed(new Runnable() { + @Override + public void run() { + resolveToNormal(); + } + }, 400); + } + }, delay); + } else { + resolveToNormal(); + } + } + + + /** + * 是否全屏一开始马上自动横屏 + */ + private void resolveChangeFirstLogic(int time) { + if (gsyVideoOptionBuilder.isLockLand()) { + if (time > 0) { + handler.postDelayed(new Runnable() { + @Override + public void run() { + if (orientationUtils.getIsLand() != 1) { + if (fullViewContainer != null) { + fullViewContainer.setBackgroundColor(Color.BLACK); + } + orientationUtils.resolveByClick(); + } + } + }, time); + } else { + if (orientationUtils.getIsLand() != 1) { + if (fullViewContainer != null) { + fullViewContainer.setBackgroundColor(Color.BLACK); + } + orientationUtils.resolveByClick(); + } + } + } + gsyVideoPlayer.setIfCurrentIsFullscreen(true); + if (gsyVideoOptionBuilder.getVideoAllCallBack() != null) { + Debuger.printfLog("onEnterFullscreen"); + gsyVideoOptionBuilder.getVideoAllCallBack().onEnterFullscreen(gsyVideoOptionBuilder.getUrl(), gsyVideoOptionBuilder.getVideoTitle(), gsyVideoPlayer); + } + } + + /** + * 保存大小和状态 + */ + private void saveLocationStatus(Context context, boolean statusBar, boolean actionBar) { + listParent.getLocationOnScreen(listItemRect); + int statusBarH = getStatusBarHeight(context); + int actionBerH = getActionBarHeight((Activity) context); + if (statusBar) { + listItemRect[1] = listItemRect[1] - statusBarH; + } + if (actionBar) { + listItemRect[1] = listItemRect[1] - actionBerH; + } + listItemSize[0] = listParent.getWidth(); + listItemSize[1] = listParent.getHeight(); + } + + + /** + * 是否当前播放 + */ + private boolean isPlayView(int position, String tag) { + return playPosition == position && TAG.equals(tag); + } + + private boolean isCurrentViewPlaying(int position, String tag) { + return isPlayView(position, tag); + } + + private boolean removeWindowContainer() { + if (windowViewContainer != null && windowViewContainer.indexOfChild(gsyVideoPlayer) != -1) { + windowViewContainer.removeView(gsyVideoPlayer); + return true; + } + return false; + } + + /** + * 动态添加视频播放 + * + * @param position 位置 + * @param imgView 封面 + * @param tag TAG类型 + * @param container player的容器 + * @param playBtn 播放按键 + */ + public void addVideoPlayer(final int position, View imgView, String tag, + ViewGroup container, View playBtn) { + container.removeAllViews(); + if (isCurrentViewPlaying(position, tag)) { + if (!isFull) { + ViewGroup viewGroup = (ViewGroup) gsyVideoPlayer.getParent(); + if (viewGroup != null) + viewGroup.removeAllViews(); + container.addView(gsyVideoPlayer); + playBtn.setVisibility(View.INVISIBLE); + } + } else { + playBtn.setVisibility(View.VISIBLE); + container.removeAllViews(); //增加封面 + container.addView(imgView); + } + } + + /** + * 设置列表播放中的位置和TAG,防止错位,回复播放位置 + * + * @param playPosition 列表中的播放位置 + * @param tag 播放的是哪个列表的tag + */ + public void setPlayPositionAndTag(int playPosition, String tag) { + this.playPosition = playPosition; + this.TAG = tag; + } + + /** + * 开始播放 + */ + public void startPlay() { + + if (isSmall()) { + smallVideoToNormal(); + } + + gsyVideoPlayer.release(); + + + if (gsyVideoOptionBuilder == null) { + throw new NullPointerException("gsyVideoOptionBuilder can't be null"); + } + + gsyVideoOptionBuilder.build(gsyVideoPlayer); + + //增加title + if (gsyVideoPlayer.getTitleTextView() != null) { + gsyVideoPlayer.getTitleTextView().setVisibility(View.GONE); + } + + //设置返回键 + if (gsyVideoPlayer.getBackButton() != null) { + gsyVideoPlayer.getBackButton().setVisibility(View.GONE); + } + + //设置全屏按键功能 + if (gsyVideoPlayer.getFullscreenButton() != null) { + gsyVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doFullBtnLogic(); + } + }); + } + gsyVideoPlayer.startPlayLogic(); + } + + /** + * 全屏按键逻辑 + */ + public void doFullBtnLogic() { + if (!isFull) { + resolveToFull(); + } else { + resolveMaterialToNormal(gsyVideoPlayer); + } + } + + + /** + * 处理返回正常逻辑 + */ + public boolean backFromFull() { + boolean isFull = false; + if (fullViewContainer != null && fullViewContainer.getChildCount() > 0) { + isFull = true; + resolveMaterialToNormal(gsyVideoPlayer); + } else if (windowViewContainer != null && windowViewContainer.indexOfChild(gsyVideoPlayer) != -1) { + isFull = true; + resolveMaterialToNormal(gsyVideoPlayer); + } + return isFull; + } + + /** + * 释放持有的视频 + */ + public void releaseVideoPlayer() { + removeWindowContainer(); + ViewGroup viewGroup = (ViewGroup) gsyVideoPlayer.getParent(); + if (viewGroup != null) + viewGroup.removeAllViews(); + playPosition = -1; + TAG = "NULL"; + if (orientationUtils != null) + orientationUtils.releaseListener(); + + } + + /** + * 显示小屏幕效果 + * + * @param size 小视频的大小 + * @param actionBar 是否有actionBar + * @param statusBar 是否有状态栏 + */ + public void showSmallVideo(Point size, final boolean actionBar, final boolean statusBar) { + if (gsyVideoPlayer.getCurrentState() == GSYVideoPlayer.CURRENT_STATE_PLAYING) { + gsyVideoPlayer.showSmallVideo(size, actionBar, statusBar); + isSmall = true; + } + } + + + /** + * 恢复小屏幕效果 + */ + public void smallVideoToNormal() { + isSmall = false; + gsyVideoPlayer.hideSmallVideo(); + } + + + /** + * 设置全屏显示的viewGroup + * 如果不设置即使用默认的 windowViewContainer + * + * @param fullViewContainer viewGroup + */ + public void setFullViewContainer(ViewGroup fullViewContainer) { + this.fullViewContainer = fullViewContainer; + } + + /** + * 是否全屏 + */ + public boolean isFull() { + return isFull; + } + + /** + * 设置配置 + */ + public void setGsyVideoOptionBuilder(GSYSmallVideoHelperBuilder gsyVideoOptionBuilder) { + this.gsyVideoOptionBuilder = gsyVideoOptionBuilder; + } + + public GSYVideoOptionBuilder getGsyVideoOptionBuilder() { + return gsyVideoOptionBuilder; + } + + public int getPlayPosition() { + return playPosition; + } + + public String getPlayTAG() { + return TAG; + } + + public boolean isSmall() { + return isSmall; + } + + /** + * 获取播放器,直接拿播放器,根据需要自定义配置 + */ + public StandardGSYVideoPlayer getGsyVideoPlayer() { + return gsyVideoPlayer; + } + + /** + * 配置 + */ + public static class GSYSmallVideoHelperBuilder extends GSYVideoOptionBuilder { + + protected boolean mHideActionBar; + + protected boolean mHideStatusBar; + + public boolean isHideActionBar() { + return mHideActionBar; + } + + public GSYSmallVideoHelperBuilder setHideActionBar(boolean hideActionBar) { + this.mHideActionBar = hideActionBar; + return this; + } + + public boolean isHideStatusBar() { + return mHideStatusBar; + } + + public GSYSmallVideoHelperBuilder setHideStatusBar(boolean hideStatusBar) { + this.mHideStatusBar = hideStatusBar; + return this; + } + + public int getShrinkImageRes() { + return mShrinkImageRes; + } + + public int getEnlargeImageRes() { + return mEnlargeImageRes; + } + + public int getPlayPosition() { + return mPlayPosition; + } + + public int getDialogProgressHighLightColor() { + return mDialogProgressHighLightColor; + } + + public int getDialogProgressNormalColor() { + return mDialogProgressNormalColor; + } + + public int getDismissControlTime() { + return mDismissControlTime; + } + + public long getSeekOnStart() { + return mSeekOnStart; + } + + public float getSeekRatio() { + return mSeekRatio; + } + + public float getSpeed() { + return mSpeed; + } + + public boolean isHideKey() { + return mHideKey; + } + + public boolean isShowFullAnimation() { + return mShowFullAnimation; + } + + public boolean isNeedShowWifiTip() { + return mNeedShowWifiTip; + } + + public boolean isRotateViewAuto() { + return mRotateViewAuto; + } + + public boolean isLockLand() { + return mLockLand; + } + + public boolean isLooping() { + return mLooping; + } + + public boolean isIsTouchWiget() { + return mIsTouchWiget; + } + + public boolean isIsTouchWigetFull() { + return mIsTouchWigetFull; + } + + public boolean isShowPauseCover() { + return mShowPauseCover; + } + + public boolean isRotateWithSystem() { + return mRotateWithSystem; + } + + public boolean isCacheWithPlay() { + return mCacheWithPlay; + } + + public boolean isNeedLockFull() { + return mNeedLockFull; + } + + public boolean isThumbPlay() { + return mThumbPlay; + } + + public boolean isSounchTouch() { + return mSounchTouch; + } + + public boolean isSetUpLazy() { + return mSetUpLazy; + } + + public String getPlayTag() { + return mPlayTag; + } + + public String getUrl() { + return mUrl; + } + + public String getVideoTitle() { + return mVideoTitle; + } + + public File getCachePath() { + return mCachePath; + } + + public Map getMapHeadData() { + return mMapHeadData; + } + + public VideoAllCallBack getVideoAllCallBack() { + return mVideoAllCallBack; + } + + public LockClickListener getLockClickListener() { + return mLockClickListener; + } + + public View getThumbImageView() { + return mThumbImageView; + } + + public Drawable getBottomProgressDrawable() { + return mBottomProgressDrawable; + } + + public Drawable getBottomShowProgressDrawable() { + return mBottomShowProgressDrawable; + } + + public Drawable getBottomShowProgressThumbDrawable() { + return mBottomShowProgressThumbDrawable; + } + + public Drawable getVolumeProgressDrawable() { + return mVolumeProgressDrawable; + } + + public Drawable getDialogProgressBarDrawable() { + return mDialogProgressBarDrawable; + } + + public GSYVideoGLView.ShaderInterface getEffectFilter() { + return mEffectFilter; + } + + public GSYVideoProgressListener getGSYVideoProgressListener() { + return mGSYVideoProgressListener; + } + } + + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatActivity.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatActivity.java new file mode 100644 index 000000000..f4dfa1005 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatActivity.java @@ -0,0 +1,82 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.annotation.RequiresApi; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用于在内部自动申请权限 + * https://github.com/yhaolpz + */ + +public class FloatActivity extends Activity { + + private static List mPermissionListenerList; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT >= 23){ + requestAlertWindowPermission(); + } + } + + @RequiresApi(api = 23) + private void requestAlertWindowPermission() { + Intent intent = new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION"); + intent.setData(Uri.parse("package:" + getPackageName())); + startActivityForResult(intent, 1); + } + + + @RequiresApi(api = 23) + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (Build.VERSION.SDK_INT >= 23){ + //todo 用23以上编译即可出现canDrawOverlays + if (Util.hasPermission(this)) { + mPermissionListener.onSuccess(); + } else { + mPermissionListener.onFail(); + } + } + finish(); + } + + static synchronized void request(Context context, PermissionListener permissionListener) { + if (mPermissionListenerList == null) { + mPermissionListenerList = new ArrayList<>(); + mPermissionListener = new PermissionListener() { + @Override + public void onSuccess() { + for (PermissionListener listener : mPermissionListenerList) { + listener.onSuccess(); + } + } + + @Override + public void onFail() { + for (PermissionListener listener : mPermissionListenerList) { + listener.onFail(); + } + } + }; + Intent intent = new Intent(context, FloatActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + mPermissionListenerList.add(permissionListener); + } + + + private static PermissionListener mPermissionListener; +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatLifecycle.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatLifecycle.java new file mode 100644 index 000000000..962ab2768 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatLifecycle.java @@ -0,0 +1,129 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.app.Activity; +import android.app.Application; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.os.Handler; + +/** + * Created by yhao on 17-12-1. + * 用于控制悬浮窗显示周期 + * 使用了三种方法针对返回桌面时隐藏悬浮按钮 + * 1.startCount计数,针对back到桌面可以及时隐藏 + * 2.监听home键,从而及时隐藏 + * 3.resumeCount计时,针对一些只执行onPause不执行onStop的奇葩情况 + */ + +class FloatLifecycle extends BroadcastReceiver implements Application.ActivityLifecycleCallbacks { + + private static final String SYSTEM_DIALOG_REASON_KEY = "reason"; + private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; + private static final long delay = 300; + private Handler mHandler; + private Class[] activities; + private boolean showFlag; + private int startCount; + private int resumeCount; + private boolean appBackground; + private LifecycleListener mLifecycleListener; + + + FloatLifecycle(Context applicationContext, boolean showFlag, Class[] activities, LifecycleListener lifecycleListener) { + this.showFlag = showFlag; + this.activities = activities; + mLifecycleListener = lifecycleListener; + mHandler = new Handler(); + ((Application) applicationContext).registerActivityLifecycleCallbacks(this); + applicationContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + } + + + private boolean needShow(Activity activity) { + if (activities == null) { + return true; + } + for (Class a : activities) { + if (a.isInstance(activity)) { + return showFlag; + } + } + return !showFlag; + } + + + @Override + public void onActivityResumed(Activity activity) { + resumeCount++; + if (needShow(activity)) { + mLifecycleListener.onShow(); + } else { + //mLifecycleListener.onHide(); + } + if (appBackground) { + appBackground = false; + } + } + + @Override + public void onActivityPaused(Activity activity) { + resumeCount--; + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (resumeCount == 0) { + appBackground = true; + //mLifecycleListener.onPostHide(); + } + } + }, delay); + + } + + @Override + public void onActivityStarted(Activity activity) { + startCount++; + } + + + @Override + public void onActivityStopped(Activity activity) { + startCount--; + if (startCount == 0) { + //mLifecycleListener.onHide(); + } + } + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action != null && action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { + String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); + if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) { + //mLifecycleListener.onHide(); + } + } + } + + + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + + } + + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + + } + + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatPhone.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatPhone.java new file mode 100644 index 000000000..a3797ceba --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatPhone.java @@ -0,0 +1,106 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.View; +import android.view.WindowManager; + +/** + * Created by yhao on 17-11-14. + * 7.1及以上需申请权限 + */ + +class FloatPhone extends FloatView { + + private final Context mContext; + + private final WindowManager mWindowManager; + private final WindowManager.LayoutParams mLayoutParams; + private View mView; + private int mX, mY; + + FloatPhone(Context applicationContext) { + mContext = applicationContext; + mWindowManager = (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE); + mLayoutParams = new WindowManager.LayoutParams(); + } + + @Override + public void setSize(int width, int height) { + mLayoutParams.width = width; + mLayoutParams.height = height; + } + + @Override + public void setView(View view) { + mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; + mLayoutParams.windowAnimations = 0; + mView = view; + } + + @Override + public void setGravity(int gravity, int xOffset, int yOffset) { + mLayoutParams.gravity = gravity; + mLayoutParams.x = mX = xOffset; + mLayoutParams.y = mY = yOffset; + } + + + @Override + public void init() { + if (Util.hasPermission(mContext)) { + mLayoutParams.format = PixelFormat.RGBA_8888; + mWindowManager.addView(mView, mLayoutParams); + } else { + FloatActivity.request(mContext, new PermissionListener() { + @Override + public void onSuccess() { + mLayoutParams.format = PixelFormat.RGBA_8888; + mWindowManager.addView(mView, mLayoutParams); + } + + @Override + public void onFail() { + + } + }); + } + } + + @Override + public void dismiss() { + mWindowManager.removeView(mView); + } + + @Override + public void updateXY(int x, int y) { + mLayoutParams.x = mX = x; + mLayoutParams.y = mY = y; + mWindowManager.updateViewLayout(mView, mLayoutParams); + } + + @Override + void updateX(int x) { + mLayoutParams.x = mX = x; + mWindowManager.updateViewLayout(mView, mLayoutParams); + + } + + @Override + void updateY(int y) { + mLayoutParams.y = mY = y; + mWindowManager.updateViewLayout(mView, mLayoutParams); + } + + @Override + int getX() { + return mX; + } + + @Override + int getY() { + return mY; + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatToast.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatToast.java new file mode 100644 index 000000000..9388634b9 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatToast.java @@ -0,0 +1,95 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.content.Context; +import android.view.View; +import android.view.WindowManager; +import android.widget.Toast; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * 自定义 toast 方式,无需申请权限 + */ + +class FloatToast extends FloatView { + + + private Toast toast; + + private Object mTN; + private Method show; + private Method hide; + + private int mWidth; + private int mHeight; + + + FloatToast(Context applicationContext) { + toast = new Toast(applicationContext); + } + + + @Override + public void setSize(int width, int height) { + mWidth = width; + mHeight = height; + } + + @Override + public void setView(View view) { + toast.setView(view); + initTN(); + } + + @Override + public void setGravity(int gravity, int xOffset, int yOffset) { + toast.setGravity(gravity, xOffset, yOffset); + } + + @Override + public void init() { + try { + show.invoke(mTN); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void dismiss() { + try { + hide.invoke(mTN); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + private void initTN() { + try { + Field tnField = toast.getClass().getDeclaredField("mTN"); + tnField.setAccessible(true); + mTN = tnField.get(toast); + show = mTN.getClass().getMethod("show"); + hide = mTN.getClass().getMethod("hide"); + + Field tnParamsField = mTN.getClass().getDeclaredField("mParams"); + tnParamsField.setAccessible(true); + WindowManager.LayoutParams params = (WindowManager.LayoutParams) tnParamsField.get(mTN); + params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + params.width = mWidth; + params.height = mHeight; + params.windowAnimations = 0; + Field tnNextViewField = mTN.getClass().getDeclaredField("mNextView"); + tnNextViewField.setAccessible(true); + tnNextViewField.set(mTN, toast.getView()); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatView.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatView.java new file mode 100644 index 000000000..86b7e7cff --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatView.java @@ -0,0 +1,38 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.view.View; + +/** + * Created by yhao on 17-11-14. + * https://github.com/yhaolpz + */ + +abstract class FloatView { + + abstract void setSize(int width, int height); + + abstract void setView(View view); + + abstract void setGravity(int gravity, int xOffset, int yOffset); + + abstract void init(); + + abstract void dismiss(); + + void updateXY(int x, int y) { + } + + void updateX(int x) { + } + + void updateY(int y) { + } + + int getX() { + return 0; + } + + int getY() { + return 0; + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatWindow.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatWindow.java new file mode 100644 index 000000000..2e1609a5c --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/FloatWindow.java @@ -0,0 +1,189 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.animation.TimeInterpolator; +import android.content.Context; +import android.support.annotation.LayoutRes; +import android.support.annotation.MainThread; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by yhao on 2017/12/22. + * https://github.com/yhaolpz + */ + +public class FloatWindow { + + private FloatWindow() { + + } + + private static final String mDefaultTag = "default_float_window_tag"; + private static Map mFloatWindowMap; + + public static IFloatWindow get() { + return get(mDefaultTag); + } + + public static IFloatWindow get(@NonNull String tag) { + return mFloatWindowMap == null ? null : mFloatWindowMap.get(tag); + } + + private static B mBuilder = null; + + @MainThread + public static B with(@NonNull Context applicationContext) { + return mBuilder = new B(applicationContext); + } + + public static void destroy() { + destroy(mDefaultTag); + } + + public static void destroy(String tag) { + if (mFloatWindowMap == null || !mFloatWindowMap.containsKey(tag)) { + return; + } + mFloatWindowMap.get(tag).dismiss(); + mFloatWindowMap.remove(tag); + } + + public static class B { + Context mApplicationContext; + View mView; + private int mLayoutId; + int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT; + int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT; + int gravity = Gravity.TOP | Gravity.START; + int xOffset; + int yOffset; + boolean mShow = true; + Class[] mActivities; + int mMoveType = MoveType.fixed; + long mDuration = 300; + TimeInterpolator mInterpolator; + private String mTag = mDefaultTag; + + private B() { + + } + + B(Context applicationContext) { + mApplicationContext = applicationContext; + } + + public B setView(@NonNull View view) { + mView = view; + return this; + } + + public B setView(@LayoutRes int layoutId) { + mLayoutId = layoutId; + return this; + } + + public B setWidth(int width) { + mWidth = width; + return this; + } + + public B setHeight(int height) { + mHeight = height; + return this; + } + + public B setWidth(@Screen.screenType int screenType, float ratio) { + mWidth = (int) ((screenType == Screen.width ? + Util.getScreenWidth(mApplicationContext) : + Util.getScreenHeight(mApplicationContext)) * ratio); + return this; + } + + + public B setHeight(@Screen.screenType int screenType, float ratio) { + mHeight = (int) ((screenType == Screen.width ? + Util.getScreenWidth(mApplicationContext) : + Util.getScreenHeight(mApplicationContext)) * ratio); + return this; + } + + + public B setX(int x) { + xOffset = x; + return this; + } + + public B setY(int y) { + yOffset = y; + return this; + } + + public B setX(@Screen.screenType int screenType, float ratio) { + xOffset = (int) ((screenType == Screen.width ? + Util.getScreenWidth(mApplicationContext) : + Util.getScreenHeight(mApplicationContext)) * ratio); + return this; + } + + public B setY(@Screen.screenType int screenType, float ratio) { + yOffset = (int) ((screenType == Screen.width ? + Util.getScreenWidth(mApplicationContext) : + Util.getScreenHeight(mApplicationContext)) * ratio); + return this; + } + + + /** + * 设置 Activity 过滤器,用于指定在哪些界面显示悬浮窗,默认全部界面都显示 + * + * @param show  过滤类型,子类类型也会生效 + * @param activities  过滤界面 + */ + public B setFilter(boolean show, @NonNull Class... activities) { + mShow = show; + mActivities = activities; + return this; + } + + + public B setMoveType(@MoveType.MOVE_TYPE int moveType) { + mMoveType = moveType; + return this; + } + + public B setMoveStyle(long duration, @Nullable TimeInterpolator interpolator) { + mDuration = duration; + mInterpolator = interpolator; + return this; + } + + public B setTag(@NonNull String tag) { + mTag = tag; + return this; + } + + public void build() { + if (mFloatWindowMap == null) { + mFloatWindowMap = new HashMap<>(); + } + if (mFloatWindowMap.containsKey(mTag)) { + throw new IllegalArgumentException("FloatWindow of this tag has been added, Please set a new tag for the new FloatWindow"); + } + if (mView == null && mLayoutId == 0) { + throw new IllegalArgumentException("View has not been set!"); + } + if (mView == null) { + mView = Util.inflate(mApplicationContext, mLayoutId); + } + IFloatWindow floatWindowImpl = new IFloatWindowImpl(this); + mFloatWindowMap.put(mTag, floatWindowImpl); + } + + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/IFloatWindow.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/IFloatWindow.java new file mode 100644 index 000000000..4cc25c0f8 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/IFloatWindow.java @@ -0,0 +1,30 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.view.View; + +/** + * Created by yhao on 2017/12/22. + * https://github.com/yhaolpz + */ + +public abstract class IFloatWindow { + public abstract void show(); + + public abstract void hide(); + + public abstract int getX(); + + public abstract int getY(); + + public abstract void updateX(int x); + + public abstract void updateX(@Screen.screenType int screenType,float ratio); + + public abstract void updateY(int y); + + public abstract void updateY(@Screen.screenType int screenType,float ratio); + + public abstract View getView(); + + abstract void dismiss(); +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/IFloatWindowImpl.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/IFloatWindowImpl.java new file mode 100644 index 000000000..e4422da43 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/IFloatWindowImpl.java @@ -0,0 +1,253 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.os.Build; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +/** + * Created by yhao on 2017/12/22. + * https://github.com/yhaolpz + */ + +public class IFloatWindowImpl extends IFloatWindow { + + + private FloatWindow.B mB; + private FloatView mFloatView; + private FloatLifecycle mFloatLifecycle; + private boolean isShow; + private boolean once = true; + private ValueAnimator mAnimator; + private TimeInterpolator mDecelerateInterpolator; + + private IFloatWindowImpl() { + + } + + IFloatWindowImpl(FloatWindow.B b) { + mB = b; + if (mB.mMoveType == MoveType.fixed) { + if (Build.VERSION.SDK_INT >=25) { + mFloatView = new FloatPhone(b.mApplicationContext); + } else { + mFloatView = new FloatToast(b.mApplicationContext); + } + } else { + mFloatView = new FloatPhone(b.mApplicationContext); + initTouchEvent(); + } + mFloatView.setSize(mB.mWidth, mB.mHeight); + mFloatView.setGravity(mB.gravity, mB.xOffset, mB.yOffset); + mFloatView.setView(mB.mView); + mFloatLifecycle = new FloatLifecycle(mB.mApplicationContext, mB.mShow, mB.mActivities, new LifecycleListener() { + @Override + public void onShow() { + show(); + } + + @Override + public void onHide() { + hide(); + } + + @Override + public void onPostHide() { + postHide(); + } + }); + } + + @Override + public void show() { + if (once) { + mFloatView.init(); + once = false; + isShow = true; + } else { + if (isShow) return; + getView().setVisibility(View.VISIBLE); + isShow = true; + } + } + + @Override + public void hide() { + if (once || !isShow) return; + getView().setVisibility(View.INVISIBLE); + isShow = false; + } + + @Override + void dismiss() { + mFloatView.dismiss(); + isShow = false; + } + + @Override + public void updateX(int x) { + checkMoveType(); + mB.xOffset = x; + mFloatView.updateX(x); + } + + @Override + public void updateY(int y) { + checkMoveType(); + mB.yOffset = y; + mFloatView.updateY(y); + } + + @Override + public void updateX(int screenType, float ratio) { + checkMoveType(); + mB.xOffset = (int) ((screenType == Screen.width ? + Util.getScreenWidth(mB.mApplicationContext) : + Util.getScreenHeight(mB.mApplicationContext)) * ratio); + mFloatView.updateX(mB.xOffset); + + } + + @Override + public void updateY(int screenType, float ratio) { + checkMoveType(); + mB.yOffset = (int) ((screenType == Screen.width ? + Util.getScreenWidth(mB.mApplicationContext) : + Util.getScreenHeight(mB.mApplicationContext)) * ratio); + mFloatView.updateY(mB.yOffset); + + } + + @Override + public int getX() { + return mFloatView.getX(); + } + + @Override + public int getY() { + return mFloatView.getY(); + } + + + @Override + public View getView() { + return mB.mView; + } + + void postHide() { + if (once || !isShow) return; + getView().post(new Runnable() { + @Override + public void run() { + getView().setVisibility(View.INVISIBLE); + } + }); + isShow = false; + } + + private void checkMoveType() { + if (mB.mMoveType == MoveType.fixed) { + throw new IllegalArgumentException("FloatWindow of this tag is not allowed to move!"); + } + } + + private void initTouchEvent() { + switch (mB.mMoveType) { + case MoveType.free: + break; + default: + getView().setOnTouchListener(new View.OnTouchListener() { + float lastX, lastY, changeX, changeY; + int newX, newY; + + @Override + public boolean onTouch(View v, MotionEvent event) { + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + lastX = event.getRawX(); + lastY = event.getRawY(); + cancelAnimator(); + break; + case MotionEvent.ACTION_MOVE: + changeX = event.getRawX() - lastX; + changeY = event.getRawY() - lastY; + newX = (int) (mFloatView.getX() + changeX); + newY = (int) (mFloatView.getY() + changeY); + mFloatView.updateXY(newX, newY); + lastX = event.getRawX(); + lastY = event.getRawY(); + break; + case MotionEvent.ACTION_UP: + switch (mB.mMoveType) { + case MoveType.slide: + int startX = mFloatView.getX(); + int endX = (startX * 2 + v.getWidth() > + Util.getScreenWidth(mB.mApplicationContext)) ? + Util.getScreenWidth(mB.mApplicationContext) - v.getWidth() : 0; + mAnimator = ObjectAnimator.ofInt(startX, endX); + mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int x = (int) animation.getAnimatedValue(); + mFloatView.updateX(x); + } + }); + startAnimator(); + break; + case MoveType.back: + PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt("x", mFloatView.getX(), mB.xOffset); + PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt("y", mFloatView.getY(), mB.yOffset); + mAnimator = ObjectAnimator.ofPropertyValuesHolder(pvhX, pvhY); + mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int x = (int) animation.getAnimatedValue("x"); + int y = (int) animation.getAnimatedValue("y"); + mFloatView.updateXY(x, y); + } + }); + startAnimator(); + break; + } + break; + + } + return false; + } + }); + } + } + + private void startAnimator() { + if (mB.mInterpolator == null) { + if (mDecelerateInterpolator == null) { + mDecelerateInterpolator = new DecelerateInterpolator(); + } + mB.mInterpolator = mDecelerateInterpolator; + } + mAnimator.setInterpolator(mB.mInterpolator); + mAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mAnimator.removeAllUpdateListeners(); + mAnimator.removeAllListeners(); + mAnimator = null; + } + }); + mAnimator.setDuration(mB.mDuration).start(); + } + + private void cancelAnimator() { + if (mAnimator != null && mAnimator.isRunning()) { + mAnimator.cancel(); + } + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/LifecycleListener.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/LifecycleListener.java new file mode 100644 index 000000000..9c8f85401 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/LifecycleListener.java @@ -0,0 +1,15 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +/** + * Created by yhao on 2017/12/22. + * https://github.com/yhaolpz + */ + +interface LifecycleListener { + + void onShow(); + + void onHide(); + + void onPostHide(); +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/MoveType.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/MoveType.java new file mode 100644 index 000000000..7209e2f38 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/MoveType.java @@ -0,0 +1,24 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Created by yhao on 2017/12/22. + * https://github.com/yhaolpz + */ + +public class MoveType { + static final int fixed = 0; + public static final int free = 1; + public static final int active = 2; + public static final int slide = 3; + public static final int back = 4; + + @IntDef({fixed, free, active, slide, back}) + @Retention(RetentionPolicy.SOURCE) + @interface MOVE_TYPE { + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/PermissionListener.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/PermissionListener.java new file mode 100644 index 000000000..44be0d119 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/PermissionListener.java @@ -0,0 +1,11 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +/** + * Created by yhao on 2017/11/14. + * https://github.com/yhaolpz + */ +interface PermissionListener { + void onSuccess(); + + void onFail(); +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/Screen.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/Screen.java new file mode 100644 index 000000000..0d346c08a --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/Screen.java @@ -0,0 +1,21 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Created by yhao on 2017/12/23. + * https://github.com/yhaolpz + */ + +public class Screen { + public static final int width = 0; + public static final int height = 1; + + @IntDef({width, height}) + @Retention(RetentionPolicy.SOURCE) + @interface screenType { + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/Util.java b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/Util.java new file mode 100644 index 000000000..07c47a002 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/utils/floatUtil/Util.java @@ -0,0 +1,57 @@ +package com.example.gsyvideoplayer.utils.floatUtil; + +import android.content.Context; +import android.graphics.Point; +import android.provider.Settings; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; + +import java.lang.reflect.Method; + +/** + * Created by yhao on 2017/12/22. + * https://github.com/yhaolpz + */ + +public class Util { + + + static View inflate(Context applicationContext, int layoutId) { + LayoutInflater inflate = (LayoutInflater) applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + return inflate.inflate(layoutId, null); + } + + public static boolean hasPermission(Context context) { + Boolean result; + try { + Class clazz = Settings.class; + Method canDrawOverlays = clazz.getDeclaredMethod("canDrawOverlays", Context.class); + result = (Boolean) canDrawOverlays.invoke(null, context); + } catch (Exception e) { + result = false; + } + return result; + } + + + private static Point sPoint; + + static int getScreenWidth(Context context) { + if (sPoint == null) { + sPoint = new Point(); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getSize(sPoint); + } + return sPoint.x; + } + + static int getScreenHeight(Context context) { + if (sPoint == null) { + sPoint = new Point(); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getSize(sPoint); + } + return sPoint.y; + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/CustomRenderVideoPlayer.java b/app/src/main/java/com/example/gsyvideoplayer/video/CustomRenderVideoPlayer.java new file mode 100644 index 000000000..8482ca088 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/CustomRenderVideoPlayer.java @@ -0,0 +1,32 @@ +package com.example.gsyvideoplayer.video; + +import android.content.Context; +import android.util.AttributeSet; + +import com.example.gsyvideoplayer.view.CustomRenderView; +import com.shuyu.gsyvideoplayer.video.NormalGSYVideoPlayer; + +/** + * 自定义渲染控件 + * Created by guoshuyu on 2018/1/30. + */ + +public class CustomRenderVideoPlayer extends NormalGSYVideoPlayer { + public CustomRenderVideoPlayer(Context context, Boolean fullFlag) { + super(context, fullFlag); + } + + public CustomRenderVideoPlayer(Context context) { + super(context); + } + + public CustomRenderVideoPlayer(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void addTextureView() { + mTextureView = new CustomRenderView(); + mTextureView.addView(getContext(), mTextureViewContainer, mRotate, this, this, mEffectFilter, mMatrixGL, mRenderer, mMode); + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/DanmakuVideoPlayer.java b/app/src/main/java/com/example/gsyvideoplayer/video/DanmakuVideoPlayer.java index 3d6771c1a..6edcb3c53 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/video/DanmakuVideoPlayer.java +++ b/app/src/main/java/com/example/gsyvideoplayer/video/DanmakuVideoPlayer.java @@ -2,34 +2,20 @@ import android.content.Context; import android.graphics.Color; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.style.BackgroundColorSpan; -import android.text.style.ImageSpan; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.view.ViewGroup; -import android.widget.SeekBar; import android.widget.TextView; import com.example.gsyvideoplayer.R; import com.example.gsyvideoplayer.adapter.DanamakuAdapter; import com.example.gsyvideoplayer.utils.BiliDanmukuParser; -import com.shuyu.gsyvideoplayer.GSYVideoManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; import com.shuyu.gsyvideoplayer.utils.Debuger; -import com.shuyu.gsyvideoplayer.video.GSYBaseVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; -import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; import java.util.HashMap; import master.flame.danmaku.controller.IDanmakuView; @@ -38,15 +24,12 @@ import master.flame.danmaku.danmaku.loader.android.DanmakuLoaderFactory; import master.flame.danmaku.danmaku.model.BaseDanmaku; import master.flame.danmaku.danmaku.model.DanmakuTimer; -import master.flame.danmaku.danmaku.model.IDanmakus; import master.flame.danmaku.danmaku.model.IDisplayer; -import master.flame.danmaku.danmaku.model.android.BaseCacheStuffer; import master.flame.danmaku.danmaku.model.android.DanmakuContext; import master.flame.danmaku.danmaku.model.android.Danmakus; import master.flame.danmaku.danmaku.model.android.SpannedCacheStuffer; import master.flame.danmaku.danmaku.parser.BaseDanmakuParser; import master.flame.danmaku.danmaku.parser.IDataSource; -import master.flame.danmaku.danmaku.util.IOUtils; import master.flame.danmaku.ui.widget.DanmakuView; /** @@ -282,7 +265,7 @@ private void onPrepareDanmaku(DanmakuVideoPlayer gsyVideoPlayer) { * 弹幕偏移 */ private void resolveDanmakuSeek(DanmakuVideoPlayer gsyVideoPlayer, long time) { - if (GSYVideoManager.instance().getMediaPlayer() != null && mHadPlay + if (getGSYVideoManager().getMediaPlayer() != null && mHadPlay && gsyVideoPlayer.getDanmakuView() != null && gsyVideoPlayer.getDanmakuView().isPrepared()) { gsyVideoPlayer.getDanmakuView().seekTo(time); } diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/EmptyControlVideo.java b/app/src/main/java/com/example/gsyvideoplayer/video/EmptyControlVideo.java new file mode 100644 index 000000000..390385ad3 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/EmptyControlVideo.java @@ -0,0 +1,51 @@ +package com.example.gsyvideoplayer.video; + +import android.content.Context; +import android.util.AttributeSet; + +import com.example.gsyvideoplayer.R; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; + +/** + * 无任何控制ui的播放 + * Created by guoshuyu on 2017/8/6. + */ + +public class EmptyControlVideo extends StandardGSYVideoPlayer { + + public EmptyControlVideo(Context context, Boolean fullFlag) { + super(context, fullFlag); + } + + public EmptyControlVideo(Context context) { + super(context); + } + + public EmptyControlVideo(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public int getLayoutId() { + return R.layout.empty_control_video; + } + + @Override + protected void touchSurfaceMoveFullLogic(float absDeltaX, float absDeltaY) { + super.touchSurfaceMoveFullLogic(absDeltaX, absDeltaY); + //不给触摸快进,如果需要,屏蔽下方代码即可 + mChangePosition = false; + + //不给触摸音量,如果需要,屏蔽下方代码即可 + mChangeVolume = false; + + //不给触摸亮度,如果需要,屏蔽下方代码即可 + mBrightness = false; + } + + @Override + protected void touchDoubleUp() { + //super.touchDoubleUp(); + //不需要双击暂停 + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/FloatingVideo.java b/app/src/main/java/com/example/gsyvideoplayer/video/FloatingVideo.java new file mode 100644 index 000000000..a3bfac961 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/FloatingVideo.java @@ -0,0 +1,187 @@ +package com.example.gsyvideoplayer.video; + + +import android.content.Context; +import android.media.AudioManager; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +import com.example.gsyvideoplayer.R; +import com.shuyu.gsyvideoplayer.utils.Debuger; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; + +import java.util.Timer; +import java.util.TimerTask; + +import static com.shuyu.gsyvideoplayer.utils.CommonUtil.hideNavKey; + +/** + * 多窗体下的悬浮窗页面支持Video + * Created by shuyu on 2017/12/25. + */ + +public class FloatingVideo extends StandardGSYVideoPlayer { + + protected DismissControlViewTimerTask mDismissControlViewTimerTask; + + /** + * 1.5.0开始加入,如果需要不同布局区分功能,需要重载 + */ + public FloatingVideo(Context context, Boolean fullFlag) { + super(context, fullFlag); + } + + public FloatingVideo(Context context) { + super(context); + } + + public FloatingVideo(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void init(Context context) { + if (getActivityContext() != null) { + this.mContext = getActivityContext(); + } else { + this.mContext = context; + } + + initInflate(mContext); + + mTextureViewContainer = (ViewGroup) findViewById(R.id.surface_container); + mStartButton = findViewById(R.id.start); + + if (isInEditMode()) + return; + mScreenWidth = getActivityContext().getResources().getDisplayMetrics().widthPixels; + mScreenHeight = getActivityContext().getResources().getDisplayMetrics().heightPixels; + mAudioManager = (AudioManager) getActivityContext().getApplicationContext().getSystemService(Context.AUDIO_SERVICE); + mStartButton = findViewById(com.shuyu.gsyvideoplayer.R.id.start); + mStartButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + clickStartIcon(); + } + }); + } + + @Override + public int getLayoutId() { + return R.layout.layout_floating_video; + } + + + @Override + protected void startPrepare() { + if (getGSYVideoManager().listener() != null) { + getGSYVideoManager().listener().onCompletion(); + } + getGSYVideoManager().setListener(this); + getGSYVideoManager().setPlayTag(mPlayTag); + getGSYVideoManager().setPlayPosition(mPlayPosition); + mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + //((Activity) getActivityContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + mBackUpPlayingBufferState = -1; + getGSYVideoManager().prepare(mUrl, mMapHeadData, mLooping, mSpeed); + setStateAndUi(CURRENT_STATE_PREPAREING); + } + + @Override + public void onAutoCompletion() { + setStateAndUi(CURRENT_STATE_AUTO_COMPLETE); + + mSaveChangeViewTIme = 0; + + if (mTextureViewContainer.getChildCount() > 0) { + mTextureViewContainer.removeAllViews(); + } + + if (!mIfCurrentIsFullscreen) + getGSYVideoManager().setLastListener(null); + mAudioManager.abandonAudioFocus(onAudioFocusChangeListener); + //((Activity) getActivityContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + releaseNetWorkState(); + + if (mVideoAllCallBack != null && isCurrentMediaListener()) { + Debuger.printfLog("onAutoComplete"); + mVideoAllCallBack.onAutoComplete(mOriginUrl, mTitle, this); + } + } + + @Override + public void onCompletion() { + //make me normal first + setStateAndUi(CURRENT_STATE_NORMAL); + + mSaveChangeViewTIme = 0; + + if (mTextureViewContainer.getChildCount() > 0) { + mTextureViewContainer.removeAllViews(); + } + + if (!mIfCurrentIsFullscreen) { + getGSYVideoManager().setListener(null); + getGSYVideoManager().setLastListener(null); + } + getGSYVideoManager().setCurrentVideoHeight(0); + getGSYVideoManager().setCurrentVideoWidth(0); + + mAudioManager.abandonAudioFocus(onAudioFocusChangeListener); + //((Activity) getActivityContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + releaseNetWorkState(); + + } + + + @Override + protected Context getActivityContext() { + return getContext(); + } + + @Override + protected void startDismissControlViewTimer() { + cancelDismissControlViewTimer(); + mDismissControlViewTimer = new Timer(); + mDismissControlViewTimerTask = new DismissControlViewTimerTask(); + mDismissControlViewTimer.schedule(mDismissControlViewTimerTask, mDismissControlTime); + } + + @Override + protected void cancelDismissControlViewTimer() { + if (mDismissControlViewTimer != null) { + mDismissControlViewTimer.cancel(); + mDismissControlViewTimer = null; + } + if (mDismissControlViewTimerTask != null) { + mDismissControlViewTimerTask.cancel(); + mDismissControlViewTimerTask = null; + } + + } + + private class DismissControlViewTimerTask extends TimerTask { + @Override + public void run() { + if (mCurrentState != CURRENT_STATE_NORMAL + && mCurrentState != CURRENT_STATE_ERROR + && mCurrentState != CURRENT_STATE_AUTO_COMPLETE) { + if (getActivityContext() != null) { + FloatingVideo.this.post(new Runnable() { + @Override + public void run() { + hideAllWidget(); + setViewShowState(mLockScreen, GONE); + if (mHideKey && mIfCurrentIsFullscreen && mShowVKey) { + hideNavKey(mContext); + } + } + }); + } + } + } + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/MultiSampleVideo.java b/app/src/main/java/com/example/gsyvideoplayer/video/MultiSampleVideo.java new file mode 100644 index 000000000..81da07499 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/MultiSampleVideo.java @@ -0,0 +1,116 @@ +package com.example.gsyvideoplayer.video; + +import android.content.Context; +import android.media.AudioManager; +import android.text.TextUtils; +import android.util.AttributeSet; + +import com.danikula.videocache.HttpProxyCacheServer; +import com.example.gsyvideoplayer.video.manager.CustomManager; +import com.shuyu.gsyvideoplayer.utils.Debuger; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge; + +import java.io.File; + +import tv.danmaku.ijk.media.player.IjkLibLoader; + +/** + * 多个同时播放的播放控件 + * Created by guoshuyu on 2018/1/31. + */ + +public class MultiSampleVideo extends SampleCoverVideo { + + private final static String TAG = "MultiSampleVideo"; + + public MultiSampleVideo(Context context, Boolean fullFlag) { + super(context, fullFlag); + } + + public MultiSampleVideo(Context context) { + super(context); + } + + public MultiSampleVideo(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void init(Context context) { + super.init(context); + onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { + @Override + public void onAudioFocusChange(int focusChange) { + switch (focusChange) { + case AudioManager.AUDIOFOCUS_GAIN: + break; + case AudioManager.AUDIOFOCUS_LOSS: + post(new Runnable() { + @Override + public void run() { + //todo 判断如果不是外界造成的就不处理 + } + }); + break; + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + post(new Runnable() { + @Override + public void run() { + //todo 判断如果不是外界造成的就不处理 + } + }); + break; + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + break; + } + } + }; + } + + @Override + public void setIjkLibLoader(IjkLibLoader libLoader) { + + } + + @Override + public GSYVideoViewBridge getGSYVideoManager() { + return CustomManager.getCustomManager(getKey()); + } + + @Override + protected boolean backFromFull(Context context) { + return CustomManager.backFromWindowFull(context, getKey()); + } + + @Override + protected void releaseVideos() { + CustomManager.releaseAllVideos(getKey()); + } + + @Override + protected HttpProxyCacheServer getProxy(Context context, File file) { + return null; + } + + + + @Override + protected int getFullId() { + return CustomManager.FULLSCREEN_ID; + } + + @Override + protected int getSmallId() { + return CustomManager.SMALL_ID; + } + + public String getKey() { + if (mPlayPosition == -22) { + Debuger.printfError(getClass().getSimpleName() + " used getKey() " + "******* PlayPosition never set. ********"); + } + if (TextUtils.isEmpty(mPlayTag)) { + Debuger.printfError(getClass().getSimpleName() + " used getKey() " + "******* PlayTag never set. ********"); + } + return TAG + mPlayPosition + mPlayTag; + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/PreViewGSYVideoPlayer.java b/app/src/main/java/com/example/gsyvideoplayer/video/PreViewGSYVideoPlayer.java new file mode 100644 index 000000000..46894fe1e --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/PreViewGSYVideoPlayer.java @@ -0,0 +1,185 @@ +package com.example.gsyvideoplayer.video; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.SeekBar; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.example.gsyvideoplayer.R; +import com.shuyu.gsyvideoplayer.utils.CommonUtil; +import com.shuyu.gsyvideoplayer.utils.Debuger; +import com.shuyu.gsyvideoplayer.video.NormalGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; + +/** + * 进度图小图预览的另类实现 + * Created by shuyu on 2016/12/10. + */ + +public class PreViewGSYVideoPlayer extends NormalGSYVideoPlayer { + + private RelativeLayout mPreviewLayout; + + private ImageView mPreView; + + //是否因为用户点击 + private boolean mIsFromUser; + + //是否打开滑动预览 + private boolean mOpenPreView = true; + + private int mPreProgress = -2; + + /** + * 1.5.0开始加入,如果需要不同布局区分功能,需要重载 + */ + public PreViewGSYVideoPlayer(Context context, Boolean fullFlag) { + super(context, fullFlag); + } + + public PreViewGSYVideoPlayer(Context context) { + super(context); + } + + public PreViewGSYVideoPlayer(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void init(Context context) { + super.init(context); + initView(); + } + + private void initView() { + mPreviewLayout = (RelativeLayout) findViewById(R.id.preview_layout); + mPreView = (ImageView) findViewById(R.id.preview_image); + } + + @Override + public int getLayoutId() { + return R.layout.video_layout_preview; + } + + + @Override + protected void prepareVideo() { + super.prepareVideo(); + } + + @Override + public void onProgressChanged(SeekBar seekBar, final int progress, boolean fromUser) { + super.onProgressChanged(seekBar, progress, fromUser); + if (fromUser && mOpenPreView) { + int width = seekBar.getWidth(); + int time = progress * getDuration() / 100; + int offset = (int) (width - (getResources().getDimension(R.dimen.seek_bar_image) / 2)) / 100 * progress; + Debuger.printfError("***************** " + progress); + Debuger.printfError("***************** " + time); + showPreView(mOriginUrl, time); + RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mPreviewLayout.getLayoutParams(); + layoutParams.leftMargin = offset; + //设置帧预览图的显示位置 + mPreviewLayout.setLayoutParams(layoutParams); + if (getGSYVideoManager().getMediaPlayer() != null + && mHadPlay && (mOpenPreView)) { + mPreProgress = progress; + } + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + super.onStartTrackingTouch(seekBar); + if (mOpenPreView) { + mIsFromUser = true; + mPreviewLayout.setVisibility(VISIBLE); + mPreProgress = -2; + } + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + if (mOpenPreView) { + if (mPreProgress >= 0) { + seekBar.setProgress(mPreProgress); + } + super.onStopTrackingTouch(seekBar); + mIsFromUser = false; + mPreviewLayout.setVisibility(GONE); + } else { + super.onStopTrackingTouch(seekBar); + } + } + + @Override + protected void setTextAndProgress(int secProgress) { + if (mIsFromUser) { + return; + } + super.setTextAndProgress(secProgress); + } + + @Override + public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionBar, boolean statusBar) { + GSYBaseVideoPlayer gsyBaseVideoPlayer = super.startWindowFullscreen(context, actionBar, statusBar); + PreViewGSYVideoPlayer customGSYVideoPlayer = (PreViewGSYVideoPlayer) gsyBaseVideoPlayer; + customGSYVideoPlayer.mOpenPreView = mOpenPreView; + return gsyBaseVideoPlayer; + } + + + @Override + public void onPrepared() { + super.onPrepared(); + startDownFrame(mOriginUrl); + } + + public boolean isOpenPreView() { + return mOpenPreView; + } + + /** + * 如果是需要进度条预览的设置打开,默认关闭 + */ + public void setOpenPreView(boolean localFile) { + this.mOpenPreView = localFile; + } + + + private void showPreView(String url, long time) { + int width = CommonUtil.dip2px(getContext(), 150); + int height = CommonUtil.dip2px(getContext(), 100); + Glide.with(getContext().getApplicationContext()) + .setDefaultRequestOptions( + new RequestOptions() + //这里限制了只从缓存读取 + .onlyRetrieveFromCache(true) + .frame(1000 * time) + .override(width, height) + .dontAnimate() + .centerCrop()) + .load(url) + .into(mPreView); + } + + + private void startDownFrame(String url) { + for (int i = 1; i <= 100; i++) { + int time = i * getDuration() / 100; + int width = CommonUtil.dip2px(getContext(), 150); + int height = CommonUtil.dip2px(getContext(), 100); + Glide.with(getContext().getApplicationContext()) + .setDefaultRequestOptions( + new RequestOptions() + .frame(1000 * time) + .override(width, height) + .centerCrop()) + .load(url).preload(width, height); + + } + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/SampleControlVideo.java b/app/src/main/java/com/example/gsyvideoplayer/video/SampleControlVideo.java new file mode 100644 index 000000000..fdde5e217 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/SampleControlVideo.java @@ -0,0 +1,265 @@ +package com.example.gsyvideoplayer.video; + +import android.content.Context; +import android.graphics.Matrix; +import android.util.AttributeSet; +import android.view.Surface; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.example.gsyvideoplayer.R; +import com.shuyu.gsyvideoplayer.utils.GSYVideoType; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; + + +/** + * Created by shuyu on 2016/12/7. + * 注意 + * 这个播放器的demo配置切换到全屏播放器 + * 这只是单纯的作为全屏播放显示,如果需要做大小屏幕切换,请记得在这里耶设置上视频全屏的需要的自定义配置 + */ + +public class SampleControlVideo extends StandardGSYVideoPlayer { + + private TextView mMoreScale; + + private TextView mChangeRotate; + + private TextView mChangeTransform; + + //记住切换数据源类型 + private int mType = 0; + + private int mTransformSize = 0; + + //数据源 + private int mSourcePosition = 0; + + /** + * 1.5.0开始加入,如果需要不同布局区分功能,需要重载 + */ + public SampleControlVideo(Context context, Boolean fullFlag) { + super(context, fullFlag); + } + + public SampleControlVideo(Context context) { + super(context); + } + + public SampleControlVideo(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void init(Context context) { + super.init(context); + initView(); + } + + private void initView() { + mMoreScale = (TextView) findViewById(R.id.moreScale); + mChangeRotate = (TextView) findViewById(R.id.change_rotate); + mChangeTransform = (TextView) findViewById(R.id.change_transform); + + //切换清晰度 + mMoreScale.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (!mHadPlay) { + return; + } + if (mType == 0) { + mType = 1; + } else if (mType == 1) { + mType = 2; + } else if (mType == 2) { + mType = 3; + } else if (mType == 3) { + mType = 4; + } else if (mType == 4) { + mType = 0; + } + resolveTypeUI(); + } + }); + + //旋转播放角度 + mChangeRotate.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (!mHadPlay) { + return; + } + if ((mTextureView.getRotation() - mRotate) == 270) { + mTextureView.setRotation(mRotate); + mTextureView.requestLayout(); + } else { + mTextureView.setRotation(mTextureView.getRotation() + 90); + mTextureView.requestLayout(); + } + } + }); + + //镜像旋转 + mChangeTransform.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (!mHadPlay) { + return; + } + if (mTransformSize == 0) { + mTransformSize = 1; + } else if (mTransformSize == 1) { + mTransformSize = 2; + } else if (mTransformSize == 2) { + mTransformSize = 0; + } + resolveTransform(); + } + }); + + } + + @Override + public void onSurfaceSizeChanged(Surface surface, int width, int height) { + super.onSurfaceSizeChanged(surface, width, height); + resolveTransform(); + } + + /** + * 处理显示逻辑 + */ + @Override + public void onSurfaceAvailable(Surface surface) { + super.onSurfaceAvailable(surface); + resolveRotateUI(); + resolveTransform(); + } + + /** + * 处理镜像旋转 + * 注意,暂停时 + */ + protected void resolveTransform() { + switch (mTransformSize) { + case 1: { + Matrix transform = new Matrix(); + transform.setScale(-1, 1, mTextureView.getWidth() / 2, 0); + mTextureView.setTransform(transform); + mChangeTransform.setText("左右镜像"); + mTextureView.invalidate(); + } + break; + case 2: { + Matrix transform = new Matrix(); + transform.setScale(1, -1, 0, mTextureView.getHeight() / 2); + mTextureView.setTransform(transform); + mChangeTransform.setText("上下镜像"); + mTextureView.invalidate(); + } + break; + case 0: { + Matrix transform = new Matrix(); + transform.setScale(1, 1, mTextureView.getWidth() / 2, 0); + mTextureView.setTransform(transform); + mChangeTransform.setText("旋转镜像"); + mTextureView.invalidate(); + } + break; + } + } + + @Override + public int getLayoutId() { + return R.layout.sample_video; + } + + + /** + * 全屏时将对应处理参数逻辑赋给全屏播放器 + * + * @param context + * @param actionBar + * @param statusBar + * @return + */ + @Override + public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionBar, boolean statusBar) { + SampleControlVideo sampleVideo = (SampleControlVideo) super.startWindowFullscreen(context, actionBar, statusBar); + sampleVideo.mSourcePosition = mSourcePosition; + sampleVideo.mType = mType; + sampleVideo.mTransformSize = mTransformSize; + //sampleVideo.resolveTransform(); + sampleVideo.resolveTypeUI(); + //sampleVideo.resolveRotateUI(); + //这个播放器的demo配置切换到全屏播放器 + //这只是单纯的作为全屏播放显示,如果需要做大小屏幕切换,请记得在这里耶设置上视频全屏的需要的自定义配置 + //比如已旋转角度之类的等等 + //可参考super中的实现 + return sampleVideo; + } + + /** + * 推出全屏时将对应处理参数逻辑返回给非播放器 + * + * @param oldF + * @param vp + * @param gsyVideoPlayer + */ + @Override + protected void resolveNormalVideoShow(View oldF, ViewGroup vp, GSYVideoPlayer gsyVideoPlayer) { + super.resolveNormalVideoShow(oldF, vp, gsyVideoPlayer); + if (gsyVideoPlayer != null) { + SampleControlVideo sampleVideo = (SampleControlVideo) gsyVideoPlayer; + mSourcePosition = sampleVideo.mSourcePosition; + mType = sampleVideo.mType; + mTransformSize = sampleVideo.mTransformSize; + resolveTypeUI(); + } + } + + /** + * 旋转逻辑 + */ + private void resolveRotateUI() { + if (!mHadPlay) { + return; + } + mTextureView.setRotation(mRotate); + mTextureView.requestLayout(); + } + + /** + * 显示比例 + * 注意,GSYVideoType.setShowType是全局静态生效,除非重启APP。 + */ + private void resolveTypeUI() { + if (!mHadPlay) { + return; + } + if (mType == 1) { + mMoreScale.setText("16:9"); + GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_16_9); + } else if (mType == 2) { + mMoreScale.setText("4:3"); + GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_4_3); + } else if (mType == 3) { + mMoreScale.setText("全屏"); + GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_FULL); + } else if (mType == 4) { + mMoreScale.setText("拉伸全屏"); + GSYVideoType.setShowType(GSYVideoType.SCREEN_MATCH_FULL); + } else if (mType == 0) { + mMoreScale.setText("默认比例"); + GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_DEFAULT); + } + changeTextureViewShowType(); + if (mTextureView != null) + mTextureView.requestLayout(); + } + + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/SampleCoverVideo.java b/app/src/main/java/com/example/gsyvideoplayer/video/SampleCoverVideo.java new file mode 100644 index 000000000..42a420498 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/SampleCoverVideo.java @@ -0,0 +1,78 @@ +package com.example.gsyvideoplayer.video; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.DecodeFormat; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.VideoBitmapDecoder; +import com.bumptech.glide.request.RequestOptions; +import com.example.gsyvideoplayer.R; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; + +/** + * 带封面 + * Created by guoshuyu on 2017/9/3. + */ + +public class SampleCoverVideo extends StandardGSYVideoPlayer { + + ImageView mCoverImage; + + String mCoverOriginUrl; + + int mDefaultRes; + + public SampleCoverVideo(Context context, Boolean fullFlag) { + super(context, fullFlag); + } + + public SampleCoverVideo(Context context) { + super(context); + } + + public SampleCoverVideo(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void init(Context context) { + super.init(context); + mCoverImage = (ImageView) findViewById(R.id.thumbImage); + + if (mThumbImageViewLayout != null && + (mCurrentState == -1 || mCurrentState == CURRENT_STATE_NORMAL || mCurrentState == CURRENT_STATE_ERROR)) { + mThumbImageViewLayout.setVisibility(VISIBLE); + } + } + + @Override + public int getLayoutId() { + return R.layout.video_layout_cover; + } + + public void loadCoverImage(String url, int res) { + mCoverOriginUrl = url; + mDefaultRes = res; + Glide.with(getContext().getApplicationContext()) + .setDefaultRequestOptions( + new RequestOptions() + .frame(1000000) + .centerCrop() + .error(res) + .placeholder(res)) + .load(url) + .into(mCoverImage); + } + + @Override + public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionBar, boolean statusBar) { + GSYBaseVideoPlayer gsyBaseVideoPlayer = super.startWindowFullscreen(context, actionBar, statusBar); + SampleCoverVideo sampleCoverVideo = (SampleCoverVideo) gsyBaseVideoPlayer; + sampleCoverVideo.loadCoverImage(mCoverOriginUrl, mDefaultRes); + return gsyBaseVideoPlayer; + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/SampleVideo.java b/app/src/main/java/com/example/gsyvideoplayer/video/SampleVideo.java index 6e0922fc2..784337fa0 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/video/SampleVideo.java +++ b/app/src/main/java/com/example/gsyvideoplayer/video/SampleVideo.java @@ -5,19 +5,18 @@ import android.graphics.SurfaceTexture; import android.os.Handler; import android.util.AttributeSet; +import android.view.Surface; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.example.gsyvideoplayer.R; import com.example.gsyvideoplayer.model.SwitchVideoModel; import com.example.gsyvideoplayer.view.SwitchVideoTypeDialog; -import com.shuyu.gsyvideoplayer.GSYVideoManager; -import com.shuyu.gsyvideoplayer.GSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; import com.shuyu.gsyvideoplayer.utils.GSYVideoType; -import com.shuyu.gsyvideoplayer.video.GSYBaseVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; import java.io.File; @@ -51,6 +50,8 @@ public class SampleVideo extends StandardGSYVideoPlayer { //数据源 private int mSourcePosition = 0; + private String mTypeText = "标准"; + /** * 1.5.0开始加入,如果需要不同布局区分功能,需要重载 */ @@ -82,7 +83,7 @@ private void initView() { mMoreScale.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - if(!mHadPlay) { + if (!mHadPlay) { return; } if (mType == 0) { @@ -93,7 +94,7 @@ public void onClick(View v) { mType = 3; } else if (mType == 3) { mType = 4; - } else if(mType == 4) { + } else if (mType == 4) { mType = 0; } resolveTypeUI(); @@ -112,19 +113,15 @@ public void onClick(View v) { mChangeRotate.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - if(!mHadPlay) { + if (!mHadPlay) { return; } if ((mTextureView.getRotation() - mRotate) == 270) { mTextureView.setRotation(mRotate); mTextureView.requestLayout(); - mCoverImageView.setRotation(mRotate); - mCoverImageView.requestLayout(); } else { mTextureView.setRotation(mTextureView.getRotation() + 90); mTextureView.requestLayout(); - mCoverImageView.setRotation(mCoverImageView.getRotation() + 90); - mCoverImageView.requestLayout(); } } }); @@ -133,7 +130,7 @@ public void onClick(View v) { mChangeTransform.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - if(!mHadPlay) { + if (!mHadPlay) { return; } if (mTransformSize == 0) { @@ -153,45 +150,46 @@ public void onClick(View v) { * 需要在尺寸发生变化的时候重新处理 */ @Override - public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { - super.onSurfaceTextureSizeChanged(surface, width, height); + public void onSurfaceSizeChanged(Surface surface, int width, int height) { + super.onSurfaceSizeChanged(surface, width, height); + resolveTransform(); + } + + @Override + public void onSurfaceAvailable(Surface surface) { + super.onSurfaceAvailable(surface); + resolveRotateUI(); resolveTransform(); } /** * 处理镜像旋转 + * 注意,暂停时 */ protected void resolveTransform() { - switch (mTransformSize) { case 1: { Matrix transform = new Matrix(); transform.setScale(-1, 1, mTextureView.getWidth() / 2, 0); mTextureView.setTransform(transform); - mCoverImageView.setScaleType(ImageView.ScaleType.MATRIX); - mCoverImageView.setImageMatrix(transform); - mTransformCover = transform; mChangeTransform.setText("左右镜像"); + mTextureView.invalidate(); } break; case 2: { Matrix transform = new Matrix(); transform.setScale(1, -1, 0, mTextureView.getHeight() / 2); mTextureView.setTransform(transform); - mCoverImageView.setScaleType(ImageView.ScaleType.MATRIX); - mCoverImageView.setImageMatrix(transform); - mTransformCover = transform; mChangeTransform.setText("上下镜像"); + mTextureView.invalidate(); } break; case 0: { Matrix transform = new Matrix(); transform.setScale(1, 1, mTextureView.getWidth() / 2, 0); mTextureView.setTransform(transform); - mCoverImageView.setScaleType(ImageView.ScaleType.MATRIX); - mCoverImageView.setImageMatrix(transform); - mTransformCover = null; mChangeTransform.setText("旋转镜像"); + mTextureView.invalidate(); } break; } @@ -203,7 +201,7 @@ protected void resolveTransform() { * * @param url 播放url * @param cacheWithPlay 是否边播边缓存 - * @param title title + * @param title title * @return */ public boolean setUp(List url, boolean cacheWithPlay, String title) { @@ -233,6 +231,7 @@ public int getLayoutId() { /** * 全屏时将对应处理参数逻辑赋给全屏播放器 + * * @param context * @param actionBar * @param statusBar @@ -245,6 +244,7 @@ public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionB sampleVideo.mType = mType; sampleVideo.mTransformSize = mTransformSize; sampleVideo.mUrlList = mUrlList; + sampleVideo.mTypeText = mTypeText; //sampleVideo.resolveTransform(); sampleVideo.resolveTypeUI(); //sampleVideo.resolveRotateUI(); @@ -256,8 +256,8 @@ public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionB } /** - * * 推出全屏时将对应处理参数逻辑返回给非播放器 + * * @param oldF * @param vp * @param gsyVideoPlayer @@ -270,32 +270,21 @@ protected void resolveNormalVideoShow(View oldF, ViewGroup vp, GSYVideoPlayer gs mSourcePosition = sampleVideo.mSourcePosition; mType = sampleVideo.mType; mTransformSize = sampleVideo.mTransformSize; + mTypeText = sampleVideo.mTypeText; setUp(mUrlList, mCache, mCachePath, mTitle); resolveTypeUI(); } } - /** - * 处理显示逻辑 - */ - @Override - public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { - super.onSurfaceTextureAvailable(surface, width, height); - resolveRotateUI(); - resolveTransform(); - } - /** * 旋转逻辑 */ private void resolveRotateUI() { - if(!mHadPlay) { + if (!mHadPlay) { return; } mTextureView.setRotation(mRotate); mTextureView.requestLayout(); - mCoverImageView.setRotation(mRotate); - mCoverImageView.requestLayout(); } /** @@ -303,42 +292,36 @@ private void resolveRotateUI() { * 注意,GSYVideoType.setShowType是全局静态生效,除非重启APP。 */ private void resolveTypeUI() { - if(!mHadPlay) { + if (!mHadPlay) { return; } if (mType == 1) { mMoreScale.setText("16:9"); GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_16_9); - if (mTextureView != null) - mTextureView.requestLayout(); } else if (mType == 2) { mMoreScale.setText("4:3"); GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_4_3); - if (mTextureView != null) - mTextureView.requestLayout(); } else if (mType == 3) { mMoreScale.setText("全屏"); GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_FULL); - if (mTextureView != null) - mTextureView.requestLayout(); } else if (mType == 4) { mMoreScale.setText("拉伸全屏"); GSYVideoType.setShowType(GSYVideoType.SCREEN_MATCH_FULL); - if (mTextureView != null) - mTextureView.requestLayout(); } else if (mType == 0) { mMoreScale.setText("默认比例"); GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_DEFAULT); - if (mTextureView != null) - mTextureView.requestLayout(); } + changeTextureViewShowType(); + if (mTextureView != null) + mTextureView.requestLayout(); + mSwitchSize.setText(mTypeText); } /** * 弹出切换清晰度 */ private void showSwitchDialog() { - if(!mHadPlay) { + if (!mHadPlay) { return; } SwitchVideoTypeDialog switchVideoTypeDialog = new SwitchVideoTypeDialog(getContext()); @@ -349,11 +332,11 @@ public void onItemClick(int position) { if (mSourcePosition != position) { if ((mCurrentState == GSYVideoPlayer.CURRENT_STATE_PLAYING || mCurrentState == GSYVideoPlayer.CURRENT_STATE_PAUSE) - && GSYVideoManager.instance().getMediaPlayer() != null) { + && getGSYVideoManager().getMediaPlayer() != null) { final String url = mUrlList.get(position).getUrl(); onVideoPause(); final long currentPosition = mCurrentPosition; - GSYVideoManager.instance().releaseMediaPlayer(); + getGSYVideoManager().releaseMediaPlayer(); cancelProgressTimer(); hideAllWidget(); new Handler().postDelayed(new Runnable() { @@ -366,6 +349,7 @@ public void run() { hideAllWidget(); } }, 500); + mTypeText = name; mSwitchSize.setText(name); mSourcePosition = position; } diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/SmartPickVideo.java b/app/src/main/java/com/example/gsyvideoplayer/video/SmartPickVideo.java new file mode 100644 index 000000000..514a79233 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/SmartPickVideo.java @@ -0,0 +1,358 @@ +package com.example.gsyvideoplayer.video; + +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.SurfaceTexture; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import com.danikula.videocache.HttpProxyCacheServer; +import com.example.gsyvideoplayer.R; +import com.example.gsyvideoplayer.model.SwitchVideoModel; +import com.example.gsyvideoplayer.view.LoadingDialog; +import com.example.gsyvideoplayer.view.SwitchVideoTypeDialog; +import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.listener.GSYMediaPlayerListener; +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer; +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * 无缝切换视频的DEMO + * 这里是切换清晰度,稍微修改下也可以作为切换下一集等 + */ + +public class SmartPickVideo extends StandardGSYVideoPlayer { + + + private TextView mSwitchSize; + + private List mUrlList = new ArrayList<>(); + + //记住切换数据源类型 + private int mType = 0; + //数据源 + private int mSourcePosition = 0; + private int mPreSourcePosition = 0; + + private String mTypeText = "标准"; + + private GSYVideoManager mTmpManager; + + //切换过程中最好弹出loading,不给其他任何操作 + private LoadingDialog mLoadingDialog; + + private boolean isChanging; + + /** + * 1.5.0开始加入,如果需要不同布局区分功能,需要重载 + */ + public SmartPickVideo(Context context, Boolean fullFlag) { + super(context, fullFlag); + } + + public SmartPickVideo(Context context) { + super(context); + } + + public SmartPickVideo(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void init(Context context) { + super.init(context); + initView(); + } + + private void initView() { + mSwitchSize = (TextView) findViewById(R.id.switchSize); + //切换视频清晰度 + mSwitchSize.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mHadPlay && !isChanging) { + showSwitchDialog(); + } + } + }); + } + + /** + * 设置播放URL + * + * @param url 播放url + * @param cacheWithPlay 是否边播边缓存 + * @param title title + * @return + */ + public boolean setUp(List url, boolean cacheWithPlay, String title) { + mUrlList = url; + return setUp(url.get(mSourcePosition).getUrl(), cacheWithPlay, title); + } + + /** + * 设置播放URL + * + * @param url 播放url + * @param cacheWithPlay 是否边播边缓存 + * @param cachePath 缓存路径,如果是M3U8或者HLS,请设置为false + * @param title title + * @return + */ + public boolean setUp(List url, boolean cacheWithPlay, File cachePath, String title) { + mUrlList = url; + return setUp(url.get(mSourcePosition).getUrl(), cacheWithPlay, cachePath, title); + } + + @Override + public int getLayoutId() { + return R.layout.sample_video_pick; + } + + + /** + * 全屏时将对应处理参数逻辑赋给全屏播放器 + * + * @param context + * @param actionBar + * @param statusBar + * @return + */ + @Override + public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionBar, boolean statusBar) { + SmartPickVideo sampleVideo = (SmartPickVideo) super.startWindowFullscreen(context, actionBar, statusBar); + sampleVideo.mSourcePosition = mSourcePosition; + sampleVideo.mType = mType; + sampleVideo.mUrlList = mUrlList; + sampleVideo.mTypeText = mTypeText; + sampleVideo.mSwitchSize.setText(mTypeText); + return sampleVideo; + } + + /** + * 推出全屏时将对应处理参数逻辑返回给非播放器 + * + * @param oldF + * @param vp + * @param gsyVideoPlayer + */ + @Override + protected void resolveNormalVideoShow(View oldF, ViewGroup vp, GSYVideoPlayer gsyVideoPlayer) { + super.resolveNormalVideoShow(oldF, vp, gsyVideoPlayer); + if (gsyVideoPlayer != null) { + SmartPickVideo sampleVideo = (SmartPickVideo) gsyVideoPlayer; + mSourcePosition = sampleVideo.mSourcePosition; + mType = sampleVideo.mType; + mTypeText = sampleVideo.mTypeText; + mSwitchSize.setText(mTypeText); + setUp(mUrlList, mCache, mCachePath, mTitle); + } + } + + @Override + public void onAutoCompletion() { + super.onAutoCompletion(); + releaseTmpManager(); + } + + @Override + public void onCompletion() { + super.onCompletion(); + releaseTmpManager(); + } + + /** + * 弹出切换清晰度 + */ + private void showSwitchDialog() { + if (!mHadPlay) { + return; + } + SwitchVideoTypeDialog switchVideoTypeDialog = new SwitchVideoTypeDialog(getContext()); + switchVideoTypeDialog.initList(mUrlList, new SwitchVideoTypeDialog.OnListItemClickListener() { + @Override + public void onItemClick(int position) { + resolveStartChange(position); + } + }); + switchVideoTypeDialog.show(); + } + + + private void resolveChangeUrl(boolean cacheWithPlay, File cachePath, String url) { + if (mTmpManager != null) { + mCache = cacheWithPlay; + mCachePath = cachePath; + mOriginUrl = url; + if (cacheWithPlay && url.startsWith("http") && !url.contains("127.0.0.1") && !url.contains(".m3u8")) { + HttpProxyCacheServer proxy = (cachePath != null) ? + mTmpManager.newProxy(getActivityContext().getApplicationContext(), cachePath) : mTmpManager.newProxy(getActivityContext().getApplicationContext()); + //此处转换了url,然后再赋值给mUrl。 + url = proxy.getProxyUrl(url); + mCacheFile = (!url.startsWith("http")); + mTmpManager.setProxy(proxy); + //注册上缓冲监听 + if (!mCacheFile && GSYVideoManager.instance() != null) { + proxy.registerCacheListener(GSYVideoManager.instance(), mOriginUrl); + } + } else if (!cacheWithPlay && (!url.startsWith("http") && !url.startsWith("rtmp") + && !url.startsWith("rtsp") && !url.contains(".m3u8"))) { + mCacheFile = true; + } + this.mUrl = url; + } + } + + + private GSYMediaPlayerListener gsyMediaPlayerListener = new GSYMediaPlayerListener() { + @Override + public void onPrepared() { + if (mTmpManager != null) { + mTmpManager.getMediaPlayer().start(); + mTmpManager.getMediaPlayer().seekTo(getCurrentPositionWhenPlaying()); + } + } + + @Override + public void onAutoCompletion() { + + } + + @Override + public void onCompletion() { + + } + + @Override + public void onBufferingUpdate(int percent) { + + } + + @Override + public void onSeekComplete() { + if (mTmpManager != null) { + GSYVideoManager.instance().releaseMediaPlayer(); + GSYVideoManager.changeManager(mTmpManager); + mTmpManager.setLastListener(SmartPickVideo.this); + mTmpManager.setListener(SmartPickVideo.this); + mTmpManager.setDisplay(mSurface); + changeUiToPlayingClear(); + resolveChangedResult(); + } + } + + @Override + public void onError(int what, int extra) { + mSourcePosition = mPreSourcePosition; + if (mTmpManager != null) { + mTmpManager.releaseMediaPlayer(); + } + post(new Runnable() { + @Override + public void run() { + resolveChangedResult(); + Toast.makeText(mContext, "change Fail", Toast.LENGTH_LONG).show(); + } + }); + } + + @Override + public void onInfo(int what, int extra) { + + } + + @Override + public void onVideoSizeChanged() { + + } + + @Override + public void onBackFullscreen() { + + } + + @Override + public void onVideoPause() { + + } + + @Override + public void onVideoResume() { + + } + + @Override + public void onVideoResume(boolean seek) { + + } + }; + + private void resolveStartChange(int position) { + final String name = mUrlList.get(position).getName(); + if (mSourcePosition != position) { + if ((mCurrentState == GSYVideoPlayer.CURRENT_STATE_PLAYING + || mCurrentState == GSYVideoPlayer.CURRENT_STATE_PAUSE) + && GSYVideoManager.instance().getMediaPlayer() != null) { + showLoading(); + final String url = mUrlList.get(position).getUrl(); + cancelProgressTimer(); + hideAllWidget(); + if (mTitle != null && mTitleTextView != null) { + mTitleTextView.setText(mTitle); + } + mPreSourcePosition = mSourcePosition; + isChanging = true; + mTypeText = name; + mSwitchSize.setText(name); + mSourcePosition = position; + //创建临时管理器执行加载播放 + mTmpManager = GSYVideoManager.tmpInstance(gsyMediaPlayerListener); + resolveChangeUrl(mCache, mCachePath, url); + mTmpManager.prepare(mUrl, mMapHeadData, mLooping, mSpeed); + changeUiToPlayingBufferingShow(); + } + } else { + Toast.makeText(getContext(), "已经是 " + name, Toast.LENGTH_LONG).show(); + } + } + + private void resolveChangedResult() { + isChanging = false; + mTmpManager = null; + final String name = mUrlList.get(mSourcePosition).getName(); + final String url = mUrlList.get(mSourcePosition).getUrl(); + mTypeText = name; + mSwitchSize.setText(name); + resolveChangeUrl(mCache, mCachePath, url); + hideLoading(); + } + + private void releaseTmpManager() { + if (mTmpManager != null) { + mTmpManager.releaseMediaPlayer(); + mTmpManager = null; + } + } + + private void showLoading() { + hideLoading(); + mLoadingDialog = new LoadingDialog(mContext); + mLoadingDialog.show(); + } + + private void hideLoading() { + if (mLoadingDialog != null) { + mLoadingDialog.dismiss(); + mLoadingDialog = null; + } + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/video/manager/CustomManager.java b/app/src/main/java/com/example/gsyvideoplayer/video/manager/CustomManager.java new file mode 100644 index 000000000..05d6f889c --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/video/manager/CustomManager.java @@ -0,0 +1,168 @@ +package com.example.gsyvideoplayer.video.manager; + +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; + +import com.example.gsyvideoplayer.R; +import com.shuyu.gsyvideoplayer.GSYVideoBaseManager; +import com.shuyu.gsyvideoplayer.utils.CommonUtil; + +import java.util.HashMap; +import java.util.Map; + +import tv.danmaku.ijk.media.player.IjkLibLoader; + +import static com.shuyu.gsyvideoplayer.utils.CommonUtil.hideNavKey; + +/** + * 多个播放的管理器 + * Created by guoshuyu on 2018/1/31. + */ + +public class CustomManager extends GSYVideoBaseManager { + + public static final int SMALL_ID = R.id.custom_small_id; + + public static final int FULLSCREEN_ID = R.id.custom_full_id; + + public static String TAG = "GSYVideoManager"; + + private static Map sMap = new HashMap<>(); + + /*** + * @param libLoader 是否使用外部动态加载so + * */ + public CustomManager(IjkLibLoader libLoader) { + init(libLoader); + } + + + /** + * 退出全屏,主要用于返回键 + * + * @return 返回是否全屏 + */ + @SuppressWarnings("ResourceType") + public static boolean backFromWindowFull(Context context, String key) { + boolean backFrom = false; + ViewGroup vp = (ViewGroup) (CommonUtil.scanForActivity(context)).findViewById(Window.ID_ANDROID_CONTENT); + View oldF = vp.findViewById(FULLSCREEN_ID); + if (oldF != null) { + backFrom = true; + hideNavKey(context); + if (getCustomManager(key).lastListener() != null) { + getCustomManager(key).lastListener().onBackFullscreen(); + } + } + return backFrom; + } + + /** + * 页面销毁了记得调用是否所有的video + */ + public static void releaseAllVideos(String key) { + if (getCustomManager(key).listener() != null) { + getCustomManager(key).listener().onCompletion(); + } + getCustomManager(key).releaseMediaPlayer(); + } + + + /** + * 暂停播放 + */ + public void onPause(String key) { + if (getCustomManager(key).listener() != null) { + getCustomManager(key).listener().onVideoPause(); + } + } + + /** + * 恢复播放 + */ + public void onResume(String key) { + if (getCustomManager(key).listener() != null) { + getCustomManager(key).listener().onVideoResume(); + } + } + + + /** + * 恢复暂停状态 + * + * @param seek 是否产生seek动作,直播设置为false + */ + public void onResume(String key, boolean seek) { + if (getCustomManager(key).listener() != null) { + getCustomManager(key).listener().onVideoResume(seek); + } + } + + + /** + * 单例管理器 + */ + public static synchronized Map instance() { + return sMap; + } + + /** + * 单例管理器 + */ + public static synchronized CustomManager getCustomManager(String key) { + if (TextUtils.isEmpty(key)) { + throw new IllegalStateException("key not be empty"); + } + CustomManager customManager = sMap.get(key); + if (customManager == null) { + customManager = new CustomManager(null); + sMap.put(key, customManager); + } + return customManager; + } + + public static void onPauseAll() { + if (sMap.size() > 0) { + for (Map.Entry header : sMap.entrySet()) { + header.getValue().onPause(header.getKey()); + } + } + } + + public static void onResumeAll() { + if (sMap.size() > 0) { + for (Map.Entry header : sMap.entrySet()) { + header.getValue().onResume(header.getKey()); + } + } + } + + /** + * 恢复暂停状态 + * + * @param seek 是否产生seek动作 + */ + public static void onResumeAll(boolean seek) { + if (sMap.size() > 0) { + for (Map.Entry header : sMap.entrySet()) { + header.getValue().onResume(header.getKey(), seek); + } + } + } + + public static void clearAllVideo() { + if (sMap.size() > 0) { + for (Map.Entry header : sMap.entrySet()) { + CustomManager.releaseAllVideos(header.getKey()); + } + } + sMap.clear(); + } + + public static void removeManager(String key) { + sMap.remove(key); + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/view/CustomRenderView.java b/app/src/main/java/com/example/gsyvideoplayer/view/CustomRenderView.java new file mode 100644 index 000000000..394b87b57 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/view/CustomRenderView.java @@ -0,0 +1,23 @@ +package com.example.gsyvideoplayer.view; + +import android.content.Context; +import android.view.ViewGroup; + +import com.shuyu.gsyvideoplayer.render.GSYRenderView; +import com.shuyu.gsyvideoplayer.render.glrender.GSYVideoGLViewBaseRender; +import com.shuyu.gsyvideoplayer.render.view.GSYVideoGLView; +import com.shuyu.gsyvideoplayer.render.view.listener.IGSYSurfaceListener; +import com.shuyu.gsyvideoplayer.utils.MeasureHelper; + +/** + * 自定义代理渲染层 + * Created by guoshuyu on 2018/1/30. + */ + +public class CustomRenderView extends GSYRenderView { + + @Override + public void addView(Context context, ViewGroup textureViewContainer, int rotate, IGSYSurfaceListener gsySurfaceListener, MeasureHelper.MeasureFormVideoParamsListener videoParamsListener, GSYVideoGLView.ShaderInterface effect, float[] transform, GSYVideoGLViewBaseRender customRender, int mode) { + mShowView = CustomTextureSurface.addSurfaceView(context, textureViewContainer, rotate, gsySurfaceListener, videoParamsListener); + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/view/CustomTextureSurface.java b/app/src/main/java/com/example/gsyvideoplayer/view/CustomTextureSurface.java new file mode 100644 index 000000000..14a632b42 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/view/CustomTextureSurface.java @@ -0,0 +1,229 @@ +package com.example.gsyvideoplayer.view; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.util.AttributeSet; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; + +import com.shuyu.gsyvideoplayer.listener.GSYVideoShotListener; +import com.shuyu.gsyvideoplayer.listener.GSYVideoShotSaveListener; +import com.shuyu.gsyvideoplayer.render.GSYRenderView; +import com.shuyu.gsyvideoplayer.render.glrender.GSYVideoGLViewBaseRender; +import com.shuyu.gsyvideoplayer.render.view.GSYVideoGLView; +import com.shuyu.gsyvideoplayer.render.view.IGSYRenderView; +import com.shuyu.gsyvideoplayer.render.view.listener.IGSYSurfaceListener; +import com.shuyu.gsyvideoplayer.utils.MeasureHelper; + +import java.io.File; + +/** + * 自定义渲染层 + * Created by guoshuyu on 2018/1/30. + */ + +public class CustomTextureSurface extends SurfaceView implements IGSYRenderView, SurfaceHolder.Callback2, MeasureHelper.MeasureFormVideoParamsListener { + + private IGSYSurfaceListener mIGSYSurfaceListener; + + private MeasureHelper measureHelper; + + private MeasureHelper.MeasureFormVideoParamsListener mVideoParamsListener; + + public CustomTextureSurface(Context context) { + super(context); + init(); + } + + public CustomTextureSurface(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public CustomTextureSurface(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + measureHelper = new MeasureHelper(this, this); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + measureHelper.prepareMeasure(widthMeasureSpec, heightMeasureSpec, (int) getRotation()); + setMeasuredDimension(measureHelper.getMeasuredWidth(), measureHelper.getMeasuredHeight()); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + if (mIGSYSurfaceListener != null) { + mIGSYSurfaceListener.onSurfaceAvailable(holder.getSurface()); + } + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + if (mIGSYSurfaceListener != null) { + mIGSYSurfaceListener.onSurfaceSizeChanged(holder.getSurface(), width, height); + } + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + //清空释放 + if (mIGSYSurfaceListener != null) { + mIGSYSurfaceListener.onSurfaceDestroyed(holder.getSurface()); + } + } + + @Override + public void surfaceRedrawNeeded(SurfaceHolder holder) { + + } + + @Override + public IGSYSurfaceListener getIGSYSurfaceListener() { + return mIGSYSurfaceListener; + } + + @Override + public void setIGSYSurfaceListener(IGSYSurfaceListener surfaceListener) { + getHolder().addCallback(this); + this.mIGSYSurfaceListener = surfaceListener; + } + + + @Override + public int getSizeH() { + return measureHelper.getMeasuredHeight(); + } + + @Override + public int getSizeW() { + return measureHelper.getMeasuredWidth(); + } + + @Override + public void taskShotPic(GSYVideoShotListener gsyVideoShotListener, boolean shotHigh) { + + } + + @Override + public void saveFrame(File file, boolean high, GSYVideoShotSaveListener gsyVideoShotSaveListener) { + + } + + @Override + public View getRenderView() { + return this; + } + + @Override + public Bitmap initCover() { + return null; + } + + @Override + public Bitmap initCoverHigh() { + return null; + } + + @Override + public void onRenderResume() { + + } + + @Override + public void onRenderPause() { + + } + + @Override + public void releaseRenderAll() { + + } + + @Override + public void setRenderMode(int mode) { + + } + + @Override + public void setRenderTransform(Matrix transform) { + + } + + @Override + public void setGLRenderer(GSYVideoGLViewBaseRender renderer) { + + } + + @Override + public void setGLMVPMatrix(float[] MVPMatrix) { + + } + + @Override + public void setGLEffectFilter(GSYVideoGLView.ShaderInterface effectFilter) { + + } + + @Override + public void setVideoParamsListener(MeasureHelper.MeasureFormVideoParamsListener listener) { + mVideoParamsListener = listener; + } + + @Override + public int getCurrentVideoWidth() { + if (mVideoParamsListener != null) { + return mVideoParamsListener.getCurrentVideoWidth(); + } + return 0; + } + + @Override + public int getCurrentVideoHeight() { + if (mVideoParamsListener != null) { + return mVideoParamsListener.getCurrentVideoHeight(); + } + return 0; + } + + @Override + public int getVideoSarNum() { + if (mVideoParamsListener != null) { + return mVideoParamsListener.getVideoSarNum(); + } + return 0; + } + + @Override + public int getVideoSarDen() { + if (mVideoParamsListener != null) { + return mVideoParamsListener.getVideoSarDen(); + } + return 0; + } + + /** + * 添加播放的view + */ + public static CustomTextureSurface addSurfaceView(Context context, ViewGroup textureViewContainer, int rotate, + final IGSYSurfaceListener gsySurfaceListener, + final MeasureHelper.MeasureFormVideoParamsListener videoParamsListener) { + if (textureViewContainer.getChildCount() > 0) { + textureViewContainer.removeAllViews(); + } + CustomTextureSurface showSurfaceView = new CustomTextureSurface(context); + showSurfaceView.setIGSYSurfaceListener(gsySurfaceListener); + showSurfaceView.setRotation(rotate); + showSurfaceView.setVideoParamsListener(videoParamsListener); + GSYRenderView.addToParent(textureViewContainer, showSurfaceView); + return showSurfaceView; + } +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/view/FloatPlayerView.java b/app/src/main/java/com/example/gsyvideoplayer/view/FloatPlayerView.java new file mode 100644 index 000000000..6a36e5b8a --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/view/FloatPlayerView.java @@ -0,0 +1,69 @@ +package com.example.gsyvideoplayer.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.example.gsyvideoplayer.video.FloatingVideo; +import com.shuyu.gsyvideoplayer.GSYVideoManager; + +/** + * 适配了悬浮窗的view + * Created by guoshuyu on 2017/12/25. + */ + +public class FloatPlayerView extends FrameLayout { + + FloatingVideo videoPlayer; + + public FloatPlayerView(Context context) { + super(context); + init(); + } + + public FloatPlayerView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public FloatPlayerView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + + videoPlayer = new FloatingVideo(getContext()); + + LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + layoutParams.gravity = Gravity.CENTER; + + addView(videoPlayer, layoutParams); + + String source1 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4"; + + videoPlayer.setUp(source1, true, "测试视频"); + + //增加封面 + /*ImageView imageView = new ImageView(getContext()); + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setImageResource(R.mipmap.xxx1); + videoPlayer.setThumbImageView(imageView);*/ + + //是否可以滑动调整 + videoPlayer.setIsTouchWiget(false); + + } + + + public void onPause() { + videoPlayer.getCurrentPlayer().onVideoPause(); + } + + public void onResume() { + videoPlayer.getCurrentPlayer().onVideoResume(); + } + +} diff --git a/app/src/main/java/com/example/gsyvideoplayer/view/LoadingDialog.java b/app/src/main/java/com/example/gsyvideoplayer/view/LoadingDialog.java new file mode 100644 index 000000000..166a5e6d7 --- /dev/null +++ b/app/src/main/java/com/example/gsyvideoplayer/view/LoadingDialog.java @@ -0,0 +1,44 @@ +package com.example.gsyvideoplayer.view; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.text.InputFilter; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.TextView; + +import com.example.gsyvideoplayer.R; + +public class LoadingDialog extends Dialog { + + private Context context; + + public LoadingDialog(Context context) { + super(context, R.style.dialog_style); + this.context = context; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + init(); + } + + public void init() { + LayoutInflater inflater = LayoutInflater.from(context); + View view = inflater.inflate(R.layout.layout_loading_dialog, null); + setContentView(view); + + setCanceledOnTouchOutside(false); + setCancelable(false); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_deatil_list_player.xml b/app/src/main/res/layout/activity_deatil_list_player.xml index e694c60cc..44536a7cf 100644 --- a/app/src/main/res/layout/activity_deatil_list_player.xml +++ b/app/src/main/res/layout/activity_deatil_list_player.xml @@ -34,4 +34,19 @@ android:layout_width="match_parent" android:layout_height="@dimen/post_media_height" /> + + + +