📹 HLS録画・変換API 仕様書

配信サーバー経由で変換サーバーにアクセスする統合APIドキュメント

📋 概要

このAPIは、配信サーバー(hls-receiving.duckdns.org)を経由して変換サーバー(localhost:8080)のHLSストリーム録画・変換機能にアクセスするためのRESTful APIです。

主な機能

ℹ️ ポイント: クライアントは配信サーバーのAPIエンドポイントにアクセスするだけで、内部的に変換サーバーへのリクエスト転送とコールバック処理が自動的に行われます。

🔄 データフロー

クライアント
配信サーバー
(hls-receiving)
変換サーバー
(hls-conversion)


コールバック通知
  1. クライアントが配信サーバーのAPIエンドポイント(/api/record/、/api/audio/、/api/screenshot/)にPOSTリクエストを送信
  2. 配信サーバーがリクエストを変換サーバーの /api/request/ に転送
  3. 変換サーバーがジョブをMySQLデータベースに登録し、sequence_idを返却
  4. cronジョブが指定時刻にジョブを実行(ffmpegによる変換処理)
  5. 変換完了後、指定されたcallback_urlに結果を通知

🌐 基本情報

ベースURL

http://hls-receiving.duckdns.org/api/

認証

現在のバージョンでは認証は不要です。

リクエスト形式

レスポンス形式

📹 録画API

POST /api/record/

説明

指定されたHLSストリームを録画し、MP4ファイルとして保存します。

リクエストパラメータ

パラメータ 必須/任意 説明
stream_name string 必須 録画対象のストリーム名(例: "live1", "live2")
duration integer 必須 録画時間(秒単位)。例: 60 = 1分間録画
callback_url string 必須 録画完了時に結果を通知するコールバックURL
start_time string 任意 録画開始時刻(HH:MM形式、24時間表記)。省略時は現在時刻

リクエスト例

curl -X POST http://hls-receiving.duckdns.org/api/record/ \
  -H "Content-Type: application/json" \
  -d '{
    "stream_name": "live1",
    "duration": 60,
    "callback_url": "http://your-domain.com/callback",
    "start_time": "14:30"
  }'
fetch('http://hls-receiving.duckdns.org/api/record/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    stream_name: 'live1',
    duration: 60,
    callback_url: 'http://your-domain.com/callback',
    start_time: '14:30'
  })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
$url = 'http://hls-receiving.duckdns.org/api/record/';
$data = [
    'stream_name' => 'live1',
    'duration' => 60,
    'callback_url' => 'http://your-domain.com/callback',
    'start_time' => '14:30'
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode($data)
]);

$response = curl_exec($ch);
$result = json_decode($response, true);
curl_close($ch);

print_r($result);
import requests
import json

url = 'http://hls-receiving.duckdns.org/api/record/'
data = {
    'stream_name': 'live1',
    'duration': 60,
    'callback_url': 'http://your-domain.com/callback',
    'start_time': '14:30'
}

response = requests.post(url, json=data)
result = response.json()
print(result)

レスポンス例

{
  "status": "queued",
  "message": "Job scheduled for later execution",
  "sequence_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

コールバック通知

録画完了後、指定されたcallback_urlに以下のJSONデータがPOSTされます:

{
  "sequence_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "success",
  "file_url": "http://hls-receiving.duckdns.org/hls/live1/record_20251201_143000.mp4",
  "file_size": 15728640,
  "duration": 60,
  "message": "Recording completed successfully"
}

🎵 音声抽出API

POST /api/audio/

説明

指定されたHLSストリームから音声のみを抽出し、AAC/MP3ファイルとして保存します。

リクエストパラメータ

パラメータ 必須/任意 説明
stream_name string 必須 音声抽出対象のストリーム名
duration integer 必須 抽出時間(秒単位)
callback_url string 必須 処理完了時の通知先URL
format string 任意 出力形式。"aac"(デフォルト)または "mp3"
start_time string 任意 処理開始時刻(HH:MM形式)

リクエスト例

curl -X POST http://hls-receiving.duckdns.org/api/audio/ \
  -H "Content-Type: application/json" \
  -d '{
    "stream_name": "live1",
    "duration": 120,
    "callback_url": "http://your-domain.com/callback",
    "format": "mp3",
    "start_time": "15:00"
  }'
fetch('http://hls-receiving.duckdns.org/api/audio/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    stream_name: 'live1',
    duration: 120,
    callback_url: 'http://your-domain.com/callback',
    format: 'mp3',
    start_time: '15:00'
  })
})
.then(response => response.json())
.then(data => console.log(data));
$data = [
    'stream_name' => 'live1',
    'duration' => 120,
    'callback_url' => 'http://your-domain.com/callback',
    'format' => 'mp3',
    'start_time' => '15:00'
];

$ch = curl_init('http://hls-receiving.duckdns.org/api/audio/');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode($data)
]);

$response = curl_exec($ch);
print_r(json_decode($response, true));

レスポンス例

{
  "status": "queued",
  "message": "Job scheduled for later execution",
  "sequence_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}

📸 スクリーンショットAPI

POST /api/screenshot/

説明

指定されたHLSストリームから静止画をキャプチャし、JPEGファイルとして保存します。

リクエストパラメータ

パラメータ 必須/任意 説明
stream_name string 必須 キャプチャ対象のストリーム名
duration integer 必須 0を指定(スクリーンショットでは使用されません)
callback_url string 必須 処理完了時の通知先URL
start_time string 任意 キャプチャ実行時刻(HH:MM形式)
⚠️ 注意: スクリーンショットAPIではdurationパラメータは使用されませんが、APIの仕様上必須となっているため、0を指定してください。

リクエスト例

curl -X POST http://hls-receiving.duckdns.org/api/screenshot/ \
  -H "Content-Type: application/json" \
  -d '{
    "stream_name": "live1",
    "duration": 0,
    "callback_url": "http://your-domain.com/callback",
    "start_time": "16:00"
  }'

レスポンス例

{
  "status": "queued",
  "message": "Job scheduled for later execution",
  "sequence_id": "c3d4e5f6-a7b8-9012-cdef-123456789012"
}

コールバック通知例

{
  "sequence_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "status": "success",
  "file_url": "http://hls-receiving.duckdns.org/hls/live1/screenshot_20251201_160000.jpg",
  "file_size": 524288,
  "message": "Screenshot captured successfully"
}

📊 レスポンスステータス

HTTPステータスコード

コード 説明
200 OK リクエストが正常に受理され、ジョブがキューに登録されました
400 Bad Request リクエストパラメータが不正または不足しています
404 Not Found 指定されたエンドポイントが存在しません
405 Method Not Allowed POSTメソッド以外でアクセスされました
500 Internal Server Error サーバー内部エラーが発生しました

ジョブステータス

ステータス 説明
queued ジョブがキューに登録され、指定時刻の実行を待っています
processing ジョブが実行中です(変換処理中)
success ジョブが正常に完了しました
error ジョブ実行中にエラーが発生しました

❌ エラーレスポンス

必須パラメータ不足

{
  "status": "error",
  "message": "Missing required fields"
}

不正なJSON

{
  "status": "error",
  "message": "Invalid JSON body"
}

不正なcallback_url

{
  "status": "error",
  "message": "Invalid callback_url"
}

不正なstart_time形式

{
  "status": "error",
  "message": "Invalid start_time format"
}

不正なtype

{
  "status": "error",
  "message": "Invalid type"
}

不正なformat(音声抽出時)

{
  "status": "error",
  "message": "Invalid format"
}

📺 利用可能なストリーム

現在、以下のストリームが利用可能です:

stream_name 説明 HLS URL
live1 カメラ1のライブストリーム http://hls-receiving.duckdns.org/hls/live1.m3u8
live2 カメラ2のライブストリーム http://hls-receiving.duckdns.org/hls/live2.m3u8
ℹ️ ヒント: ストリームの追加や設定変更は、変換サーバーのstreams.jsonファイルで行います。

🔔 コールバック実装例

処理完了時に呼び出されるコールバックエンドポイントの実装例です。

PHP実装例

<?php
// callback.php

header('Content-Type: application/json');

// POSTデータを取得
$json = file_get_contents('php://input');
$data = json_decode($json, true);

// ログに記録
$logEntry = date('Y-m-d H:i:s') . " - " . json_encode($data) . PHP_EOL;
file_put_contents('callback.log', $logEntry, FILE_APPEND);

// データベースに結果を保存する例
if ($data['status'] === 'success') {
    // 成功時の処理
    $sequence_id = $data['sequence_id'];
    $file_url = $data['file_url'];
    $file_size = $data['file_size'];

    // データベース更新処理など
    // updateDatabase($sequence_id, $file_url, $file_size);

    echo json_encode(['received' => true]);
} else {
    // エラー時の処理
    $error_message = $data['message'];

    // エラー通知処理など
    // sendErrorNotification($error_message);

    echo json_encode(['received' => true, 'error' => $error_message]);
}
?>

Node.js (Express) 実装例

const express = require('express');
const app = express();

app.use(express.json());

app.post('/callback', (req, res) => {
    const data = req.body;

    console.log('Callback received:', data);

    if (data.status === 'success') {
        // 成功時の処理
        console.log(`File available at: ${data.file_url}`);
        console.log(`File size: ${data.file_size} bytes`);

        // データベース更新やメール通知などの処理

        res.json({ received: true });
    } else {
        // エラー時の処理
        console.error(`Error: ${data.message}`);

        res.json({ received: true, error: data.message });
    }
});

app.listen(3000, () => {
    console.log('Callback server running on port 3000');
});

🛠️ 実装ガイド

基本的な使い方の流れ

  1. APIリクエストの送信

    配信サーバーのAPIエンドポイントに必要なパラメータを含めてPOSTリクエストを送信します。

  2. sequence_idの取得

    レスポンスとして返却されるsequence_idを保存します。このIDでジョブを識別できます。

  3. コールバックの待機

    指定した時刻にジョブが実行され、完了後にコールバックURLに結果が通知されます。

  4. ファイルの取得

    コールバックで受け取ったfile_urlから生成されたファイルをダウンロードできます。

時刻指定のポイント

ファイルの保存場所

生成されたファイルは以下のパスに保存されます:

種類 ファイル名形式
録画 record_YYYYMMdd_HHmmss.mp4
音声 audio_YYYYMMdd_HHmmss.aac または .mp3
スクリーンショット screenshot_YYYYMMdd_HHmmss.jpg
✅ ベストプラクティス:
  • コールバックURLは必ずHTTPS化されたエンドポイントを使用してください
  • sequence_idをデータベースに保存し、コールバック受信時に照合してください
  • ファイルは定期的にクリーンアップする仕組みを実装してください
  • 大量のリクエストを送信する場合は、適切な間隔を設けてください

❓ よくある質問(FAQ)

Q1: 同時に複数のジョブを実行できますか?

A: はい、可能です。各ジョブは独立したプロセスとして実行されるため、複数のストリームや複数の時刻で同時にジョブを実行できます。

Q2: 最大録画時間に制限はありますか?

A: 技術的な制限はありませんが、サーバーのディスク容量やネットワーク帯域を考慮して適切な時間を設定してください。一般的には30分〜2時間程度を推奨します。

Q3: コールバックが届かない場合はどうすればよいですか?

A: 以下を確認してください:

Q4: ストリームが存在しない場合はどうなりますか?

A: ジョブは登録されますが、実行時にエラーとなり、コールバックにエラーステータスが通知されます。

Q5: 生成されたファイルはいつまで保存されますか?

A: 現在のバージョンでは自動削除機能はありません。必要に応じて手動でクリーンアップするか、独自の削除スクリプトを実装してください。

Q6: APIの利用に認証は必要ですか?

A: 現在のバージョンでは認証機能はありません。必要に応じてリバースプロキシやファイアウォールでアクセス制限を実装してください。

🔧 トラブルシューティング

問題: "Missing required fields" エラーが返される

原因: 必須パラメータが不足しているか、JSONの形式が正しくありません。

解決策:

問題: ジョブが実行されない

原因: cronジョブが動作していないか、start_timeが過去の時刻です。

解決策:

問題: ファイルが生成されない

原因: ストリームが利用できないか、ffmpegの変換処理でエラーが発生しています。

解決策:

📝 バージョン情報

バージョン リリース日 変更内容
1.0.0 2025-12-01 初回リリース - 録画、音声抽出、スクリーンショット機能の実装

📞 サポート情報

ログファイルの場所

システム構成