RTSP 로컬 스트리밍 및 웹출력

choiyongheon·2025년 3월 16일

회사 업무 중 RTSP 영상을 웹으로 출력해야해서 작성하는 글.

HLS, RTC 등이 있지만 인증 문제 등으로 인해 가장 구현이 쉬운 WebSocket으로 정했다!

참고 사항으로는, rtsp 주소가 미리 존재하면 좋지만, 해당 포스팅에서는 로컬에서 임의의 동영상을 돌리고 웹으로 출력한다.


흐름은 아래와 같다.

  1. mediamtx로 rtsp 서버를 만듦. (ex. rtsp 주소 = localhost:8554/stream)
  2. ffmpeg를 통해 로컬 영상을 mediamtx 서버로 전송
  3. mediamtx 서버를 node에서 참조해서 웹으로 출력

우선 mediamtx를 cmd를 통해 파일 경로에서 mediamtx.exe를 실행한다. 아래와 같이 나오면 성공.

그 다음은 ffmpeg를 통해 구축된 mediamtx 서버에 로컬 동영상 파일을 올린다.

ffmpeg -re -stream_loop -1 -i video.mp4 -c:v libx264 -preset ultrafast -tune zerolatency -c:a aac -f rtsp rtsp://localhost:8554/stream


frame이 증가한다면 성공한 것이다.


코드 작성

Node + Html로 구성했다.

const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const { spawn } = require("child_process");

const app = express();
const server = http.createServer(app);
const io = socketIo(server);
const PORT = 6148; // WebSocket 서버 포트

// 사용할 RTSP 주소 설정
const RTSP_URL = "rtsp://localhost:8554/stream";

app.use(express.static(__dirname));

io.on("connection", (socket) => {
  console.log("WebSocket 클라이언트 연결됨");

  // FFmpeg 실행 (RTSP에서 영상 받아오기)
  const ffmpeg = spawn("ffmpeg", [
    "-rtsp_transport",
    "tcp", // RTSP over TCP 사용
    "-i",
    RTSP_URL, // RTSP 주소
    "-vf",
    "fps=15,scale=640:360", // 프레임 속도 및 크기 조정
    "-f",
    "image2pipe", // 이미지 스트림 형식
    "-vcodec",
    "mjpeg", // JPEG 변환
    "-q:v",
    "5", // 품질 설정
    "pipe:1",
  ]);

  // FFmpeg의 표준 출력을 WebSocket을 통해 전달
  ffmpeg.stdout.on("data", (data) => {
    socket.emit("data", Buffer.from(data).toString("base64")); // Base64 변환 후 전송
  });

  // FFmpeg 에러 로그 출력
  ffmpeg.stderr.on("data", (data) => {
    console.error("FFmpeg 오류:", data.toString());
  });

  // 클라이언트가 연결 종료 시 FFmpeg 프로세스 종료
  socket.on("disconnect", () => {
    console.log("WebSocket 클라이언트 연결 종료");
    ffmpeg.kill("SIGINT");
  });
});

// WebSocket 서버 실행
server.listen(PORT, () => {
  console.log(`WebSocket 서버 실행 중: http://localhost:${PORT}`);
  console.log(`RTSP 주소: ${RTSP_URL}`);
});

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Web RTSP Player</title>
  </head>
  <body>
    <h1>Web RTSP Player (RTSP to WebSocket)</h1>
    <canvas id="canvas" width="640" height="360"></canvas>

    <!-- WebSocket을 통한 영상 스트리밍 -->
    <script src="/socket.io/socket.io.js"></script>
    <script>
      var canvas = document.getElementById("canvas");
      var ctx = canvas.getContext("2d");
      var socket = io("http://localhost:6148");

      socket.on("data", function (data) {
        var image = new Image();
        image.src = "data:image/jpeg;base64," + data;
        image.onload = function () {
          ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
        };
      });

      socket.on("connect", function () {
        console.log("WebSocket 연결 성공");
      });

      socket.on("disconnect", function () {
        console.log("WebSocket 연결 종료");
      });
    </script>
  </body>
</html>

결과

임의로 설정한 영상이 잘 나온다!

<mediamtx 깃허브>
https://github.com/bluenviron/mediamtx/releases

profile
주니어 백엔드 개발자

0개의 댓글