You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现RTSP视频流到React应用的传输?Node.js与React(均基于TypeScript)环境下的替代方案咨询

RTSP Streaming in React + TypeScript + Node.js: Alternatives to node-rtsp-stream + jsmpeg

Hey there, I totally get the frustration of trying to get RTSP streams working in a React + TypeScript setup—jsmpeg's compatibility hiccups can be a real pain. Let’s walk through some reliable alternatives that play nicely with your tech stack, complete with code snippets and TypeScript-friendly tips.

Option 1: Transcode RTSP to HLS with FFmpeg (Most Compatible)

Browsers don’t natively support RTSP, so transcoding to HLS (HTTP Live Streaming) is a tried-and-true approach. We’ll use Node.js to handle transcoding with fluent-ffmpeg, then serve the HLS segments to React where we can play them with hls.js.

Backend (Node.js + TypeScript)

First, install dependencies:

npm install fluent-ffmpeg @types/fluent-ffmpeg express

Here’s a basic server that transcodes an RTSP stream to HLS and serves the segments:

import express from 'express';
import ffmpeg from 'fluent-ffmpeg';
import path from 'path';

const app = express();
const PORT = 3001;

// Serve HLS segments from a static directory
app.use('/hls', express.static(path.join(__dirname, 'hls')));

// Start transcoding on server boot (or trigger via API)
const startTranscoding = () => {
  const rtspUrl = 'rtsp://your-camera-ip:554/stream';
  const outputPath = path.join(__dirname, 'hls', 'stream.m3u8');

  ffmpeg(rtspUrl)
    .addOptions([
      '-c:v libx264',
      '-c:a aac',
      '-hls_time 2',
      '-hls_list_size 5',
      '-hls_flags delete_segments',
      '-f hls'
    ])
    .output(outputPath)
    .on('start', () => console.log('Transcoding started'))
    .on('error', (err) => console.error('FFmpeg error:', err))
    .run();
};

startTranscoding();

app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));

Frontend (React + TypeScript)

Install hls.js and its types:

npm install hls.js @types/hls.js

Create a React component to play the HLS stream:

import React, { useEffect, useRef } from 'react';
import Hls from 'hls.js';

const RtspPlayer = () => {
  const videoRef = useRef<HTMLVideoElement>(null);

  useEffect(() => {
    if (!videoRef.current) return;

    const hls = new Hls();
    const streamUrl = 'http://localhost:3001/hls/stream.m3u8';

    if (Hls.isSupported()) {
      hls.loadSource(streamUrl);
      hls.attachMedia(videoRef.current);
      hls.on(Hls.Events.MANIFEST_PARSED, () => {
        videoRef.current?.play();
      });
    } else if (videoRef.current.canPlayType('application/vnd.apple.mpegurl')) {
      // Fallback for Safari which natively supports HLS
      videoRef.current.src = streamUrl;
      videoRef.current.play();
    }

    return () => hls.destroy();
  }, []);

  return <video ref={videoRef} width="100%" controls />;
};

export default RtspPlayer;

Pros: Wide browser support, easy to implement, full TypeScript type support.
Cons: Moderate latency (2-10 seconds) due to HLS segmenting.

Option 2: Low-Latency Streaming with WebRTC

If you need near-real-time latency (<1 second), WebRTC is the way to go. We’ll use Node.js as a WebRTC signaling server and gateway to pull the RTSP stream, then stream it directly to React.

Backend (Node.js + TypeScript)

We’ll use mediasoup (a robust WebRTC media server) to handle the RTSP-to-WebRTC conversion. Install dependencies:

npm install mediasoup @types/mediasoup express socket.io

Here’s a simplified example of setting up a mediasoup worker and pulling the RTSP stream:

import mediasoup from 'mediasoup';
import express from 'express';
import { Server } from 'socket.io';
import ffmpeg from 'fluent-ffmpeg';
import path from 'path';

const app = express();
const httpServer = app.listen(3001);
const io = new Server(httpServer);

let worker: mediasoup.Worker;

// Initialize mediasoup worker
const initWorker = async () => {
  worker = await mediasoup.createWorker({
    rtcMinPort: 40000,
    rtcMaxPort: 49999,
  });

  // Create a router for media streams
  const router = await worker.createRouter({
    mediaCodecs: [
      {
        kind: 'video',
        mimeType: 'video/H264',
        clockRate: 90000,
        parameters: {
          'packetization-mode': 1,
          'profile-level-id': '42e01f',
          'level-asymmetry-allowed': 1,
        },
      },
    ],
  });

  // Handle client connections
  io.on('connection', async (socket) => {
    // Send router RTP capabilities to client
    socket.emit('routerRtpCapabilities', router.rtpCapabilities);

    // Create a producer to ingest the RTSP stream
    const producer = await router.createProducer({
      kind: 'video',
      rtpParameters: {
        codecs: [router.rtpCapabilities.codecs.find(c => c.mimeType === 'video/H264')!],
        encodings: [{ rid: 'r0' }],
      },
    });

    // Use FFmpeg to push RTSP stream to the producer
    const rtspUrl = 'rtsp://your-camera-ip:554/stream';
    ffmpeg(rtspUrl)
      .addOptions([
        '-rtsp_transport tcp',
        '-c:v copy',
        '-f rtp',
        `-sdp_file ${path.join(__dirname, 'stream.sdp')}`
      ])
      .output(`rtp://localhost:${producer.rtpParameters.encodings[0].port}`)
      .run();

    // Forward producer events to client (simplified)
    socket.emit('producerId', producer.id);
  });
};

initWorker();

Frontend (React + TypeScript)

Use simple-peer (a lightweight WebRTC library with TypeScript support) to connect to the server:

npm install simple-peer @types/simple-peer socket.io-client

React component example:

import React, { useEffect, useRef } from 'react';
import SimplePeer from 'simple-peer';
import { io } from 'socket.io-client';

const WebRtcPlayer = () => {
  const videoRef = useRef<HTMLVideoElement>(null);
  const socket = io('http://localhost:3001');

  useEffect(() => {
    if (!videoRef.current) return;

    const peer = new SimplePeer({ initiator: false, trickle: false });

    socket.on('routerRtpCapabilities', (capabilities) => {
      // Send client's RTP capabilities to server
      socket.emit('join', { capabilities });
    });

    socket.on('offer', (offer) => {
      peer.signal(offer);
    });

    peer.on('signal', (signal) => {
      socket.emit('answer', signal);
    });

    peer.on('stream', (stream) => {
      videoRef.current!.srcObject = stream;
      videoRef.current!.play();
    });

    return () => {
      peer.destroy();
      socket.disconnect();
    };
  }, []);

  return <video ref={videoRef} width="100%" controls />;
};

export default WebRtcPlayer;

Pros: Ultra-low latency, ideal for real-time use cases.
Cons: Steeper learning curve, more complex server setup.

Option 3: Pure JavaScript FFmpeg (No System Dependencies)

If you want to avoid installing FFmpeg on your server, use @ffmpeg/ffmpeg (a WebAssembly port of FFmpeg) to transcode the RTSP stream directly in Node.js.

Backend (Node.js + TypeScript)

Install dependencies:

npm install @ffmpeg/ffmpeg @ffmpeg/core express ws

Example code to transcode RTSP to a WebM stream over WebSocket:

import express from 'express';
import { createServer } from 'http';
import { WebSocketServer } from 'ws';
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { fetchFile } from '@ffmpeg/util';

const app = express();
const httpServer = createServer(app);
const wss = new WebSocketServer({ server: httpServer });
const PORT = 3001;

wss.on('connection', async (ws) => {
  const ffmpeg = new FFmpeg();
  // Load WebAssembly FFmpeg core
  await ffmpeg.load({ coreURL: 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/ffmpeg-core.js' });

  const rtspUrl = 'rtsp://your-camera-ip:554/stream';
  await ffmpeg.writeFile('input.rtsp', await fetchFile(rtspUrl));

  // Stream output to WebSocket
  ffmpeg.on('progress', async () => {
    const data = await ffmpeg.readFile('output.webm');
    ws.send(data);
  });

  await ffmpeg.exec([
    '-i', 'input.rtsp',
    '-c:v', 'libvpx',
    '-c:a', 'libopus',
    '-f', 'webm',
    'output.webm'
  ]);
});

httpServer.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));

Frontend (React + TypeScript)

Create a WebSocket client to receive and play the stream:

import React, { useEffect, useRef } from 'react';

const WebSocketPlayer = () => {
  const videoRef = useRef<HTMLVideoElement>(null);
  const mediaSource = useRef<MediaSource | null>(null);
  const sourceBuffer = useRef<SourceBuffer | null>(null);

  useEffect(() => {
    if (!videoRef.current) return;

    mediaSource.current = new MediaSource();
    videoRef.current.src = URL.createObjectURL(mediaSource.current);

    mediaSource.current.addEventListener('sourceopen', () => {
      sourceBuffer.current = mediaSource.current!.addSourceBuffer('video/webm; codecs="vp9,opus"');
      const ws = new WebSocket('ws://localhost:3001');

      ws.onmessage = async (event) => {
        if (sourceBuffer.current && !sourceBuffer.current.updating) {
          const buffer = await event.data.arrayBuffer();
          sourceBuffer.current.appendBuffer(buffer);
        }
      };
    });

    return () => {
      mediaSource.current?.endOfStream();
      URL.revokeObjectURL(videoRef.current.src);
    };
  }, []);

  return <video ref={videoRef} width="100%" controls />;
};

export default WebSocketPlayer;

Pros: No system FFmpeg installation required, cross-platform.
Cons: Lower performance than native FFmpeg, not ideal for high-resolution streams.

Final Tips

  • Always check if your camera supports RTSP over TCP (add -rtsp_transport tcp to FFmpeg options if you get buffering issues).
  • For TypeScript, stick to libraries with official @types packages—most popular streaming tools have them.
  • Prioritize latency needs first: if real-time isn’t critical, HLS is the simplest and most reliable path.

内容的提问来源于stack exchange,提问作者redd_d0gg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 11:32:42