利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4

利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4

利用 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

 

 

posted on   漫思  阅读(14)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有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 做的优秀软件

导航

< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5
点击右上角即可分享
微信分享提示