Skip to content

Commit b1332d9

Browse files
committedNov 26, 2019
add ExoPlayer part
1 parent 46fa7f8 commit b1332d9

9 files changed

+2015
-17
lines changed
 

‎BasicKnowledge/反编译.md

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
反编译
2+
===
3+
4+
- [资源文件获取Apktool](https://ibotpeaches.github.io/Apktool/install/)
5+
按照官网的指示配置完成后,执行apktool命令
6+
7+
```
8+
apktool d xxx.apk
9+
// 如果提示-bash: /usr/local/bin/apktool: Permission denied
10+
cd /usr/local/bin
11+
sudo chmod +x apktool
12+
sudo chmod +x apktool.jar
13+
```
14+
执行完成后会在apktool.jar的目录下升级一个文件,里面可以看到xml的信息
15+
```
16+
cd /usr/loca/bin
17+
open .
18+
```
19+
- [源码文件获取dex2jar](https://github.com/pxb1988/dex2jar)
20+
将apk文件解压后获取class.dex文件,然后将dex文件拷贝到dex2jar目录中
21+
```
22+
sh d2j-dex2jar.sh classes.dex
23+
d2j-dex2jar.sh: line 36: ./d2j_invoke.sh: Permission denied
24+
// chmod一下
25+
sudo chmod +x d2j_invoke.sh
26+
sh d2j-dex2jar.sh classes.dex
27+
```
28+
执行完成后会在当前目录中生成一个 classes-dex2jar.jar
29+
30+
- [jar包源码查看工具jd-gui](https://github.com/java-decompiler/jd-gui)
31+
里面有osx的版本,安装后直接打开上面用dex2jar编译出来的.jar文件就可以查看源码了
32+
33+
34+
### 反编译后的源码修改
35+
36+
修改代码及资源,最好的方式是修改apktool反编译后的资源级smali代码。JD-GUI查看的java代码不适宜修改,因为修改后还需要重新转换成smali,才能重新编译打包会apk。
37+
至于smali的修改,则要学习smali语言的语法了,smali是一种类似汇编语言的语言,具体语法可自行上网学习。
38+
在smali文件夹中找到与具体类对应的smali文件,然后进行修改
39+
可以用到[java2smali](https://plugins.jetbrains.com/plugin/7385-java2smali)将java代码转换成smali代码
40+
41+
### 重新打包
42+
43+
```
44+
B0000000134553m:bin xuchuanren$ apktool b xxxfilename
45+
I: Using Apktool 2.4.0
46+
I: Checking whether sources has changed...
47+
I: Smaling smali folder into classes.dex...
48+
I: Checking whether resources has changed...
49+
I: Building resources...
50+
S: WARNING: Could not write to ( instead...
51+
S: Please be aware this is a volatile directory and frameworks could go missing, please utilize --frame-path if the default storage directory is unavailable
52+
I: Copying libs... (/lib)
53+
I: Building apk file...
54+
I: Copying unknown files/dir...
55+
I: Built apk...
56+
57+
```
58+
生成的apk在该文件xxxfilename中的dist目录中
59+
60+
### 重新签名
61+
62+
重新签名用的是jarsigner命令
63+
```
64+
jarsigner -verbose -keystore [your_key_store_path] -signedjar [signed_apk_name] [usigned_apk_name] [your_key_store_alias] -digestalg SHA1 -sigalg MD5withRSA
65+
```
66+
67+
- [your_key_store_path]:密钥所在位置的绝对路径
68+
- [signed_apk_name]:签名后安装包名称
69+
- [usigned_apk_name]:未签名的安装包名称
70+
- [your_key_store_alias]:密钥的别名
71+
72+
如:
73+
74+
```
75+
jarsigner -verbose -keystore /development/key.keystore -signedjar signed_apk.apk xxx.apk charon -digestalg SHA1 -sigalg MD5withRSA
76+
Enter Passphrase for keystore:
77+
adding: META-INF/MANIFEST.MF
78+
adding: META-INF/CHARON.SF
79+
adding: META-INF/CHARON.RSA
80+
81+
```
82+
执行完后会在当前目录下生成签名后的apk文件
83+
84+
85+
---
86+
87+
- 邮箱 :charon.chui@gmail.com
88+
- Good Luck!

‎Tools&Library/Icon制作.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Icon制作
2+
3+
===
4+
5+
子日:工欲善其事必先利其器
6+
7+
[logoko在线制作](https://www.logoko.com.cn)
8+
9+
[图标工厂,一键生成各种分辨率图片](http://icon.wuruihong.com/)
10+
11+
12+
---
13+
14+
- 邮箱 :charon.chui@gmail.com
15+
-
16+
Good Luck!
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
ExoPlayer简介
2+
---
3+
4+
[ExoPlayer](https://github.com/google/ExoPlayer)是google开源的应用级媒体播放器项目。
5+
6+
7+
与内置的MediaPlayer相比,ExoPlayer的优点主要有:
8+
9+
- 支持通过Http(DASH)和SmoothStreaming进行动态自适应流,这两种都不受MediaPlayer的支持。它还支持其他格式的数据资源,比如MP4、M4A、FMP4、MKV、MP3、Ogg、WAV、FLV等
10+
- 支持高级的HLS个性,比如正确处理#EXT-X-DISCONTINUITY标签
11+
- 无缝连接,合并和循环播放多媒体的能力
12+
- 和应用一起更新播放器(ExoPlayer),因为ExoPlayer是一个集成到应用APK的库,可以随着应用的更新把ExoPlayer更新到一个更新的版本。
13+
- 在不同的Android版本和设备上很少会有不同的表现。
14+
- 能够自定义和扩展播放器,以适应各种不同的需求
15+
- 各个组件都可以自定义,还可以接入ffmpeg组件
16+
17+
缺点就是,在音频播放时ExoPlayer会比MediaPlayer消耗更多的电量。
18+
19+
集成
20+
---
21+
22+
在app的module中的`build.gradle`文件添加如下依赖(这种方式是添加全部的依赖):
23+
`implementation 'com.google.android.exoplayer:exoplayer:2.X.X'`
24+
25+
如果不需要依赖全部的类库,也可以只选择添加你需要的类库,例如下面的方式是只需要播放DASH内容的app,就是只添加Core、DASH和UI库:
26+
```
27+
implementation 'com.google.android.exoplayer:exoplayer-core:2.X.X'
28+
implementation 'com.google.android.exoplayer:exoplayer-dash:2.X.X'
29+
implementation 'com.google.android.exoplayer:exoplayer-ui:2.X.X'
30+
```
31+
32+
下面列出了所有的依赖库:
33+
34+
- `exoplayer-core`:核心功能库(基础库、必要)
35+
- `exoplayer-dash`:支持DASH
36+
- `exoplayer-hls`:支持HLS
37+
- `exoplayer-smoothstreaming`:支持SmoothStreaming
38+
- `exoplayer-ui`:使用ExoPlayer所需的UI部分和资源
39+
40+
上面讲到了DASH、HLS、SmoothStreaming,具体的介绍可以参考[流媒体通信协议]()
41+
42+
除了上面的几个类库外,ExoPlayer还有很多扩展库提供一些额外的功能,有一些可以直接通过JCenter进行依赖,有一些需要手动去编译,具体的可以通过[扩展库目录](https://github.com/google/ExoPlayer/tree/release-v2/extensions/)中的README来查看详细的内容。
43+
可以通过JCenter进行依赖的类库和扩展可以从[ExoPlayer的Binatry](https://bintray.com/google/exoplayer)上查看。
44+
45+
如果依赖完后仍然不行,你需要将build.gradle文件中的android节点打开Java 8的支持:
46+
```
47+
compileOptions {
48+
targetCompatibility = 1.8
49+
}
50+
```
51+
52+
53+
ExoPlayer库的核心是ExoPlayer接口,ExoPlayer公开了传统的高级媒体播放器功能,例如缓冲、播放、暂停、seek等。在具体实现方面,该开源库对播放器的媒体类型、存储方式、位置、渲染方式等进行了最少的实现,旨在让开发者自定义各种特性。ExoPlayer的实现不是直接实现加载和呈现媒体,而是将这项工作委托给各种组件。主要有:
54+
55+
- TrackSelector:轨道提取器,从MediaSource中提取各个轨道的二进制数据,交给Renderer渲染,创建播放器时传入。
56+
- Renderer:对多媒体中的各个轨道(音轨、视频轨、字母轨等)数据进行渲染,渲染就是"播放",把二进制文件渲染成声音、画面,创建播放器时传入。
57+
- MediaSource:定义多媒体数据源,这个类的功能就是从Uri中读取多媒体文件的二进制数据。MediaSource在播放开始时通过ExoPlayer.prepare()注入。
58+
- LoadControl:对MediaSource进行控制,比如什么时候开始缓冲、缓冲多少等。
59+
60+
它们之间的关系是:
61+
62+
渲染器(Render) ---刷数据--->提取器(Extraor) ----读取数据---> 加载控制器(LoadControl) ----控制数据加载方式---> 媒体源(MediaSource)
63+
64+
65+
66+
67+
该库提供了这些组件的默认实现,既能满足大部分需求,也可通过自定义来实现特殊的需求。例如可以通过自定义LoadControl来更改播放器的缓冲策略,或自定义Renderer来渲染Android本身不支持的编解码器。
68+
69+
[支持的格式](https://exoplayer.dev/supported-formats.html)
70+
71+
72+
### 创建播放器
73+
74+
为了满足不同的需求,ExoPlayer提供了一个工厂类ExoPlayerFactory,通过该工厂类来创建一个ExoPlayer实例,大多数情况下直接使用`ExoPlayerFactory.newSimpleInstance(context)`方法即可:
75+
76+
```
77+
public static SimpleExoPlayer newSimpleInstance(Context context) {
78+
return newSimpleInstance(context, new DefaultTrackSelector());
79+
}
80+
```
81+
它返回的SimpleExoPlayer是一个实现ExoPlayer接口并添加了一些额外的高级播放器功能。
82+
83+
### 把播放器实例附着到一个View上
84+
85+
ExoPlayer库提供了一个PlayerView(A high level view for Player media playbacks. It displays video, subtitles and album art during playback, and displays playback controls using a PlayerControlView.)类,他封装了PlayerControlView和渲染视频的一个默认的SurfaceView以及字幕等功能。可以通过xml中surface_type来指定视频播放的Surface类型,除了值spherical_view(这是球形视频播放一个特殊的值)时,允许值是surface_view,texture_view和none。如果视图仅用于音频播放,则应使用none以避免必须创建Surface,因为这样做可能耗费资源。
86+
87+
如果视图是用于常规视频播放那么surface_view或texture_view 应该使用。对于视频播放,相比TextureView,SurfaceView有许多好处:
88+
89+
- 显着降低了许多设备的功耗。
90+
- 更准确的帧定时,使视频播放更流畅。
91+
- 播放受DRM保护的内容时支持安全输出。
92+
因此,相比较于TextureView,SurfaceView应尽可能优先考虑。 TextureView只有在SurfaceView不符合您需求的情况下才能使用。一个示例是在Android N之前需要平滑动画或滚动视频表面,如下所述。对于这种情况,最好 TextureView 只在SDK_INT小于24(Android N)时使用, 否则,使用SurfaceView。
93+
94+
SurfaceView在Android N之前,渲染未与视图动画正确同步。在早期版本SurfaceView中,当放入滚动容器或受到动画影响时,这可能会导致不必要的效果 。这些效果包括视图的内容看起来略微落后于它应该显示的位置,并且视图在受到动画时变黑。为了在Android N之前实现流畅的动画或视频滚动,因此必须使用TextureView而不是SurfaceView。
95+
96+
xml声明:
97+
```
98+
<com.google.android.exoplayer2.ui.PlayerView
99+
android:id="@+id/mPlayerView"
100+
android:layout_width="match_parent"
101+
android:layout_height="match_parent" />
102+
```
103+
104+
```kotlin
105+
private lateinit var mPlayer: SimpleExoPlayer
106+
private fun initView(context: Context) {
107+
val view = View.inflate(context, R.layout.video_view, this)
108+
mPlayer = ExoPlayerFactory.newSimpleInstance(context)
109+
// 通过PlayerView.setPlayer方法来将ExoPlayer绑定到View上
110+
mPlayerView.player = mPlayer
111+
}
112+
```
113+
114+
### 开始播放
115+
116+
ExoPlayer中将每一种媒体资源都封装成MediaSource,如果想要播放一种媒体资源,首先需要为他创建对应的MediaSource对象,然后把这个对象传递给ExoPlayer.prepared方法。ExoPlayer提供了多种MediaSource的实现类,例如播放[DASH](https://exoplayer.dev/dash.html)的DashMediaSource,[SmoothStreaming](https://exoplayer.dev/smoothstreaming.html)的SsMediaSource,[HLS](https://exoplayer.dev/hls.html)的HlsMediaSource,以及[常规媒体文件](https://exoplayer.dev/progressive.html)的ProgressiveMediaSource。
117+
118+
119+
```
120+
fun playSingleMp4Video(url: String) {
121+
val uri = Uri.parse(url)
122+
val mediaSource = buildMediaSource(uri)
123+
// setPlayWhenReady()方法可以设置prepared完成后是否自动播放,如果已经准备好了该方法可实现开始和暂停播放的功能
124+
mPlayer.playWhenReady = true
125+
// setShuffleModeEnabled控制播放列表 setPlaybackParameters控制亮度和音量
126+
127+
// 设置监听
128+
mPlayer.addListener(mPlayerEventListener)
129+
mPlayer.addVideoListener(mPlayerVideoListener)
130+
// 移除监听
131+
// mPlayer.removeListener(mPlayerEventListener)
132+
mPlayer.prepare(mediaSource, false, false)
133+
}
134+
135+
private fun buildMediaSource(uri: Uri): MediaSource {
136+
val dataSourceFactory = DefaultDataSourceFactory(context, Util.getUserAgent(context, "you application name"))
137+
return ProgressiveMediaSource.Factory(dataSourceFactory)
138+
.createMediaSource(uri)
139+
}
140+
141+
private var mPlayerEventListener = object : EventListener {
142+
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
143+
when (playbackState) {
144+
Player.STATE_IDLE -> {
145+
// 出事状态、播放器停止或播放失败时的状态
146+
}
147+
Player.STATE_BUFFERING -> {
148+
// 开始加载数据,无法立即从当前位置进行播放
149+
}
150+
Player.STATE_READY -> {
151+
// ready状态,可以直接从当前位置播放
152+
}
153+
Player.STATE_ENDED -> {
154+
// 播放完成
155+
}
156+
}
157+
}
158+
159+
override fun onPlayerError(error: ExoPlaybackException?) {
160+
// error.getSourceException()可以获取更多信息
161+
when(error?.type) {
162+
ExoPlaybackException.TYPE_SOURCE -> {
163+
// 加载资源时出错
164+
}
165+
166+
ExoPlaybackException.TYPE_RENDERER -> {
167+
// 渲染时出错
168+
}
169+
170+
ExoPlaybackException.TYPE_UNEXPECTED -> {
171+
// 意外
172+
}
173+
174+
ExoPlaybackException.TYPE_OUT_OF_MEMORY -> {
175+
// OOM
176+
}
177+
178+
ExoPlaybackException.TYPE_REMOTE -> {
179+
// 远程错误
180+
}
181+
}
182+
}
183+
}
184+
185+
private var mPlayerVideoListener = object : VideoListener {
186+
override fun onVideoSizeChanged(
187+
width: Int,
188+
height: Int,
189+
unappliedRotationDegrees: Int,
190+
pixelWidthHeightRatio: Float
191+
) {
192+
193+
}
194+
195+
override fun onRenderedFirstFrame() {
196+
197+
}
198+
199+
override fun onSurfaceSizeChanged(width: Int, height: Int) {
200+
201+
}
202+
}
203+
```
204+
205+
206+
### 资源释放
207+
208+
```
209+
if (mPlayer != null) {
210+
mPlayer.removeListener(mPlayerEventListener)
211+
mPlayer.removeVideoListener(mPlayerVideoListener)
212+
mPlayer.release()
213+
}
214+
```
215+
216+
217+
---
218+
219+
- 邮箱 :charon.chui@gmail.com
220+
- Good Luck!
221+
222+
223+
224+
225+
226+
227+

0 commit comments

Comments
 (0)
Please sign in to comment.