タイトルの通りです。Jetsonにはせっかくハードウェアエンコーダがあるのでそれを利用してみよう!という魂胆です。
(筆者の意図としてはROSを実行している際に,CPU側に負担をかけずにrvizの画面を録画したいだけです。しょうじき、Jetson AGX Orin Dev KitではCPUが12コアもあるため、録画にコアを割く余裕はありそうですが…)
環境
- Jetson AGX Orin 32GB Dev Kit
- JetPack 5.1.2 / L4T 35.4.1
以下、クリーンな環境で実行したわけではないので、要所要所でパッケージのインストールが必要かもしれません。
(筆者はこれを行う前にaptでffmpegやobsを入れたため、そのあたりの依存パッケージが必要なんじゃないかなーと思います)
ハードウェアエンコーダを使えるffmpegのビルド
aptでffmpegを入れてもJetsonのハードウェアエンコーダは利用できないため、カスタムビルドを行います。
(偉大な先人がいっぱいいるので、それに倣います!)
参考:
https://qiita.com/tetsu_koba/items/44a91bc04805b34e297f
https://qiita.com/kitazaki/items/02298356703418450dcc
jetson-ffmpegのビルド
上記の参考例ではjocover/jetson-ffmpegが利用されていますが、Issueを見ると以下のフォーク版を使うのが良いようです。
なので、こうなります。(途中までREADMEそのままです)
git clone https://github.com/Keylost/jetson-ffmpeg.git
cd jetson-ffmpeg
ここで、お好きなテキストエディタでCMakeLists.txt
を開き、以下の行をコメントアウトします。
(2023/11/23時点。今後リポジトリが更新されたら必要なくなるかも)
# これを
find_library(LIB_NVBUF nvbuf_utils PATHS /usr/lib/aarch64-linux-gnu/tegra)
# こう
# find_library(LIB_NVBUF nvbuf_utils PATHS /usr/lib/aarch64-linux-gnu/tegra)
READMEの続きを実行します。
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig
ここまでで、ffmpegでNVENC(nvmpi)を使うための準備ができました。
ffmpegのビルド
jetson-ffmpegのREADMEの後半部分です。デスクトップ収録(特に音声)のためにちょっと改変します。
まずはffmpegを持ってきてパッチを当てます。READMEでは3パターン書いてありますが、筆者は6.0にしてみました。
git clone git://source.ffmpeg.org/ffmpeg.git -b release/4.2 --depth=1
cd ffmpeg
wget -O ffmpeg_nvmpi.patch https://github.com/Keylost/jetson-ffmpeg/raw/master/ffmpeg_patches/ffmpeg4.2_nvmpi.patch
git clone git://source.ffmpeg.org/ffmpeg.git -b release/4.4 --depth=1
cd ffmpeg
wget -O ffmpeg_nvmpi.patch https://github.com/Keylost/jetson-ffmpeg/raw/master/ffmpeg_patches/ffmpeg4.4_nvmpi.patch
git clone git://source.ffmpeg.org/ffmpeg.git -b release/6.0 --depth=1
cd ffmpeg
wget -O ffmpeg_nvmpi.patch https://github.com/Keylost/jetson-ffmpeg/raw/master/ffmpeg_patches/ffmpeg6.0_nvmpi.patch
パッチを当てたら、configureしてmakeします。ここで、デスクトップで流れている音声をキャプチャしたいかどうかで分岐します。
とにかくデスクトップ画面を録画したいからNVENCだけ有効ならいいよという場合↓
(単純にビデオエンコードやwebカム映像を保存するだけの場合もこっちですかね?)
git apply ffmpeg_nvmpi.patch
./configure --enable-nvmpi
make
デスクトップ音声もキャプチャする場合↓
git apply ffmpeg_nvmpi.patch
sudo apt install -y libpulse-dev # 筆者の環境では必要でした
./configure --enable-nvmpi --enable-libpulse
make
また、その他諸々のオプションがあるため、必要に応じて https://github.com/FFmpeg/FFmpeg/blob/master/configure を参考に設定してください。
ちなみに、以下で行う画面収録ではx11grab
が有効になっていないとダメなようです。上記の例ではアリでビルドされているみたいです。
ここまで終えたら、必要に応じてPATHを通しておきます。
いざ録画
ここでも、デスクトップ画面だけで良いのか、デスクトップ音声も収録したいのかで話が変わってきます。
とりあえずデスクトップ画面をキャプチャ
オプションはよしなに弄ってください。
ffmpeg -y \
-video_size 1920x1080 -framerate 30 -f x11grab -i :0.0+0,0 \
-vf scale=1280:-2 -c:v h264_nvmpi -b:v 2500k \
-an \
-pix_fmt yuv420p \
$HOME/Videos/hoge.mkv
-
-video_size
: 取得する画像サイズ。デスクトップ全体ならそれに合わせる(上記の例では1920x1080)。 -
-framerate
: フレームレート。30とか60とか。 -
-f x11grab
: スクリーン録画。 -
-i :0.0+0,0
: 画面:0.0
の左上0,0
から録画する。(ここで、:0.0+10,100
とか指定すると左上から10px横に、100px縦にずれた位置から-video_size
で指定したエリアを録画します。たぶん。) -
-vf scale=1280:-2
: 横が1280pxになるようにスケーリング。縦はアス比を可能な限り保つように切り捨てだか切り上げだかする。今回は1920x1080が1280x720にスケールされる。 -
-c:v h264_nvmpi
: コーデック指定。Jetsonのハードウェアエンコーダでh264エンコード。 -
-b:v 2500k
: ビデオビットレートを2500kbpsにする。クオリティ指定の方が良いかも? -
-an
: オーディオを含めない。 -
-pix_fmt yuv420p
: つけてると再生できるソフトが増えるらしい。 -
$HOME/Videos/hoge.mkv
: ホームディレクトリのVideosディレクトリに、hoge.mkvという名前で出力する。
音声付きでキャプチャ
上記の例とほとんど同じです。音声に関する部分が変わっています。
ffmpeg -y \
-video_size 1920x1080 -framerate 30 -f x11grab -i :0.0+0,0 \
-f pulse -ac 2 -i alsa_output.platform-3510000.hda.hdmi-stereo.monitor -c:a aac -ar 44100 \
-vf scale=1280:-2 -c:v h264_nvmpi -b:v 2500k \
-pix_fmt yuv420p \
$HOME/Videos/hoge.mkv
増えたオプションだけ:
-
-f pulse
: pulseaudioで収録 -
-ac 2
: オーディオチャネル数。2なのでステレオ. -
-i alsa_output.platform-3510000.hda.hdmi-stereo.monitor
: 使うデバイス(※) -
-c:a aac
: オーディオコーデック。この場合はaacを使う。 -
-ar 44100
: オーディオサンプルレート。44100か48000を指定しておけばいいと思う。
※: これを確認するためにはpactl list short sources
を実行します。↓のような感じで出てくるので、今使っているものを選択してください。HDMIオーディオを使っているなら、hdmi-stereo.monitor
と入っているやつでいいと思います。
$ pactl list short sources
0 alsa_output.platform-sound.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
1 alsa_input.platform-sound.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
2 alsa_output.platform-3510000.hda.hdmi-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz IDLE
このあたりも参考:
http://underpop.online.fr/f/ffmpeg/help/x11grab.htm.gz
http://trac.ffmpeg.org/wiki/Capture/Desktop
ちなみに変な解像度のビデオを食わせるとnvmpiがエラーを出すので、1920とか3840とか食いやすそうな値を入れてあげてください。
また、ハードウェアエンコーダが働いているかどうかを見るには、以下のjtop
が便利だと思います。
テキトーにまとめたスクリプト
以下のスクリプトを実行すると,勝手にデスクトップ解像度を取得して録画してくれます。
スケーリングとオーディオ収録でそれぞれオプションをつけておきました。デフォルトでは1080pでオーディオ無しを収録しますが、./screen_record.sh --scale 720p --audio
とすると、720pでオーディオ付きで画面収録します。
# get screen resolution
RESOLUTION=`xdpyinfo | grep dimensions | sed -r 's/^[^0-9]*([0-9]+x[0-9]+).*$/\1/'`
# get current date and time, like 20231123-123456
CURRENT_DT=`date "+%Y%m%d-%H%M%S"`
# output file path
OUT_PATH=$HOME/Videos/record_$CURRENT_DT.mkv
# default output scaling and audio record option
SCALE="1080p" # scales are written below
AUDIO_OPT="-an"
# command line args treatment
while (( $# > 0 ))
do
case $1 in
# to check the input, run: pactl list short sources
# TODO: automatically decide input source
-a | --audio)
AUDIO_OPT="-f pulse -ac 2 -i alsa_output.platform-3510000.hda.hdmi-stereo.monitor -c:a aac -ar 44100"
;;
-s | --scale | --scale=*)
if [[ "$1" =~ ^--scale= ]]; then
SCALE=$(echo $1 | sed -e 's/^--scale=//')
elif [[ -z "$2" ]] || [[ "$2" =~ ^-+ ]]; then
echo "'option' requires an argument." 1>&2
exit 1
else
SCALE="$2"
shift
fi
;;
esac
shift
done
echo "AUDIO OPTOIN IS $AUDIO_OPT"
echo "OUTPUT SCALE SELECTION IS $SCALE"
# I did not check whether the resolutions below are OK
if [ $SCALE = "2160p" ]; then
SCALE="-2:2160"
elif [ $SCALE = "1440p" ]; then
SCALE="-2:1440"
elif [ $SCALE = "1080p" ]; then
SCALE="-2:1080"
elif [ $SCALE = "720p" ]; then
SCALE="-2:720"
elif [ $SCALE = "540p" ]; then
SCALE="-2:540"
elif [ $SCALE = "480p" ]; then
SCALE="-2:480"
fi
echo "SO THE SCALE OPTION OF ffmpeg will be $SCALE"
sleep 2 # wait for 2 secs
ffmpeg -y \
-video_size $RESOLUTION -framerate 30 -f x11grab -i $DISPLAY.0+0,0 \
$AUDIO_OPT -vf scale=$SCALE -c:v h264_nvmpi -b:v 2500k -pix_fmt yuv420p $OUT_PATH