先上代码:

  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. 百炼成钢 —— 声网实时网络的自动运维丨Dev for Dev 专栏

    本文为「Dev for Dev 专栏」系列内容,作者为声网大数据算法工程师黄南薰. 01 自动运维介绍 2016 年,Gartner 创新性地提出了 AIOps 的概念[1],开创了人工智能辅助运维决 ...

  2. 详解低延时高音质:丢包、抖动与 last mile 优化那些事儿

    本篇是「详解低延时高音质系列」的第三篇技术分享.我们这次要将视角放大,从整个音频引擎链路的角度,来讲讲在时变的网络下,针对不同的应用场景,如何权衡音质和互动的实时性. 当我们在讨论实时互动场景下的低延 ...

  3. windows作业系统部署nfs服务

    文件共享的需求是如何产生的? 据说当年美国和苏联冷战期间,双方都有摧毁对方的能力.而苏联 不怕死的性格让美国人多少有些害怕.美国当时害怕自己的军事指挥中心被苏联摧毁.于是,美国建立了阿帕网,并把自己的 ...

  4. Oracle 服务器概念梳理

    Oracle 公司是世界上最大的信息管理软件及服务提供商,因其复杂的关系数据库产品而闻名.Oracle 的关系数据库是世界上第一个支持 SQL 语言的数据库.支持服务器/客户机等部署.Oracle 数 ...

  5. Go语言:利用 TDD 逐步为一个字典应用创建完整的 CRUD API

    前言 在数组这一章节中,我们学会了如何按顺序存储值.现在,我们再来看看如何通过键存储值,并快速查找它们. Maps 允许你以类似于字典的方式存储值.你可以将键视为单词,将值视为定义. 所以,难道还有比 ...

  6. PDD也可以通过ID获取商品详情?

    先我们可以通过pinduoduo.item_get的接口传入商品的ID参数,这个接口可以获取到拼多多商品的详情数据,包括商品的标题.价格.原价.卖家的昵称.库存.销量.宝贝的链接.商品的备注.宝贝图片 ...

  7. kubernetes核心实战(六)--- ConfigMap

    8.ConfigMap 抽取应用配置,并且可以自动更新 创建配置文件 [root@k8s-master-node1 ~/yaml/test]# vim configmap.yaml [root@k8s ...

  8. python入门教程之二十邮件操作

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式. python的smtplib提供了一 ...

  9. [中间件]Fastjson [转载]

    1 Fastjson的安全漏洞 本段摘自: fastjson到底做错了什么?为什么会被频繁爆出漏洞? 前段时间,fastjson被爆出过多次存在漏洞,很多文章报道了这件事儿,并且给出了升级建议. 但是 ...

  10. 人工智能AI库Spleeter免费人声和背景音乐分离实践(Python3.10)

    在视频剪辑工作中,假设我们拿到了一段电影或者电视剧素材,如果直接在剪辑的视频中播放可能会遭遇版权问题,大部分情况需要分离其中的人声和背景音乐,随后替换背景音乐进行二次创作,人工智能AI库Spleete ...