Skip to content

Commit 54de87b

Browse files
committed
feat: add unified subtitle support
1 parent 86acebf commit 54de87b

30 files changed

Lines changed: 2091 additions & 121 deletions

README_CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
**播放** | **单例播放、多个同时播放、视频列表滑动自动播放、列表切换详情页面无缝播放。**
2525
**窗口** | **小窗口、多窗体下(包括桌面)的小窗口播放。**
2626
**广告** | **片头广告、跳过广告支持、中间插入广告功能。**
27-
**字幕** | **[media3(exo2)模式下支持自定增加外挂字幕](https://github.com/CarGuo/GSYVideoPlayer/tree/master/app/src/main/java/com/example/gsyvideoplayer/exosubtitle)**
27+
**字幕** | **支持通用外挂字幕 Overlay,SRT/WebVTT 可跨 IJK、Media3(EXOPlayer)、MediaPlayer 等内核使用;Media3 内嵌字幕可桥接到同一套 UI。[说明](doc/SUBTITLE_CN.md)**
2828
**dash** | **media3(exo2) 模式支持dash**
2929
**stream** | **支持元数据播放**
3030
**适配 16k** | **ex_so 适配 16K Page Size**

app/src/main/AndroidManifest.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,11 @@
234234
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
235235
android:screenOrientation="portrait"
236236
android:theme="@style/Theme.AppCompat.Transitions" />
237+
<activity
238+
android:name=".SubtitleDetailPlayer"
239+
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
240+
android:screenOrientation="portrait"
241+
android:theme="@style/Theme.AppCompat.Transitions" />
237242

238243
<meta-data
239244
android:name="android.max_aspect"

app/src/main/java/com/example/gsyvideoplayer/MainActivity.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ protected void onCreate(Bundle savedInstanceState) {
8383
binding.detailDownloadActivity.setOnClickListener(this);
8484
binding.detailAudioActivity.setOnClickListener(this);
8585
binding.detailSubtitleActivity.setOnClickListener(this);
86+
binding.detailSubtitleCommonActivity.setOnClickListener(this);
8687
binding.changeCore.setOnClickListener(this);
8788
binding.viewPager2Activity.setOnClickListener(this);
8889
binding.viewPagerDemoActivity.setOnClickListener(this);
@@ -230,6 +231,9 @@ public void onClick(View view) {
230231
case R.id.detail_subtitle_activity:
231232
JumpUtils.goToGSYExoSubTitleDetailPlayer(this);
232233
break;
234+
case R.id.detail_subtitle_common_activity:
235+
JumpUtils.goToSubtitleDetailPlayer(this);
236+
break;
233237
case R.id.detail_audio_activity:
234238
JumpUtils.goToDetailAudioActivity(this);
235239
break;
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
package com.example.gsyvideoplayer;
2+
3+
import android.graphics.Color;
4+
import android.os.Bundle;
5+
import android.view.View;
6+
import android.widget.ImageView;
7+
8+
import androidx.annotation.NonNull;
9+
import androidx.appcompat.app.AppCompatActivity;
10+
11+
import com.example.gsyvideoplayer.databinding.ActivityDetailSubtitlePlayerBinding;
12+
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder;
13+
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack;
14+
import com.shuyu.gsyvideoplayer.listener.LockClickListener;
15+
import com.shuyu.gsyvideoplayer.player.IjkPlayerManager;
16+
import com.shuyu.gsyvideoplayer.player.PlayerFactory;
17+
import com.shuyu.gsyvideoplayer.subtitle.GSYSubtitleSource;
18+
import com.shuyu.gsyvideoplayer.subtitle.GSYSubtitleStyle;
19+
import com.shuyu.gsyvideoplayer.utils.Debuger;
20+
import com.shuyu.gsyvideoplayer.utils.OrientationUtils;
21+
import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer;
22+
23+
import java.util.ArrayList;
24+
import java.util.HashMap;
25+
import java.util.List;
26+
import java.util.Map;
27+
28+
public class SubtitleDetailPlayer extends AppCompatActivity {
29+
30+
private boolean isPlay;
31+
private boolean isPause;
32+
private boolean subtitleEnabled = true;
33+
private boolean largeSubtitle;
34+
private OrientationUtils orientationUtils;
35+
private ActivityDetailSubtitlePlayerBinding binding;
36+
private List<GSYSubtitleSource> subtitleSources;
37+
private int subtitleSourceIndex;
38+
39+
@Override
40+
protected void onCreate(Bundle savedInstanceState) {
41+
super.onCreate(savedInstanceState);
42+
PlayerFactory.setPlayManager(IjkPlayerManager.class);
43+
44+
binding = ActivityDetailSubtitlePlayerBinding.inflate(getLayoutInflater());
45+
setContentView(binding.getRoot());
46+
47+
ImageView imageView = new ImageView(this);
48+
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
49+
imageView.setImageResource(R.mipmap.xxx1);
50+
51+
binding.detailPlayer.getTitleTextView().setVisibility(View.GONE);
52+
binding.detailPlayer.getBackButton().setVisibility(View.GONE);
53+
54+
orientationUtils = new OrientationUtils(this, binding.detailPlayer);
55+
orientationUtils.setEnable(false);
56+
57+
Map<String, String> header = new HashMap<>();
58+
header.put("allowCrossProtocolRedirects", "true");
59+
60+
new GSYVideoOptionBuilder()
61+
.setThumbImageView(imageView)
62+
.setIsTouchWiget(true)
63+
.setRotateViewAuto(false)
64+
.setLockLand(false)
65+
.setShowFullAnimation(false)
66+
.setNeedLockFull(true)
67+
.setUrl(getUrl())
68+
.setMapHeadData(header)
69+
.setCacheWithPlay(false)
70+
.setVideoTitle("通用字幕 IJK Demo")
71+
.setVideoAllCallBack(new GSYSampleCallBack() {
72+
@Override
73+
public void onPrepared(String url, Object... objects) {
74+
super.onPrepared(url, objects);
75+
Debuger.printfError("***** subtitle ijk onPrepared **** " + objects[0]);
76+
orientationUtils.setEnable(binding.detailPlayer.isRotateWithSystem());
77+
isPlay = true;
78+
}
79+
80+
@Override
81+
public void onEnterFullscreen(String url, Object... objects) {
82+
super.onEnterFullscreen(url, objects);
83+
Debuger.printfError("***** subtitle ijk onEnterFullscreen **** " + objects[0]);
84+
}
85+
86+
@Override
87+
public void onQuitFullscreen(String url, Object... objects) {
88+
super.onQuitFullscreen(url, objects);
89+
Debuger.printfError("***** subtitle ijk onQuitFullscreen **** " + objects[0]);
90+
if (orientationUtils != null) {
91+
orientationUtils.backToProtVideo();
92+
}
93+
}
94+
})
95+
.setLockClickListener(new LockClickListener() {
96+
@Override
97+
public void onClick(View view, boolean lock) {
98+
if (orientationUtils != null) {
99+
orientationUtils.setEnable(!lock);
100+
}
101+
}
102+
})
103+
.build(binding.detailPlayer);
104+
105+
subtitleSources = createSubtitleSources();
106+
binding.detailPlayer.setSubtitleSources(subtitleSources);
107+
applySubtitleStyle(16);
108+
109+
binding.detailPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {
110+
@Override
111+
public void onClick(View v) {
112+
orientationUtils.resolveByClick();
113+
binding.detailPlayer.startWindowFullscreen(SubtitleDetailPlayer.this, true, true);
114+
}
115+
});
116+
117+
binding.subtitleToggle.setOnClickListener(new View.OnClickListener() {
118+
@Override
119+
public void onClick(View v) {
120+
subtitleEnabled = !subtitleEnabled;
121+
getCurPlay().setSubtitleEnabled(subtitleEnabled);
122+
binding.subtitleToggle.setText(subtitleEnabled ? "GSY SUBTITLE OFF" : "GSY SUBTITLE ON");
123+
}
124+
});
125+
126+
binding.subtitleSize.setOnClickListener(new View.OnClickListener() {
127+
@Override
128+
public void onClick(View v) {
129+
largeSubtitle = !largeSubtitle;
130+
int size = largeSubtitle ? 22 : 16;
131+
getCurPlay().setSubtitleStyle(createSubtitleStyle(size));
132+
binding.subtitleSize.setText(largeSubtitle ? "SUBTITLE SIZE 16" : "SUBTITLE SIZE 22");
133+
}
134+
});
135+
136+
binding.subtitleSource.setOnClickListener(new View.OnClickListener() {
137+
@Override
138+
public void onClick(View v) {
139+
if (subtitleSources == null || subtitleSources.isEmpty()) {
140+
return;
141+
}
142+
subtitleSourceIndex = (subtitleSourceIndex + 1) % subtitleSources.size();
143+
GSYSubtitleSource source = subtitleSources.get(subtitleSourceIndex);
144+
if (getCurPlay().selectSubtitle(source.getId())) {
145+
binding.subtitleSource.setText("SUBTITLE " + source.getLabel());
146+
}
147+
}
148+
});
149+
}
150+
151+
@Override
152+
protected void onPause() {
153+
getCurPlay().onVideoPause();
154+
super.onPause();
155+
isPause = true;
156+
}
157+
158+
@Override
159+
protected void onResume() {
160+
getCurPlay().onVideoResume(false);
161+
super.onResume();
162+
isPause = false;
163+
}
164+
165+
@Override
166+
protected void onDestroy() {
167+
super.onDestroy();
168+
if (isPlay) {
169+
getCurPlay().release();
170+
}
171+
if (orientationUtils != null) {
172+
orientationUtils.releaseListener();
173+
}
174+
}
175+
176+
@Override
177+
public void onConfigurationChanged(@NonNull android.content.res.Configuration newConfig) {
178+
super.onConfigurationChanged(newConfig);
179+
if (isPlay && !isPause) {
180+
binding.detailPlayer.onConfigurationChanged(this, newConfig, orientationUtils, true, true);
181+
}
182+
}
183+
184+
private void applySubtitleStyle(int sizeSp) {
185+
binding.detailPlayer.setSubtitleStyle(createSubtitleStyle(sizeSp));
186+
}
187+
188+
private GSYSubtitleStyle createSubtitleStyle(int sizeSp) {
189+
return new GSYSubtitleStyle.Builder()
190+
.setTextColor(Color.WHITE)
191+
.setTextSizeSp(sizeSp)
192+
.setShadow(Color.BLACK, 3, 1, 1)
193+
.setBottomMarginDp(56)
194+
.build();
195+
}
196+
197+
private GSYVideoPlayer getCurPlay() {
198+
if (binding.detailPlayer.getFullWindowPlayer() != null) {
199+
return binding.detailPlayer.getFullWindowPlayer();
200+
}
201+
return binding.detailPlayer;
202+
}
203+
204+
private String getUrl() {
205+
return "https://www.w3schools.com/html/mov_bbb.mp4";
206+
}
207+
208+
private List<GSYSubtitleSource> createSubtitleSources() {
209+
List<GSYSubtitleSource> sources = new ArrayList<>();
210+
sources.add(new GSYSubtitleSource.Builder(getLocalSrtSubtitleUri())
211+
.setId("local-srt")
212+
.setLabel("SRT LOCAL")
213+
.setLanguage("zh")
214+
.setDefault(true)
215+
.build());
216+
sources.add(new GSYSubtitleSource.Builder(getLocalVttSubtitleUri())
217+
.setId("local-vtt")
218+
.setLabel("VTT LOCAL")
219+
.setLanguage("en")
220+
.build());
221+
sources.add(new GSYSubtitleSource.Builder(getNetworkSrtSubtitleUrl())
222+
.setId("network-srt")
223+
.setLabel("SRT NETWORK")
224+
.setLanguage("zh")
225+
.build());
226+
return sources;
227+
}
228+
229+
private String getLocalSrtSubtitleUri() {
230+
return "android.resource://" + getPackageName() + "/" + R.raw.demo_subtitle;
231+
}
232+
233+
private String getLocalVttSubtitleUri() {
234+
return "android.resource://" + getPackageName() + "/" + R.raw.demo_subtitle_vtt;
235+
}
236+
237+
private String getNetworkSrtSubtitleUrl() {
238+
return "http://img.cdn.guoshuyu.cn/subtitle2.srt";
239+
}
240+
}

0 commit comments

Comments
 (0)