【问题标题】:Sending & Saving MediaRecorder Data Producing Extremely Glitchy Results?发送和保存 MediaRecorder 数据会产生非常错误的结果?
【发布时间】:2021-02-19 09:04:43
【问题描述】:

我有一个脚本,可以在 MediaStream 运行时通过 Websockets 将 MediaRecorder 数据发送到后端。然后后端将这些数据保存到一个文件中以便回放。

我遇到了一个问题,结果像这样

视频非常有问题(有时它的输出有些流畅,但大多数时候它出现故障),我不知道为什么。

我已经在 Chrome(最新版本)和 Microsoft Edge 上对此进行了测试,并且都产生了相同的故障结果。我确实注意到 Firefox 似乎更流畅,但我在 Firefox 上做了有限的测试。

我的前端代码:

const socket = io('/')

document.querySelector("#startReccy").addEventListener('click', async () => {

    socket.emit('recID', ROOM_ID)


    let screenStream = await navigator.mediaDevices.getDisplayMedia({
        video: {
            cursor: "never"
        },
        audio: true
    })

    let vidId = document.querySelector("#myLiveVid")
    vidId.srcObject = screenStream;

    let videoMediaRecObj = new MediaRecorder(screenStream, {
        audioBitsPerSecond: 128000,
        videoBitsPerSecond: 2500000
      });

    //Send to server
    videoMediaRecObj.addEventListener('dataavailable', (e) => {
        //console.log(e.data)
        //socket.emit('writeInfoData', ROOM_ID, e.data)
        e.data.arrayBuffer().then ( buf => {
            socket.emit('writeInfoData', ROOM_ID, buf) 
        })
    })
    videoMediaRecObj.start(3000)

    //When we stop
    screenStream.addEventListener('ended', () => {
        videoMediaRecObj.stop();
        //screenStream.getTracks().forEach(track => track.stop());
      })

    

})

后端

const express = require('express')
const app = express()
server = require('http').Server(app)
const io = require('socket.io')(server)


var fs = require('fs');


const { v4: uuidV4 } = require('uuid')

app.set('view engine', 'ejs')
app.use(express.static("public"))

app.get("/", (req, res) => {
    res.redirect(`${uuidV4()}`)
})

app.get('/:room', (req, res) => {
    res.render('room', {roomId: req.params.room})
})

io.on('connection', socket => {
    socket.on('screen-rec', (roomId)=> {
      /* Seems to get room ID with no problem*/
        console.log(`${roomId}`)
        /* We join a room*/
        socket.join(roomId)

        socket.roomId = path.join(__dirname, 'media', roomId + '.webm')

        socket.emit('startRecording')
    })

    /* Write media file to disk*/
    socket.on('writeInfoData', (roomId, data) => {
        /* trying to read the data */
        //console.log(data) - This works

        fs.appendFile(`file-${roomId}.webm`, data, function (err) {
            if (err) {
                throw err;
            }
            console.log(`${Date().toLocaleString()} - ${roomId} - Saved!`);
          }); 
    })
})

server.listen(3000, () => {
    console.log("Listening")
})

我认为问题是因为它们可能被乱序接收,我想我可以通过发出连续的 POST 请求来解决这个问题,但我知道 Websockets 在 TCP 上运行,所以数据包必须按顺序发送,我每次都发送它2 秒,所以它应该有时间在下一个请求到来之前发送数据并保存到磁盘(虽然不确定,只是我的猜测)

我的实现有问题吗?

编辑:由 O. Jones 解决。我认为有一个更大的时间更好,但似乎我需要一个非常小的时间。非常感谢!

【问题讨论】:

  • 您正在丢失非关键帧。如果使用 appendFileSync 代替 appendFile 会发生什么?
  • 而且,您在 .start() 操作中的数据包之间有 3 秒的间隔。这些数据包将非常大。尝试将其设置为 20 毫秒。
  • 由@O.Jones 解决!非常感谢!

标签: node.js google-chrome websocket socket.io getusermedia


【解决方案1】:

每次MediaRecorder 调用您的ondataavailable 处理程序时,它都会在event.data 中为您提供一个Blob。该 Blob 包含所有累积的编码数据。在每秒 2.6 兆比特的组合数据速率下,其中三秒几乎是一兆字节。对于 POST 请求和 appendFile,这是一个非常大的负载。

减少拨打ondataavailble 的频率。使用.start(20) 而不是.start(3000)。您仍在移动大量数据,但以较小的块移动数据可以降低发生故障或丢失一些数据的可能性。

并且,考虑使用 nodejs 流来编写您的文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 2021-10-08
    • 2017-02-02
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多