如何将大块传入二进制文件合并到视频(WebM)文件节点JS中? [英] How to concat chunks of incoming binary into video (webm) file node js?

查看:279
本文介绍了如何将大块传入二进制文件合并到视频(WebM)文件节点JS中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将base64的块上载到节点js服务器,并将这些块保存到一个文件中

I am trying to upload chunks of base64 to node js server and save those chunks into one file

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})
});

上面的代码存在视频无法播放的问题,我不知道我为什么做错了并且我还尝试了可写流,它也不起作用

Problem with the above code is video is not playable I don't why Am I really doing something wrong and I've also tried writable streams it is not working either

更新-我

而不是发送Blob我已经实现了发送二进制文件的功能,但是即使我遇到类似 TypeError的问题:第一个参数必须是字符串,Buffer,ArrayBuffer,Array或类似数组的对象。

Instead of sending blobs I've implemented to send binary but even though I am facing a problem like TypeError: First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.

client.js

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

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

我能够接收二进制块并将其追加到流中,但是在最后的视频中,只有第一个块正在播放,我不知道其他块发生了什么,视频结束了。

I am able to receive the binary chunk and append to a stream but in the final video only first chunk is playing I don't know what happened to other chunks and the video ends.

代码

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

my client code | Note: I've tried other ways to upload blobs I've commented out

     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)
        //         })
        // })


    };


推荐答案

我能够通过转换为base64来使其工作使用 FileReader api在前端进行编码。在后端,从发送的数据块创建一个新的 Buffer 并将其写入文件流。我的代码示例中的一些关键事项:

I was able to get this working by converting to base64 encoding on the front-end with the FileReader api. On the backend, create a new Buffer from the data chunk sent and write it to a file stream. Some key things with my code sample:


  1. 我正在使用 fetch ,因为我不想插入 axios

  2. 使用 fetch 时,您必须确保在后端使用 bodyParser

  3. 我不确定您在块中收集了多少数据(即,将持续时间值传递给 MediaRecorder 对象上的 start 方法),但是您需要确保您的后端可以处理传入的数据块的大小。我将我的确实设置为 50MB 很高,但这可能不是必需的。

  4. 我从不明确地关闭写入流...您可以在 / final 路由中完成此操作。否则, createWriteStream 默认为自动关闭,因此 node 进程将自动执行此操作。

  1. I'm using fetch because I didn't want to pull in axios.
  2. When using fetch, you have to make sure you use bodyParser on the backend
  3. I'm not sure how much data you're collecting in your chunks (i.e. the duration value passed to the start method on the MediaRecorder object), but you'll want to make sure your backend can handle the size of the data chunk coming in. I set mine really high to 50MB, but this may not be necessary.
  4. I never close the write stream explicitly... you could potentially do this in your /final route. Otherwise, createWriteStream defaults to AutoClose, so the node process will do it automatically.

下面的完整示例:

前端:

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});
  }
});

这篇关于如何将大块传入二进制文件合并到视频(WebM)文件节点JS中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆