简介
需要在视频播放时,同步显示字幕,市面上主流的字幕文件一般为SRT文件,一般流程为:从服务器请求一个url地址,此为zip字幕压缩文件,一般需要请求url,下载zip文件,解析zip文件得到字幕srt文件,最后进行显示
下载
请求就不在此多言了,每个服务器请求体,返回题各异,没有参考价值。
下载zip文件我们需要在本地创建一个本地文件夹用来存储此文件。
创建文件夹
public String createDirectory(String name) {
File dir = new File(BaseApplication.getContext().getCacheDir(), name);
File file = BaseApplication.getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
if (file != null) {
dir = new File(file, name);
}
if (!dir.exists()) {
dir.mkdirs();
}
return dir.toString();
}
文件下载
文件下载使用的开源框架Filedownloader
implementation 'com.liulishuo.filedownloader:library:1.7.7'//download
参数一:下载地址
参数二:文件存储地址
参数三:回调
从外部传入需要的下载参数,然后通过callback回调出去,进行页面更新操作
public void StartDownloadFile(String url,String path,FileDownloaderCallback callback){
FileDownloader.getImpl().create(url).setPath(path,true).setListener(new FileDownloadListener() {
@Override
protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {
callback.start();
}
@Override
protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {
}
@Override
protected void completed(BaseDownloadTask task) {
callback.completed(task.getPath());
}
@Override
protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) {
}
@Override
protected void error(BaseDownloadTask task, Throwable e) {
callback.failed();
}
@Override
protected void warn(BaseDownloadTask task) {
}
}).start();
}
下载调用以及文件解析调用
此处建立文件下载文件夹以及解析完成的文件夹地址,然后通过调用上述filedownloader文件下载回调,然后在下载完成的回调中进行文件zip解析
public void download(String url,String title,DownloadResultCallback callback){
String input = "InputDirectory";
String output = "OutputDirectory";
String inPath = FileUtils.getInstance().createDirectory(input);
String outPath = FileUtils.getInstance().createDirectory(output);
String sub = FileUtils.getInstance().createFile(inPath,"subTitleFile"+ File.separator);
DownloadUtils.getInstance().StartDownloadFile(url, sub, new DownloadUtils.FileDownloaderCallback() {
@Override
public void start() {
callback.downloadStart();
}
@Override
public void completed(String inputPath) {
callback.downloadSuccess();
String path = inputPath + "/" + title +".zip";
try {
ZipUtils.UnZipFolder(path,outPath);
callback.resolveSuccess();
} catch (Exception e) {
callback.resolveFailed(e.getMessage());
e.printStackTrace();
}
}
@Override
public void failed() {
callback.downloadFailed();
}
});
}
解析
ZIP文件解析
此处被上述调用,用于zip文件解析
参数一:需要被解析的zip文件地址
参数二:输出文件夹地址
public class ZipUtils {
public static void UnZipFolder(String zipFileString, String outPathString)throws Exception {
java.util.zip.ZipInputStream inZip = new java.util.zip.ZipInputStream(new java.io.FileInputStream(zipFileString));
java.util.zip.ZipEntry zipEntry;
String szName = "";
while ((zipEntry = inZip.getNextEntry()) != null) {
szName = zipEntry.getName();
if (zipEntry.isDirectory()) {
// get the folder name of the widget
szName = szName.substring(0, szName.length() - 1);
java.io.File folder = new java.io.File(outPathString + java.io.File.separator + szName);
folder.mkdirs();
} else {
java.io.File file = new java.io.File(outPathString + java.io.File.separator + szName);
file.createNewFile();
// get the output stream of the file
java.io.FileOutputStream out = new java.io.FileOutputStream(file);
int len;
byte[] buffer = new byte[1024];
// read (len) bytes into buffer
while ((len = inZip.read(buffer)) != -1) {
// write (len) byte from buffer at the position 0
out.write(buffer, 0, len);
out.flush();
}
out.close();
}
}//end of while
inZip.close();
}//end o
}
外部引用
参数一:下载url地址
参数二:存储文件夹名称
参数三:callback
上述zip文件下载以及zip文件解析为一个封装类,此处为在外部传入参数,通过回调进行页面更新,然后在resolveSuccess()方法中进行异步操作(此方法代表zip文件被下载成功并且已被成功解析)
private void download(){
if (titleBeanList == null || titleBeanList.size() == 0)return;
if (curSubTitlePos == 0)return;
DownloadUtils.getInstance().download(titleBeanList.get(curSubTitlePos).getSub(), titleBeanList.get(curSubTitlePos).getT_name(), new DownloadUtils.DownloadResultCallback() {
@Override
public void downloadStart() {
Log.d(TAG,"download start");
}
@Override
public void downloadSuccess() {
Log.d(TAG,"download success");
}
@Override
public void downloadFailed() {
Log.d(TAG,"download fail");
}
@Override
public void resolveSuccess() {
Log.d(TAG,"resolve success");
handler.sendEmptyMessage(6);
}
@Override
public void resolveFailed(String failMsg) {
Log.d(TAG,"resolve error:"+failMsg);
}
});
}
转换
转换SRT字幕文件
通过将本地的SRT字幕文件转为相对应集合实体数据,具体实体类型根据SRT文件内容而定
public static List<SrtEntity> getSrtInfoList(String srtPath){
List<SrtEntity> srtList = new ArrayList<>();
try {
InputStreamReader read = new InputStreamReader(new FileInputStream(srtPath), "utf-8");
BufferedReader bufferedReader = new BufferedReader(read);
String textLine;
CursorStatus cursorStatus = CursorStatus.NONE;
SrtEntity entity = null;
while ((textLine = bufferedReader.readLine()) != null){
textLine = textLine.trim();
if (cursorStatus == CursorStatus.NONE) {
if (textLine.isEmpty()) {
continue;
}
if (!isNumeric(textLine)){
continue;
}
// New cue
entity = new SrtEntity();
// First textLine is the cue number
try {
entity.setNumber(Integer.parseInt(textLine));
} catch (NumberFormatException e) {
}
cursorStatus = CursorStatus.CUE_ID;
continue;
}
// Second textLine defines the start and end time codes
// 00:01:21,456 --> 00:01:23,417
if (cursorStatus == CursorStatus.CUE_ID) {
if (!textLine.substring(13, 16).equals("-->")) {
throw new Exception(String.format(
"Timecode textLine is badly formated: %s", textLine));
}
entity.setBg(parseTimeCode(textLine.substring(0, 12)));
entity.setEd(parseTimeCode(textLine.substring(17)));
cursorStatus = CursorStatus.CUE_TIMECODE;
continue;
}
// Following lines are the cue lines
if (!textLine.isEmpty() && (
cursorStatus == CursorStatus.CUE_TIMECODE ||
cursorStatus == CursorStatus.CUE_TEXT)) {
entity.addLine(textLine);
cursorStatus = CursorStatus.CUE_TEXT;
continue;
}
if (cursorStatus == CursorStatus.CUE_TIMECODE && textLine.isEmpty()) {
entity.addLine(textLine);
cursorStatus = CursorStatus.CUE_TEXT;
continue;
}
if (cursorStatus == CursorStatus.CUE_TEXT && textLine.isEmpty()) {
// End of cue
srtList.add(entity);
entity = null;
cursorStatus = CursorStatus.NONE;
continue;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
return srtList;
}
获取SRT文件list实体数据
通过以上步骤之后,即可将SRT文件转为相对应的list实体数据,最后与视频声音进行同步即可达到字幕与声音同步的效果
String outPath = FileUtils.getInstance().createDirectory("OutputDirectory");
String path = outPath +"/" +titleBeanList.get(curSubTitlePos).getT_name();
srtEntityList.addAll(SrtParser.getSrtInfoList(path));
显示
字幕显示
然后通过获取字幕文件的片段的开始时间与结束时间,若当前视频的播放进度在此范围之内,即显示字幕,否则继续寻找;
private void showSubTitle(){
if (srtEntityList == null || srtEntityList.size() == 0)return;
for (int i = curSubTitleNum; i < srtEntityList.size(); i++) {
long start = srtEntityList.get(i).getBg().getTime()+subtitleSpeed;
long end = srtEntityList.get(i).getEd().getTime()+subtitleSpeed;
if (curProgress >= start && curProgress <= end){
/**
* 字幕与进度相匹配*/
binding.VideoPlay.setSubTitle(srtEntityList.get(i).content.getText());
curSubTitleNum = i;
break;
}
}
}
若用户往前拖动视频进度条,则将字幕文件片段下标置为0,从头开始匹配
if (currentPosition - curProgress < 0){
//seek --
curSubTitleNum = 0;
}
今天的文章Android——SRT字幕文件的下载、解压、转换、显示分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/32208.html