先上代码:

  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文件,获取新资源,可以通过这个特新来实现直播效果;

												

利用简单的IO操作实现M3U8文件之间的合并的更多相关文章

  1. uniapp中拿到base64转blob对象,或base64转bytes字节数组,io操作写入字节流文件bytes

    1. uniAPP中拿到附件的base64如何操作,如word文件 /*** 实现思路:* 通过native.js的io操作创建文件,拿到平台绝对路径* 再通过原生类进行base64解码,拿到字节流b ...

  2. Python中的文件IO操作(读写文件、追加文件)

    Python中文件的读写包含三个步骤:打开文件,读/写文件,关闭文件. 文件打开之后必须关闭,因为在磁盘上读写文件的功能是由操作系统提供的,文件作为对象,被打开后会占用操作系统的资源,而操作系统在同一 ...

  3. [python 学习] IO操作之读写文件

    一.读取全部文件: # -*- coding: utf-8 -*- f = open('qq_url.txt','r'); print f.read(); f.close(); 二.读取规定长度文件 ...

  4. python 利用三方的xlrd模块读取excel文件,处理合并单元格

      目的: python能使用xlrd模块实现对Excel数据的读取,且按照想要的输出形式.  总体思路: (1)要想实现对Excel数据的读取,需要用到第三方应用,直接应用. (2)实际操作时候和我 ...

  5. 【UNIX环境高级编程】文件 IO 操作 一 ( open | close | creat | lseek | write | read )

    博客地址 : http://blog.csdn.net/shulianghan/article/details/46980271 一. 文件打开关闭操作相关函数介绍 1. open 函数 (1) op ...

  6. C# IO操作(二)File类和Directory类的常用方法

    本篇主要介绍一些常用的IO操作,对文件和目录的操作:留给自己复习之用. 1.创建文件 string sPath1=Path.GetDirectoryName(Assembly.GetExecuting ...

  7. Linux系统编程:简单文件IO操作

    使用Linux的文件API,经常看见一个东西,叫做文件描述符. 什么是文件描述符? (1)文件描述符其实实质是一个数字,这个数字在一个进程中表示一个特定的含义,当我们open打开一个文件时,操作系统在 ...

  8. [.NET] 利用 async & await 进行异步 IO 操作

    利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html  序 上次,博主 ...

  9. 文件IO操作

    前言 本文介绍使用java进行简单的文件IO操作. 操作步骤 - 读文件 1. 定义一个Scanner对象 2. 调用该对象的input函数族进行文件读取 (参见下面代码) 3. 关闭输入流 说明:其 ...

  10. 树莓派学习笔记——使用文件IO操作GPIO SysFs方式

    0 前言     本文描写叙述假设通过文件IO sysfs方式控制树莓派 GPIO端口.通过sysfs方式控制GPIO,先訪问/sys/class/gpio文件夹,向export文件写入GPIO编号, ...

随机推荐

  1. Linux部分文件管理类命令

    1.创建空文件和刷新时间 touch命令可以用来创建空文件或刷新文件的时间 touch [OPTION]... FILE... 选项: -a 仅改变atime和ctime -m 仅改变mtime和ct ...

  2. 美团面试:熟悉哪些JVM调优参数?

    本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...

  3. windows下使用docker安装hyperf

    https://blog.csdn.net/weixin_39398904/article/details/128469190 http://wiki.fengfengphp.com/zh-cn/ba ...

  4. TiDB SQL调优案例之避免TiFlash帮倒忙

    背景 早上收到某系统的告警tidb节点挂掉无法访问,情况十万火急.登录中控机查了一下display信息,4个TiDB.Prometheus.Grafana全挂了,某台机器hang死无法连接,经过快速重 ...

  5. react状态管理器(分模块)之redux和redux + react-redux + reducer和redux + react-redux + reducer分模块 + 异步操作redux-thunk

    1.回顾 cnpm i redux react-redux redux-thunk -S store/index.js src/index.js src/views/home/index.jsx + ...

  6. MINIO搭建单机以及集群

    MINIO简介 Minio是Apache License v2.0下发布的对象存储服务器.它与Amazon S3云存储服务兼容.它最适合存储非结构化数据,如照片,视频,日志文件,备份和容器/VM映像. ...

  7. 四月九号java知识

    1.do{}while();和while(){}结构最主要区别就是前者后面要一个分号 2.System.out.print();与System.out.println();的区别后者输出换行, 前者不 ...

  8. sql 开窗函数排序遇到空值的处理办法

    sql sever默认null最小 升序排序 null值在最前面,若要放在后面,则: order by case when col is null then 1 else 0 end, col 降序排 ...

  9. LNMP搭建静态网页服务器

    chattr -i default/.user.ini LNMP搭建使用 1.安装screen,命令或者操作可以一直运行下去 yum install screen 2.获取及安装 LNMP wget ...

  10. 安装Zookeeper和Kafka集群

    安装Zookeeper和Kafka集群 本文介绍如何安装Zookeeper和Kafka集群.为了方便,介绍的是在一台服务器上的安装,实际应该安装在多台服务器上,但步骤是一样的. 安装Zookeeper ...