有时候上传接口可能会有限制,需要先划分成小文件再进行上传.
避免增大内存压力,应该采用流进行操作
const fs = require('fs');
const { Writable } = require('stream');
const maxPieceSize = 1024 * 1024 * 100;
const pieceExt = '.temp.mp4';
async function split(readStream){
let currPieceNumber = 0;
let currPieceSize = 0;
let currPiceWriteStream = fs.createWriteStream(`./split/${currPieceNumber}${pieceExt}`);
const countSizeWritable = new Writable({
write: (chunk, encoding, callback) => {
if(chunk.length+ currPieceSize >= maxPieceSize){
currPiceWriteStream.end()
currPieceNumber++
currPieceSize = 0
currPiceWriteStream = fs.createWriteStream(`./split/${currPieceNumber}${pieceExt}`);
}
currPieceSize += chunk.length
currPiceWriteStream.write(chunk)
callback()
},
});
readStream.pipe(countSizeWritable).on('unpipe', () => {
// 结束了
console.log(`文件停止推流,切片结束`);
});
}
// 需要切片的文件流
const inputFile = './data/test.mp4';
const originReadStream = fs.createReadStream(inputFile);
split(originReadStream);
当然你会发现虽然切均匀了,但是视频却无法播放
所以应该借用 ffmpeg 进行转换.
# 可以通过时间规范大小
ffmpeg -i 鱼钩的前端.mp4 -f segment -segment_time 1200 output%2d.mp4
转换结果如下,%2d依次转为 00 01 02...:
PS: 网上说可以 结合 ffprobe 与 -fs 进行以限定文件固定大小进行切分, 但是我没搞懂,望有识之士相助评论.
node 下可以用 fluent-ffmpeg
const ffmpeg = require('fluent-ffmpeg');
const fs = require('fs')
const fileStream = fs.createReadStream('./data/鱼钩的前端.mp4')
const filePath = './data/split/split'
ffmpeg()
.input(fileStream)
.outputOptions(['-c copy', '-f segment', '-segment_time 1200'])
.output(`${filePath}_piece_%02d.mp4`)
.on('start', () => {
console.log(`<<<<11-29 14:39:54>>>>⬇️\n✨`,`start`)
})
.on('error', (err) => {
console.log(`<<<<11-29 14:40:17>>>>⬇️\n✨`, `error`, err);
})
.on('end', () => {
onsole.log(`<<<<11-29 14:40:17>>>>⬇️\n✨`, `end`);
})
.run();
或者 MP4box 也可以轻松解决
# 默认kB
mp4box -splits 200000 test.mp4
# 等同 可以加单位
mp4box -splits 200m test.mp4
转换成响应的结果如下:
如果你想使用 node 进行操作,那么你可以安装 mp4box 后这样进行操作
const spawn= require('cross-spawn')
const result = spawn.sync('mp4box', ['-splits', '200000', './data/test.mp4'], {
stdio: 'inherit'
});
console.log('radiorz...结束划分 MP4 文件',result)
PS: 也可以用 google/zx, 或者 shelljs 执行 shell 命令.
PS: MP4box.js 没整明白,欲哭无泪.
参考
- ^using-ffmpeg-to-split-video-files-by-size stackoverflow.com/questions/3…
- ^mp4box 官方文档 github.com/gpac/gpac/w…
- ^google/zx github.com/google/zx
- ^github: shelljs github.com/shelljs/she…
- ^stackoverflow.com/questions/7…