Android SRT字幕文件基础操作讲解

目录
  • 简介
  • 下载
    • 创建文件夹
    • 文件下载
    • 下载调用以及文件解析调用
  • 解析
    • ZIP文件解析
    • 外部引用
  • 转换
    • 转换SRT字幕文件
    • 获取SRT文件list实体数据
  • 显示
    • 字幕显示

简介

需要在视频播放时,同步显示字幕,市面上主流的字幕文件一般为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字幕文件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Andorid TextView字幕效果实例

    一.效果图 二.代码 复制代码 代码如下: public class TextSubView extends TextView { private TextPaint mPaint; public TextSubView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new TextPaint(getPaint()); mPaint.setStyle(TextPaint.Style.STROKE);

  • Android 实现视频字幕Subtitle和横竖屏切换示例

    系统自带的VideoView有些视频格式不支持,那么我们可以用第三方实现的VideoView替代系统的来播放视频,比较流行的有ijkplayer.vitamio. 最近有个需求就是需要给视频添加字幕,其实也挺简单的.字幕比较常用的格式是srt,实际它就是文本,把它解析出来,然后根据时间再展示就OK.还有就是实现了即使旋转按钮关闭,根据方向感应器也能做到横竖屏切换. 本文用的是系统VideoView,然后播放sd卡中的视频来作为演示(源码中带有f2.mp4和f2.srt,运行时拷贝到sd卡就行).

  • Android实现字幕滚动的方法

    本文实例介绍了安卓Android实现字幕滚动效果的方法.主要是一个现成的Java类文件实现的,该程序由Android达人Tony编写,本次是转发,还望原作者Tony不要介意.这个Android字幕滚动类的自定义功能比较多,可定义当前滚动到结尾时的停顿时间,单位:毫秒,还可设置当前的滚动速度,值越小,速度越快. 主要实现代码如下: package com.tony.autoscroll; import android.content.Context; import android.os.Handl

  • Android编程实现类似天气预报图文字幕垂直滚动效果的方法

    本文实例讲述了Android编程实现类似天气预报图文字幕垂直滚动效果的方法.分享给大家供大家参考,具体如下: 在很多天气或者新闻的应用中,我们都能看到一些字幕滚动的效果,最简单的实现为跑马灯效果,用系统提供的属性即可实现. 复杂一些的就需要自己去用自定义控件实现. 比如 让TextView 实现垂直滚动. 这里我要讲的是垂直滚动的字幕效果,并且内容并不仅为文字,还可以加入图片或者其他元素. 废话不多说,还是直接上效果图: 首先还是看一下核心的实现: 目前我的做法是重写了ScrollView,对外

  • Android编程之文件读写操作与技巧总结【经典收藏】

    本文实例总结了Android文件读写操作.分享给大家供大家参考,具体如下: 在Android中的文件放在不同位置,它们的读取方式也有一些不同. 本文对android中对资源文件的读取.数据区文件的读取.SD卡文件的读取及RandomAccessFile的方式和方法进行了整理.供参考. 一.资源文件的读取: 1) 从resource的raw中读取文件数据: String res = ""; try{ //得到资源中的Raw数据流 InputStream in = getResources

  • python文件操作的基础详细讲解(write、read、readlines、readline)

    目录 前言 1 文件操作 1.1 文件打开与关闭 1.1.1 打开文件 1.1.2 关闭文件 2 文件读写 2.1 写数据(write) 2.2 读数据(read) 2.3 读数据(readlines) 2.3 读数据(readline) 3 文件的相关操作 3.1 文件重命名 3.2 删除文件 3.3 创建文件夹 3.4 获取当前目录 3.5 改变默认目录 补充:文件综合操作实例 总结 前言 python 文件操作.文件读写(write.read.readlines.readline).文件的

  • Android同步异步任务与多线程及Handler消息处理机制基础详细讲解

    目录 一.同步与异步 Android中的多线程 Android中的多线程与主线程与子线程 Handler异步通信系统 使用新线程计算质数 一.同步与异步 同步的执行任务:在执行程序时,如果没有收到执行结果,就一直等,不继续往下执行,直到收到执行结果,才接着往下执行. 异步的执行任务:在执行程序时,如果遇到需要等待的任务,就另外开辟一个子线程去执行它,自己继续往下执行其他程序.子线程有结果时,会将结果发送给主线程 Android中的多线程 线程:通俗点讲就是一个执行过程.多线程自然就是多个执行过程

  • Android开发之文件操作详解

    本文实例讲述了Android开发之文件操作.分享给大家供大家参考,具体如下: 目前,几乎所有的设备都会涉及到文件的操作,例如什么电脑,手机等设备.Android的文件操作和电脑是比较类似的,既可以存储在手机内置的存储器里也可以是sd卡.在这篇文章里主要介绍在手机内置存储器里的文件操作. 一. 开发流程 (1)界面的设计 (2)设计android的业务层 (3)单元测试 (4)设置android的控制器层 二. 开发步骤 (1)设计软件界面 <?xml version="1.0"

  • Android编程之在SD卡上进行文件读写操作实例详解

    本文实例讲述了Android编程之在SD卡上进行文件读写操作的方法.分享给大家供大家参考,具体如下: 很多知识只有真正理解掌握之后才能运用自如,举一反三.对Java中的文件操作和android系统SD卡里面的文件操作,你觉得有区别吗,显然没有本质区别,如果勉强说有,那也是不足为道滴,但我们在实际运用中却要注意如下几点,不然问题会缠上你. 1.首先想要对android系统SD卡里文件操作需要添加使用权限: android系统是不会让外来程序随意动自己内存的,如果没有许可证,不好意思,不准你动我地盘

  • Android编程之SharedPreferences文件存储操作实例分析

    本文实例讲述了Android编程之SharedPreferences文件存储操作的方法.分享给大家供大家参考.具体分析如下: SharedPreferences类提供了一种简单的文件存储功能,像程序的配置文件可以通过它来实现. 源代码: package com.test.sharedpreferences; import android.app.Activity; import android.content.Context; import android.content.SharedPrefe

  • Python文件的操作示例的详细讲解

    1. 文件的读写原理: 文件的读写称为I/O操作. 操作原理: .py文件是用解释器去运行,调用OS操作系统的资源,去操作磁盘上的文件. 操作流程: 在去操作一个文件的文件的时候,首先打开或者创建一个文件,进行读或者写. 读: 从文件拿到内存当中来 写:把内存的文件放入文件中 最后进行关闭资源. 内置函数: open() 可以创建或者打开一个文件 语法规则: file=open(filename [mode,encoding] 打开模式默认为只读 默认文本中的字符编码格式为gbk # 作者:互联

  • C语言由浅入深讲解文件的操作上篇

    目录 为什么使用文件 什么是文件 文件名 关于文件的一些概念 文件函数 fopen fclose 实例代码 绝对路径 文件的打开方式 文件操作流程 为什么使用文件 前面写的通讯录,增加人数退出程序后,数据就会消失.此时数据是存放在内存中,下次运行通讯录程序的时候,数据又得重新录入,如果使用这样的通讯录就很难受. 所以文件操作就应运而生.数据持久化的方法有两种:1.把数据存放在磁盘文件2.存放到数据库使用文件我们们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化. 什么是文件 但是在程序设计中

  • C语言由浅入深讲解文件的操作下篇

    目录 文件的顺序读写 字符输入输出fgetc和fputc 文本行输入输出函数fgets和fputs 格式化输入输出函数fscanf和fprintf 二进制输入输出函数fread和fwrite 文件的随机读写 fseek ftell fwind 文本文件和二进制文件 文件结束的判定 feof 文件缓冲区 第一篇讲了文件的基本概念,和文件如何打开和关闭.第二篇主要介绍文件的顺序读写和随机读写.外加文件缓冲区的知识点. 文件的顺序读写 字符输入输出fgetc和fputc fgetc:字符输入函数,也就

  • C语言超详细讲解文件的操作

    目录 一.为什么使用文件 二.什么是文件 1.程序文件 2.数据文件 3.文件名 三.文件指针 四.文件的打开和关闭 五.文件的顺序读写 六.文件的随机读写 fseek ftell rewind 七.文件结束判定 一.为什么使用文件 当我们写一些项目的时候,我们应该要把写的数据存储起来.只有我们自己选择删除数据的时候,数据才不复存在.这就涉及到了数据的持久化的问题,为我们一般数据持久化的方法有,把数据存在磁盘文件.存放到数据库等方式.使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久

随机推荐