首页 > 其他分享 >利用简单的IO操作实现M3U8文件之间的合并

利用简单的IO操作实现M3U8文件之间的合并

时间:2023-05-16 21:12:58浏览次数:38  
标签:文件 m3u8 M3U8 合并 ts EXT IO new line

先上代码:

  1    @SneakyThrows  //合并操作,最终文件不包含结束标识,方便多次合并
  2     private static void mergeM3U8File(String source, String target) {
  3         
  4         //读取target
  5         List<String> sl = new ArrayList<>();
  6         try (BufferedReader reader = new BufferedReader(new FileReader(source))) {
  7             String line;
  8             while ((line = reader.readLine()) != null) {
  9                 sl.add(line);
 10             }
 11         }
 12         //读取source
 13         List<String> tl = new ArrayList<>();
 14         try (BufferedReader reader = new BufferedReader(new FileReader(target))) {
 15             String line;
 16             while ((line = reader.readLine()) != null) {
 17                 tl.add(line);
 18             }
 19         }
 20         //合并且统一ts文件名
 21         String filename = target.replace(dir,"");
 22         filename = filename.replace(".m3u8","");
 23         Long order = 0l;
 24         if (tl.size() <= 0) {
 25             for (String s : sl) {
 26                 if(s.startsWith("#")) tl.add(s);
 27                 else {
 28                     tl.add(filename + order + ".ts");
 29                     log.info("转存文件 {}{} 存在状态 {}", dir, s, Files.exists(Paths.get(dir + s)));
 30                     Files.copy(Paths.get(dir + s), Paths.get(dir + filename + order + ".ts"));
 31                     Files.delete(Paths.get(dir + s));
 32                     order++;
 33                 }
 34             }
 35         }
 36         else {
 37             //删除结束段落
 38             if(tl.get(tl.size()-1).startsWith("#EXT-X-ENDLIST")) {
 39                 tl.remove(tl.size() - 1);
 40             }
 41             //获取文件序号(dir+filename+order.ts)
 42             String s = tl.get(tl.size() - 1);
 43             s = s.replace(".ts","");
 44             s = s.replace(filename,"");
 45             order = Long.parseLong(s);
 46             //sl处理 获取头部标识的下标并移除头部
 47             int i = 0;
 48             for (i = 0; i < sl.size(); i++) {
 49                 if (sl.get(i).startsWith("#EXTINF")) break;
 50             }
 51             for (int j = 0; j < i; j++) {
 52                 sl.remove(0);
 53             }
 54             sl.remove(sl.size() - 1);
 55             tl.add("#EXT-X-DISCONTINUITY");
 56             //sl文件内容写入tl
 57             for (int j = 0; j < sl.size(); j++) {
 58                 String s1 = sl.get(j);
 59                 if(s1.startsWith("#EXTINF")) //#EXTINF
 60                     tl.add(s1);
 61                 else//按规则写入文件索引
 62                 {
 63                     order++;
 64                     tl.add(filename + order + ".ts");
 65                     log.info("转存文件 {}{} 存在状态 {}",dir,s1,Files.exists(Paths.get(dir + s1)));
 66                     Files.copy(Paths.get(dir + s1), Paths.get(dir + filename + order + ".ts"));
 67                     Files.delete(Paths.get(dir + s1));
 68                 }
 69             }
 70         }
 71         //生成新的buffer
 72         StringBuffer buffer = new StringBuffer();
 73         for (String t : tl) {
 74             buffer.append(t).append(System.lineSeparator());
 75         }
 76         //写入文件
 77         try (BufferedWriter writer = new BufferedWriter(new FileWriter(target))) {
 78             writer.write(buffer.toString());
 79         }
 80         //清除source
 81         Files.delete(Paths.get(source));
 82     }
 83 
 84     @SneakyThrows //给m3u8文件添加结束标识
 85     private static void endM3u8(String m3u8) {
 86         List<String> sl = new ArrayList<>();
 87         try (BufferedReader reader = new BufferedReader(new FileReader(m3u8))) {
 88             String line;
 89             while ((line = reader.readLine()) != null) {
 90                 sl.add(line);
 91             }
 92         }
 93         sl.add("#EXT-X-ENDLIST");
 94         //生成新的buffer
 95         StringBuffer buffer = new StringBuffer();
 96         for (String t : sl) {
 97             buffer.append(t).append(System.lineSeparator());
 98         }
 99         //写入文件
100         try (BufferedWriter writer = new BufferedWriter(new FileWriter(m3u8))) {
101             writer.write(buffer.toString());
102         }
103 
104     }

关于m3u8文件的说明:

- #EXTM3U:文件头,标识这是一个M3U8文件。
- #EXT-X-VERSION:表示M3U8的版本号。
- #EXT-X-TARGETDURATION:表示每个分段的最长时间(以秒为单位)。
- #EXT-X-MEDIA-SEQUENCE:表示播放列表中的第一个分段的编号。
- #EXTINF:表示当前分段的播放时间长度(以秒为单位)和URI。
- #EXT-X-ENDLIST:表示播放列表结束。

- #EXT-X-STREAM-INF:表示变换码率视频流中的音视频属性。
- #EXT-X-DISCONTINUITY:表示两个分段之间的不连续性。
- #EXT-X-PROGRAM-DATE-TIME:表示当前分段的播放时间点。
- #EXT-X-BYTERANGE:表示分段的字节范围。

合并代码中的m3u8文件的格式:

 * #EXTM3U
* #EXT-X-VERSION:3
* #EXT-X-TARGETDURATION:2
* #EXT-X-MEDIA-SEQUENCE:0
* #EXT-X-PLAYLIST-TYPE:EVENT
* #EXTINF:1.441000,
* 2052636967-12640237988249000.ts
* #EXTINF:1.848000,
* 2052636967-12640237988249001.ts
* #EXT-X-ENDLIST

关于代码中的一些说明:

1、由于m3u8文件中的ts文件索引规则一般是  m3u8文件名+索引号,因此在合并文件之前需要先统一索引文件名;

2、由于m3u8文件之间是相互独立的,所以要在写入外部m3u8索引文件之前加入 #EXT-X-DISCONTINUITY 标识,否则播放器会在播放完第一部分的m3u8文件之后停止播放;

3、关于m3u8文件的结束行 #EXT-X-ENDLIST 问题,大部分播放器在未识别到结束标识且已经读取到文件最后一行索引时,会不断的请求m3u8文件,获取新资源,可以通过这个特新来实现直播效果;

合并后的文件内容:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:EVENT
# EXTINF: 1.441000.
2052636967-12640237988249000.ts
# EXTINF: 1.848000.
2052636967-12640237988249001.ts
#EXT-X-DISCONTINUITY
# EXTINF: 1.741000.
2052636967-12640237988249002.ts
# EXTINF: 1.148000.
2052636967-12640237988249003.ts
#EXT-X-ENDLIST


标签:文件,m3u8,M3U8,合并,ts,EXT,IO,new,line
From: https://www.cnblogs.com/tangzeqi/p/17406810.html

相关文章

  • SSM整合报错:errorCode 1045, state 28000 java.sql.SQLException: Access denied for
    SSM整合报错:errorCode1045,state28000java.sql.SQLException:Accessdeniedforuser简述SSM整合项目配置好环境后,当要对数据库进行操作,加载jdbc.properties数据库配置文件时,出现下面的报错createconnectionSQLException,url:jdbc:mysql://localhost:3306/furn_ssm,......
  • Android 控件之Notification
    [quote]最近一直在研究android,并一边研究一边做应用。其中遇到了把程序通知常驻在Notification栏,并且不能被clear掉的问题。虽然notify()的第一个参数可以写死并clear掉,但这个值我并不想写死,但是这个值如果是随机生成一个数怎么传给Activity,用Intent当中的Bu......
  • Android Studio学习日志二,Toast用法
    首先,创建一个util,在ToastUtil里面调用方法在里面编写Toast类的代码,方便以后调用packagecom.example.appdemo.util;importandroid.content.Context;importandroid.widget.Toast;publicclassToastUtil{publicstaticToastmToast;publicstaticvoidsh......
  • 【Azure 应用服务】应用服务连接 Azure MySQL 一直失败,报错 Create connection error
    问题描述AppService上部署的Java应用,连接 AzureDatabaseforMySQL失败。错误信息:Createconnectionerror,url:jdbc:mysql://.......................communicationslinkfailure. 问题解答应用的错误信息提示为:与MySQL数据库建立连接失败。所以需要考虑如下几种......
  • Android Studio学习日志一,直接跳转和密码正确跳转
    记录一下我跟着手把手教你用AndroidStudio写一个APP_UP主Superior-Leo进行app开发小项目UP主的笔记首先,在资源文件创建一个文件夹,用来放APP背景图片,按钮图片一、直接跳转第一步、声明控件第二步,找到控件第三步骤,实现跳转代码packagecom.example.appdemo;importa......
  • could not initialize proxy - no Session
    在<many-to-on>中这错误很常见,字面意义就是不能被初始化,因为session已经关闭了。简单理解就是因为,你使用了lazy=true,这样hibernate在从数据库中调数据的时候是不会把关联的对象查出来的,而是保存一个获取值得方法,在你使用getXXX()调用的时候,hiberante会利用这个保存的方法去从数据库......
  • Educational Codeforces Round 148 (Rated for Div. 2) A-D2
    EducationalCodeforcesRound148(RatedforDiv.2) A.NewPalindromemap<int,int>mp;voidsolve(){strings;mp.clear();cin>>s;for(inti=0;i<s.size()/2;i++){mp[s[i]]++;}puts(mp.size()>=2?"YES......
  • 什么是 SAP UI5 Application Index
    SAPUI5ApplicationIndex是一个集成在SAPFioriLaunchpad中的应用程序索引。它提供了一个集中式的位置,用于展示和访问已安装的SAPUI5应用程序。在SAPFioriLaunchpad的主页上,用户可以看到一个应用程序索引页面,其中包含了所有已经安装的SAPUI5应用程序。这个索引页面提供了......
  • minio 客户端使用
       直接用Aws  python (S3 SDK)importboto3defbackup_s3(filepath,s3_bucket,s3key,s3_access_key=None,s3_secret_key=None,endpoint_url=None):s3=Noneifs3_access_keyands3_secret_key:s3=boto3.client('s3',aws_access_k......
  • 使用 SAP Fiori Tools 提供的中间件导入本地下载的 SAP UI5 库文件来启动 SAP UI5 应
    本教程第100个步骤,笔者介绍了如何使用本地部署的SAPUI5库文件来运行SAPUI5应用的技巧:SAPUI5应用开发教程之一百-如何修改SAPUI5框架的源代码实现,以及使用本地部署的SAPUI5SDK我们简单回顾一下这种方法的实现步骤:从SAPUI5官网将我们想使用的SAPUI5SDK......