2020年04月29日

RaspberryPi4でyoutube liveに配信するスクリプト

Raspberry Pi 4を使ってRTSPで配信される動画をRTMPに変換してyoutube liveで配信するシェルスクリプトです。

Webカメラ

Webカメラには、IO-Dataの屋外WebカメラのTS-NA200Wを使用しています。
AC100Vが50Hzの地域では25fpsで1920x1080の動画を撮影する事が可能です。ビットレートはCBRで2Mbpsになります。これを無線LANで転送する事が可能です。

Raspberry Pi 4

Raspberry Pi 4にRaspbianをインストールして使用しています。インストールしたパッケージは一番ミニマルなパッケージになります。

pi@raspberrypi:~ $ uname -a
Linux raspberrypi 4.19.97-v7l+ #1294 SMP Thu Jan 30 13:21:14 GMT 2020 armv7l GNU/Linux

ffmpegの設定

ffmpegでTS-NA200WからRTSPでパケットを受け、ffmpegで現在時刻等の字幕を合成して、RTMPでyoutube liveに送信をします。
ffmpegにはハードウェアエンコーダが搭載されており、Raspbianでも使用することが可能です。ffmpegでハードウェアエンコーダを指定するにはエンコーダーにh264_omxを指定することで可能となります。
ハードウェアエンコーダを使用して変換をしましたが、CPU使用率は抑えることができましたが、fpsを稼ぐことができずリアルタイムエンコードが難しい状況でした。そのため、4コアあるCPUを活用する方針としてCPUエンコーダーであるlibx264を使用しました。

また、youtube liveの仕様で音声ストリームが無い動画は受け付けないようだったので、無音の音声を追加して配信をしています。

#!/bin/sh

#=====CONFIG=====
# youtubeで指定されたlivekeyを設定する
LIVEKEY="xxxx-xxxx-xxxx-xxxx"
# ライブ配信を開始した時刻を設定する
STREAMING_START_TIME=`date +%s -d '2020-4-21 19:38:0'`

#=====URL_SETTING=====
RTSP_URL="rtsp://userid:password@192.168.1.x:16272/ipcam_h264.sdp"
RTMP_URL="rtmp://a.rtmp.youtube.com/live2/${LIVEKEY}"

#=====MAIN=====
while true
do
  echo "==========Start[`date +%Y%m%d_%H%M%S`]=========="

  ELAPSED_TIME=$((`date +%s` - ${STREAMING_START_TIME}))
  TEXT="drawtext=fontfile=./ipagp.ttf: text='gaso / Current Time %{localtime\:%F %T} JST (UTC+9) / Elapsed Time %{pts\:hms\:$ELAPSED
_TIME}': fontcolor=white@0.7: fontsize=32: bordercolor=black: borderw=3: x=8: y=8'"

  #FFMPEG OPTION
  # -thread 0
  #  ffmpegのスレッド数を0(最適)に設定する
  # -re
  #  入力ストリームのフレームレート速度で読み込む
  #  (TS-NA220Wの出力フレームレートは25pfsに設定)
  # -rtsp_transport tcp
  #  RTSP transport protcolにTCPを使用する
  #  デフォルト値のUDPを使用するとパケットロスが発生しブロックノイズが発生する
  # -i $RTSP_URL
  #  入力ストリームの指定
  #  IDとpasswordはIPアドレスの前に指定する
  # -filter_complex "$TEXT"
  #  動画に表示する現在時刻や経過時間などを合成するためのフィルター
  #  filter_complexは複数入力ストリームを扱えるが今回はRTPSの入力ソース1つだけを使用
  # -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100
  #  仮想デバイスから無音の音声を生成する
  # -c:a aac
  #  音声はaacコーデックで変換する
  # -f flv
  #  出力フォーマットはyoutubeが指定するFLVとする
  # -loglevel info
  #  ログレベルを指定する
  #  動作状況を確認する時はinfo、本番稼働時はfatalとする
  # -b:v 5000k
  #  出力ビットレートを5Mbpsに指定する
  #  youtubeの推奨値は1920x1080で3500kbpsとされているがyoutube側で再変換する際にビットレートが低いと画質劣化が生じる
  # -c:v libx264
  #  エンコーダーをlibx264に指定する
  #  raspberry pi 4はハードウェアエンコーダh264_omxが使用できるが4coreのCPUで計算する方がパフォーマンスが良かった
  # -preset ultrafast
  #  圧縮率の指定を最も圧縮率の悪いultrafastに指定する
  #  帯域に余裕があるのであれば圧縮率を上げる必要はない
  #  ultrafast以外のsuperfast, veryfast等ではリアルタイム処理が間に合わない
  # -force_key_frames expr:gte\(t,n_forced*4\)
  #  キーフレームを4秒に1回入れるように指定する
  #  youtubeが2から4秒毎にキーフレームを入れるよう推奨している
  # $RTMP_URL
  #  出力ストリームを指定する
  ffmpeg -threads 0 -re -rtsp_transport tcp -i $RTSP_URL -filter_complex "$TEXT" -f lavfi -i anullsrc=channel_layout=stereo:sample_r
ate=44100 -c:a aac -f flv -loglevel info -b:v 5000k -c:v libx264 -preset ultrafast -force_key_frames expr:gte\(t,n_forced*4\) $RTMP_
URL

  #=====WAITING TIME=====
  echo "==========Finished[`date +%Y%m%d_%H%M%S`]=========="
  sleep 2
done

スクリプトの動作にあたっては、スクリプトのあるパスと同じ場所にフォントファイルが必要になります。このスクリプトではIPAフォントを使用しました。

パフォーマンス

ロードアベレージは4を超える事もあります。概ねCPU使用率は300%から350%程度でした。

pi@raspberrypi:~ $ more hoge
top - 19:01:47 up 15:30,  2 users,  load average: 4.08, 3.25, 1.71
Tasks: 107 total,   1 running, 106 sleeping,   0 stopped,   0 zombie
%Cpu(s): 28.1 us,  4.7 sy, 57.8 ni,  9.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   3728.0 total,   3339.5 free,    221.3 used,    167.2 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   3384.4 avail Mem

CPUを酷使するためCPU温度はかなり高温になります。4月の気温でもCPUにヒートシンクを付け小型のファンを付けた状態で温度は60度を越えました。

pi@raspberrypi:~ $ vcgencmd measure_temp
temp=61.0'C