如何将传入的二进制块连接到视频(webm)文件节点js中?
Posted
技术标签:
【中文标题】如何将传入的二进制块连接到视频(webm)文件节点js中?【英文标题】:How to concat chunks of incoming binary into video (webm) file node js? 【发布时间】:2019-11-11 13:03:31 【问题描述】:我正在尝试将 base64 块上传到节点 js 服务器并将这些块保存到一个文件中
let chunks = [];
app.post('/api', (req, res) =>
let blob = req.body;
//converting chunks of base64 to buffer
chunks.push(Buffer.from(blob, 'base64'));
res.json(gotit:true)
);
app.post('/finish', (req, res) =>
let buf = Buffer.concat(chunks);
fs.writeFile('finalvideo.webm', buf, (err) =>
console.log('Ahh....', err)
);
console.log('SAVED')
res.json(save:true)
);
上面代码的问题是视频无法播放,我不知道为什么我真的做错了什么,我也尝试过可写流它也不起作用
更新 - 我
我没有发送 blob,而是实现了发送二进制文件,但即使我面临TypeError: First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.
之类的问题
client.js
postBlob = async blob =>
let arrayBuffer = await new Response(blob).arrayBuffer();
let binary = new Uint8Array(arrayBuffer)
console.log(binary) // logging typed Uint8Array
axios.post('/api',binary)
.then(res =>
console.log(res)
)
;
server.js
let chunks = [];
app.post('/api', (req, res) =>
let binary = req.body;
let chunkBuff = Buffer.from(binary) // This code throwing Error
chunks.push(chunkBuff);
console.log(chunkBuff)
res.json(gotit:true)
);
//Somehow combine those chunks into one file
app.post('/finish', (req, res) =>
console.log('Combinig the files',chunks.length);
let buf = Buffer.concat(chunks);
console.log(buf) //empty buff
fs.writeFile('save.webm', buf, (err) =>
console.log('Ahh....', err)
);
res.json(save:true)
);
更新 - II
我能够接收二进制块并附加到流中,但在最终视频中,只有第一个块正在播放,我不知道其他块发生了什么,视频结束了。
代码
const writeMyStream = fs.createWriteStream(__dirname+'/APPENDED.webm', flags:'a', encoding:null);
app.post('/api', (req, res) =>
let binary = req.body;
let chunkBuff = Buffer.from(new Uint8Array(binary));
writeMyStream.write(chunkBuff);
res.json(gotit:true)
);
更新 - III
我的客户代码 |注意:我已经尝试过其他方式来上传已注释掉的 blob
customRecordStream = stream =>
let recorder = new MediaStreamRecorder(stream);
recorder.mimeType = 'video/webm;codecs=vp9';
recorder.ondataavailable = this.postBlob
recorder.start(INT_REC)
;
postBlob = async blob =>
let arrayBuffer = await new Response(blob).arrayBuffer();
let binary = new Uint8Array(arrayBuffer)
axios.post('/api',binary)
.then(res =>
console.log(res)
)
// let binaryUi8 = new Uint8Array(arrayBuffer);
// let binArr = Array.from(binaryUi8);
// // console.log(new Uint8Array(arrayBuffer))
//
// console.log(blob);
// console.log(binArr)
// let formData = new FormData();
// formData.append('fname', 'test.webm')
// formData.append("file", blob);
//
// console.log(formData,'Checjk Me',blob)
// axios(
// method:'post',
// url:'/api',
// data:formData,
// config: headers: 'Content-Type': 'multipart/form-data'
// ).then(res =>
// console.log(res,'FROM SERBER')
//
// )
//
//
// .then(res =>
// console.log(res)
// )
// this.blobToDataURL(blob, (blobURL) =>
//
// axios.post('/api',blob:blobURL)
// .then(res =>
// console.log(res)
// )
// )
;
【问题讨论】:
为什么base-64编码这个?很有可能,您的编码/解码分段错误。只需发送二进制数据,效率会高得多! 发送二进制数据听起来不错,但我可以将这些二进制文件合并到一个视频文件中吗? 是的,最好的办法就是将流写入文件。但是如果你不能这样做,你也可以追加到一个文件,或者写一系列的缓冲区等等。 如果你发布一个例子会很棒 这有 6 个不同的部分。贴一个具体的例子。例如,发布一个问题,询问如何将二进制文件放入服务器,并显示您目前拥有的代码。然后,发布一个关于在 Node.js 中接收它的问题,并显示到目前为止的代码。 【参考方案1】:我可以通过在前端使用FileReader
api 转换为base64 编码来实现这一点。在后端,从发送的数据块中创建一个新的Buffer
,并将其写入文件流。我的代码示例中的一些关键内容:
-
我正在使用
fetch
,因为我不想加入axios
。
使用fetch
时,必须确保在后端使用bodyParser
我不确定您在块中收集了多少数据(即传递给MediaRecorder
对象上的start
方法的持续时间值),但您需要确保您的后端可以处理传入的数据块的大小。我将我的设置得很高50MB
,但这可能没有必要。
我从不明确关闭写入流...您可能会在您的/final
路由中执行此操作。否则,createWriteStream
默认为 AutoClose,因此node
进程将自动执行此操作。
下面的完整工作示例:
前端:
const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen, false);
let mediaRecorder;
let sourceBuffer;
function customRecordStream(stream)
// should actually check to see if the given mimeType is supported on the browser here.
let options = mimeType: 'video/webm;codecs=vp9' ;
recorder = new MediaRecorder(window.stream, options);
recorder.ondataavailable = postBlob
recorder.start(INT_REC)
;
function postBlob(event)
if (event.data && event.data.size > 0)
sendBlobAsBase64(event.data);
function handleSourceOpen(event)
sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"');
function sendBlobAsBase64(blob)
const reader = new FileReader();
reader.addEventListener('load', () =>
const dataUrl = reader.result;
const base64EncodedData = dataUrl.split(',')[1];
console.log(base64EncodedData)
sendDataToBackend(base64EncodedData);
);
reader.readAsDataURL(blob);
;
function sendDataToBackend(base64EncodedData)
const body = JSON.stringify(
data: base64EncodedData
);
fetch('/api',
method: 'POST',
headers:
'Content-Type': 'application/json',
,
body
).then(res =>
return res.json()
).then(json => console.log(json));
;
后端:
const fs = require('fs');
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const server = require('http').createServer(app);
app.use(bodyParser.urlencoded( extended: true ));
app.use(bodyParser.json( limit: "50MB", type:'application/json'));
app.post('/api', (req, res) =>
try
const data = req.body;
const dataBuffer = new Buffer(data, 'base64');
const fileStream = fs.createWriteStream('finalvideo.webm', flags: 'a');
fileStream.write(dataBuffer);
console.log(dataBuffer);
return res.json(gotit: true);
catch (error)
console.log(error);
return res.json(gotit: false);
);
【讨论】:
感谢您的详细回答,但问题是我用来记录 blob 的库是问题MediaStreamRecorder
,我删除了它并用纯 javascript 构建它,它正在工作
太棒了!真高兴你做到了。下次,请务必包含您可能使用的任何库,以便您获得最全面的答案来解决您的问题。
我继续添加了使用 MediaRecorder 的其余客户端代码,以便其他人也可以从中受益。
@willascend,从主题来看,我假设对于单个视频,我们在特定的时间间隔将多个块文件传输到服务器,并在服务器端合并这些文件以制作组合视频文件。我能够在服务器端发送文件,但面临在服务器端的 java 应用程序中合并文件的问题。我查看了您的后端代码,并意识到我们只调用它一次。例如,我们正在录制 X 人的视频,所以我们假设获取块 C1、C2、C3 并将其推送到服务器上。
在服务器端,我们必须对这些 C1、C2、C3 进行俱乐部,并且必须准备 X 人的组合视频文件。如果您能在这个问题上指导我,那将很有帮助,因为您的服务器端代码不包含文件合并。在这里,我附上我的客户端和服务器端代码供您参考。 @nane gist.github.com/geekdiv/1d4e70ae08e8178c4ea2316a7dc5d392【参考方案2】:
灵感来自@willascend 答案:
后端:
app.use(express.raw());
app.post('/video-chunck', (req, res) =>
fs.createWriteStream('myvideo.webm', flags: 'a' ).write(req.body);
res.sendStatus(200);
);
前端:
mediaRecorder.ondataavailable = event =>
if (event.data && event.data.size > 0)
fetch(this.serverUrl + '/video-chunck',
method: 'POST',
headers: 'Content-Type': 'application/octet-stream',
body: event.data
);
;
我的 express 版本是 4.17.1
【讨论】:
【参考方案3】:我今天遇到了同样的问题 作为后端的解决方案,我使用了 fs.appendfile
fs.appendFile(Path, rawData, function (err)
if (err) throw err;
console.log('Chunck Saved!');
)
【讨论】:
以上是关于如何将传入的二进制块连接到视频(webm)文件节点js中?的主要内容,如果未能解决你的问题,请参考以下文章