Ubuntu 20.04 に接続した Web カメラの映像を FFmpeg でキャプチャしながら HTTP Live Streaming (HLS) で HEVC/H.265 配信

NVIDIA GeForce のビデオカードを接続した Ubuntu 20.04 に Web カメラを接続し、その映像とマイクの音声を FFmpeg でキャプチャしながらリアルタイムに HTTP Live Streming (HLS) で配信できるようにしてみます。ビデオのフォーマットは HEVC/H.265 です。ビデオファイルのコンテナは fMP4 です。

私の環境

  • Ubuntu 20.04
  • NVIDIA GeForce GTX-1050
  • Logicool HD Webcam C910
  • FFmpeg 4.3.1

FFmpeg はソースコードからビルドしてインストールした FFmpeg 4.3.1 です。

Ubuntu と NVIDIA GeForce GTX-1050 と FFmpeg で HEVC/H.265 ハードウェアエンコードを行うための設定は下記の投稿で紹介しています。

Web カメラのオーディオデバイス番号の固定化

Ubuntu 20.04 に Web カメラを接続する場合、接続する度に Web カメラのマイクのオーディオデバイス番号が変更されることがあります。それを防ぐために、その番号を固定化します。

固定化の方法については、下記の投稿で紹介しています。

ここでは、Web カメラのマイクのオーディオデバイス番号を

  • card は 0
  • device は 0

としました。つまり、FFmpeg の i オプションで hw:0,0 あるいは default として設定することができます。

FFmpeg のコマンド

Web カメラのビデオデバイス名は /dev/video0 です。

下記のコマンドを実行すると、最終行の /path/to/ に M3U8 プレイリストファイルと fMP4 ファイルが作成されていきます。

/path/to/ のパスを Web サーバーで公開できるパスに設定しておけば、Web カメラのキャプチャを HLS の HEVC/H.265 に対応したクライアントで再生することができるでしょう。

ffmpeg \
  -f video4linux2 \
  -s 960x540 \
  -i /dev/video0 \
  -f alsa \
  -ac 2 \
  -i hw:0,0 \
  -acodec aac \
  -ab 128k \
  -ar 44100 \
  -s 960x540 \
  -vcodec hevc_nvenc \
  -tag:v hvc1 \
  -vf yadif \
  -g 10 \
  -b:v 1600k \
  -pix_fmt yuv420p \
  -threads 1 \
  -f hls \
  -hls_segment_type fmp4 \
  -hls_time 5 \
  -hls_fmp4_init_filename init.mp4 \
  /path/to/hls.m3u8

上記のコマンドを実行した際の FFmpeg のログは下記の通りです。ビデオが HEVC/H.265 (hevc (hevc_nvenc)) に変換されていることがわかります。また、変換速度も 1x であり、リアルタイムにエンコードできていることもわかります。さらに、fMP4 の m4s ファイルもシーケンス番号が増えながら作成されていることがわかります。

ffmpeg version 4.3.1 Copyright (c) 2000-2020 the FFmpeg developers
  built with gcc 9 (Ubuntu 9.3.0-10ubuntu2)
  configuration: --disable-shared --enable-static
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
[video4linux2,v4l2 @ 0x55b4329b4e00] The V4L2 driver changed the video from 960x540 to 960x544
Input #0, video4linux2,v4l2, from '/dev/video0':
  Duration: N/A, start: 486531.924850, bitrate: 167116 kb/s
    Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 960x544, 167116 kb/s, 20 fps, 20 tbr, 1000k tbn, 1000k tbc
Guessed Channel Layout for Input Stream #1.0 : stereo
Input #1, alsa, from 'hw:0,0':
  Duration: N/A, start: 1596876680.787106, bitrate: 1024 kb/s
    Stream #1:0: Audio: pcm_s16le, 32000 Hz, stereo, s16, 1024 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (rawvideo (native) -> hevc (hevc_nvenc))
  Stream #1:0 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
[alsa @ 0x55b4329b8dc0] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8)
[hls @ 0x55b4329dbc80] Opening '/tmp/init.mp4' for writing
Output #0, hls, to '/tmp/hls.m3u8':
  Metadata:
    encoder         : Lavf58.45.100
    Stream #0:0: Video: hevc (hevc_nvenc) (Main) (hvc1 / 0x31637668), yuv420p, 960x540, q=-1--1, 1600 kb/s, 20 fps, 10240 tbn, 20 tbc
    Metadata:
      encoder         : Lavc58.91.100 hevc_nvenc
    Side data:
      cpb: bitrate max/min/avg: 0/0/1600000 buffer size: 3200000 vbv_delay: N/A
    Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc58.91.100 aac
[video4linux2,v4l2 @ 0x55b4329b4e00] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8)
[hls @ 0x55b4329dbc80] Opening '/tmp/hls0.m4s' for writingte=N/A dup=15 drop=0 speed=0.996x    
[hls @ 0x55b4329dbc80] Opening '/tmp/hls.m3u8.tmp' for writing
[mp4 @ 0x55b4330e9540] Application provided duration: -5 / timestamp: 222223 is out of range for mov/mp4 format
[hls @ 0x55b4329dbc80] Opening '/tmp/hls1.m4s' for writingte=N/A dup=15 drop=0 speed=0.998x    
[hls @ 0x55b4329dbc80] Opening '/tmp/hls.m3u8.tmp' for writing
[hls @ 0x55b4329dbc80] Opening '/tmp/hls2.m4s' for writingte=N/A dup=15 drop=0 speed=0.999x    
[hls @ 0x55b4329dbc80] Opening '/tmp/hls.m3u8.tmp' for writing
[mp4 @ 0x55b4330e9540] Application provided duration: -3 / timestamp: 662555 is out of range for mov/mp4 format
[hls @ 0x55b4329dbc80] Opening '/tmp/hls3.m4s' for writingte=N/A dup=15 drop=0 speed=0.999x    
[hls @ 0x55b4329dbc80] Opening '/tmp/hls.m3u8.tmp' for writing
[mp4 @ 0x55b4330e9540] Application provided duration: -2 / timestamp: 883737 is out of range for mov/mp4 format
[hls @ 0x55b4329dbc80] Opening '/tmp/hls4.m4s' for writingte=N/A dup=15 drop=0 speed=   1x     
[hls @ 0x55b4329dbc80] Opening '/tmp/hls.m3u8.tmp' for writing
[hls @ 0x55b4329dbc80] Opening '/tmp/hls5.m4s' for writingte=N/A dup=15 drop=0 speed=0.999x    
[hls @ 0x55b4329dbc80] Opening '/tmp/hls.m3u8.tmp' for writing
frame=  658 fps= 20 q=25.0 size=N/A time=00:00:32.80 bitrate=N/A dup=15 drop=0 speed=0.999x 

なお、-r 30 のようにフレームレートを設定するオプションを付けると、私の環境では著しくエンコード速度が落ちてしまい、リアルタイム配信をすることができませんでした。

また、Web カメラのマイクのチャンネルがステレオではない場合、-ac 2 を -ac 1 に変更する必要があります。