post-cover

本記事で紹介するプログラムは以下の GitHub リポジトリで公開しています

GitHub - isec-promotion/ptz-controller-local

本記事は連載形式でお届けしています。各回の内容は以下のリンクからご覧いただけます。

はじめに

今回は、社内で開発した「ISAPI 対応 PTZ カメラ制御システム」の概要を紹介します。

本記事では、システム開発の背景、採用した技術、リアルタイム映像配信や PTZ 制御の仕組みについて、紹介します。

開発の背景

開発のきっかけはお客様の声でした。

「ISAPI 対応カメラは、ブラウザで管理画面を開いたり、専用アプリを使えば PTZ 操作やライブビューができるけど、必要なのはそれらの専用画面ではなく、自社製品のダッシュボードに組み込んで、ライブビューの確認と PTZ 操作をしたい。」

そこで、Web ブラウザ上でライブビューと PTZ 操作を完結でき、他の Web アプリに柔軟に組み込めるシステムを開発しました。

このシステムでできること

PC・スマホ・タブレットからブラウザだけで直感的に PTZ カメラを操作できます。主な機能は以下の通りです。

  • ライブ映像表示: RTSP ストリームを低遅延で表示
  • PTZ 制御: ボタンを押している間だけ移動、8方向対応
  • プリセット: よく使う画角を登録・ワンクリック復帰
  • レスポンシブ対応: 画面サイズに応じて UI 最適化
  • 接続状態表示: カメラとの通信状況をリアルタイム表示

システム構成

本システムは Node.js バックエンド(API・ストリーミング)と React フロントエンド(UI)で構成されています。

ptz-controller/
├── backend/          # Node.js + TypeScript APIサーバー
│   ├── index.ts      # PTZ制御API(Hono)
│   ├── stream-server.ts  # RTSPストリーミングサーバー
│   └── package.json
├── frontend/         # React + TypeScript Webアプリ
│   ├── src/
│   │   ├── App.tsx
│   │   └── components/
│   │       ├── PTZControls.tsx      # PTZ制御パネル
│   │       └── RTSPVideoPlayer.tsx  # 映像表示コンポーネント
│   └── package.json
└── .env              # 環境設定ファイル

技術選定の理由

【Backend】 Node.js, Hono, WebSocket, FFmpeg

  • Node.js + TypeScript: 非同期処理に強く、リアルタイム通信に最適
  • Hono: 軽量・高速な API フレームワーク
  • FFmpeg + WebSocket: RTSP を MJPEG に変換し、低遅延で配信
  • Digest 認証: ISAPI カメラの標準認証方式に対応

【Frontend】 React, Vite, Tailwind CSS, Canvas API

  • React + TypeScript: UI を効率的にコンポーネント化
  • Vite: 高速ビルドと快適な開発体験
  • Tailwind CSS: シンプルにレスポンシブ対応
  • Canvas API: MJPEG 映像を柔軟に描画

実装のハイライト

1. ライブ映像表示

RTSP ストリームを以下の流れで表示します。

  1. Node.js サーバーFFmpeg を起動
  2. FFmpeg が RTSP を MJPEG に変換
  3. WebSocket サーバーに MJPEG データを送信
  4. フロントエンドが WebSocket 経由で受信
  5. React コンポーネント (RTSPVideoPlayer.tsx) が Canvas に描画

→ ブラウザのみでクロスプラットフォームな映像表示を実現。

2. PTZ 制御

操作性のポイントは「押している間だけ動く」。
React 側でイベントを検知し、API にリクエストを送ります。

  • onMouseDown / onTouchStart: /api/ptz/move に移動指示を送信
  • onMouseUp / onTouchEnd: /api/ptz/stop で停止

バックエンド (Hono) が Digest 認証付きで ISAPI に転送し、カメラが動作します。

// 例: 右下にスピード50で移動
POST /api/ptz/move
{
  "direction": "downRight",
  "speed": 50
}

セットアップ方法

以下の手順でローカル環境に構築できます。

前提条件

  • Node.js 18 以上
  • FFmpeg インストール済み
  • ISAPI 対応 PTZ カメラ

1. リポジトリのクローン

git clone https://github.com/isec-promotion/ptz-controller-local.git
cd ptz-controller-local

2. 環境設定 プロジェクトのルートに .env ファイルをコピーして作成し、ご自身のカメラ情報や環境に合わせて内容を編集します。

# カメラ設定
CAMERA_IP=192.168.1.100
CAMERA_USERNAME=admin
CAMERA_PASSWORD=your_password

# サーバー設定
BACKEND_PORT=3001
STREAM_WS_PORT=8080
CORS_ORIGIN=http://localhost:5173

# ISAPI設定 (カメラの仕様に合わせて変更)
ISAPI_BASE_PATH=/ISAPI
MJPEG_STREAM_PATH=/Streaming/channels/101/httppreview

3. 依存関係のインストール

# Backend
cd backend
npm install

# Frontend
cd ../frontend
npm install

4. 開発サーバーの起動 2 つのターミナルを開いて、それぞれ以下のコマンドを実行します。

# ターミナル1: Backendサーバー (API & Stream)
cd backend
npm run dev:all

# ターミナル2: Frontendサーバー
cd frontend
npm run dev

→ ブラウザで http://localhost:5173 にアクセスすれば完了です。

まとめと今後の展望

本記事では、Node.js と React を使った Web ブラウザからの PTZ カメラ制御システムを紹介しました。
RTSP の扱いや ISAPI 連携といった課題を、モダンな Web 技術で解決し、シンプルで拡張性の高い仕組みを実現しています。

SNSでシェアしよう

この記事が役に立ったら、ぜひシェアしてください