├── .travis.yml ├── Dockerfile ├── entrypoint.sh └── readme.md /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | language: bash 4 | services: docker 5 | 6 | env: 7 | - DOCKER_IMAGE=nginx-rtmp-ffmpeg 8 | 9 | script: 10 | - docker build -t ${DOCKER_IMAGE} . 11 | 12 | after_script: 13 | - docker images 14 | - docker run -d -p 1935:1935 -t ${DOCKER_IMAGE} 15 | - docker ps -a 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile for a simple Nginx stream replicator 2 | FROM alpine:3.16 3 | 4 | ENV USER nginx 5 | RUN adduser -s /sbin/nologin -D -H ${USER} 6 | 7 | RUN \ 8 | apk update && \ 9 | apk upgrade && \ 10 | apk add \ 11 | nginx-mod-rtmp \ 12 | ffmpeg && \ 13 | rm -rf /var/cache/apk/* 14 | 15 | RUN ln -sf /dev/stdout /var/log/nginx/access.log && \ 16 | ln -sf /dev/stderr /var/log/nginx/error.log 17 | 18 | RUN chown nginx /etc/nginx/nginx.conf 19 | 20 | COPY entrypoint.sh / 21 | RUN chmod +x entrypoint.sh 22 | 23 | USER ${USER} 24 | EXPOSE 1935 25 | 26 | CMD ["./entrypoint.sh"] 27 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ -z ${BITRATE+x} ]; then BITRATE=2500; fi 5 | if [ -z ${BUFSIZE+x} ]; then BUFSIZE=$((($BITRATE + 3 + 1) / 3)); fi 6 | if [ -z ${RESOLUTION+x} ]; then RESOLUTION=1280x720; fi 7 | if [ -z ${PRESET+x} ]; then PRESET=veryfast; fi 8 | if [ -z ${PROFILE+x} ]; then PROFILE=high; fi 9 | if [ -z ${FRAMERATE+x} ]; then FRAMERATE=30; fi 10 | if [ -z ${BFRAMES+x} ]; then BFRAMES=3; fi 11 | if [ -z ${THREADS+x} ]; then THREADS=0; fi 12 | if [ -z ${SCALER+x} ]; then SCALER=lanczos; fi 13 | if [ -z ${RC_LOOKAHEAD+x} ]; then RC_LOOKAHEAD=$((($FRAMERATE + 3 - 1) / 3)); fi 14 | if [ -z ${INGEST+x} ]; then INGEST="rtmp://live-jfk.twitch.tv/app"; fi 15 | if [ "${INGEST_2}" ]; then INGEST_STATEMENT_2="push ${INGEST_2}/${STREAM_KEY_2};"; fi 16 | INGEST_STATEMENT="push ${INGEST}/${STREAM_KEY};" 17 | FRAMERATE_2X=$(($FRAMERATE * 2)) 18 | 19 | echo BITRATE=$BITRATE 20 | echo BUFSIZE=$BUFSIZE 21 | echo RESOLUTION=$RESOLUTION 22 | echo PRESET=$PRESET 23 | echo PROFILE=$PROFILE 24 | echo FRAMERATE=$FRAMERATE 25 | echo BFRAMES=$BFRAMES 26 | echo THREADS=$THREADS 27 | echo SCALER=$SCALER 28 | echo RC_LOOKAHEAD=$RC_LOOKAHEAD 29 | echo INGEST=$INGEST 30 | echo STREAM_KEY=$STREAM_KEY 31 | 32 | if [ -z ${FFMPEG_ARGS+x} ]; then FFMPEG_ARGS="-s ${RESOLUTION} -r ${FRAMERATE} -c:v libx264 -preset ${PRESET} -profile:v ${PROFILE} -g ${FRAMERATE_2X} -x264-params \"bitrate=${BITRATE}:vbv_maxrate=${BITRATE}:vbv_bufsize=${BUFSIZE}:threads=${THREADS}:bframes=${BFRAMES}:rc_lookahead=${RC_LOOKAHEAD}:keyint=${FRAMERATE_2X}:keyint_min=${FRAMERATE_2X}:nal_hrd=cbr:scenecut=0:rc=cbr:force_cfr=1\" -sws_flags ${SCALER} -pix_fmt yuv420p -c:a copy -f flv -strict normal"; fi 33 | 34 | cat >/etc/nginx/nginx.conf << EOF 35 | error_log logs/error.log debug; 36 | load_module /usr/lib/nginx/modules/ngx_rtmp_module.so; 37 | 38 | events { 39 | worker_connections 1024; 40 | } 41 | 42 | rtmp { 43 | server { 44 | listen 1935; 45 | chunk_size 4096; 46 | max_message 10M; 47 | 48 | application livein { 49 | live on; 50 | record off; 51 | exec ffmpeg -i "rtmp://127.0.0.1/livein/${STREAM_KEY}" ${FFMPEG_ARGS} "rtmp://127.0.0.1/liveout"; 52 | } 53 | 54 | application liveout { 55 | live on; 56 | record off; 57 | ${INGEST_STATEMENT} 58 | ${INGEST_STATEMENT_2} 59 | } 60 | } 61 | } 62 | EOF 63 | 64 | exec nginx -g "pid /tmp/nginx.pid; daemon off;" 65 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # nginx-rtmp-ffmpeg 2 | 3 | An nginx-rtmp container for encoding streams with ffmpeg, and pushing to other streaming servers, e.g. twitch.tv 4 | 5 | This is useful if you would like to offload the CPU cost of expensive video compression, 6 | allowing you to stream relatively uncompressed video at high bitrates on a fast, local network, 7 | and have a different PC encode and publish the stream to the remote server. 8 | 9 | ## required environment variables 10 | 11 | - `STREAM_KEY`: the stream key required by your streaming service, e.g. `live_x01234567890123456789x` 12 | 13 | ## optional environment variables 14 | 15 | - `BITRATE`: the bitrate, in Kbps, to output (ensure your internet upstream can handle this value), default `2500` 16 | - `BUFSIZE`: the bufsize, in Kbps, default `BITRATE / 3` 17 | - `RESOLUTION` the resolution to output, default `1280x720` 18 | - `PRESET` the [x264 preset](https://trac.ffmpeg.org/wiki/Encode/H.264#Preset) to encode with, default `veryfast` 19 | - `PROFILE` the x264 profile to use, default `high` 20 | - `FRAMERATE` the framerate to output, default `30` 21 | - `BFRAMES` the number of [B-Frames](https://en.wikipedia.org/wiki/Video_compression_picture_types) to use, default `3` 22 | - `THREADS` the number of CPU threads to use for encoding, default `0` for auto 23 | - `SCALER` the [x264 scaler](https://ffmpeg.org/ffmpeg-scaler.html) to use, default `lanczos` 24 | - `RC_LOOKAHEAD` the number of frames to lookahead for rate control, default `FRAMERATE / 3` 25 | - `INGEST` the streaming service ingest server, default `rtmp://live-jfk.twitch.tv/app` 26 | - `STREAM_KEY_2`: the stream key for a second streaming service 27 | - `INGEST_2` a second streaming service ingest server, default none 28 | 29 | The variables you set will be assembled into the following ffmpeg arguments: 30 | 31 | ``` 32 | -s ${RESOLUTION} -c:v libx264 -preset ${PRESET} -profile:v ${PROFILE} -r ${FRAMERATE} -g ${FRAMERATE_2X} \ 33 | -x264-params \"bitrate=${BITRATE}:vbv_maxrate=${BITRATE}:vbv_bufsize=${BUFSIZE}:threads=${THREADS}:bframes=${BFRAMES}:rc_lookahead=${RC_LOOKAHEAD}:keyint=${FRAMERATE_2X}:min-keyint=${FRAMERATE_2X}:nal_hrd=cbr:scenecut=0:rc=cbr:force-cfr=1\" -sws_flags ${SCALER} -pix_fmt yuv420p -c:a copy -f flv -strict normal 34 | ``` 35 | 36 | If you prefer to customize the ffmpeg arguments, you can instead set the `FFMPEG_ARGS` environment variable, in which case none of the other optional environment variables will be used. 37 | 38 | ## tips 39 | 40 | You can see a list of Twitch suggested settings and ingest endpoints at [stream.twitch.tv](https://stream.twitch.tv/), and you can validate your configuration is proper and stable at [inspector.twitch.tv](https://inspector.twitch.tv). 41 | 42 | When selecting your options, be aware that presets from `veryfast` and above noticeably lower picture quality. For more information about stream quality, read [https://streamquality.report](https://streamquality.report). 43 | 44 | ## standalone examples 45 | 46 | simplified: 47 | ``` 48 | docker run --rm -it -p 1935:1935 -e STREAM_KEY=live_x01234567890123456789x \ 49 | shamelesscookie/nginx-rtmp-ffmpeg:latest 50 | ``` 51 | 52 | customized: 53 | ``` 54 | docker run --rm -it -p 1935:1935 -e STREAM_KEY=live_x01234567890123456789x -e THREADS=0 \ 55 | -e BITRATE=2500 -e RESOLUTION=1280x720 -e PRESET=veryfast -e FRAMERATE=30 -e PROFILE=high \ 56 | -e BFRAMES=3 -e INGEST=rtmp://live-jfk.twitch.tv/app shamelesscookie/nginx-rtmp-ffmpeg:latest 57 | ``` 58 | 59 | ## docker-compose example 60 | 61 | ``` 62 | version: '2' 63 | services: 64 | nginx-rtmp-ffmpeg: 65 | container_name: nginx-rtmp-ffmpeg 66 | image: shamelesscookie/nginx-rtmp-ffmpeg:latest 67 | network_mode: host 68 | ports: 69 | - 1935 70 | restart: always 71 | environment: 72 | - STREAM_KEY=live_x01234567890123456789x 73 | - BITRATE=2500 74 | - BUFSIZE=833 75 | - RESOLUTION=1280x720 76 | - PRESET=veryfast 77 | - FRAMERATE=30 78 | - PROFILE=high 79 | - THREADS=0 80 | - BFRAMES=3 81 | - SCALER=area 82 | - RC_LOOKAHEAD=10 83 | - INGEST=rtmp://live-jfk.twitch.tv/app 84 | ``` 85 | 86 | ## source PC settings 87 | 88 | Configure your streaming software to output to `rtmp://:1935/livein` 89 | Make sure you include your stream key in your streaming software as well, e.g. for OBS: 90 | 91 | - File > Settings > Stream 92 | - Stream Type: `Custom Streaming Server` 93 | - URL: `rtmp://:1935/livein`, e.g. `rtmp://mydockerbox:1935/livein` 94 | - Stream key: `` 95 | 96 | Then use video settings that are very high in quality and low in overhead, e.g. for nVidia video cards: 97 | 98 | - File > Settings > Output > Streaming 99 | - Encoder: `NVENC H.264` 100 | - Rate Control: `CBR` 101 | - Bitrate: `50000` or `100000` or `150000` (depending on your local network) 102 | - Keyframe Interval: `2` 103 | - Preset: `High Quality` 104 | - Profile: `high` 105 | - B-Frames: `0` --------------------------------------------------------------------------------