本記事で紹介するプログラムは以下の GitHub リポジトリで公開しています
本記事は連載形式でお届けしています。各回の内容は以下のリンクからご覧いただけます。
- 【第1回】【Node.js + React】PTZ カメラを Web ブラウザから操作!リアルタイム制御システムの開発
- 【第2回】PTZ カメラ制御システムを GCP へ!Raspberry Pi を中継して実現する遠隔操作方法の紹介
はじめに
今回は、社内で開発した「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 ストリームを以下の流れで表示します。
- Node.js サーバーが
FFmpegを起動 FFmpegが RTSP を MJPEG に変換- WebSocket サーバーに MJPEG データを送信
- フロントエンドが WebSocket 経由で受信
- 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 技術で解決し、シンプルで拡張性の高い仕組みを実現しています。