文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

AndroidSRT字幕文件基础操作讲解

2023-01-16 18:00

关注

简介

需要在视频播放时,同步显示字幕,市面上主流的字幕文件一般为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字幕文件基础操作讲解的文章就介绍到这了,更多相关Android SRT字幕文件内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯