これまで、MediaMTXで映像配信、静止画配信の投稿をしてきました。
今回は、配信のために集めた映像を録画し後で見え返せるようにしてみます。
もろもろコードは以下にあります。
録画を有効化
mediamtx.ymlに以下を記載しておきます。
paths:
recording:
record: yes
recordPath: /recordings/%path/%Y%m%d%H%M%S_%f
recordFormat: fmp4
こうすることで、recordingというpathにWebRTCを送信すると録画をしてくれます。もちろん配信もこれまで通り可能です。
/recordingsというフォルダは、Dockerで以下のように設定しています。
services:
mediamtx:
volumes:
- /share/Documents/mediamtx/recordings:/recordings
ただし、このままだと、所有者がadminユーザの録画ファイルができてしまうため、QNAPサーバの一般ユーザの所有者で保存するようにします。
services:
mediamtx:
user: "1000:100"
user:groupの番号は、QNAPのユーザ・グループのIDを指定してください。
WebRTC入力映像のコーディックをH.264にする
入力映像は、WebRTCにしようと思いますが、デフォルトの動画のコーデックがVP8で、MediaMTXで録画可能なフォーマットではないです。
そこで、H.264でMediaMTXに入力する必要があります。
そのためには、WebRTCのネゴシエーション時に生成されるSDPにおいて、VP8よりH.264の優先度を上げる必要があります。そのために、ちょっと強引ですが、生成されたSDPを編集してからMediaMTXに渡すようにします。
function prioritizeH264(sdp) {
const h264pts = [...sdp.matchAll(/a=rtpmap:(\d+) H264\/90000/g)].map(m => m[1]);
if (h264pts.length === 0)
return sdp;
const firstH264 = h264pts[0];
return sdp.replace(/m=video .*\r\n/, (line) => {
const parts = line.trim().split(" ");
const header = parts.slice(0, 3).join(" "); // m=video 9 UDP/TLS/RTP/SAVPF
const pts = parts.slice(3);
const reordered = [firstH264, ...pts.filter(pt => pt !== firstH264)];
return `${header} ${reordered.join(" ")}\r\n`;
});
}
録画ファイルのリスト取得
録画ファイルを再生するには、以下のように有効にします。
playback: yes
playbackAddress: [QNAPサーバ]:9996
そうすると、次のように呼び出すと、録画ファイルの一覧(URLと開始時間と記録時間)が取得されます。
const recording_base_url = 'https://[QNAPサーバ]:29996';
const recording_base_url_old = 'http://[QNAPサーバ]:9996';
if( event.path == '/mediamtx-get-recording'){
var user = event.requestContext.basicAuth.basic[0];
var password = event.requestContext.basicAuth.basic[1];
var input = {
url: recording_base_url_old + "/list?path=recording",
method: "GET",
headers: {
Authorization: "Basic " + btoa(user + ":" + password)
}
};
var result = await HttpUtils.do_http(input);
console.log(result);
result = result.map(item => {
item.url_view = item.url.replace(recording_base_url_old, recording_base_url);
return item;
});
return new Response({ list: result });
}else
返ってきたURLが、Dockerに立ち上げているのでlocalhostになってしまっているので、変換しています。
クライアント側で、このURLをブラウザから開くとその動画が表示されます。
以上