読者です 読者をやめる 読者になる 読者になる

nginx-rtmp-module + FFmpeg + HLSで動画配信ができるdocker-composeをつくった

タイトルのdocker-composeをつくっていきます。ローカルで配信確認したいときにシュッと起動できるようにします。
次のような構成でつくりました。

コンテナ構成

f:id:n_soushi:20170217102235p:plain

それぞれのコンテナについてまとめます。

RTMP server

  • nginx-rtmp-moduleをつかってRTMP serverをたてる。

github.com

  • RTMP serverは`rtmp context`でストリームを受け取るapplicationを追加(`application encoder`)。
  • `application encoder`はストリームを受け取るとFFmpegで動画を3つのビットレードにエンコードする。
  • `application encoder`でエンコードした動画をHLS変換する`application hls`へストリームする。
  • `application hls`は変換したm3u8、tsファイルを`/data/hls`に配置する。
  • `/data/hls`はホストで同期されていてStreaming serverからもm3u8、tsファイルを参照できるようにしている。
rtmp {
    server {
        listen 1935;

        application encoder {
            live on;

            exec ffmpeg -i rtmp://localhost:1935/$app/$name
                        -c:a aac -strict -2 -b:a 32k -c:v libx264 -x264opts bitrate=128:vbv-maxrate=128:vbv-bufsize=128 -rtbufsize 100M -bufsize 256k -preset veryfast -f flv rtmp://localhost:1935/hls/${name}_low
                        -c:a aac -strict -2 -b:a 64k -c:v libx264 -x264opts bitrate=256:vbv-maxrate=256:vbv-bufsize=256 -rtbufsize 100M -bufsize 512k -preset veryfast -f flv rtmp://localhost:1935/hls/${name}_mid
                        -c:a aac -strict -2 -b:a 128k -c:v libx264 -x264opts bitrate=512:vbv-maxrate=512:vbv-bufsize=512 -rtbufsize 100M -bufsize 1024k -preset veryfast -f flv rtmp://localhost:1935/hls/${name}_high;
        }

        application hls {
            live on;

            hls on;
            hls_path /data/hls;
            hls_nested on;
            hls_fragment 2s;

            hls_variant _low BANDWIDTH=160000;
            hls_variant _mid BANDWIDTH=320000;
            hls_variant _high  BANDWIDTH=640000;
        }
    }
}

Broadcast server

  • mp4ファイルをFFmpegを使いループ再生させRTMP serverへストリームしている。
  • Broadcast serverはコンテナの1つのためlocalhostではRTMP serverに接続できない。
  • 次のように環境変数を参照するようにしている。
ffmpeg -re -stream_loop -1 -i '/data/broadcast_source.mp4' -f flv "${RTMP_SERVER_URL}/${STREAM_NAME}"
  • docker-composeで環境変数 'RTMP_SERVER_URL'と'STREAM_NAME'を定義している。

Streaming server

  • NginxでHTTP serverをたてる。
  • typesに'm3u8'と'ts'を追加している。
  • rootを'/data'としてRTMP serverと同期しているm3u8とtsファイルにアクセスしている。
server {
        listen 80;

        location /hls {
            types {
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
            }
            root /data;
            add_header Cache-Control no-cache;
            add_header Access-Control-Allow-Origin *;
        }
    }
}

docker-compose

ホストとコンテナでファイルを同期しているのでdindを使いホストもコンテナ化しています。

ホスト側のdocker-compose

version: "3"

services:
  dind_streaming_host:
    container_name: streaming_host
    image: docker:1.13.0-dind
    privileged: true
    ports:
      - 5301:2375
      - 1935:1935
      - 80:80
      - 5000:5000
    volumes:
      - ./video/clouds_over_the_mountain_hd_stock_video.mp4.mp4:/var/container/data/broadcast_source.mp4

コンテナに必要なポートと`Broadcast server`から配信する動画をコンテナに同期しています。

コンテナ群のdocker-compose

version: "3"

services:
  rtmp:
    container_name: rtmp_server
    build: ./container/nginx_rtmp
    ports:
      - 1935:1935
    volumes:
      - /var/container/data:/data
      - /var/container/log/rtmp/nginx/:/var/log/nginx

  stream:
    container_name: stream_server
    build: ./container/nginx_stream
    ports:
      - 80:80
    volumes:
      - /var/container/data:/data
      - /var/container/log/stream/nginx/:/var/log/nginx

  broadcast:
    container_name: broadcast_server
    build: ./container/ffmpeg_broadcast
    depends_on:
      - rtmp
    environment:
      RTMP_SERVER_URL: "rtmp://rtmp:1935/encoder"
      STREAM_NAME: broadcast
    volumes:
      - /var/container/data/:/data

起動方法と動画配信方法

ホストとコンテナでファイルを同期しているのでdindを使いホストもコンテナ化しているので起動にはdindとdirenvが必要です。

docker-composeの起動方法

まずはホスト側の起動から。
もしdindのイメージがなければプルします。

docker pull docker:1.13.0-dind

ホスト側を起動します。

$ cd (path-to 'streaming-host-sample')
$ docker-compose up -d

続いてコンテナ群をまとめているdocker-composeを起動します。

$ cd (path-to 'streaming_host')
direnv: loading .envrc
direnv: export +DOCKER_HOST
$ docker-compose up -d

※ 'streaming_host'ディレクトではdirenvによってディレクトリでは環境変数`DOCKER_HOST`が先に起動したdockerのホストに切り替わっています。

これですべてのコンテナが起動できました。

動画の確認方法

コンテナが起動できたらsafariで`http://localhost/hls/broadcast.m3u8`にアクセスすると`Broadcast server`から配信している動画を再生できます。
今回はプレイヤーを用意せずsafariで直接m3u8を参照しています。

f:id:n_soushi:20170217113815p:plain

サンプルの動画はDISTILLからDLしました。

www.wedistill.io

ライブ配信方法

wirecastなどの配信ツールを使うことでライブ配信ができます。

www.telestream.net

出力先のRTMPサーバに'rtmp://localhost:1935/encoder'を指定します。
ストリームを'live'として配信した場合は`http://localhost/hls/live.m3u8`にアクセスするとライブ配信した動画を確認できます。

まとめ

ソースを公開しています

github.com