利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4
利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4
2019-09-26 10:40 muamaker 阅读(14利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4
以前看视频的时候,直接找到 video标签,查看视频地址,然后下载下来。。
后来发现,好多 video 标签打开元素审查,如下:
blob开始的东西,下载不了啦。。。
其实我们打开 network 还是能看见,加载了一堆的 .ts 文件。其实.ts文件就是被切成一段一段的视频。 理论上,把这些文件都下载下来,再合并,就完成了,,,
理论一句话,代码上千行...
一、问题
1、ts文件到底有多少和,地址从哪来。。。
答案: ts 相关的信息,都存在一个叫 m3u8 的文件。 如果仔细点观察 network 是可以找到这个文件的请求的。该文件内容大致如下:
这个文件,很显然,存了每个 ts 的文件名称,当然也有存完整的地址的。。只需要提取出里面的ts文件名称,再加上目标网站的域名,就可以下载了。。
我这里是手动的把 m3u8 下载到了本地,当然也可以自己写脚本来下载m3u8文件
解析代码如下:
1
2
3
4
5
6
|
const fs = require( "fs" ); var source = fs.readFileSync( "./test.m3u8" , "utf-8" ); //读取 m3u8 var arr = source.split( "\n" ); arr = arr.filter((item)=>{ return item.match(/\.ts$/); }); |
2、使用什么技术来合并这些 ts
这里我尝试了两种办法
第一种: 使用node js 直接读取文件流,合并到一个文件。。。最后结果,合并确实成功了,也能播放,但是有卡顿现象,应该是视频帧被破坏了。
第二种: 使用一款强大的工具, ffmpeg 来合并,成功了。具体 ffmpeg 安装看这里 :https://www.cnblogs.com/xswl/p/10042195.html
其中 ffmpeg 的视频合成指令,我找到到了三类:
1
|
ffmpeg -i "concat:1.ts|2.ts" -acodec copy out.mp3 |
1
|
ffmpeg -i "concat:1.ts|2.ts" -acodec copy -vcodec copy -absf aac_adtstoasc output.mp4 |
前两类,都是要文件名称拼接到 指令里面,,考虑到 cmd 指令的长度有限制,所以并未采用。
采用了如下文件输入办法:
1
|
ffmpeg -i input.txt -acodec copy -vcodec copy -absf aac_adtstoasc output.mp4 |
其中 input.txt 是一个输入配置文件,内容为需要合并的文件名称,如下:
1
2
3
|
ffconcat version 1.0 file 0.ts file 1.ts |
二、正式开始
新建 down.js 写入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
const request = require( "request" ); const fs = require( "fs" ); const path = require( "path" ); const child_process = require( 'child_process' ); const fsextra = require( 'fs-extra' ); module.exports = function (opt){ opt = opt || {}; var arr = opt.arr || []; //所有 ts的文件名或者地址 var host = opt.host || "" ; //下载 ts 的 域名,如果 arr 里面的元素已经包含,可以不传 var outputName = opt.name || `output${( new Date()).getTime()}.mp4`; //导出视频的名称 const tsFile = path.join(__dirname,`./source/${arr[0].split( "." )[0]}`,); createDir(tsFile); //递归创建文件 console.log( "本次资源临时文件:" ,tsFile); const resultDir = path.join(__dirname, "./result" ); createDir(resultDir); //递归创建文件 const resultFile = path.join(resultDir,outputName); var localPath = [] ; //下载到本地的路径 //开始下载ts文件 load(); function load(){ if (arr.length > 0){ var u = arr.shift(); var url = host + u; console.log( "progress---:" ,url); down(url); } else { //下载完成 console.log( "下载完成--开始生成配置" ); localPath.unshift( "ffconcat version 1.0" ); try { fs.writeFileSync(path.join(tsFile, "./input.txt" ), localPath.join( "\n" ) , undefined, 'utf-8' ) } catch (e){ console.log( "写入配置出错--" ,e); return ; } //开始依赖配置合成 console.log( "开始合成-----" ); child_process.exec(`cd ${tsFile} && ffmpeg -i input.txt -acodec copy -vcodec copy -absf aac_adtstoasc ${resultFile}`, function (error, stdout, stderr){ if (error){ console.error( "合成失败---" ,error); } else { console.log( "合成成功--" ,stdout); //删除临时文件 fsextra.remove(tsFile, err => { if (err) return console.error( "删除文件是失败" ,err) console.log( '删除文件成功!' ) }); } }); } } //下载 ts 文件 function down(url){ var p = url.split( "?" )[0]; var nm = path.parse(p); var nme = nm[ "name" ] + nm[ "ext" ]; rpath = path.join(tsFile,nme); localPath.push(`file ${nme}`); //缓存本地路径,用来合成 request({ url:url, headers:{ 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36' , 'X-Requested-With' : 'XMLHttpRequest' } }, function (err, response, body) { if (!err && response.statusCode == 200) { load(); } else { console.log( "错误" ,err) } }).pipe(fs.createWriteStream(rpath)); } //递归的创建文件夹 function mkdirs(dirpath) { if (!fs.existsSync(path.dirname(dirpath))) { mkdirs(path.dirname(dirpath)); } fs.mkdirSync(dirpath); } function createDir(myPath){ fs.existsSync(myPath) == false && mkdirs(myPath); } } //ffmpeg -i "concat:1.ts|2.ts" -acodec copy out.mp3 //ffmpeg -i "concat:1.ts|2.ts" -acodec copy -vcodec copy -absf aac_adtstoasc output.mp4 // ffmpeg -i input.txt -acodec copy -vcodec copy -absf aac_adtstoasc output.mp4 /* ffconcat version 1.0 file 0.ts file 1.ts */ /* //文件移动 function moveFile(oldPath,newPath){ try { fs.renameSync(oldPath, newPath); } catch (e) { console.log("报错后强制移动",e); fs.renameSync(oldPath, newPath); } } */ |
然后再新建 main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
const fs = require( "fs" ); const down = require( "./down" ); var host = 'https://xxxx/' ;目标网站 var outputName = "output.mp4" ; var source = fs.readFileSync( "./test.m3u8" , "utf-8" ); //读取 m3u8 var arr = source.split( "\n" ); arr = arr.filter((item)=>{ return item.match(/\.ts$/); }); down({ arr, host, name:outputName }) |
里面使用到了 fs-extra 模块,所以先安装
1
|
npm i fs-extra |
最后执行:
node main.js
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2023-03-03 Microsoft Visual Studio 2010 Service Pack 1官方下载版(ISO)
2023-03-03 Visual Studio2010保姆式安装教程(VS2010 旗舰版),以及如何运行第一个C语言程序,超详细
2023-03-03 最热的前端Web组态工具(可视化)
2023-03-03 10 个值得掌握的 reduce 技巧
2023-03-03 一个程序员的成功故事:从开源工具到 75 亿美元的软件帝国
2023-03-03 串口通信原理详解232、422、485,入门必看!
2023-03-03 QT 做的优秀软件