├── .github
└── workflows
│ └── build_publish.yml
├── .gitlab-ci.yml
├── Dockerfile
├── Dockerfile.nvidia
├── README.md
├── docker-compose.yml
├── entrypoint.sh
├── nginx.conf
├── player.html
├── profiles
├── abr_transcoding_hd.sh
├── abr_transcoding_hd_1080p.sh
├── abr_transcoding_sd.sh
├── passthrough.sh
├── transcoding_hd.sh
└── transcoding_sd.sh
├── profiles_nvidia
├── .helpers.sh
├── abr_transcoding_hd.sh
├── abr_transcoding_hd_1080p.sh
├── abr_transcoding_sd.sh
├── passthrough.sh
├── transcoding_hd.sh
└── transcoding_sd.sh
└── supervisord.conf
/.github/workflows/build_publish.yml:
--------------------------------------------------------------------------------
1 | name: Build and publish image
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'master'
7 |
8 | env:
9 | REGISTRY: ghcr.io
10 |
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 | name: Build and publish image job
15 | permissions:
16 | contents: read
17 | packages: write
18 | steps:
19 | - name: Checkout master
20 | uses: actions/checkout@master
21 | - name: Build and publish image
22 | uses: ilteoood/docker_buildx@master
23 | with:
24 | tag: latest
25 | imageName: ${{ env.REGISTRY }}/${{ github.repository }}
26 | platform: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/arm/v7
27 | publish: true
28 | dockerServer: ${{ env.REGISTRY }}
29 | dockerUser: ${{ github.actor }}
30 | dockerPassword: ${{ secrets.GITHUB_TOKEN }}
31 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | default:
2 | image: docker:19.03.12
3 | services:
4 | - docker:19.03.12-dind
5 | before_script:
6 | - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
7 |
8 | stages:
9 | - build
10 |
11 | build:
12 | stage: build
13 | variables:
14 | IMAGE_TAG: $CI_REGISTRY_IMAGE:latest
15 | script:
16 | - docker build -t $IMAGE_TAG .
17 | - docker push $IMAGE_TAG
18 | only:
19 | - master
20 |
21 | build nivdia:
22 | stage: build
23 | variables:
24 | IMAGE_TAG: $CI_REGISTRY_IMAGE:nivdia
25 | script:
26 | - docker build --build-arg "BASE_IMAGE=${NVIDIA_FFMPEG_IMAGE}" -t $IMAGE_TAG -f Dockerfile.nvidia .
27 | - docker push $IMAGE_TAG
28 | only:
29 | - master
30 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu
2 |
3 | WORKDIR /usr/src
4 |
5 | RUN set -eux; apt-get update; \
6 | apt-get install -y --no-install-recommends ffmpeg nginx supervisor; \
7 | #
8 | # clean up
9 | rm -rf /var/lib/apt/lists/*;
10 |
11 | ARG USERNAME=user
12 | ARG USER_UID=1000
13 | ARG USER_GID=$USER_UID
14 |
15 | RUN mkdir -p /var/log/supervisor; \
16 | mkdir -p /var/www/html; \
17 | groupadd --gid $USER_GID $USERNAME; \
18 | useradd --uid $USER_UID --gid $USERNAME --shell /bin/bash --create-home $USERNAME; \
19 | chown $USERNAME /var/www/html;
20 |
21 | COPY supervisord.conf entrypoint.sh ./
22 | COPY profiles profiles
23 | COPY player.html /var/www/html/index.html
24 | COPY nginx.conf /etc/nginx/sites-enabled/default
25 |
26 | ENV USER=$USERNAME
27 |
28 | CMD ["./entrypoint.sh"]
29 |
--------------------------------------------------------------------------------
/Dockerfile.nvidia:
--------------------------------------------------------------------------------
1 | ARG BASE_IMAGE=willprice/nvidia-ffmpeg
2 | FROM $BASE_IMAGE as base
3 |
4 | WORKDIR /usr/src
5 |
6 | RUN set -eux; apt-get update; \
7 | apt-get install -y --no-install-recommends nginx supervisor; \
8 | #
9 | # clean up
10 | rm -rf /var/lib/apt/lists/*;
11 |
12 | ARG USERNAME=user
13 | ARG USER_UID=1000
14 | ARG USER_GID=$USER_UID
15 |
16 | RUN mkdir -p /var/log/supervisor; \
17 | mkdir -p /var/www/html; \
18 | groupadd --gid $USER_GID $USERNAME; \
19 | useradd --uid $USER_UID --gid $USERNAME --shell /bin/bash --create-home $USERNAME; \
20 | chown $USERNAME /var/www/html;
21 |
22 | COPY supervisord.conf entrypoint.sh ./
23 | COPY profiles_nvidia profiles
24 | COPY player.html /var/www/html/index.html
25 | COPY nginx.conf /etc/nginx/sites-enabled/default
26 |
27 | ENV USER=$USERNAME
28 |
29 | ENV NVIDIA_VISIBLE_DEVICES all
30 | ENV NVIDIA_DRIVER_CAPABILITIES compute,video,utility
31 |
32 | ENTRYPOINT ["./entrypoint.sh"]
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hls-restream
2 | Restream live content as HLS using ffmpeg in docker.
3 |
4 | # Usage
5 |
6 | You need to have docker & docker-compose installed.
7 |
8 | 1. Clone this repository:
9 | ```sh
10 | git clone https://github.com/m1k1o/hls-restream
11 | cd hls-restream
12 | ```
13 |
14 | 2. Modify `docker-compose.yml` and add your own sources:
15 | ```yml
16 | version: "3.4"
17 | services:
18 | hls:
19 | build: "./"
20 | container_name: "hls"
21 | restart: "always"
22 | tmpfs:
23 | - "/var/www/html:mode=777,size=128M,uid=1000,gid=1000"
24 | ports:
25 | - "80:80"
26 | environment:
27 | PROFILE: passthrough
28 | SOURCES: |
29 | # SD Channels:
30 | ch1 rtsp://192.168.1.5:554/ch1
31 | ch2 rtsp://192.168.1.5:554/ch2
32 | # HD Channels:
33 | ch1_hd http://192.168.1.6/stream/channelid/8967896?profile=pass
34 | ch2_hd http://192.168.1.6/stream/channelid/4969639?profile=pass
35 | ```
36 |
37 | Profiles can you find in `profiles/` folder.
38 | * passthrough - default, no transcoding.
39 |
40 | H264 adaptive bitrate transcoding:
41 | * abr_transcoding_sd - 360p and 480p
42 | * abr_transcoding_hd - 360p, 480p and 720p
43 | * abr_transcoding_hd_1080p - 360p, 480p, 720p and 1080p
44 |
45 | H264 transcoding:
46 | * transcoding_hd - 720p only
47 | * transcoding_sd - 480p only
48 |
49 | 3. Start docker compose (run this everytime you modify stream sources):
50 | ```sh
51 | docker-compose up -d --build
52 | ```
53 |
54 | 4. Watch streams:
55 | ```
56 | http://localhost/ch1.m3u8
57 | http://localhost/ch2.m3u8
58 | http://localhost/ch1_hd.m3u8
59 | http://localhost/ch2_hd.m3u8
60 | ```
61 |
62 | In case of error, troubleshoot:
63 |
64 | ```sh
65 | docker logs hls
66 | docker exec -it hls sh -c 'cd /var/log/supervisor && /bin/bash'
67 | ```
68 |
69 | # NVIDIA GPU hardware acceleration
70 |
71 | You will need to have [nvidia-docker](https://github.com/NVIDIA/nvidia-docker) installed.
72 |
73 | ```
74 | docker build -t hls_nvidia -f Dockerfile.nvidia .
75 | docker run -d --gpus=all \
76 | --name hls_nvidia \
77 | --tmpfs /var/www/html:mode=777,size=128M,uid=1000,gid=1000 \
78 | -p 80:80 \
79 | -e 'PROFILE=transcoding_sd' \
80 | -e 'SOURCES=
81 | # SD Channels:
82 | ch1 rtsp://192.168.1.5:554/ch1
83 | ch2 rtsp://192.168.1.5:554/ch2
84 | # HD Channels:
85 | ch1_hd http://192.168.1.6/stream/channelid/8967896?profile=pass
86 | ch2_hd http://192.168.1.6/stream/channelid/4969639?profile=pass
87 | ' \
88 | hls_nvidia
89 | ```
90 |
91 | ## Supported inputs
92 |
93 | Input codec will be automatically determined from given stream. Please check your graphic card's supported codec and maximum concurrent sessions [here](https://developer.nvidia.com/video-encode-decode-gpu-support-matrix).
94 |
95 | | Codec | CUVID | Codec Name |
96 | | ---------- | ----------- | ----------------------------------------- |
97 | | h264 | h264_cuvid | H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 |
98 | | hevc | hevc_cuvid | H.265 / HEVC |
99 | | mjpeg | mjpeg_cuvid | Motion JPEG |
100 | | mpeg1video | mpeg1_cuvid | MPEG-1 video |
101 | | mpeg2video | mpeg2_cuvid | MPEG-2 video |
102 | | mpeg4 | mpeg4_cuvid | MPEG-4 part 2 |
103 | | vc1 | vc1_cuvid | SMPTE VC-1 |
104 | | vp8 | vp8_cuvid | On2 VP8 |
105 | | vp9 | vp9_cuvid | Google VP9 |
106 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.4"
2 | services:
3 | hls:
4 | build: "./"
5 | container_name: "hls"
6 | restart: "always"
7 | tmpfs:
8 | - "/var/www/html:mode=777,size=128M,uid=1000,gid=1000"
9 | ports:
10 | - "80:80"
11 | environment:
12 | SOURCES: |
13 | ch1 rtsp://192.168.1.5:554/ch1
14 | ch2 rtsp://192.168.1.5:554/ch2
15 | ch1_hd http://192.168.1.6/stream/channelid/8967896?profile=pass
16 | ch2_hd http://192.168.1.6/stream/channelid/4969639?profile=pass
17 |
--------------------------------------------------------------------------------
/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function generate_entry {
4 | echo ''
5 | echo "[program:ffmpeg-$1]"
6 | echo "command=/usr/src/profiles/${PROFILE:=passthrough}.sh '$1' '$2'"
7 | echo 'autostart=true'
8 | echo 'autorestart=true'
9 | echo 'startretries=5'
10 | echo 'numprocs=1'
11 | echo 'startsecs=0'
12 | echo 'user=%(ENV_USER)s'
13 | echo 'process_name=%(program_name)s_%(process_num)02d'
14 | echo 'stderr_logfile=/var/log/supervisor/%(program_name)s_stderr.log'
15 | echo 'stderr_logfile_maxbytes=10MB'
16 | echo 'stdout_logfile=/var/log/supervisor/%(program_name)s_stdout.log'
17 | echo 'stdout_logfile_maxbytes=10MB'
18 | } >> /usr/src/supervisord.conf
19 |
20 | SAVEIFS=$IFS # Save current IFS
21 | IFS=$'\n' # Change IFS to new line
22 | SOURCES=($SOURCES) # split to array $SOURCES
23 | IFS=$SAVEIFS # Restore IFS
24 |
25 | for (( i=0; i<${#SOURCES[@]}; i++ ))
26 | do
27 | ROW=(${SOURCES[$i]})
28 | NAME=${ROW[0]}
29 | URL=${ROW[1]}
30 |
31 | if [[ ${NAME:0:1} == "#" ]]; then
32 | continue
33 | fi
34 |
35 | echo "[$i] name: ${NAME}"
36 | echo "[$i] url: ${URL}"
37 |
38 | generate_entry "${NAME}" "${URL}"
39 | done
40 |
41 | cat /usr/src/supervisord.conf
42 |
43 | #
44 | # start supervisor
45 | /usr/bin/supervisord -c /usr/src/supervisord.conf
46 |
47 |
--------------------------------------------------------------------------------
/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | root /var/www/html/;
4 | index index.html;
5 |
6 | location / {
7 | add_header 'Access-Control-Allow-Origin' '*';
8 | add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
9 | add_header 'Access-Control-Allow-Headers' 'Origin,Keep-Alive,Cache-Control,Content-Type,Accept,Range';
10 |
11 | if ($request_method = 'OPTIONS') {
12 | add_header 'Access-Control-Max-Age' 3600;
13 | add_header 'Content-Type' 'text/plain charset=UTF-8';
14 | add_header 'Content-Length' 0;
15 | return 204;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/player.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Player
6 |
7 |
8 |
9 |
10 | Player
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/profiles/abr_transcoding_hd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function generate_playlist {
4 | echo '#EXTM3U'
5 | echo '#EXT-X-VERSION:3'
6 | echo '#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360'
7 | echo "$1_360p.m3u8"
8 | echo '#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480'
9 | echo "$1_480p.m3u8"
10 | echo '#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720'
11 | echo "$1_720p.m3u8"
12 | } > "/var/www/html/$1.m3u8"
13 | generate_playlist "$1"
14 |
15 | ffmpeg -hide_banner \
16 | -i "$2" \
17 | -map 0:v:0 -map 0:a:0 \
18 | -vf scale=w=640:h=360:force_original_aspect_ratio=decrease \
19 | -c:a aac \
20 | -ar 48000 \
21 | -b:a 96k \
22 | -c:v h264 \
23 | -profile:v main \
24 | -b:v 800k \
25 | -maxrate 856k \
26 | -bufsize 1200k \
27 | -crf 20 \
28 | -sc_threshold 0 \
29 | -g 48 \
30 | -keyint_min 48 \
31 | -f hls \
32 | -hls_time 6 \
33 | -hls_list_size 4 \
34 | -hls_delete_threshold 1 \
35 | -hls_flags delete_segments \
36 | -hls_start_number_source datetime \
37 | -hls_segment_filename "/var/www/html/$1_360p_%03d.ts" \
38 | "/var/www/html/$1_360p.m3u8" \
39 | -map 0:v:0 -map 0:a:0 \
40 | -vf scale=w=842:h=480:force_original_aspect_ratio=decrease \
41 | -c:a aac \
42 | -ar 48000 \
43 | -b:a 128k \
44 | -c:v h264 \
45 | -profile:v main \
46 | -b:v 1400k \
47 | -maxrate 1498k \
48 | -bufsize 2100k \
49 | -crf 20 \
50 | -sc_threshold 0 \
51 | -g 48 \
52 | -keyint_min 48 \
53 | -f hls \
54 | -hls_time 6 \
55 | -hls_list_size 4 \
56 | -hls_delete_threshold 1 \
57 | -hls_flags delete_segments \
58 | -hls_start_number_source datetime \
59 | -hls_segment_filename "/var/www/html/$1_480p_%03d.ts" \
60 | "/var/www/html/$1_480p.m3u8" \
61 | -map 0:v:0 -map 0:a:0 \
62 | -vf scale=w=1280:h=720:force_original_aspect_ratio=decrease \
63 | -c:a aac \
64 | -ar 48000 \
65 | -b:a 128k \
66 | -c:v h264 \
67 | -profile:v main \
68 | -b:v 2800k \
69 | -maxrate 2996k \
70 | -bufsize 4200k \
71 | -crf 20 \
72 | -sc_threshold 0 \
73 | -g 48 \
74 | -keyint_min 48 \
75 | -f hls \
76 | -hls_time 6 \
77 | -hls_list_size 4 \
78 | -hls_delete_threshold 1 \
79 | -hls_flags delete_segments \
80 | -hls_start_number_source datetime \
81 | -hls_segment_filename "/var/www/html/$1_720p_%03d.ts" \
82 | "/var/www/html/$1_720p.m3u8";
83 |
--------------------------------------------------------------------------------
/profiles/abr_transcoding_hd_1080p.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function generate_playlist {
4 | echo '#EXTM3U'
5 | echo '#EXT-X-VERSION:3'
6 | echo '#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360'
7 | echo "$1_360p.m3u8"
8 | echo '#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480'
9 | echo "$1_480p.m3u8"
10 | echo '#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720'
11 | echo "$1_720p.m3u8"
12 | echo '#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080'
13 | echo "$1_1080p.m3u8"
14 | } > "/var/www/html/$1.m3u8"
15 | generate_playlist "$1"
16 |
17 | ffmpeg -hide_banner \
18 | -i "$2" \
19 | -map 0:v:0 -map 0:a:0 \
20 | -vf scale=w=640:h=360:force_original_aspect_ratio=decrease \
21 | -c:a aac \
22 | -ar 48000 \
23 | -b:a 96k \
24 | -c:v h264 \
25 | -profile:v main \
26 | -b:v 800k \
27 | -maxrate 856k \
28 | -bufsize 1200k \
29 | -crf 20 \
30 | -sc_threshold 0 \
31 | -g 48 \
32 | -keyint_min 48 \
33 | -f hls \
34 | -hls_time 6 \
35 | -hls_list_size 4 \
36 | -hls_delete_threshold 1 \
37 | -hls_flags delete_segments \
38 | -hls_start_number_source datetime \
39 | -hls_segment_filename "/var/www/html/$1_360p_%03d.ts" \
40 | "/var/www/html/$1_360p.m3u8" \
41 | -map 0:v:0 -map 0:a:0 \
42 | -vf scale=w=842:h=480:force_original_aspect_ratio=decrease \
43 | -c:a aac \
44 | -ar 48000 \
45 | -b:a 128k \
46 | -c:v h264 \
47 | -profile:v main \
48 | -b:v 1400k \
49 | -maxrate 1498k \
50 | -bufsize 2100k \
51 | -crf 20 \
52 | -sc_threshold 0 \
53 | -g 48 \
54 | -keyint_min 48 \
55 | -f hls \
56 | -hls_time 6 \
57 | -hls_list_size 4 \
58 | -hls_delete_threshold 1 \
59 | -hls_flags delete_segments \
60 | -hls_start_number_source datetime \
61 | -hls_segment_filename "/var/www/html/$1_480p_%03d.ts" \
62 | "/var/www/html/$1_480p.m3u8" \
63 | -map 0:v:0 -map 0:a:0 \
64 | -vf scale=w=1280:h=720:force_original_aspect_ratio=decrease \
65 | -c:a aac \
66 | -ar 48000 \
67 | -b:a 128k \
68 | -c:v h264 \
69 | -profile:v main \
70 | -b:v 2800k \
71 | -maxrate 2996k \
72 | -bufsize 4200k \
73 | -crf 20 \
74 | -sc_threshold 0 \
75 | -g 48 \
76 | -keyint_min 48 \
77 | -f hls \
78 | -hls_time 6 \
79 | -hls_list_size 4 \
80 | -hls_delete_threshold 1 \
81 | -hls_flags delete_segments \
82 | -hls_start_number_source datetime \
83 | -hls_segment_filename "/var/www/html/$1_720p_%03d.ts" \
84 | "/var/www/html/$1_720p.m3u8" \
85 | -map 0:v:0 -map 0:a:0 \
86 | -vf scale=w=1920:h=1080:force_original_aspect_ratio=decrease \
87 | -c:a aac \
88 | -ar 48000 \
89 | -b:a 192k \
90 | -c:v h264 \
91 | -profile:v main \
92 | -b:v 5000k \
93 | -maxrate 5350k \
94 | -bufsize 7500k \
95 | -crf 20 \
96 | -sc_threshold 0 \
97 | -g 48 \
98 | -keyint_min 48 \
99 | -f hls \
100 | -hls_time 6 \
101 | -hls_list_size 4 \
102 | -hls_delete_threshold 1 \
103 | -hls_flags delete_segments \
104 | -hls_start_number_source datetime \
105 | -hls_segment_filename "/var/www/html/$1_1080p_%03d.ts" \
106 | "/var/www/html/$1_1080p.m3u8";
107 |
--------------------------------------------------------------------------------
/profiles/abr_transcoding_sd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function generate_playlist {
4 | echo '#EXTM3U'
5 | echo '#EXT-X-VERSION:3'
6 | echo '#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360'
7 | echo "$1_360p.m3u8"
8 | echo '#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480'
9 | echo "$1_480p.m3u8"
10 | } > "/var/www/html/$1.m3u8"
11 | generate_playlist "$1"
12 |
13 | ffmpeg -hide_banner \
14 | -i "$2" \
15 | -map 0:v:0 -map 0:a:0 \
16 | -vf scale=w=640:h=360:force_original_aspect_ratio=decrease \
17 | -c:a aac \
18 | -ar 48000 \
19 | -b:a 96k \
20 | -c:v h264 \
21 | -profile:v main \
22 | -b:v 800k \
23 | -maxrate 856k \
24 | -bufsize 1200k \
25 | -crf 20 \
26 | -sc_threshold 0 \
27 | -g 48 \
28 | -keyint_min 48 \
29 | -f hls \
30 | -hls_time 6 \
31 | -hls_list_size 4 \
32 | -hls_delete_threshold 1 \
33 | -hls_flags delete_segments \
34 | -hls_start_number_source datetime \
35 | -hls_segment_filename "/var/www/html/$1_360p_%03d.ts" \
36 | "/var/www/html/$1_360p.m3u8" \
37 | -map 0:v:0 -map 0:a:0 \
38 | -vf scale=w=842:h=480:force_original_aspect_ratio=decrease \
39 | -c:a aac \
40 | -ar 48000 \
41 | -b:a 128k \
42 | -c:v h264 \
43 | -profile:v main \
44 | -b:v 1400k \
45 | -maxrate 1498k \
46 | -bufsize 2100k \
47 | -crf 20 \
48 | -sc_threshold 0 \
49 | -g 48 \
50 | -keyint_min 48 \
51 | -f hls \
52 | -hls_time 6 \
53 | -hls_list_size 4 \
54 | -hls_delete_threshold 1 \
55 | -hls_flags delete_segments \
56 | -hls_start_number_source datetime \
57 | -hls_segment_filename "/var/www/html/$1_480p_%03d.ts" \
58 | "/var/www/html/$1_480p.m3u8";
59 |
--------------------------------------------------------------------------------
/profiles/passthrough.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | ffmpeg -hide_banner \
3 | -i "$2" \
4 | -map 0:v:0 -map 0:a:0 \
5 | -c:v copy \
6 | -c:a copy \
7 | -f hls \
8 | -hls_time 6 \
9 | -hls_list_size 4 \
10 | -hls_delete_threshold 1 \
11 | -hls_flags delete_segments \
12 | -hls_start_number_source datetime \
13 | "/var/www/html/$1.m3u8";
14 |
--------------------------------------------------------------------------------
/profiles/transcoding_hd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | ffmpeg -hide_banner \
3 | -i "$2" \
4 | -map 0:v:0 -map 0:a:0 \
5 | -vf scale=w=1280:h=720:force_original_aspect_ratio=decrease \
6 | -c:a aac \
7 | -ar 48000 \
8 | -b:a 128k \
9 | -c:v h264 \
10 | -profile:v main \
11 | -b:v 2800k \
12 | -maxrate 2996k \
13 | -bufsize 4200k \
14 | -crf 20 \
15 | -sc_threshold 0 \
16 | -g 48 \
17 | -keyint_min 48 \
18 | -f hls \
19 | -hls_time 6 \
20 | -hls_list_size 4 \
21 | -hls_delete_threshold 1 \
22 | -hls_flags delete_segments \
23 | -hls_start_number_source datetime \
24 | -hls_segment_filename "/var/www/html/$1_%03d.ts" \
25 | "/var/www/html/$1.m3u8";
26 |
--------------------------------------------------------------------------------
/profiles/transcoding_sd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | ffmpeg -hide_banner \
3 | -i "$2" \
4 | -map 0:v:0 -map 0:a:0 \
5 | -vf scale=w=842:h=480:force_original_aspect_ratio=decrease \
6 | -c:a aac \
7 | -ar 48000 \
8 | -b:a 128k \
9 | -c:v h264 \
10 | -profile:v main \
11 | -b:v 1400k \
12 | -maxrate 1498k \
13 | -bufsize 2100k \
14 | -crf 20 \
15 | -sc_threshold 0 \
16 | -g 48 \
17 | -keyint_min 48 \
18 | -f hls \
19 | -hls_time 6 \
20 | -hls_list_size 4 \
21 | -hls_delete_threshold 1 \
22 | -hls_flags delete_segments \
23 | -hls_start_number_source datetime \
24 | -hls_segment_filename "/var/www/html/$1_%03d.ts" \
25 | "/var/www/html/$1.m3u8";
26 |
--------------------------------------------------------------------------------
/profiles_nvidia/.helpers.sh:
--------------------------------------------------------------------------------
1 | function cuvid_codec {
2 | SUPPORTED_CODECS="h264 hevc mjpeg mpeg1video mpeg2video mpeg4 vc1 vp8 vp9"
3 | CODEC=$(ffprobe -hide_banner -loglevel panic -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$1" | head -1)
4 |
5 | if [[ ! " ${SUPPORTED_CODECS} " =~ " ${CODEC} " ]]; then
6 | echo "Unsupported codec ${CODEC}."
7 | return 1
8 | fi
9 |
10 | if [[ "${CODEC}" == "mpeg1video" ]]; then
11 | echo "mpeg1_cuvid"
12 | return 0
13 | fi
14 |
15 | if [[ "${CODEC}" == "mpeg2video" ]]; then
16 | echo "mpeg2_cuvid"
17 | return 0
18 | fi
19 |
20 | echo "${CODEC}_cuvid"
21 | }
22 |
--------------------------------------------------------------------------------
/profiles_nvidia/abr_transcoding_hd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "$(dirname "$0")"
4 | source .helpers.sh
5 |
6 | function generate_playlist {
7 | echo '#EXTM3U'
8 | echo '#EXT-X-VERSION:3'
9 | echo '#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360'
10 | echo "$1_360p.m3u8"
11 | echo '#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480'
12 | echo "$1_480p.m3u8"
13 | echo '#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720'
14 | echo "$1_720p.m3u8"
15 | } > "/var/www/html/$1.m3u8"
16 | generate_playlist "$1"
17 |
18 | ffmpeg -hide_banner -hwaccel_output_format cuda -c:v "$(cuvid_codec "$2")" \
19 | -i "$2" \
20 | -map 0:v:0 -map 0:a:0 \
21 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=640:360:interp_algo=super \
22 | -c:a aac \
23 | -ar 48000 \
24 | -b:a 96k \
25 | -c:v h264_nvenc \
26 | -profile:v main \
27 | -b:v 800k \
28 | -maxrate 856k \
29 | -bufsize 1200k \
30 | -crf 20 \
31 | -sc_threshold 0 \
32 | -g 48 \
33 | -keyint_min 48 \
34 | -f hls \
35 | -hls_time 6 \
36 | -hls_list_size 4 \
37 | -hls_delete_threshold 1 \
38 | -hls_flags delete_segments \
39 | -hls_start_number_source datetime \
40 | -hls_segment_filename "/var/www/html/$1_360p_%03d.ts" \
41 | "/var/www/html/$1_360p.m3u8" \
42 | -map 0:v:0 -map 0:a:0 \
43 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=842:480:interp_algo=super \
44 | -c:a aac \
45 | -ar 48000 \
46 | -b:a 128k \
47 | -c:v h264_nvenc \
48 | -profile:v main \
49 | -b:v 1400k \
50 | -maxrate 1498k \
51 | -bufsize 2100k \
52 | -crf 20 \
53 | -sc_threshold 0 \
54 | -g 48 \
55 | -keyint_min 48 \
56 | -f hls \
57 | -hls_time 6 \
58 | -hls_list_size 4 \
59 | -hls_delete_threshold 1 \
60 | -hls_flags delete_segments \
61 | -hls_start_number_source datetime \
62 | -hls_segment_filename "/var/www/html/$1_480p_%03d.ts" \
63 | "/var/www/html/$1_480p.m3u8" \
64 | -map 0:v:0 -map 0:a:0 \
65 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=1280:720:interp_algo=super \
66 | -c:a aac \
67 | -ar 48000 \
68 | -b:a 128k \
69 | -c:v h264_nvenc \
70 | -profile:v main \
71 | -b:v 2800k \
72 | -maxrate 2996k \
73 | -bufsize 4200k \
74 | -crf 20 \
75 | -sc_threshold 0 \
76 | -g 48 \
77 | -keyint_min 48 \
78 | -f hls \
79 | -hls_time 6 \
80 | -hls_list_size 4 \
81 | -hls_delete_threshold 1 \
82 | -hls_flags delete_segments \
83 | -hls_start_number_source datetime \
84 | -hls_segment_filename "/var/www/html/$1_720p_%03d.ts" \
85 | "/var/www/html/$1_720p.m3u8";
86 |
--------------------------------------------------------------------------------
/profiles_nvidia/abr_transcoding_hd_1080p.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "$(dirname "$0")"
4 | source .helpers.sh
5 |
6 | function generate_playlist {
7 | echo '#EXTM3U'
8 | echo '#EXT-X-VERSION:3'
9 | echo '#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360'
10 | echo "$1_360p.m3u8"
11 | echo '#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480'
12 | echo "$1_480p.m3u8"
13 | echo '#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720'
14 | echo "$1_720p.m3u8"
15 | echo '#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080'
16 | echo "$1_1080p.m3u8"
17 | } > "/var/www/html/$1.m3u8"
18 | generate_playlist "$1"
19 |
20 | ffmpeg -hide_banner -hwaccel_output_format cuda -c:v "$(cuvid_codec "$2")" \
21 | -i "$2" \
22 | -map 0:v:0 -map 0:a:0 \
23 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=640:360:interp_algo=super \
24 | -c:a aac \
25 | -ar 48000 \
26 | -b:a 96k \
27 | -c:v h264_nvenc \
28 | -profile:v main \
29 | -b:v 800k \
30 | -maxrate 856k \
31 | -bufsize 1200k \
32 | -crf 20 \
33 | -sc_threshold 0 \
34 | -g 48 \
35 | -keyint_min 48 \
36 | -f hls \
37 | -hls_time 6 \
38 | -hls_list_size 4 \
39 | -hls_delete_threshold 1 \
40 | -hls_flags delete_segments \
41 | -hls_start_number_source datetime \
42 | -hls_segment_filename "/var/www/html/$1_360p_%03d.ts" \
43 | "/var/www/html/$1_360p.m3u8" \
44 | -map 0:v:0 -map 0:a:0 \
45 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=842:480:interp_algo=super \
46 | -c:a aac \
47 | -ar 48000 \
48 | -b:a 128k \
49 | -c:v h264_nvenc \
50 | -profile:v main \
51 | -b:v 1400k \
52 | -maxrate 1498k \
53 | -bufsize 2100k \
54 | -crf 20 \
55 | -sc_threshold 0 \
56 | -g 48 \
57 | -keyint_min 48 \
58 | -f hls \
59 | -hls_time 6 \
60 | -hls_list_size 4 \
61 | -hls_delete_threshold 1 \
62 | -hls_flags delete_segments \
63 | -hls_start_number_source datetime \
64 | -hls_segment_filename "/var/www/html/$1_480p_%03d.ts" \
65 | "/var/www/html/$1_480p.m3u8" \
66 | -map 0:v:0 -map 0:a:0 \
67 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=1280:720:interp_algo=super \
68 | -c:a aac \
69 | -ar 48000 \
70 | -b:a 128k \
71 | -c:v h264_nvenc \
72 | -profile:v main \
73 | -b:v 2800k \
74 | -maxrate 2996k \
75 | -bufsize 4200k \
76 | -crf 20 \
77 | -sc_threshold 0 \
78 | -g 48 \
79 | -keyint_min 48 \
80 | -f hls \
81 | -hls_time 6 \
82 | -hls_list_size 4 \
83 | -hls_delete_threshold 1 \
84 | -hls_flags delete_segments \
85 | -hls_start_number_source datetime \
86 | -hls_segment_filename "/var/www/html/$1_720p_%03d.ts" \
87 | "/var/www/html/$1_720p.m3u8" \
88 | -map 0:v:0 -map 0:a:0 \
89 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=1920:1080:interp_algo=super \
90 | -c:a aac \
91 | -ar 48000 \
92 | -b:a 192k \
93 | -c:v h264_nvenc \
94 | -profile:v main \
95 | -b:v 5000k \
96 | -maxrate 5350k \
97 | -bufsize 7500k \
98 | -crf 20 \
99 | -sc_threshold 0 \
100 | -g 48 \
101 | -keyint_min 48 \
102 | -f hls \
103 | -hls_time 6 \
104 | -hls_list_size 4 \
105 | -hls_delete_threshold 1 \
106 | -hls_flags delete_segments \
107 | -hls_start_number_source datetime \
108 | -hls_segment_filename "/var/www/html/$1_1080p_%03d.ts" \
109 | "/var/www/html/$1_1080p.m3u8";
110 |
--------------------------------------------------------------------------------
/profiles_nvidia/abr_transcoding_sd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "$(dirname "$0")"
4 | source .helpers.sh
5 |
6 | function generate_playlist {
7 | echo '#EXTM3U'
8 | echo '#EXT-X-VERSION:3'
9 | echo '#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360'
10 | echo "$1_360p.m3u8"
11 | echo '#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480'
12 | echo "$1_480p.m3u8"
13 | } > "/var/www/html/$1.m3u8"
14 | generate_playlist "$1"
15 |
16 | ffmpeg -hide_banner -hwaccel_output_format cuda -c:v "$(cuvid_codec "$2")" \
17 | -i "$2" \
18 | -map 0:v:0 -map 0:a:0 \
19 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=640:360:interp_algo=super \
20 | -c:a aac \
21 | -ar 48000 \
22 | -b:a 96k \
23 | -c:v h264_nvenc \
24 | -profile:v main \
25 | -b:v 800k \
26 | -maxrate 856k \
27 | -bufsize 1200k \
28 | -crf 20 \
29 | -sc_threshold 0 \
30 | -g 48 \
31 | -keyint_min 48 \
32 | -f hls \
33 | -hls_time 6 \
34 | -hls_list_size 4 \
35 | -hls_delete_threshold 1 \
36 | -hls_flags delete_segments \
37 | -hls_start_number_source datetime \
38 | -hls_segment_filename "/var/www/html/$1_360p_%03d.ts" \
39 | "/var/www/html/$1_360p.m3u8" \
40 | -map 0:v:0 -map 0:a:0 \
41 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=842:480:interp_algo=super \
42 | -c:a aac \
43 | -ar 48000 \
44 | -b:a 128k \
45 | -c:v h264_nvenc \
46 | -profile:v main \
47 | -b:v 1400k \
48 | -maxrate 1498k \
49 | -bufsize 2100k \
50 | -crf 20 \
51 | -sc_threshold 0 \
52 | -g 48 \
53 | -keyint_min 48 \
54 | -f hls \
55 | -hls_time 6 \
56 | -hls_list_size 4 \
57 | -hls_delete_threshold 1 \
58 | -hls_flags delete_segments \
59 | -hls_start_number_source datetime \
60 | -hls_segment_filename "/var/www/html/$1_480p_%03d.ts" \
61 | "/var/www/html/$1_480p.m3u8";
62 |
--------------------------------------------------------------------------------
/profiles_nvidia/passthrough.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | ffmpeg -hide_banner \
3 | -i "$2" \
4 | -map 0:v:0 -map 0:a:0 \
5 | -c:v copy \
6 | -c:a copy \
7 | -f hls \
8 | -hls_time 6 \
9 | -hls_list_size 4 \
10 | -hls_delete_threshold 1 \
11 | -hls_flags delete_segments \
12 | -hls_start_number_source datetime \
13 | "/var/www/html/$1.m3u8";
14 |
15 |
--------------------------------------------------------------------------------
/profiles_nvidia/transcoding_hd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "$(dirname "$0")"
4 | source .helpers.sh
5 |
6 | ffmpeg -hide_banner -hwaccel_output_format cuda -c:v "$(cuvid_codec "$2")" \
7 | -i "$2" \
8 | -map 0:v:0 -map 0:a:0 \
9 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=1280:720:interp_algo=super \
10 | -c:a aac \
11 | -ar 48000 \
12 | -b:a 128k \
13 | -c:v h264_nvenc \
14 | -profile:v main \
15 | -b:v 2800k \
16 | -maxrate 2996k \
17 | -bufsize 4200k \
18 | -crf 20 \
19 | -sc_threshold 0 \
20 | -g 48 \
21 | -keyint_min 48 \
22 | -f hls \
23 | -hls_time 6 \
24 | -hls_list_size 4 \
25 | -hls_delete_threshold 1 \
26 | -hls_flags delete_segments \
27 | -hls_start_number_source datetime \
28 | -hls_segment_filename "/var/www/html/$1_%03d.ts" \
29 | "/var/www/html/$1.m3u8";
30 |
--------------------------------------------------------------------------------
/profiles_nvidia/transcoding_sd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "$(dirname "$0")"
4 | source .helpers.sh
5 |
6 | ffmpeg -hide_banner -hwaccel_output_format cuda -c:v "$(cuvid_codec "$2")" \
7 | -i "$2" \
8 | -map 0:v:0 -map 0:a:0 \
9 | -vf hwupload_cuda,yadif_cuda=0:-1:0,scale_npp=842:480:interp_algo=super \
10 | -c:a aac \
11 | -ar 48000 \
12 | -b:a 128k \
13 | -c:v h264_nvenc \
14 | -profile:v main \
15 | -b:v 1400k \
16 | -maxrate 1498k \
17 | -bufsize 2100k \
18 | -crf 20 \
19 | -sc_threshold 0 \
20 | -g 48 \
21 | -keyint_min 48 \
22 | -f hls \
23 | -hls_time 6 \
24 | -hls_list_size 4 \
25 | -hls_delete_threshold 1 \
26 | -hls_flags delete_segments \
27 | -hls_start_number_source datetime \
28 | -hls_segment_filename "/var/www/html/$1_%03d.ts" \
29 | "/var/www/html/$1.m3u8";
30 |
--------------------------------------------------------------------------------
/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | nodaemon=true
3 | pidfile=/var/run/supervisord.pid
4 | logfile=/dev/null
5 | logfile_maxbytes=0
6 | loglevel=debug
7 |
8 | [program:nginx]
9 | command=/usr/sbin/nginx -g "daemon off;"
10 | autostart=true
11 | autorestart=true
12 | startretries=5
13 | numprocs=1
14 | startsecs=0
15 | process_name=%(program_name)s_%(process_num)02d
16 | stderr_logfile=/var/log/supervisor/%(program_name)s_stderr.log
17 | stderr_logfile_maxbytes=10MB
18 | stdout_logfile=/var/log/supervisor/%(program_name)s_stdout.log
19 | stdout_logfile_maxbytes=10MB
20 |
21 |
--------------------------------------------------------------------------------