JavaScript MediaSource && ffmpeg chunks

247 Views Asked by At

I have written the following code for a player that can receive chunks sent by ffmpeg through stdout and display them using mediaSource:

index.js (server of this request)

const express = require('express')
const app = express()
const port = 4545
const cp = require('child_process')
const cors = require('cors')
const { Readable } = require('stream');



app.use(cors())

app.get('/startRecording', (req, res) => {
    const ffmpeg = cp.spawn('ffmpeg', ['-f', 'dshow', '-i', 'video=HP Wide Vision HD Camera', '-profile:v', 'high', '-pix_fmt', 'yuvj420p', '-level:v', '4.1', '-preset', 'ultrafast', '-tune', 'zerolatency', '-vcodec', 'libx264', '-r', '10', '-b:v', '512k', '-s', '640x360', '-acodec', 'aac', '-ac', '2', '-ab', '32k', '-ar', '44100', '-f', 'mpegts', '-flush_packets', '0', '-' /*'udp://235.235.235.235:12345?pkt_size=1316'*/ ]);
   
    ffmpeg.stdout.on('data', (data) => {
        //console.log(`stdout: ${data}`);
        res.write(data)
    });

    ffmpeg.stderr.on('data', (data) => {
      const byteData = Buffer.from(data, 'utf8');  // Replace with your actual byte data
      const byteStream = new Readable();
      byteStream.push(byteData);
      byteStream.push(null);
      const encoding = 'utf8';
      let text = '';
      byteStream.on('data', (chunk) => {
        text += chunk.toString(encoding);
      });

      byteStream.on('end', () => {
        console.log(text);  // Output the converted text
      });


      //console.log({data})
        //res.write(data)
    });

    ffmpeg.on('close', (code) => {
        console.log(`child process exited with code ${code}`);
    });
})

app.listen(port, () => {
  console.log(`Video's Server listening on port ${port}`); 
});

App.js (In react, the side of the player):

import { useEffect } from 'react';

function App() {
  async function transcode() {
    const mediaSource = new MediaSource();
    const videoElement = document.getElementById('videoElement');
    videoElement.src = URL.createObjectURL(mediaSource);
  
    
    mediaSource.addEventListener('sourceopen', async () => {
      console.log('MediaSource open');
      const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42c01e"');
      try {
        const response = await fetch('http://localhost:4545/startRecording');
        const reader = response.body.getReader();
  
        reader.read().then(async function processText({ done, value }) {
          if (done) {
            console.log('Stream complete');
            return;
          }

          console.log("B4 append", videoElement)
          await sourceBuffer.appendBuffer(value);
          console.log("after append",value);
          // Display the contents of the sourceBuffer
          sourceBuffer.addEventListener('updateend', function(e) {         if (!sourceBuffer.updating && mediaSource.readyState === 'open') {           mediaSource.endOfStream();         }       });
  
          // Call next read and repeat the process
          return reader.read().then(processText);
        });
      } catch (error) {
        console.error(error);
      }
    });

    console.log("B4 play")
    await videoElement.play();
    console.log("after play")

  }
  
  
  useEffect(() => {}, []);

  return (
    <div className="App">
      <div>
        <video id="videoElement"></video>
      </div>
      <button onClick={transcode}>start streaming</button>
    </div>
  );
}

export default App;

this what i get: what i get

the chunks are being received and passed to the Uint8Array correctly, but the video is not being displayed. why can be the result of this and how to correct it?

0

There are 0 best solutions below