Android——SRT字幕文件的下载、解压、转换、显示

Android——SRT字幕文件的下载、解压、转换、显示需要在视频播放时,同步显示字幕,市面上主流的字幕文件一般为SRT文件,一般流程为从服务器请求一个url地址,此为zip字幕压缩文件,一般需要请求url,下载zip文件,解析zip文件得到字幕srt文件,最后进行显示。…

Android——SRT字幕文件的下载、解压、转换、显示"

简介

需要在视频播放时,同步显示字幕,市面上主流的字幕文件一般为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

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注