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

Posted muamaker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4相关的知识,希望对你有一定的参考价值。

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

以前看视频的时候,直接找到 video标签,查看视频地址,然后下载下来。。

后来发现,好多 video 标签打开元素审查,如下:

技术图片

 

blob开始的东西,下载不了啦。。。

 

其实我们打开 network 还是能看见,加载了一堆的 .ts 文件。其实.ts文件就是被切成一段一段的视频。 理论上,把这些文件都下载下来,再合并,就完成了,,,

理论一句话,代码上千行...

 

一、问题

1、ts文件到底有多少和,地址从哪来。。。

    答案: ts 相关的信息,都存在一个叫 m3u8 的文件。 如果仔细点观察 network 是可以找到这个文件的请求的。该文件内容大致如下:

  技术图片

 

  这个文件,很显然,存了每个 ts 的文件名称,当然也有存完整的地址的。。只需要提取出里面的ts文件名称,再加上目标网站的域名,就可以下载了。。

  我这里是手动的把 m3u8 下载到了本地,当然也可以自己写脚本来下载m3u8文件

  解析代码如下:

  

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 的视频合成指令,我找到到了三类:

 

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

  

前两类,都是要文件名称拼接到 指令里面,,考虑到 cmd 指令的长度有限制,所以并未采用。

采用了如下文件输入办法:

ffmpeg -i input.txt -acodec copy -vcodec copy -absf aac_adtstoasc output.mp4  

 

其中 input.txt 是一个输入配置文件,内容为需要合并的文件名称,如下:

ffconcat version 1.0
file  0.ts
file  1.ts

  

二、正式开始

 新建 down.js 写入:

 

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

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,
	outputName
)

  

里面使用到了 fs-extra 模块,所以先安装

npm i fs-extra

  

 

最后执行:

node main.js

 

以上是关于利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4的主要内容,如果未能解决你的问题,请参考以下文章

m3u8文件格式讲解,Python解析m3u8文件,并获取在线地址

如何解析youku的m3u8文件,拿到mp4文件?

Android---视频模块需求-android M3U8格式视频解析

m3u8是啥格式,能在手机上播放吗?

关于m3u8格式的视频文件ts转mp4下载和key加密问题

如何把m3u8格式转换成mp4格式?