SRT视频字幕的解析与同步原理

本文介绍了一种SRT字幕文件的解析方法及其实现思路,并演示了如何将解析后的字幕与视频播放器同步显示的技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://www.eoeandroid.com/thread-171556-1-1.html


在论坛搜索srt字幕的解析,没有资源,于是自己琢磨,有点结果,与大家分享。


srt字幕文件的格式是:
1
00:00:02,580 --> 00:00:05,980
This is from Gagarin.

2
00:00:11,260 --> 00:00:15,760
<b><u><font color='RED'>出卖我的爱.</font></u></b>
<b><u><font color='RED'>       离开就离开.</font></u></b>
<b><u><font color='RED'>       分手就分手.</font></u></b>
<b><u><font color='RED'>没啥了不起.</font></u></b>

3
00:00:18,660 --> 00:00:22,660
初次发帖,欢迎分享.

4
00:00:23,860 --> 00:00:30,860
Trust is like a piece of paper. When it creases, it cannot recover even it is smoothed.
信任就像一张纸,皱了,即使抚平,也恢复不了原样了。

即:
数字
时间 --> 时间
字幕内容(可以多行)
空行
数字
时间 --> 时间
字幕内容(可以多行)
空行
.
.
.
这里为了说明方便,把
数字
时间 --> 时间
字幕内容(可以多行)
空行
叫做字幕元素。

思路应该是比较清晰的,先解析字幕后同步显示字幕。


1.解析字幕
字幕在解析的时候,就是解析出每一个字幕元素。关键是字幕元素的时间和内容,时间可以解析出开始时间和结束时间,内容可能一行,可能多行,有的还有格式。这里我们可以先声明一个SRT的Bean来存放解析出来的字幕元素。

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package wjj.player.entity;  
  2.    
  3. public class SRT {  
  4. private int beginTime;  
  5. private int endTime;  
  6. private String srtBody;  
  7.    
  8. public int getBeginTime() {  
  9. return beginTime;  
  10. }  
  11.    
  12. public void setBeginTime(int beginTime) {  
  13. this.beginTime = beginTime;  
  14. }  
  15.    
  16. public int getEndTime() {  
  17. return endTime;  
  18. }  
  19.    
  20. public void setEndTime(int endTime) {  
  21. this.endTime = endTime;  
  22. }  
  23.    
  24. public String getSrtBody() {  
  25. return srtBody;  
  26. }  
  27.    
  28. public void setSrtBody(String srtBody) {  
  29. this.srtBody = srtBody;  
  30. }  
  31.    
  32. @Override  
  33. public String toString() {  
  34. return "" + beginTime + ":" + endTime + ":" + srtBody;  
  35. }  
  36. }  

然后就可以把字幕解析的结果放在这个SRT的对象中,由于字幕文件中有多个字幕元素,我们可以把它放在一个Map中存放。这里选用TreeMap。声明一个全局变量 TreeMap<Integer, SRT> srt_map =null;于是就可以把整个字幕文件解析到这个TreeMap中。


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2. * 解析SRT字幕文件 
  3.  
  4. * @param srtPath 
  5. * 字幕路径 
  6. */  
  7. private void parseSrt(String srtPath) {  
  8. FileInputStream inputStream = null;  
  9. try {  
  10. inputStream = new FileInputStream(srtPath);  
  11. catch (FileNotFoundException e) {  
  12. // TODO Auto-generated catch block  
  13. e.printStackTrace();  
  14. return;// 有异常,就没必要继续下去了  
  15. }  
  16. BufferedReader br = new BufferedReader(new InputStreamReader(  
  17. inputStream));  
  18. String line = null;  
  19. srt_map = new TreeMap<Integer, SRT>();  
  20. StringBuffer sb = new StringBuffer();  
  21. int key = 0;  
  22. try {  
  23. while ((line = br.readLine()) != null) {  
  24. if (!line.equals("")) {  
  25. sb.append(line).append("@");  
  26. continue;  
  27. }  
  28.    
  29. String[] parseStrs = sb.toString().split("@");  
  30. // 该if为了适应一开始就有空行以及其他不符格式的空行情况  
  31. if (parseStrs.length < 3) {  
  32. <i>sb.delete(0, sb.length());// 清空,否则影响下一个字幕元素的解析</i>  
  33. continue;  
  34. }  
  35.    
  36. SRT srt = new SRT();  
  37. // 解析开始和结束时间  
  38. String timeTotime = parseStrs[1];  
  39. int begin_hour = Integer.parseInt(timeTotime.substring(02));  
  40. int begin_mintue = Integer.parseInt(timeTotime.substring(35));  
  41. int begin_scend = Integer.parseInt(timeTotime.substring(68));  
  42. int begin_milli = Integer.parseInt(timeTotime.substring(912));  
  43. int beginTime = (begin_hour * 3600 + begin_mintue * 60 + begin_scend)  
  44. 1000 + begin_milli;  
  45. int end_hour = Integer.parseInt(timeTotime.substring(1719));  
  46. int end_mintue = Integer.parseInt(timeTotime.substring(2022));  
  47. int end_scend = Integer.parseInt(timeTotime.substring(2325));  
  48. int end_milli = Integer.parseInt(timeTotime.substring(2629));  
  49. int endTime = (end_hour * 3600 + end_mintue * 60 + end_scend)  
  50. 1000 + end_milli;  
  51.    
  52. // System.out.println("开始:" + begin_hour + ":" + begin_mintue +  
  53. // ":"  
  54. // + begin_scend + ":" + begin_milli + "=" + beginTime  
  55. // + "ms");  
  56. // System.out.println("结束:" + end_hour + ":" + end_mintue + ":"  
  57. // + end_scend + ":" + end_milli + "=" + endTime + "ms");  
  58. // 解析字幕文字  
  59. String srtBody = "";  
  60. // 可能1句字幕,也可能2句及以上。  
  61. for (int i = 2; i < parseStrs.length; i++) {  
  62. srtBody += parseStrs</strong><i><strong> + "\n";  
  63. }  
  64. // 删除最后一个"\n"  
  65. srtBody = srtBody.substring(0, srtBody.length() - 1);  
  66. // 设置SRT  
  67. srt.setBeginTime(beginTime);  
  68. srt.setEndTime(endTime);  
  69. srt.setSrtBody(new String(srtBody.getBytes(), "UTF-8"));  
  70. // 插入队列  
  71. srt_map.put(key, srt);  
  72. key++;  
  73. sb.delete(0, sb.length());// 清空,否则影响下一个字幕元素的解析  
  74. }  
  75. catch (Exception e) {  
  76. // TODO: handle exception  
  77. e.printStackTrace();  
  78. }  
  79. }  

2.同步显示
解析完成后,接下来就是显示的问题了。由于SRT字幕元素中有了开始时间,结束时间,而播放器也可以通过getCurrentPosition()获得当前播放的时间,同步显示的原理就是先获取当前播放时间,然后与SRT字幕元素中的开始时间和结束时间比较,在此范围内的就可以显示SRT字幕元素中的字幕内容。比较是通过一个while循环遍历完成。


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. private void showSRT() {  
  2. TextView tvSrt = (TextView) srtView.findViewById(R.id.srt);//项目中显示字幕的控件  
  3. int currentPosition = vv.getCurrentPosition();//vv是VideoView播放器  
  4. Iterator<Integer> keys = srt_map.keySet().iterator();  
  5. //通过while循环遍历比较  
  6. while (keys.hasNext()) {  
  7. Integer key = keys.next();  
  8. SRT srtbean = srt_map.get(key);  
  9. if (currentPosition > srtbean.getBeginTime()  
  10. && currentPosition < srtbean.getEndTime()) {  
  11. //Html.fromHtml可以解析出字幕内容的格式  
  12. Spanned srtBodyHtml = Html.fromHtml(srtbean  
  13. .getSrtBody());  
  14. tvsrt.setText(srtBodyHtml);  
  15. break;//找到后就没必要继续遍历下去,节约资源  
  16. }  
  17. }  
  18. }  

到此SRT字幕的解析与同步显示算是讲完了。我觉得关键还是个思路,有了思路就有了代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值