25 |
26 | FFmpeg compilation made easy with additional libraries and runs inside a Docker container. A RESTful API runs alongside written in Node.js utilising `express` and `fluent-ffmpeg`.
27 |
28 | For more information read the [documentation](https://ryan.mccartney.info/ffmpeg-docker/).
29 |
30 | :exclamation: This project is a work in progress, it is still in the early stages of development and functions may not work as expected.
31 |
32 | ## Pre-built Image
33 |
34 | You can use the pre-built image straight away - however, this is contains pre-compiled FFmpeg as a result it does not have the following options enabled to comply with FFmpeg licensing;
35 |
36 | - `--enable-nonfree`
37 | - `--enable-libndi_newtek`
38 | - `--enable-decklink`
39 | - `--enable-libsrt`
40 | - `--disable-libaom`
41 | - `--disable-libsvtav1`
42 | - `--enable-libklvanc`
43 | - `--enable-libvmaf`
44 | - `--enable-libfdk-aac`
45 |
46 | If this isn't a problem then you can get the image here;
47 |
48 | `docker pull ghcr.io/ryanmccartney/ffmpeg-docker:latest`
49 |
50 | ## Building
51 |
52 | If you want to contribute to this project or you'd like some of the above features, you'll need to build a copy of this image yourself which will compile FFmpeg locally.
53 |
54 | 1. Clone the repository `git clone https://github.com/ryanmccartney/ffmpeg-docker`
55 | 2. Change directory to the repository `cd ./ffmpeg-docker`
56 | 3. Build the image using `docker compose build`.
57 |
58 | ### on an M1 Mac
59 |
60 | 1. Install your packages locally - `npm install --platform=linux --arch=arm64v8 sharp`
61 |
62 | ## About
63 |
64 | This software uses libraries from the FFmpeg project under the LGPLv2.1.
65 |
66 | This software uses code of [FFmpeg](http://ffmpeg.org) licensed under the [LGPLv2.1](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and its source can be downloaded [here](https://github.com/ryanmccartney/ffmpeg-docker)
67 |
--------------------------------------------------------------------------------
/data/hls/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/data/hls/.gitkeep
--------------------------------------------------------------------------------
/data/media/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/data/media/.gitkeep
--------------------------------------------------------------------------------
/data/playlist/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/data/playlist/.gitkeep
--------------------------------------------------------------------------------
/data/qr/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/data/qr/.gitkeep
--------------------------------------------------------------------------------
/data/thumbnail/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/data/thumbnail/.gitkeep
--------------------------------------------------------------------------------
/data/vmaf/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/data/vmaf/.gitkeep
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | #
2 | # FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | # Copyright (C) 2022 Ryan McCartney
4 | #
5 | # This file is part of the FFmpeg Docker (ffmpeg-docker).
6 | #
7 | # FFmpeg Docker is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 | #
20 |
21 | version: "3.8"
22 |
23 | services:
24 | ffmpeg:
25 | container_name: ffmpeg
26 | # network_mode: "host" #Change this as required
27 | build:
28 | context: "."
29 | args:
30 | DECKLINK_SUPPORT: "false"
31 | DECKLINK_SDK_URL: "https://swr.cloud.blackmagicdesign.com/DeckLink/v12.4.1/Blackmagic_DeckLink_SDK_12.4.1.zip?verify="
32 | DECKLINK_DRIVER_URL: "https://swr.cloud.blackmagicdesign.com/DesktopVideo/v12.4.1/Blackmagic_Desktop_Video_Linux_12.4.1.tar.gz?verify="
33 | DECKLINK_DRIVER_VERSION: "12.4.1"
34 | NDI_SUPPORT: "false"
35 | NDI_SDK_URL: "https://downloads.ndi.tv/SDK/NDI_SDK_Linux/Install_NDI_SDK_v5_Linux.tar.gz"
36 | NON_FREE: "true"
37 | restart: always
38 | volumes:
39 | - ./:/home/node/app
40 | #devices:
41 | # - /dev/blackmagic/io0:/dev/blackmagic/io0
42 | environment:
43 | NODE_ENV: "development"
44 | PORT: 80
45 | HOST: "localhost"
46 | WEB_GUI: "true"
47 | AUTH_KEY: "averysecretkey"
48 | AUTH_USER: admin
49 | AUTH_PASSWORD: admin
50 | ports:
51 | - 80:80
52 |
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem "jekyll", "~> 4.3" # installed by `gem jekyll`
4 | # gem "webrick" # required when using Ruby >= 3 and Jekyll <= 4.2.2
5 |
6 | gem "just-the-docs", "0.4.0.rc3" # currently the latest pre-release
7 | # gem "just-the-docs" # the latest release - currently 0.3.3
8 |
--------------------------------------------------------------------------------
/docs/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.8.1)
5 | public_suffix (>= 2.0.2, < 6.0)
6 | colorator (1.1.0)
7 | concurrent-ruby (1.1.10)
8 | em-websocket (0.5.3)
9 | eventmachine (>= 0.12.9)
10 | http_parser.rb (~> 0)
11 | eventmachine (1.2.7)
12 | ffi (1.15.5)
13 | forwardable-extended (2.6.0)
14 | http_parser.rb (0.8.0)
15 | i18n (1.12.0)
16 | concurrent-ruby (~> 1.0)
17 | jekyll (4.3.0)
18 | addressable (~> 2.4)
19 | colorator (~> 1.0)
20 | em-websocket (~> 0.5)
21 | i18n (~> 1.0)
22 | jekyll-sass-converter (>= 2.0, < 4.0)
23 | jekyll-watch (~> 2.0)
24 | kramdown (~> 2.3, >= 2.3.1)
25 | kramdown-parser-gfm (~> 1.0)
26 | liquid (~> 4.0)
27 | mercenary (>= 0.3.6, < 0.5)
28 | pathutil (~> 0.9)
29 | rouge (>= 3.0, < 5.0)
30 | safe_yaml (~> 1.0)
31 | terminal-table (>= 1.8, < 4.0)
32 | webrick (~> 1.7)
33 | jekyll-sass-converter (2.2.0)
34 | sassc (> 2.0.1, < 3.0)
35 | jekyll-seo-tag (2.8.0)
36 | jekyll (>= 3.8, < 5.0)
37 | jekyll-watch (2.2.1)
38 | listen (~> 3.0)
39 | just-the-docs (0.4.0.rc3)
40 | jekyll (>= 3.8.5)
41 | jekyll-seo-tag (>= 2.0)
42 | rake (>= 12.3.1)
43 | kramdown (2.4.0)
44 | rexml
45 | kramdown-parser-gfm (1.1.0)
46 | kramdown (~> 2.0)
47 | liquid (4.0.3)
48 | listen (3.7.1)
49 | rb-fsevent (~> 0.10, >= 0.10.3)
50 | rb-inotify (~> 0.9, >= 0.9.10)
51 | mercenary (0.4.0)
52 | pathutil (0.16.2)
53 | forwardable-extended (~> 2.6)
54 | public_suffix (5.0.0)
55 | rake (13.0.6)
56 | rb-fsevent (0.11.2)
57 | rb-inotify (0.10.1)
58 | ffi (~> 1.0)
59 | rexml (3.2.5)
60 | rouge (4.0.0)
61 | safe_yaml (1.0.5)
62 | sassc (2.4.0)
63 | ffi (~> 1.9)
64 | terminal-table (3.0.2)
65 | unicode-display_width (>= 1.1.1, < 3)
66 | unicode-display_width (2.3.0)
67 | webrick (1.7.0)
68 |
69 | PLATFORMS
70 | arm64-darwin-21
71 | x86_64-darwin-19
72 | x86_64-linux
73 |
74 | DEPENDENCIES
75 | jekyll (~> 4.3)
76 | just-the-docs (= 0.4.0.rc3)
77 |
78 | BUNDLED WITH
79 | 2.3.9
80 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | title: Docker FFmpeg
2 | description: FFmpeg in Docker with a RESTful API for control
3 | remote_theme: pmarsceill/just-the-docs
4 | url: https://ryan.mccartney.info/ffmpeg-docker
5 | show_downloads: true
6 |
--------------------------------------------------------------------------------
/docs/assets/Blackmagic DeckLink SDK.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/docs/assets/Blackmagic DeckLink SDK.pdf
--------------------------------------------------------------------------------
/docs/assets/css/style.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 | {% if site.color_scheme and site.color_scheme != "nil" %}
4 | {% assign color_scheme = site.color_scheme %}
5 | {% else %}
6 | {% assign color_scheme = "light" %}
7 | {% endif %}
8 | {% include css/just-the-docs.scss.liquid color_scheme=color_scheme %}
9 |
10 | a {
11 | color: #7EC77F;
12 | }
13 |
14 | .main-content {
15 | h1,
16 | h2,
17 | h3,
18 | h4,
19 | h5,
20 | h6 {
21 | color: #7EC77F;
22 | }
23 | }
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Home
3 | layout: home
4 | nav_order: 1
5 | ---
6 |
7 | # FFmpeg in Docker
8 |
9 | [](https://github.com/ryanmccartney/ffmpeg-docker/actions/workflows/docker.yml) [](https://github.com/ryanmccartney/ffmpeg-docker/actions/workflows/pages.yml)
10 |
11 | FFmpeg compiled with additional libraries and running inside a Docker container. A RESTful API runs alongside written in Node.js utilsing `fluent-ffmpeg`.
12 |
13 | ## Exmaple
14 |
15 | `POST` comand to the following endpoint `http://localhost/api/bars/rtmp` with the JSON body
16 |
17 | ```json
18 | {
19 | "input": {
20 | "type": "smptehdbars"
21 | },
22 | "output": {
23 | "address": "a.rtmp.youtube.com/live2",
24 | "key": "YOUTUBE_STREAM_KEY",
25 | "bitrate": "10M"
26 | },
27 | "overlay": {
28 | "line1": "Test RTMP Stream",
29 | "line2": "FFmpeg in Docker",
30 | "font": "swansea-bold.ttf"
31 | },
32 | "thumbnail": true
33 | }
34 | ```
35 |
36 | This renders the following output.
37 |
38 |
39 |
40 | Try it with file inputs, decklink inputs and RIST, SRT or RTMP output.
41 |
42 | ## Pre-built Image
43 |
44 | You can use the pre-built image straight away - however, this is contains pre-compiled FFmpeg as a result it does not have the following options enabled to comply with FFmpeg licensing;
45 |
46 | - `--enable-nonfree`
47 | - `--enable-libndi_newtek`
48 | - `--enable-decklink`
49 | - `--enable-libsrt`
50 | - `--disable-libaom`
51 | - `--disable-libsvtav1`
52 | - `--enable-libklvanc`
53 | - `--enable-libvmaf`
54 | - `--enable-libfdk-aac`
55 |
56 | If this isn't a problem then you can get the image here;
57 |
58 | `docker pull ghcr.io/ryanmccartney/ffmpeg-docker:latest`
59 |
60 | ## Future Work
61 |
62 | - SRT/RIST statistics - unavalible in FFmpeg, so dificult to report SRT information like, maxRTT, recovered packets, lost packets, jitter, etc.
63 | - SRT Bonding - SRT v1.5 supports bonding through socket groups, again this is not implemented in FFmpeg
64 |
65 | ## About
66 |
67 | This software uses libraries from the FFmpeg project under the LGPLv2.1.
68 |
69 | This software uses code of [FFmpeg](http://ffmpeg.org) licensed under the [LGPLv2.1](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and its source can be downloaded [here](https://github.com/ryanmccartney/ffmpeg-docker)
70 |
71 | ### Media Passthrough
72 |
73 | Mounting media from your host machine directly into the running container allows FFmpeg to scan and analyse it in the background. It can then be directly used when running FFmpeg commands.
74 |
75 | Mount media in `/home/node/app/data/media` directory for use.
76 |
--------------------------------------------------------------------------------
/docs/pages/installation/decklink.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Decklink
4 | parent: Installation
5 | nav_order: 2
6 | ---
7 |
8 | # Decklink Support
9 |
10 | # Host Machine
11 |
12 | To use the decklink device you'll need to have the correct drivers installed on your host machine.
13 |
14 | You can use the script in this repository to do this;
15 |
16 | - `chmod +x setup.sh`
17 | - `./setup.sh`
18 |
19 | If your Decklink card required an update during this process you'll need to reboot the host machine.
20 |
21 | # Building
22 |
23 | Before building you'll need to set the build argument variable `DECKLINK_SUPPORT` to `true`.
24 |
25 | Additionally, you'll need to get a download link for the Blackmagic Design SDK from the [Blackmagic Website](https://www.blackmagicdesign.com/support/download/2438c76b9f734f69b4a914505e50a5ab/Linux).
26 |
27 | It'll come in the form `https://swr.cloud.blackmagicdesign.com/DeckLink/v12.X.X/Blackmagic_DeckLink_SDK_12.X.X.zip?verify=VALUE`
28 |
29 | Then set the build argument variable `DEKSTOP_VIDEO_SDK_URL` to this url.
30 |
31 | When running the container you'll then need to pass through the device. To do this;
32 |
33 | 1. Install Decklink Driver on your host machine.
34 | 2. Check device is connected and update any firmware
35 | 3. Determine the Blackmagic device mapping on the host. Expect something like - `dev/blackmagic/dv0`.
36 |
--------------------------------------------------------------------------------
/docs/pages/installation/environment.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Environment Variables
4 | parent: Installation
5 | nav_order: 2
6 | ---
7 |
8 | # Environment Variables
9 |
10 | Docker image environment variables are given below
11 |
12 | | Variable | Default | Required | Type | Description |
13 | | ------------- | -------------- | -------- | ------- | ---------------------------------------------------------------------------------- |
14 | | PORT | 80 | No | Integer | Port that the backend API runs on |
15 | | HOST | localhost | No | String | |
16 | | RATE_LIMIT | 1000 | No | Integer | The number of requests allowed per client to the API in a 5 minute windows |
17 | | NODE_ENV | production | No | String | Options are "production" or "development" |
18 | | WEB_GUI | true | No | Boolean | Determines whether the API runs a simple frontend or not |
19 | | AUTH_ENABLE | false | No | Boolean | Use JWT auth for API |
20 | | AUTH_USER | admin | No | String | Auth username for login |
21 | | AUTH_PASSWORD | ffmp3gap1 | No | String | Auth password for login |
22 | | AUTH_KEY | averysecretkey | No | String | Private key for generating JWT tokens. Change this if you're using authentication |
23 | | MEDIA_PATH | ./data/media | No | String | Directory to keep media in. Useful to change if media is stored in a network share |
24 | | QUEUE_SIZE | 5 | No | Integer | Number of FFMpeg processes that can run simultaneously |
25 | | LOG_FOLDER | logs | No | String | Folder that logs are stored in |
26 | | LOG_NAME | ffmpeg | No | String | Log file names |
27 | | LOG_LEVEL | info | No | String | Logging level "debug", "error", "info", "http" or "warning" |
28 |
--------------------------------------------------------------------------------
/docs/pages/installation/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Installation
4 | nav_order: 2
5 | has_children: true
6 | ---
7 |
8 | ### With Decklink Support
9 |
10 | Before building you'll need to set the build argument variable `DECKLINK_SUPPORT` to `true`.
11 |
12 | Additionally, you'll need to get a download link for the Blackmagic Design SDK from the [Blackmagic Website](https://www.blackmagicdesign.com/support/download/2438c76b9f734f69b4a914505e50a5ab/Linux).
13 |
14 | It'll come in the form `https://sw.blackmagicdesign.com/DeckLink/v12.x.x/Blackmagic_DeckLink_SDK_12.x.x.zip?Key-Pair-Id=VALUE==&Expires=VALUE`
15 |
16 | Then set the build argument variable `DEKSTOP_VIDEO_SDK_URL` to this url.
17 |
18 | When running the container you'll then need to pass through the device. To do this;
19 |
20 | 1. Install Decklink Driver on your host machine.
21 | 2. Check device is connected and update any firmware
22 | 3. Determine the Blackmagic device mapping on the host. Expect something like - `dev/blackmagic/dv0`.
23 |
24 | ### With NDI Support
25 |
26 | Using a [patch](https://framagit.org/tytan652/ffmpeg-ndi-patch) to re-add Newtec NDI to FFmpeg on building.
27 |
28 | Before building you'll need to set the build argument variable `NDI_SUPPORT` to `true`.
29 |
--------------------------------------------------------------------------------
/docs/pages/installation/ndi.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Newtec NDI
4 | parent: Installation
5 | nav_order: 2
6 | ---
7 |
8 | # NDI Support
9 |
10 | NDI is not supported by FFmpeg as of 2018 due to [licensing issues](https://trac.ffmpeg.org/ticket/7589).
11 |
12 | Howevever, a [patch](https://framagit.org/tytan652/ffmpeg-ndi-patch) exists to readd the relevant code to the FFmpeg source - created by [tytan652](https://tytan652.frama.io/).
13 |
14 | ## Building
15 |
16 | To enable NDI inside the container you'll need to set the build argument variable `NDI_SUPPORT` to `true` before building.
17 |
18 | This will download the NDI SDK, unpack it and set the enable flag for NDI in the FFmpeg build configuration.
19 |
20 | ## Sample Commands
21 |
22 | `ffmpeg -i test.mp4 -vf format=rgb32 -c:v libndi_newtek -pix_fmt uyvy422 -f libndi_newtek "NDI Test Stream"`
23 |
--------------------------------------------------------------------------------
/docs/pages/installation/prebuilt.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Pre Built Image
4 | parent: Installation
5 | nav_order: 1
6 | ---
7 |
8 | At this point you've either built the image from scratch, pulled it from and internal repository or the public options have the suitable options for your requirements.
9 |
10 | ## Pulling the Image
11 |
12 | You can pull the public image with the following command
13 |
14 | ```
15 | docker pull ghcr.io/ryanmccartney/ffmpeg-docker:latest
16 | ```
17 |
18 | ## Running the Image
19 |
20 | For production you should make sure that the source code is not mounted into the container. If the NODE_ENV option is set it should be set to `production`. This is the default if it is not set.
21 |
22 | ### Docker Standalone
23 |
24 | You can run the container with the prebuilt image just pulled using the following commands;
25 |
26 | ```
27 | docker run -d\
28 | --network host\
29 | --volume ffmpeg-docker-data:/home/node/app/data\
30 | --env PORT=80\
31 | --env WEB_GUI=true\
32 | --env NODE_ENV=production\
33 | ghcr.io/ryanmccartney/ffmpeg-docker:latest
34 | ```
35 |
36 | ### Docker Compose
37 |
38 | A sample `docker-compose.yml` file for production is shown below;
39 |
40 | ```
41 | # NAME: docker-compose.yml
42 | # AUTH: Ryan McCartney
43 | # DATE: 30/10/2023
44 | # DESC: Run ffmpeg-docker prebuilt version
45 |
46 | version: "3.8"
47 |
48 | services:
49 | ffmpeg:
50 | image: ghcr.io/ryanmccartney/ffmpeg-docker:latest
51 | restart: always
52 | volumes:
53 | - ./data:/home/node/app/data
54 | environment:
55 | PORT: 80
56 | WEB_GUI: "true"
57 | NODE_ENV: "production"
58 | network_mode: "host"
59 | ```
60 |
61 | Paste this into a file called `docker-compose.yml`
62 |
63 | Finally run it with `docker compose up -d`.
64 |
--------------------------------------------------------------------------------
/docs/pages/ndi/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: NDI
4 | nav_order: 3
5 | has_children: false
6 | ---
7 |
8 | # NDI
9 |
10 | Readding support for NDI is very much a work in progress and remains untested.
11 |
12 | Using a [patch](https://framagit.org/tytan652/ffmpeg-ndi-patch) to re-add Newtec NDI to FFmpeg on building.
13 |
14 | Before building you'll need to set the build argument variable `NDI_SUPPORT` to `true`.
15 |
--------------------------------------------------------------------------------
/docs/pages/usage/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Usage
4 | nav_order: 4
5 | has_children: true
6 | ---
7 |
8 | # Usage
9 |
10 | The image provides a RESTful API exposing a number of endpoints allowing you to perform common functions on media.
11 |
12 | ## Endpoints
13 |
14 | - `api/vmaf` - For running VMAF tests on files and obtaining the results
15 | - `api/system` - For obtaining system stats and status of running jobs
16 | - `api/INPUT/OUTPUT` - For processing media, the api takes the following format
17 |
18 | `INPUT` options include;
19 |
20 | - `file`
21 | - `decklink`
22 | - `hls`
23 | - `udp`
24 | - `rtp`
25 | - `srt`
26 | - `bars`
27 |
28 | `OUTPUT` options include;
29 |
30 | - `file`
31 | - `decklink`
32 | - `hls`
33 | - `udp`
34 | - `rtp`
35 | - `srt`
36 | - `bars`
37 | - `rtmp`
38 |
39 | All commands that run FFmpeg processes in the container are POST requests. They have a common body format for passing arguments with specific variables that are aplicable to indicudual codecs and input/output types
40 | Common body options for all these media proccessing endpoints shown as follows;
41 |
42 | ```json
43 | {
44 | "input": {
45 | "inputVariable1": "specifically applies to chosen input type",
46 | "inputVariable2": "specifically applies to chosen input type"
47 | },
48 | "output": {
49 | "outputVariable1": "specifically applies to chosen output type",
50 | "outputVariable2": "specifically applies to chosen output type"
51 | },
52 | "overlay": {
53 | "fontSize": 90,
54 | "line1": "Line 1 Text",
55 | "line2": "Line 2 Text",
56 | "timecode": true,
57 | "font": "swansea-bold.ttf",
58 | "offset": 1,
59 | "topRight": {
60 | "line1": "%{pts\\:hms}",
61 | "line2": "Frame %{n}"
62 | }
63 | },
64 | "thumbnail": {
65 | "frequency": 25
66 | }
67 | }
68 | ```
69 |
70 | ## Media
71 |
72 | Media can be added into the container at `home/node/app/data/media`. This can then be called relative to this directory.
73 |
74 | For example `home/node/app/data/media/test.mp4` can be called using the `file` parameter in a request body as `test.mp4`.
75 |
--------------------------------------------------------------------------------
/docs/pages/vmaf/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: VMAF
4 | nav_order: 4
5 | has_children: false
6 | ---
7 |
8 | # VMAF Support
9 |
10 | [VMAF](https://github.com/Netflix/vmaf) - Video Multi-Method Assessment Fusion is a [Netflix](https://github.com/Netflix) Open Source project for evaluating the quality of video files.
11 |
12 | FFmpeg-Docker provides build instructions for VMAF by default, and exposes an API endpoint for processing files with VMAF and generating results.
13 |
14 | Media files can be processes relative to the `media` directory and result exported to a `MY-VMAF-TEST.json` file.
15 |
16 | ## Endpoints
17 |
18 | - `api/vmaf`
19 |
20 | ## Running a VMAF test
21 |
22 | GET - `api/vmaf/file`
23 |
24 | Request Body
25 |
26 | ```
27 | {
28 | "input": {
29 | "filename": "test-file.mov"
30 | },
31 | "reference": {
32 | "filename": "reference-file.mov"
33 | },
34 | "output": "test-output.json",
35 | "model": "vmaf_v0.6.1.json"
36 | }
37 | ```
38 |
39 | Alternatively, running from the broswers
40 |
41 | `http://SERVER_IP:SERVER_PORT/api/vmaf/test?filename=test-file.mov&reference=reference-file.mov`
42 |
43 | Running the above command again after starting the test will display information about the task progress.
44 |
45 | If you need to stop the current command running you can use the following command;
46 |
47 | `http://SERVER_IP:SERVER_PORT/api/vmaf/test?kill=true`
48 |
49 | ## Underlying Command
50 |
51 | Sending the above API command results in the following underlying command being run on the server is;
52 |
53 | `ffmpeg -i test-file.mov -i reference-file.mov -y -lavfi libvmaf=model_path=/ffmpeg_sources/vmaf/model/vmaf_v0.6.1.json:log_fmt=json:psnr=1:ssim=1:ms_ssim=1:log_path=test-output.json -f null -`
54 |
55 | ## Generating Graphs from the outputs
56 |
57 | In the example above the parameter `output` was set to `test-output.json`. This means that all of the results are saved in text to this file.
58 |
59 | This can be directly downloaded as follows
60 |
61 | - As a JSON object - `http://SERVER_IP:SERVER_PORT/api/vmaf/results/json?filename=test-output.json`
62 | - As a CSV object - `http://SERVER_IP:SERVER_PORT/api/vmaf/results/csv?filename=test-output.json`
63 | - As a JSON file - `http://SERVER_IP:SERVER_PORT/api/vmaf/results/download/json?filename=test-output.json`
64 | - As a CSV file - `http://SERVER_IP:SERVER_PORT/api/vmaf/results/download/csv?filename=test-output.json`
65 |
66 | A graph of the results can be generated here - `http://SERVER_IP:SERVER_PORT/html/chart.html?filename=test-output.json` using Chart.js.
67 |
68 | Rememebr to change the filename query in the URL to the one set as the `output` parameter when running the test.
69 |
70 | ## Docker Build
71 |
72 | ```
73 | # Add source and compile for Netflix VMAF support
74 | RUN git -C libvmaf pull 2> /dev/null || git clone --depth 1 https://github.com/Netflix/vmaf.git && \
75 | cd ./vmaf/libvmaf && \
76 | apt -y install ninja-build meson && \
77 | meson build --buildtype release && \
78 | ninja -vC build && \
79 | ninja -vC build install
80 | ```
81 |
82 | Adding VMAF support to FFmpeg Build configuration
83 |
84 | ```
85 | RUN ./configure \
86 | ...
87 | --enable-libvmaf
88 | ```
89 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const register = require("module-alias/register");
25 | const app = require("@bin/app");
26 | const logger = require("@utils/logger")(module);
27 | const http = require("http");
28 |
29 | const port = process.env.PORT || "80";
30 | app.set("port", port);
31 |
32 | const server = http.createServer(app);
33 |
34 | const serve = async () => {
35 | try {
36 | server.on("error", onError);
37 | server.on("listening", onListening);
38 | server.listen(port);
39 | } catch (error) {
40 | throw error;
41 | }
42 | };
43 |
44 | const onError = (error) => {
45 | if (error.syscall !== "listen") {
46 | throw error;
47 | }
48 |
49 | const bind = typeof port === "string" ? "Pipe " + port : "Port " + port;
50 |
51 | // handle specific listen errors with friendly messages
52 | switch (error.code) {
53 | case "EACCES":
54 | logger.error(bind + " requires elevated privileges");
55 | process.exit(1);
56 | break;
57 | case "EADDRINUSE":
58 | logger.error(bind + " is already in use");
59 | process.exit(1);
60 | break;
61 | default:
62 | throw error;
63 | }
64 | };
65 |
66 | const onListening = () => {
67 | const addr = server.address();
68 | const bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port;
69 | logger.info(`ffmpeg listening on ${bind}`);
70 | };
71 |
72 | serve();
73 |
--------------------------------------------------------------------------------
/logs/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/logs/.gitkeep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ffmpeg-docker",
3 | "version": "1.0.0",
4 | "description": "FFmpeg compiled in a docker container with an API for control",
5 | "main": "index.js",
6 | "scripts": {
7 | "development": "nodemon index",
8 | "production": "node index",
9 | "docs": "node ./utils/markdown && swagger-markdown --force-version 2 -i ./docs/assets/api-spec.yml -o ./docs/pages/usage/endpoints.md"
10 | },
11 | "author": "Ryan McCartney",
12 | "license": "GPLv3",
13 | "dependencies": {
14 | "bootstrap": "^5.3.2",
15 | "bootstrap-icons": "^1.11.1",
16 | "chart.js": "^4.4.0",
17 | "check-disk-space": "^3.4.0",
18 | "cookie-parser": "^1.4.6",
19 | "cors": "^2.8.5",
20 | "date-fns": "^2.30.0",
21 | "express": "^4.18.1",
22 | "express-async-handler": "^1.2.0",
23 | "express-rate-limit": "^7.1.4",
24 | "express-validator": "^7.0.1",
25 | "fluent-ffmpeg": "^2.1.2",
26 | "gaugeJS": "^1.3.7",
27 | "helmet": "^5.0.1",
28 | "jest": "^29.7.0",
29 | "jsonwebtoken": "^9.0.2",
30 | "md5": "^2.3.0",
31 | "module-alias": "^2.2.2",
32 | "morgan": "^1.10.0",
33 | "multer": "^1.4.5-lts.1",
34 | "mustache": "^4.2.0",
35 | "mustache-express": "^1.3.2",
36 | "nanoid": "^4.0.0",
37 | "node-cache": "^5.1.2",
38 | "node-gyp": "^9.4.0",
39 | "ntp-time": "^2.0.2",
40 | "os": "^0.1.2",
41 | "passport": "^0.6.0",
42 | "passport-jwt": "^4.0.1",
43 | "pidusage": "^3.0.2",
44 | "qrcode": "^1.5.3",
45 | "serve-favicon": "^2.5.0",
46 | "sharp": "^0.32.6",
47 | "swagger-jsdoc": "^6.0.2",
48 | "swagger-ui-express": "^4.3.0",
49 | "uuid": "^8.3.2",
50 | "validator": "^13.11.0",
51 | "video.js": "^8.6.1",
52 | "winston": "^3.3.3",
53 | "winston-daily-rotate-file": "^4.5.5",
54 | "winston-mongodb": "^5.0.7",
55 | "yaml": "^2.3.1"
56 | },
57 | "optionalDependencies": {
58 | "macadam": "^2.0.18"
59 | },
60 | "devDependencies": {
61 | "nodemon": "^2.0.22",
62 | "swagger-markdown": "^2.3.0"
63 | },
64 | "nodemonConfig": {
65 | "ignore": [
66 | "./public/*",
67 | "./data/*",
68 | "./docs/*"
69 | ]
70 | },
71 | "_moduleAliases": {
72 | "@root": ".",
73 | "@bin": "./bin/",
74 | "@routes": "./routes/",
75 | "@utils": "./utils/",
76 | "@services": "./services/",
77 | "@validators": "./validators/"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/public/fonts/short-baby.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/public/fonts/short-baby.ttf
--------------------------------------------------------------------------------
/public/fonts/swansea-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/public/fonts/swansea-bold.ttf
--------------------------------------------------------------------------------
/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanmccartney/ffmpeg-docker/bce5f16f219694c2fe29d9fce754f018e7d12699/public/images/favicon.ico
--------------------------------------------------------------------------------
/public/js/chart.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | const queryString = window.location.search;
23 | const urlParams = new URLSearchParams(queryString);
24 |
25 | getData();
26 |
27 | async function getData() {
28 | const file = urlParams.get("file");
29 | const frames = [];
30 | const psnr = [];
31 | const vmaf = [];
32 |
33 | const response = await fetch(`/api/vmaf/results/json?file=${file}`);
34 | const data = await response.json();
35 |
36 | const framesData = data.data.frames;
37 | for (let frame of framesData) {
38 | frames.push(frame.frameNum);
39 | psnr.push(frame.metrics.psnr);
40 | vmaf.push(frame.metrics.vmaf);
41 | }
42 |
43 | new Chart("myChart", {
44 | type: "line",
45 | data: {
46 | labels: frames,
47 | datasets: [
48 | {
49 | label: "PSNR",
50 | fill: false,
51 | lineTension: 0,
52 | backgroundColor: "rgba(0,0,255,0.6)",
53 | borderColor: "rgba(0,0,255,0.6)",
54 | pointRadius: 0,
55 | data: psnr,
56 | },
57 | {
58 | label: "VMAF",
59 | fill: false,
60 | lineTension: 0,
61 | backgroundColor: "rgba(255,0,0,0.6)",
62 | borderColor: "rgba(255,0,0,0.6)",
63 | pointRadius: 0,
64 | data: vmaf,
65 | },
66 | ],
67 | },
68 | options: {
69 | plugins: {
70 | legend: {
71 | position: "bottom",
72 | display: true,
73 | },
74 | title: {
75 | display: true,
76 | text: `VMAF Results for ${file}`,
77 | },
78 | },
79 | responsive: true,
80 | scales: {
81 | x: {
82 | display: true,
83 | title: {
84 | display: true,
85 | text: "Frames",
86 | padding: { top: 20, left: 0, right: 0, bottom: 0 },
87 | },
88 | ticks: {
89 | stepSize: 10,
90 | },
91 | },
92 | y: {
93 | display: true,
94 | title: {
95 | display: true,
96 | text: "Percentage (0-100%)",
97 | },
98 | max: 100,
99 | min: 0,
100 | ticks: {
101 | stepSize: 2,
102 | },
103 | padding: { top: 20, left: 0, right: 0, bottom: 0 },
104 | },
105 | },
106 | },
107 | });
108 | }
109 |
--------------------------------------------------------------------------------
/public/js/clock.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | let offset = 0;
23 | getTime();
24 |
25 | function updateClock() {
26 | var now = new Date(new Date() - offset);
27 | var hours = now.getHours();
28 | var minutes = now.getMinutes();
29 | var seconds = now.getSeconds();
30 | var milliseconds = now.getMilliseconds();
31 |
32 | hours = hours.toString().padStart(2, "0");
33 | minutes = minutes.toString().padStart(2, "0");
34 | seconds = seconds.toString().padStart(2, "0");
35 | milliseconds = Math.floor(milliseconds / 100).toString();
36 |
37 | var time = hours + ":" + minutes + ":" + seconds;
38 | var millisecondsText = milliseconds;
39 | document.getElementById("clock").textContent = time;
40 | document.getElementById("milliseconds").textContent = "." + millisecondsText;
41 | }
42 |
43 | async function getTime() {
44 | const startTime = performance.now();
45 | const response = await fetch(`/api/system/time`);
46 | const data = await response.json();
47 | const endTime = performance.now();
48 | const duration = endTime - startTime;
49 |
50 | if (data.data.datatime) {
51 | const serverTime = new Date(new Date(data.data.datatime) - duration);
52 | offset = new Date() - serverTime;
53 |
54 | console.log(`Request toook ${duration}ms`);
55 | console.log(`Server time is ${serverTime}`);
56 | console.log(`Offset time is ${offset}ms`);
57 | document.getElementById("subtitle").textContent = `Synced to ${location.hostname}. Offset is ${offset}ms`;
58 | } else {
59 | document.getElementById("subtitle").textContent = `Could not sync with server. Offset is ${offset}ms`;
60 | }
61 |
62 | setInterval(updateClock, 1); // Update every millisecond
63 | }
64 |
--------------------------------------------------------------------------------
/public/js/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | const gaugeOptions = {
23 | angle: 0, // The span of the gauge arc
24 | lineWidth: 0.44, // The line thickness
25 | radiusScale: 1, // Relative radius
26 | pointer: {
27 | length: 0.6, // // Relative to gauge radius
28 | strokeWidth: 0.035, // The thickness
29 | color: "#000000", // Fill color
30 | },
31 | limitMax: false, // If false, max value increases automatically if value > maxValue
32 | limitMin: false, // If true, the min value of the gauge will be fixed
33 | percentColors: [
34 | [0.25, "#0BD70B"],
35 | [0.5, "#FFB300"],
36 | [1.0, "#FF3300"],
37 | ],
38 | staticLabels: {
39 | font: "10px sans-serif", // Specifies font
40 | labels: [0, 100], // Print labels at these values
41 | color: "#000000", // Optional: Label text color
42 | fractionDigits: 0,
43 | },
44 | strokeColor: "#E0E0E0",
45 | generateGradient: false,
46 | highDpiSupport: true, // High resolution support
47 | };
48 |
49 | const gaugeCpuElement = document.getElementById("gaugeCpu");
50 | const gaugeMemoryElement = document.getElementById("gaugeMemory");
51 | const gaugeDiskElement = document.getElementById("gaugeDisk");
52 |
53 | const textCpuElement = document.getElementById("textCpu");
54 | const textMemoryElement = document.getElementById("textMemory");
55 | const textDiskElement = document.getElementById("textDisk");
56 |
57 | const gaugeCpu = new Gauge(gaugeCpuElement).setOptions(gaugeOptions);
58 | const gaugeMemory = new Gauge(gaugeMemoryElement).setOptions(gaugeOptions);
59 | const gaugeDisk = new Gauge(gaugeDiskElement).setOptions(gaugeOptions);
60 |
61 | gaugeCpu.maxValue = 100;
62 | gaugeCpu.setMinValue(0);
63 | gaugeCpu.set(0);
64 |
65 | gaugeMemory.maxValue = 100;
66 | gaugeMemory.setMinValue(0);
67 | gaugeMemory.set(0);
68 |
69 | gaugeDisk.maxValue = 100;
70 | gaugeDisk.setMinValue(0);
71 | gaugeDisk.set(0);
72 |
73 | const getData = async () => {
74 | const response = await fetch(`/api/system/stats`);
75 | const data = await response.json();
76 |
77 | gaugeCpu.set(data?.load * 100);
78 | gaugeMemory.set(data?.memory?.usage * 100);
79 | gaugeDisk.set(data?.disk?.usage * 100);
80 |
81 | textCpuElement.innerHTML = `${Math.round(data?.load * 100)}%`;
82 | textMemoryElement.innerHTML = `${Math.round(data?.memory?.usage * 100)}% (${Math.round(
83 | (data?.memory?.total - data?.memory?.free) / 1000000000
84 | )}GB / ${Math.round(data?.memory?.total / 1000000000)}GB)`;
85 |
86 | textDiskElement.innerHTML = `${Math.round(data?.disk?.usage * 100)}% (${Math.round(
87 | (data?.disk?.size - data?.disk?.free) / 1000000000
88 | )}GB / ${Math.round(data?.disk?.size / 1000000000)}GB)`;
89 | };
90 |
91 | getData();
92 | const interval = setInterval(getData, 1000);
93 |
--------------------------------------------------------------------------------
/public/js/jobs.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | const table = document.getElementById("jobTable");
23 | let interval;
24 |
25 | getJobs();
26 |
27 | async function killJob(jobId) {
28 | const response = await fetch(`/api/system/job/kill/${jobId}`, {
29 | method: "POST",
30 | });
31 | console.log(`Killed Job ID ${jobId}`);
32 | }
33 |
34 | async function killAll() {
35 | const response = await fetch(`/api/system/job/kill/all`, {
36 | method: "POST",
37 | });
38 | console.log(`Killed all Jobs`);
39 | }
40 |
41 | async function getJobs() {
42 | for (let i = table.rows.length; i >= 1; i--) {
43 | try {
44 | await table.deleteRow(i);
45 | } catch (error) {
46 | console.log(error);
47 | }
48 | }
49 |
50 | const response = await fetch(`/api/system/job/all`);
51 | const data = await response.json();
52 |
53 | for (let [jobId, job] of Object.entries(data?.jobs)) {
54 | const row = await table.insertRow(table.rows.length);
55 |
56 | const cell1 = await row.insertCell(0);
57 | const cell2 = await row.insertCell(1);
58 | const cell3 = await row.insertCell(2);
59 | const cell4 = await row.insertCell(3);
60 | const cell5 = await row.insertCell(4);
61 | const cell6 = await row.insertCell(5);
62 | const cell7 = await row.insertCell(6);
63 | const cell8 = await row.insertCell(7);
64 | const cell9 = await row.insertCell(8);
65 |
66 | // Add some text to the new cells:
67 | cell1.innerHTML = job?.jobNumber || "-";
68 | cell2.innerHTML = job?.jobName || "-";
69 | cell3.innerHTML = job?.jobId || "-";
70 |
71 | for (let tag of job?.type) {
72 | if (tag === "file") {
73 | cell4.innerHTML += `${tag}`;
74 | } else if (tag === "bars") {
75 | cell4.innerHTML += `${tag}`;
76 | } else if (tag === "decklink") {
77 | cell4.innerHTML += `${tag}`;
78 | } else {
79 | cell4.innerHTML += `${tag}`;
80 | }
81 | }
82 |
83 | cell5.innerHTML = job?.started || "-";
84 | cell6.innerHTML = `${Math.round(job?.load?.cpu * 100)}%`;
85 | cell7.innerHTML = job?.progress
86 | ? `
87 | ${job?.progress}%
88 |
`
89 | : "-";
90 | cell8.innerHTML = ``;
91 | cell9.innerHTML = ``;
92 | }
93 | }
94 |
95 | interval = setInterval(getJobs, 2000);
96 |
--------------------------------------------------------------------------------
/public/js/video.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | const queryString = window.location.search;
23 | const urlParams = new URLSearchParams(queryString);
24 | const file = urlParams.get("file");
25 | const filePath = `/api/hls/${file}.m3u8`;
26 |
27 | const options = {
28 | sources: [
29 | {
30 | src: filePath,
31 | type: "application/x-mpegURL",
32 | },
33 | ],
34 | fluid: true,
35 | };
36 |
37 | const player = videojs("video-player", options, function onPlayerReady() {
38 | videojs.log("Video player is ready.");
39 | this.play();
40 | });
41 |
--------------------------------------------------------------------------------
/routes/auth.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const router = require("express").Router();
25 | const { checkSchema, validationResult } = require("express-validator");
26 | const hashResponse = require("@utils/hash-response");
27 | const jwt = require("jsonwebtoken");
28 | const md5 = require("md5");
29 |
30 | const authValidator = require("@validators/auth");
31 |
32 | /**
33 | * @swagger
34 | * /auth/login:
35 | * post:
36 | * description: Authorize user.
37 | * tags: [auth]
38 | * produces:
39 | * - application/json
40 | * parameters:
41 | * - in: formData
42 | * name: username
43 | * type: string
44 | * description: Username for API by default "admin"
45 | * required: false
46 | * - in: formData
47 | * name: password
48 | * type: string
49 | * description: Password for API by default "ffmp3gap1"
50 | * required: false
51 | * responses:
52 | * '200':
53 | * description: Success
54 | */
55 | router.post("/login", checkSchema(authValidator), async (req, res, next) => {
56 | let response = {};
57 | const errors = await validationResult(req);
58 |
59 | if (errors.isEmpty()) {
60 | const user = process.env.AUTH_USER || "admin";
61 | const passwordHash = md5(process.env.AUTH_PASSWORD || "ffmp3gap1");
62 |
63 | if (req.body.username === user && md5(req.body.password) === passwordHash) {
64 | const token = jwt.sign({ id: user }, process.env.AUTH_KEY || "averysecretkey");
65 | response.token = token;
66 | } else {
67 | response.errors = ["Username or password is incorrect"];
68 | }
69 | } else {
70 | response.errors = errors.array();
71 | }
72 |
73 | hashResponse(res, req, { ...response, ...{ status: response.errors ? "error" : "success" } });
74 | });
75 |
76 | module.exports = router;
77 |
--------------------------------------------------------------------------------
/routes/hls.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const router = require("express").Router();
25 | const express = require("express");
26 | const path = require("path");
27 |
28 | /**
29 | * @swagger
30 | * /hls:
31 | * get:
32 | * description: Servers the HLS manifest files.
33 | * tags: [hls]
34 | * produces:
35 | * - application/json
36 | * responses:
37 | * '200':
38 | * description: Success
39 | */
40 | router.use("/", express.static(path.join(__dirname, "..", "data", "hls")));
41 |
42 | module.exports = router;
43 |
--------------------------------------------------------------------------------
/routes/page.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const router = require("express").Router();
25 | const path = require("path");
26 |
27 | /**
28 | * @swagger
29 | * /:
30 | * get:
31 | * description: Index page if web GUI option is enabled
32 | * tags: [page]
33 | * produces:
34 | * - application/json
35 | * responses:
36 | * '200':
37 | * description: Success
38 | */
39 | router.get("/", async (req, res, next) => {
40 | res.render("index", { title: "Home" });
41 | });
42 |
43 | /**
44 | * @swagger
45 | * /clock:
46 | * get:
47 | * description: An HTML page with a live clock showing server time - suitable for latency measurements
48 | * tags: [page]
49 | * produces:
50 | * - application/json
51 | * responses:
52 | * '200':
53 | * description: Success
54 | */
55 | router.get("/clock", async (req, res, next) => {
56 | res.render("clock", { title: "Clock" });
57 | });
58 |
59 | /**
60 | * @swagger
61 | * /jobs:
62 | * get:
63 | * description: An HTML page showing a simple job manager
64 | * tags: [page]
65 | * produces:
66 | * - application/json
67 | * responses:
68 | * '200':
69 | * description: Success
70 | */
71 | router.get("/jobs", async (req, res, next) => {
72 | res.render("jobs", { title: "Jobs" });
73 | });
74 |
75 | /**
76 | * @swagger
77 | * /chart:
78 | * get:
79 | * description: An HTML page showing VMAF test results as a chart
80 | * tags: [page]
81 | * produces:
82 | * - application/json
83 | * responses:
84 | * '200':
85 | * description: Success
86 | */
87 | router.get("/chart", async (req, res, next) => {
88 | res.render("chart", { title: "Chart" });
89 | });
90 |
91 | /**
92 | * @swagger
93 | * /video:
94 | * get:
95 | * description: An HTML page with a video player for hls streams
96 | * tags: [page]
97 | * produces:
98 | * - application/json
99 | * responses:
100 | * '200':
101 | * description: Success
102 | */
103 | router.get("/video", async (req, res, next) => {
104 | res.render("video", { title: "Video" });
105 | });
106 |
107 | module.exports = router;
108 |
--------------------------------------------------------------------------------
/routes/playlist.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const router = require("express").Router();
25 | const { checkSchema, validationResult } = require("express-validator");
26 | const hashResponse = require("@utils/hash-response");
27 | const ffconcat = require("@utils/ffconcat");
28 |
29 | /**
30 | * @swagger
31 | * /playlist/:playlist:
32 | * get:
33 | * description: Get all the items in a playlist
34 | * tags: [files]
35 | * produces:
36 | * - application/json
37 | * responses:
38 | * '200':
39 | * description: Success
40 | */
41 | router.get("/:playlist", async (req, res, next) => {
42 | const response = await ffconcat.getItems(req.params.playlist);
43 | hashResponse(res, req, { ...response, ...{ status: response.error ? "error" : "success" } });
44 | });
45 |
46 | /**
47 | * @swagger
48 | * /playlist/:playlist:
49 | * post:
50 | * description: Set all the items in a playlist
51 | * tags: [files]
52 | * produces:
53 | * - application/json
54 | * responses:
55 | * '200':
56 | * description: Success
57 | */
58 | router.post("/:playlist", async (req, res, next) => {
59 | const response = await ffconcat.set(req.params.playlist, req.body.items);
60 | hashResponse(res, req, { ...response, ...{ status: response.error ? "error" : "success" } });
61 | });
62 |
63 | /**
64 | * @swagger
65 | * /playlist/:playlist/add:
66 | * post:
67 | * description: Add a single file to the playlist.
68 | * tags: [files]
69 | * produces:
70 | * - application/json
71 | * responses:
72 | * '200':
73 | * description: Success
74 | */
75 | router.post("/:playlist/add", async (req, res, next) => {
76 | const response = await ffconcat.add(req.params.playlist, req.body.item);
77 | hashResponse(res, req, { ...response, ...{ status: response.error ? "error" : "success" } });
78 | });
79 |
80 | /**
81 | * @swagger
82 | * /playlist/:playlist/remove:
83 | * post:
84 | * description: Add a single file to the playlist.
85 | * tags: [files]
86 | * produces:
87 | * - application/json
88 | * responses:
89 | * '200':
90 | * description: Success
91 | */
92 | router.post("/:playlist/remove", async (req, res, next) => {
93 | const response = await ffconcat.remove(req.params.playlist, req.body.item);
94 | hashResponse(res, req, { ...response, ...{ status: response.error ? "error" : "success" } });
95 | });
96 |
97 | module.exports = router;
98 |
--------------------------------------------------------------------------------
/routes/rtp.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const router = require("express").Router();
25 | const { checkSchema, validationResult } = require("express-validator");
26 | const hashResponse = require("@utils/hash-response");
27 |
28 | const rtpFile = require("@services/rtp-file");
29 | const rtpDecklink = require("@services/rtp-decklink");
30 |
31 | const overlayValidator = require("@validators/overlay");
32 | const thumbnailValidator = require("@validators/thumbnail");
33 | const decklinkValidator = require("@validators/decklink");
34 | const fileValidator = require("@validators/file");
35 | const rtpValidator = require("@validators/rtp");
36 |
37 | /**
38 | * @swagger
39 | * /rtp/file:
40 | * post:
41 | * description: Takes an RTP input and turns it into a file.
42 | * tags: [rtp]
43 | * produces:
44 | * - application/json
45 | * responses:
46 | * '200':
47 | * description: Success
48 | */
49 | router.post(
50 | "/file",
51 | checkSchema({
52 | ...rtpValidator("input"),
53 | ...fileValidator("output"),
54 | ...thumbnailValidator(),
55 | ...overlayValidator(),
56 | }),
57 | async (req, res, next) => {
58 | let response = {};
59 | const errors = await validationResult(req);
60 |
61 | if (errors.isEmpty()) {
62 | response = await rtpFile(req.body);
63 | } else {
64 | response.errors = errors.array();
65 | }
66 |
67 | hashResponse(res, req, { ...response, ...{ status: response.errors ? "error" : "success" } });
68 | }
69 | );
70 |
71 | /**
72 | * @swagger
73 | * /rtp/decklink:
74 | * post:
75 | * description: Takes an RTP input and outputs it to a decklink card.
76 | * tags: [rtp]
77 | * produces:
78 | * - application/json
79 | * responses:
80 | * '200':
81 | * description: Success
82 | */
83 | router.post(
84 | "/decklink",
85 | checkSchema({
86 | ...rtpValidator("input"),
87 | ...decklinkValidator("output"),
88 | ...thumbnailValidator(),
89 | ...overlayValidator(),
90 | }),
91 | async (req, res, next) => {
92 | let response = {};
93 | const errors = await validationResult(req);
94 |
95 | if (errors.isEmpty()) {
96 | response = await rtpDecklink(req.body);
97 | } else {
98 | response.errors = errors.array();
99 | }
100 |
101 | hashResponse(res, req, { ...response, ...{ status: response.errors ? "error" : "success" } });
102 | }
103 | );
104 |
105 | module.exports = router;
106 |
--------------------------------------------------------------------------------
/routes/srt.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const router = require("express").Router();
25 | const { checkSchema, validationResult } = require("express-validator");
26 | const hashResponse = require("@utils/hash-response");
27 |
28 | const srtFile = require("@services/srt-file");
29 | const srtDecklink = require("@services/srt-decklink");
30 |
31 | const overlayValidator = require("@validators/overlay");
32 | const thumbnailValidator = require("@validators/thumbnail");
33 | const decklinkValidator = require("@validators/decklink");
34 | const fileValidator = require("@validators/file");
35 | const srtValidator = require("@validators/srt");
36 |
37 | /**
38 | * @swagger
39 | * /srt/file:
40 | * post:
41 | * description: Takes an SRT input and turns it into a file.
42 | * tags: [srt]
43 | * produces:
44 | * - application/json
45 | * responses:
46 | * '200':
47 | * description: Success
48 | */
49 | router.post(
50 | "/file",
51 | checkSchema({
52 | ...srtValidator("input"),
53 | ...fileValidator("output"),
54 | ...thumbnailValidator(),
55 | ...overlayValidator(),
56 | }),
57 | async (req, res, next) => {
58 | let response = {};
59 | const errors = await validationResult(req);
60 |
61 | if (errors.isEmpty()) {
62 | response = await srtFile(req.body);
63 | } else {
64 | response.errors = errors.array();
65 | }
66 |
67 | hashResponse(res, req, { ...response, ...{ status: response.errors ? "error" : "success" } });
68 | }
69 | );
70 |
71 | /**
72 | * @swagger
73 | * /srt/decklink:
74 | * post:
75 | * description: Takes an SRT input and outputs it to a decklink card.
76 | * tags: [srt]
77 | * produces:
78 | * - application/json
79 | * responses:
80 | * '200':
81 | * description: Success
82 | */
83 | router.post(
84 | "/decklink",
85 | checkSchema({
86 | ...srtValidator("input"),
87 | ...decklinkValidator("output"),
88 | ...thumbnailValidator(),
89 | ...overlayValidator(),
90 | }),
91 | async (req, res, next) => {
92 | let response = {};
93 | const errors = await validationResult(req);
94 |
95 | if (errors.isEmpty()) {
96 | response = await srtDecklink(req.body);
97 | } else {
98 | response.errors = errors.array();
99 | }
100 |
101 | hashResponse(res, req, { ...response, ...{ status: response.errors ? "error" : "success" } });
102 | }
103 | );
104 |
105 | module.exports = router;
106 |
--------------------------------------------------------------------------------
/routes/udp.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const router = require("express").Router();
25 | const { checkSchema, validationResult } = require("express-validator");
26 | const hashResponse = require("@utils/hash-response");
27 |
28 | const udpDecklink = require("@services/udp-decklink");
29 | const udpFile = require("@services/udp-file");
30 |
31 | const overlayValidator = require("@validators/overlay");
32 | const thumbnailValidator = require("@validators/thumbnail");
33 | const decklinkValidator = require("@validators/decklink");
34 | const fileValidator = require("@validators/file");
35 | const udpValidator = require("@validators/udp");
36 |
37 | /**
38 | * @swagger
39 | * /udp/decklink:
40 | * post:
41 | * description: Takes an UDP input and outputs it to a decklink card.
42 | * tags: [udp]
43 | * produces:
44 | * - application/json
45 | * responses:
46 | * '200':
47 | * description: Success
48 | */
49 | router.post(
50 | "/decklink",
51 | checkSchema({
52 | ...udpValidator("input"),
53 | ...decklinkValidator("output"),
54 | ...thumbnailValidator(),
55 | ...overlayValidator(),
56 | }),
57 | async (req, res, next) => {
58 | let response = {};
59 | const errors = await validationResult(req);
60 |
61 | if (errors.isEmpty()) {
62 | response = await udpDecklink(req.body);
63 | } else {
64 | response.errors = errors.array();
65 | }
66 |
67 | hashResponse(res, req, { ...response, ...{ status: response.errors ? "error" : "success" } });
68 | }
69 | );
70 |
71 | /**
72 | * @swagger
73 | * /udp/file:
74 | * post:
75 | * description: Takes an UDP input and outputs it to a file.
76 | * tags: [udp]
77 | * produces:
78 | * - application/json
79 | * responses:
80 | * '200':
81 | * description: Success
82 | */
83 | router.post(
84 | "/file",
85 | checkSchema({
86 | ...udpValidator("input"),
87 | ...fileValidator("output"),
88 | ...thumbnailValidator(),
89 | ...overlayValidator(),
90 | }),
91 | async (req, res, next) => {
92 | let response = {};
93 | const errors = await validationResult(req);
94 |
95 | if (errors.isEmpty()) {
96 | response = await udpFile(req.body);
97 | } else {
98 | response.errors = errors.array();
99 | }
100 |
101 | hashResponse(res, req, { ...response, ...{ status: response.errors ? "error" : "success" } });
102 | }
103 | );
104 |
105 | module.exports = router;
106 |
--------------------------------------------------------------------------------
/services/bars-decklink.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const ffmpeg = require("fluent-ffmpeg");
26 | const path = require("path");
27 | const filterCombine = require("@utils/filter-combine");
28 | const filterText = require("@utils/filter-text");
29 | const filterImage = require("@utils/filter-image");
30 | const jobManager = require("@utils/jobManager");
31 |
32 | const process = async (options) => {
33 | const response = { options: options };
34 |
35 | ffmpeg.setFfmpegPath("/root/bin/ffmpeg");
36 |
37 | try {
38 | const job = jobManager.start(`${options?.output?.cardName}-out`, `Bars to ${options?.output?.cardName}`, [
39 | "bars",
40 | "decklink",
41 | ]);
42 |
43 | const filters = await filterCombine(await filterText({ ...options, ...job }));
44 |
45 | let command = ffmpeg({ logger: logger })
46 | .addInput(`${options.input?.type || "smptehdbars"}=rate=25:size=1920x1080`)
47 | .inputOptions(["-re", "-f lavfi"])
48 | .addInput(`sine=frequency=${options.input?.frequency || 1000}:sample_rate=48000`)
49 | .inputOptions(["-f lavfi"])
50 | .outputOptions([
51 | "-pix_fmt uyvy422",
52 | "-s 1920x1080",
53 | "-ac 16",
54 | "-f decklink",
55 | `-af volume=${options?.output?.volume || 0.25}`,
56 | "-flags low_delay",
57 | "-bufsize 0",
58 | "-muxdelay 0",
59 | ])
60 | .output(options.output?.cardName);
61 |
62 | if (Array.isArray(filters)) {
63 | command.videoFilters(filters);
64 | }
65 |
66 | if (options?.thumbnail !== false) {
67 | command
68 | .output(path.join(__dirname, "..", "data", "thumbnail", `${job?.jobId}.png`))
69 | .outputOptions([`-r ${options?.thumbnail?.frequency || 1}`, "-update 1"]);
70 |
71 | if (Array.isArray(filters)) {
72 | command.videoFilters(filters);
73 | }
74 | }
75 |
76 | command.on("end", () => {
77 | logger.info("Finished processing");
78 | jobManager.end(job?.jobId, false);
79 | });
80 |
81 | command.on("start", (commandString) => {
82 | logger.debug(`Spawned FFmpeg with command: ${commandString}`);
83 | response.job = jobManager.update(job?.jobId, {
84 | command: commandString,
85 | pid: command.ffmpegProc.pid,
86 | options: options,
87 | });
88 | return response;
89 | });
90 |
91 | command.on("stderr", (stderrLine) => {
92 | logger.info("ffmpeg: " + stderrLine);
93 | });
94 |
95 | command.on("error", (error) => {
96 | logger.error(error);
97 | jobManager.end(job?.jobId, false);
98 | });
99 |
100 | command.run();
101 | } catch (error) {
102 | logger.error(error.message);
103 | response.errors = [error];
104 | }
105 |
106 | response.job = await jobManager.get(`${options?.output?.cardName}-out`);
107 | return response;
108 | };
109 |
110 | module.exports = process;
111 |
--------------------------------------------------------------------------------
/services/decklink-config-get.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | const logger = require("@utils/logger")(module);
23 | const os = require("os");
24 |
25 | module.exports = async () => {
26 | if (os.arch() === "x64" && os.platform() === "linux") {
27 | const os = require("os");
28 | const macadam = require("macadam");
29 | const deviceInfo = await macadam.getDeviceInfo();
30 | return { devices: deviceInfo };
31 | } else {
32 | logger.error(`Invalid Architecture - this command is not supported on ${os.platform()}-${os.arch()}`);
33 | return {
34 | error: "Invalid Architecture - this command is not supported on your system architecture",
35 | arch: os.arch(),
36 | platform: os.platform(),
37 | };
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/services/decklink-config-set.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | const logger = require("@utils/logger")(module);
23 | const os = require("os");
24 |
25 | module.exports = async (options) => {
26 | if (os.arch() === "x64" && os.platform() === "linux") {
27 | const macadam = require("macadam");
28 | let status;
29 | try {
30 | status = await macadam.setDeviceConfig({
31 | deviceIndex: parseInt(options?.cardIndex || 0),
32 | duplexMode: macadam.bmdDuplexModeFull,
33 | });
34 | } catch (error) {
35 | status = false;
36 | logger.warn(error);
37 | }
38 | return status;
39 | } else {
40 | logger.error(`Invalid Architecture - this command is not supported on ${os.arch()}`);
41 | return {
42 | error: "Invalid Architecture - this command is not supported on your system architecture",
43 | arch: os.arch(),
44 | };
45 | }
46 | };
47 |
--------------------------------------------------------------------------------
/services/file-list.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const path = require("path");
26 | const fs = require("fs");
27 | const util = require("util");
28 |
29 | const readdir = util.promisify(fs.readdir);
30 |
31 | module.exports = async (options) => {
32 | try {
33 | const directoryPath = path.join(process.cwd(), "data", "media");
34 | const files = await readdir(directoryPath, { withFileTypes: options?.extensions || true });
35 | const filesDetail = [];
36 |
37 | for (let file of files) {
38 | if (file.name !== ".gitkeep") {
39 | const stat = await fs.promises.stat(path.join(directoryPath, file.name));
40 | filesDetail.push({
41 | name: file.name,
42 | size: stat.size,
43 | ctime: stat.ctime,
44 | });
45 | }
46 | }
47 |
48 | return { files: filesDetail };
49 | } catch (error) {
50 | logger.warn(`Cannot list files ${error.message}`);
51 | return { errors: [error] };
52 | }
53 | };
54 |
--------------------------------------------------------------------------------
/services/file-metadata.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const util = require("util");
26 | const ffmpeg = require("fluent-ffmpeg");
27 | const path = require("path");
28 |
29 | module.exports = async (file) => {
30 | ffmpeg.setFfmpegPath("/root/bin/ffmpeg");
31 | try {
32 | const ffprobe = util.promisify(ffmpeg.ffprobe);
33 | const metadata = await ffprobe(path.join(__dirname, "..", "data", "media", file));
34 | return { data: metadata };
35 | } catch (error) {
36 | logger.warn("Cannot probe media " + error.message);
37 | return { errors: [error] };
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/services/system-info.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const path = require("path");
26 | const os = require("os");
27 | const fileReadJson = require("@utils/file-read-json");
28 | const fileRead = require("@utils/file-read");
29 | const ffmpegCodecs = require("@utils/ffmpeg-getcodecs");
30 | const gitCommit = require("@utils/git-commit");
31 | const nodeVersion = require("@utils/node-version");
32 | const osVersion = require("@utils/os-version");
33 | const decklinkVersion = require("@utils/decklink-version");
34 |
35 | module.exports = async () => {
36 | try {
37 | const packageJson = await fileReadJson(path.join(__dirname, "..", "package.json"));
38 | return {
39 | time: new Date(),
40 | platform: os.platform(),
41 | uptime: os.uptime(),
42 | decklink: await decklinkVersion(),
43 | os: await osVersion(),
44 | ffmpeg: {
45 | commit: await gitCommit(path.resolve("/", "ffmpeg_sources", "ffmpeg")),
46 | version: await fileRead(path.resolve("/", "ffmpeg_sources", "ffmpeg", "RELEASE")),
47 | codecs: await ffmpegCodecs(),
48 | },
49 | package: {
50 | commit: await gitCommit(path.resolve("/", "home", "node", "app")),
51 | version: packageJson?.version,
52 | name: packageJson?.name,
53 | author: packageJson?.author,
54 | description: packageJson?.description,
55 | license: packageJson?.license,
56 | node: await nodeVersion(),
57 | },
58 | };
59 | } catch (error) {
60 | return { error: error.toString() };
61 | }
62 | };
63 |
--------------------------------------------------------------------------------
/services/system-job-get.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const jobManager = require("@utils/jobManager");
26 |
27 | module.exports = async (jobId) => {
28 | try {
29 | const job = jobManager.getbyId(jobId);
30 | return job;
31 | } catch (error) {
32 | logger.warn(error.message);
33 | return { error: error.toString() };
34 | }
35 | };
36 |
--------------------------------------------------------------------------------
/services/system-job-getall.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const jobManager = require("@utils/jobManager");
26 |
27 | module.exports = async () => {
28 | try {
29 | const jobs = await jobManager.getAll();
30 | return { jobs: jobs };
31 | } catch (error) {
32 | logger.warn(error.message);
33 | return { error: error.toString() };
34 | }
35 | };
36 |
--------------------------------------------------------------------------------
/services/system-job-getthumbnail.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const sharp = require("sharp");
26 | const path = require("path");
27 | const thumbnailCache = require("@utils/thumbnail-cache");
28 |
29 | module.exports = async (jobId, resize = 0.2) => {
30 | try {
31 | const resizedThumbnail = await sharp(path.join(__dirname, "..", "data", "thumbnail", `${jobId}.png`))
32 | .resize(parseInt(1920 * resize), parseInt(1080 * resize))
33 | .png()
34 | .toBuffer();
35 |
36 | await thumbnailCache.set(jobId, resizedThumbnail);
37 |
38 | return `data:image/png;base64,${resizedThumbnail.toString("base64")}`;
39 | } catch (error) {
40 | let fallbackThumbnail = await thumbnailCache.get(jobId);
41 |
42 | if (!fallbackThumbnail) {
43 | fallbackThumbnail = await sharp({
44 | create: {
45 | width: 48,
46 | height: 48,
47 | channels: 3,
48 | background: { r: 0, g: 0, b: 0 },
49 | },
50 | })
51 | .resize(parseInt(1920 * resize), parseInt(1080 * resize))
52 | .png()
53 | .toBuffer();
54 | }
55 |
56 | return `data:image/png;base64,${fallbackThumbnail.toString("base64")}`;
57 | }
58 | };
59 |
--------------------------------------------------------------------------------
/services/system-job-kill.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const jobManager = require("@utils/jobManager");
26 |
27 | module.exports = async (jobId) => {
28 | try {
29 | logger.info(`Killing job ${jobId}`);
30 | const job = jobManager.end(jobId);
31 | return job;
32 | } catch (error) {
33 | logger.warn("Cannot kill job. " + error.message);
34 | return { error: error.toString() };
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/services/system-job-killall.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const jobManager = require("@utils/jobManager");
26 |
27 | module.exports = async () => {
28 | try {
29 | const jobs = jobManager.getAll();
30 |
31 | for (let [jobId, job] of Object.entries(jobs)) {
32 | logger.info(`Killing job ${job?.jobId}`);
33 | jobManager.end(job?.jobId);
34 | }
35 |
36 | return jobs;
37 | } catch (error) {
38 | logger.warn(error.message);
39 | return { error: error.toString() };
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/services/system-stats.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const checkDiskSpace = require("check-disk-space").default;
26 | const os = require("os");
27 | const jobLoad = require("@utils/job-load");
28 | const path = require("path");
29 |
30 | const interval = 1000;
31 | let load = 0;
32 | let cpus = {};
33 | let cpusPrevious = os.cpus();
34 | let jobs = {};
35 |
36 | setInterval(async () => {
37 | try {
38 | cpus = os.cpus();
39 | let loadTotal = 0;
40 | jobs = await jobLoad();
41 |
42 | for (let i in cpus) {
43 | const usagePrevious = cpusPrevious[i].times?.user + cpusPrevious[i].times?.sys + cpusPrevious[i].times?.irq;
44 | const usage = cpus[i].times?.user + cpus[i].times?.sys + cpus[i].times?.irq;
45 |
46 | const load = (usage - usagePrevious) / interval;
47 | cpus[i].load = Math.round(load * 100) / 100;
48 |
49 | loadTotal += load;
50 | }
51 |
52 | load = Math.round((loadTotal / cpus.length) * 100) / 100;
53 | cpusPrevious = cpus;
54 | } catch (error) {}
55 | }, interval);
56 |
57 | module.exports = async () => {
58 | try {
59 | const disk = await checkDiskSpace(process.env.MEDIA_PATH || path.join(__dirname, "..", "data", "media"));
60 | disk.usage = (disk.size - disk.free) / disk.size;
61 | disk.usage = Math.round(disk.usage * 100) / 100;
62 |
63 | return {
64 | time: new Date(),
65 | cores: cpus.length,
66 | load: load,
67 | cpu: cpus,
68 | env: process.env,
69 | jobs: jobs,
70 | memory: {
71 | total: os.totalmem(),
72 | free: os.freemem(),
73 | usage: Math.round(((os.totalmem - os.freemem()) / os.totalmem) * 100) / 100,
74 | },
75 | network: os.networkInterfaces(),
76 | platform: os.platform(),
77 | uptime: os.uptime(),
78 | disk: disk,
79 | };
80 | } catch (error) {
81 | return { error: error.toString() };
82 | }
83 | };
84 |
--------------------------------------------------------------------------------
/services/system-time-set.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const NTP = require("ntp-time").Client;
26 |
27 | module.exports = async (ntpServer = "uk.pool.ntp.org") => {
28 | try {
29 | const client = new NTP(ntpServer, 123, { timeout: 5000 });
30 | await client.syncTime();
31 | return { data: client };
32 | } catch (error) {
33 | logger.warn("Cannot probe media " + error.message);
34 | return { error: error.toString() };
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/services/vmaf-models-get.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const getFilenames = require("@utils/filenames-get");
26 |
27 | module.exports = async () => {
28 | try {
29 | const data = await getFilenames("/ffmpeg_sources/vmaf/model");
30 | return { data: data };
31 | } catch (error) {
32 | logger.warn("Cannot probe media " + error.message);
33 | return { error: error.toString() };
34 | }
35 | };
36 |
--------------------------------------------------------------------------------
/services/vmaf-results-csv.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const path = require("path");
26 | const fs = require("fs");
27 | const vmafJsonCsv = require("@utils/vmaf-json-csv");
28 |
29 | const get = async (filePath) => {
30 | try {
31 | const contents = await fs.readFileSync(filePath);
32 | return contents.toString();
33 | } catch (error) {
34 | logger.warn(error);
35 | return false;
36 | }
37 | };
38 |
39 | module.exports = async (filename) => {
40 | let csvData = false;
41 |
42 | try {
43 | const dataString = await get(path.join(__dirname, "..", "data", "vmaf", filename));
44 | const jsonData = JSON.parse(dataString);
45 | csvData = await vmafJsonCsv(jsonData);
46 | } catch (error) {
47 | logger.warn(error);
48 | }
49 |
50 | return csvData;
51 | };
52 |
--------------------------------------------------------------------------------
/services/vmaf-results-json.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const path = require("path");
26 | const fs = require("fs");
27 |
28 | const get = async (filePath) => {
29 | try {
30 | const contents = await fs.readFileSync(filePath);
31 | return contents.toString();
32 | } catch (error) {
33 | logger.warn(error);
34 | return false;
35 | }
36 | };
37 |
38 | module.exports = async (filename) => {
39 | let data = false;
40 |
41 | try {
42 | const dataString = await get(path.join(__dirname, "..", "data", "vmaf", filename));
43 | data = JSON.parse(dataString);
44 | } catch (error) {
45 | logger.warn(error);
46 | }
47 |
48 | return data;
49 | };
50 |
--------------------------------------------------------------------------------
/services/zz-decklink-pause.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const ffmpeg = require("fluent-ffmpeg");
26 | const path = require("path");
27 | const filterCombine = require("@utils/filter-combine");
28 | const filterText = require("@utils/filter-text");
29 | const filterImage = require("@utils/filter-image");
30 |
31 | let command;
32 |
33 | //ffmpeg -ss 00:00:10 -i input.mp4 -vf "select='eq(n,0)',setpts=N/FRAME_RATE/TB" -r 25 -f decklink 'Decklink Output'
34 |
35 | module.exports = async (cardIndex, options) => {
36 | let status = true;
37 | let repeat = "";
38 | ffmpeg.setFfmpegPath("/root/bin/ffmpeg");
39 |
40 | const filters = await filterCombine(await filterText({ ...options, ...job }));
41 |
42 | if (options?.input?.repeat) {
43 | repeat = "-stream_loop -1";
44 | }
45 |
46 | if (command) {
47 | logger.info("Killing already running FFmpeg process");
48 | await command.kill();
49 | }
50 | command = ffmpeg({ logger: logger })
51 | .input(`${path.join(__dirname, "..", "data", "media", options.file)}`)
52 | .seekInput(options.timestamp)
53 | .complexFilter([
54 | {
55 | filter: "split",
56 | options: "2",
57 | outputs: ["selected", "dummy"],
58 | },
59 | {
60 | filter: "trim",
61 | options: "start_frame=0:end_frame=0",
62 | inputs: "selected",
63 | outputs: "output",
64 | },
65 | {
66 | filter: "setpts",
67 | options: "PTS-STARTPTS",
68 | inputs: "output",
69 | },
70 | ])
71 | // .inputOptions([`-re`,repeat])
72 | // .outputOptions(["-pix_fmt uyvy422","-s 1920x1080","-ac 2","-f decklink"])
73 | .output(options.cardName)
74 | .outputOptions(["-r 25", "-f decklink", "-format_code 8", "-pix_fmt uyvy422"]);
75 | //.outputOptions(["-pix_fmt uyvy422","-s 1920x1080","-ac 2","-f decklink"]);
76 |
77 | if (Array.isArray(filters)) {
78 | command.videoFilters(filters);
79 | }
80 |
81 | command.on("end", () => {
82 | logger.info("Finished playing file");
83 | });
84 |
85 | command.on("error", () => {
86 | logger.info("FFmpeg process killed");
87 | });
88 |
89 | command.on("start", (commandString) => {
90 | logger.debug(`Spawned FFmpeg with command: ${commandString}`);
91 | return { options: options, command: commandString };
92 | });
93 |
94 | command.on("progress", (progress) => {
95 | logger.info("ffmpeg-progress: " + Math.floor(progress.percent) + "% done");
96 | });
97 |
98 | command.on("stderr", (stderrLine) => {
99 | logger.info("ffmpeg: " + stderrLine);
100 | });
101 |
102 | try {
103 | command.run();
104 | } catch (error) {
105 | logger.warn(error);
106 | status = "false";
107 | }
108 |
109 | return { error: status, options: options };
110 | };
111 |
--------------------------------------------------------------------------------
/services/zz-decklink-stop.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const ffmpeg = require("fluent-ffmpeg");
26 | const path = require("path");
27 |
28 | let command;
29 |
30 | module.exports = async (cardIndex, options) => {
31 | logger.info(`Stopping the output on Decklink Device ${cardIndex}.`);
32 | let status = true;
33 | ffmpeg.setFfmpegPath("/root/bin/ffmpeg");
34 |
35 | command = ffmpeg({ logger: logger });
36 | command.kill();
37 |
38 | command.on("error", () => {
39 | logger.info("FFmpeg process killed");
40 | });
41 |
42 | command.on("stderr", (stderrLine) => {
43 | logger.debug("Stderr output: " + stderrLine);
44 | });
45 |
46 | return { error: status, options: options };
47 | };
48 |
--------------------------------------------------------------------------------
/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #
4 | # FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
5 | # Copyright (C) 2022 Ryan McCartney
6 | #
7 | # This file is part of the FFmpeg Docker (ffmpeg-docker).
8 | #
9 | # FFmpeg Docker is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # This program is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with this program. If not, see .
21 | #
22 |
23 | # Install host dependencies for BMD Decklink
24 |
25 | echo Input the URL for Blackmagic Video Driver URL:
26 | read DEKSTOP_VIDEO_DRIVER_URL
27 |
28 | echo Input the Version for Blackmagic Video Driver:
29 | read DESKTOP_VIDEO_DRIVER_VERSION
30 |
31 | echo Input the Name of the .deb frole for the Blackmagic Video Driver:
32 | read DESKTOP_VIDEO_DRIVER_DEB
33 |
34 | apt update
35 | apt install -y wget dkms dctrl-tools
36 | apt autoremove -y
37 |
38 | #Download and extract
39 | wget -O "desktop-video-driver.tar.gz" "$DEKSTOP_VIDEO_DRIVER_URL"
40 | tar -xvf desktop-video-driver.tar.gz
41 |
42 | #Get .deb name and location
43 | SEARCH_DIR="./Blackmagic_Desktop_Video_Linux_$DESKTOP_VIDEO_DRIVER_VERSION/deb/x86_64/"
44 | echo "Searching for driver in $SEARCH_DIR"
45 |
46 | for FILE in "$SEARCH_DIR"/*
47 | do
48 | echo "$FILE"
49 | if [[ $FILE == *"desktopvideo_"* ]]; then
50 | echo "Found Desktop Video Drivers"
51 | DESKTOP_VIDEO_DRIVER_DEB=$FILE
52 | fi
53 | done
54 |
55 | #Install the .deb
56 | echo "Installing driver from $DESKTOP_VIDEO_DRIVER_DEB"
57 | dpkg --install $DESKTOP_VIDEO_DRIVER_DEB | true
58 | apt install -f -y
59 | dpkg --install $DESKTOP_VIDEO_DRIVER_DEB || true &&\
60 |
61 | #Cleanup files and folder
62 | rm -r "./Blackmagic_Desktop_Video_Linux_$DESKTOP_VIDEO_DRIVER_VERSION"
63 | rm "desktop-video-driver.tar.gz"
64 |
65 | #Get the firmware info and update if needed
66 | DesktopVideoUpdateTool --list
67 | DesktopVideoUpdateTool --update --all
--------------------------------------------------------------------------------
/utils/barsTypes.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | //https://ffmpeg.org/ffmpeg-filters.html#allrgb_002c-allyuv_002c-color_002c-colorchart_002c-colorspectrum_002c-haldclutsrc_002c-nullsrc_002c-pal75bars_002c-pal100bars_002c-rgbtestsrc_002c-smptebars_002c-smptehdbars_002c-testsrc_002c-testsrc2_002c-yuvtestsrc
25 | module.exports = [
26 | "smptehdbars",
27 | "smptebars",
28 | "rgbtestsrc",
29 | "pal100bars",
30 | "pal75bars",
31 | "pal100bars",
32 | "colorchart",
33 | "testsrc",
34 | "testsrc2",
35 | "yuvtestsrc",
36 | "allrgb",
37 | "allyuv",
38 | ];
39 |
--------------------------------------------------------------------------------
/utils/decklink-version.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const { execSync } = require("child_process");
25 | const { version } = require("os");
26 |
27 | module.exports = async () => {
28 | let decklinkObject = {};
29 | const decklink = await execSync(`dpkg -l | grep -i blackmagic`).toString().trim();
30 |
31 | if (decklink) {
32 | const items = decklink.split(" ");
33 | decklinkObject.version = items[2].trim();
34 | decklinkObject.arch = items[5].trim();
35 | decklinkObject.name = items[6].trim();
36 | }
37 |
38 | return decklinkObject;
39 | };
40 |
--------------------------------------------------------------------------------
/utils/decklinkFormats.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = [
25 | {
26 | rawFormat: "auto",
27 | description:
28 | "This is the default which means 8-bit YUV 422 or 8-bit ARGB if format autodetection is used, 8-bit YUV 422 otherwise.",
29 | },
30 | {
31 | rawFormat: "uyvy422",
32 | description: "8-bit YUV 422",
33 | },
34 | {
35 | rawFormat: "yuv422p10",
36 | description: "10-bit YUV 422",
37 | },
38 | {
39 | rawFormat: "argb",
40 | description: "8-bit RGB",
41 | },
42 | {
43 | rawFormat: "bgra",
44 | description: "8-bit RGB",
45 | },
46 | {
47 | rawFormat: "rgb10",
48 | description: "10-bit RGB",
49 | },
50 | ];
51 |
--------------------------------------------------------------------------------
/utils/documentation.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const express = require("express");
25 | const documentation = express.Router();
26 |
27 | const swaggerUi = require("swagger-ui-express");
28 | const swaggerJSDoc = require("swagger-jsdoc");
29 |
30 | const host = process.env.HOST || "localhost";
31 | const port = process.env.PORT || "80";
32 | const url = `http://${host}:${port}/api/`;
33 |
34 | const swaggerOptions = {
35 | definition: {
36 | openapi: "3.0.0",
37 | info: {
38 | title: "FFmpeg Docker API",
39 | version: "0.1.0",
40 | description: "Common FFmpeg functions from a RESTful API",
41 | license: {
42 | name: "GPLv3",
43 | url: "https://www.gnu.org/licenses/gpl-3.0.en.html",
44 | },
45 | contact: {
46 | name: "Ryan McCartney",
47 | url: "https://ryan.mccartney.info/ffmpeg-docker",
48 | email: "ryan@mccartney.info",
49 | },
50 | },
51 | servers: [
52 | {
53 | url: url,
54 | },
55 | ],
56 | },
57 | apis: ["./routes/*.js", "./modules/*.js"],
58 | };
59 |
60 | const swaggerDocs = swaggerJSDoc(swaggerOptions);
61 | documentation.use("/", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
62 |
63 | module.exports = documentation;
64 |
--------------------------------------------------------------------------------
/utils/encodePresets.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = ["ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow"];
25 |
--------------------------------------------------------------------------------
/utils/ffconcat.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const fs = require("fs");
25 | const path = require("path");
26 | const logger = require("@utils/logger")(module);
27 |
28 | const parse = async (data) => {
29 | try {
30 | const lines = data.split("\n");
31 | const items = [];
32 | for (let line of lines) {
33 | if (line && line[0] !== "#") {
34 | const lineParts = line.split("/");
35 | items.push(lineParts[lineParts.length - 1]);
36 | }
37 | }
38 | return items;
39 | } catch (error) {
40 | logger.warn(error);
41 | return false;
42 | }
43 | };
44 |
45 | const get = async (playlist = "playlist") => {
46 | try {
47 | const playlistFilePath = path.join(__dirname, "..", "data", "playlist", `${playlist}.ffconcat`);
48 | const contents = await fs.readFileSync(playlistFilePath);
49 | return contents.toString();
50 | } catch (error) {
51 | logger.warn(error);
52 | return false;
53 | }
54 | };
55 |
56 | const set = async (playlist = "playlist", items = []) => {
57 | try {
58 | const playlistFilePath = path.join(__dirname, "..", "data", "playlist", `${playlist}.ffconcat`);
59 | let data = `# Playlist Name: ${playlist}.ffconcat`;
60 |
61 | for (let item of items) {
62 | data += `\n\n# File Name: ${item}\n${path.join(__dirname, "..", "data", "media", item)}`;
63 | }
64 |
65 | await fs.writeFileSync(playlistFilePath, data);
66 |
67 | return { data: { raw: data, items: items } };
68 | } catch (error) {
69 | logger.warn(error);
70 | return false;
71 | }
72 | };
73 |
74 | const add = async (playlist = "playlist", item) => {
75 | try {
76 | let data = await get(playlist);
77 |
78 | if (item) {
79 | data += `\n\n# File Name: ${item}\n${path.join(__dirname, "..", "data", "media", item)}`;
80 | }
81 |
82 | const items = await parse(data);
83 | const setData = await set(playlist, items);
84 |
85 | return { data: { raw: data, items: items } };
86 | } catch (error) {
87 | logger.warn(error);
88 | return false;
89 | }
90 | };
91 |
92 | const remove = async (playlist = "playlist", item) => {
93 | try {
94 | const itemPath = path.join(__dirname, "..", "data", "media", item);
95 | const data = await get(playlist);
96 | const lines = data.split("\n");
97 | const items = [];
98 |
99 | for (let line of lines) {
100 | if (line && line[0] !== "#" && line !== itemPath) {
101 | const lineParts = line.split("/");
102 | items.push(lineParts[lineParts.length - 1]);
103 | }
104 | }
105 |
106 | const setData = await set(playlist, items);
107 | return { data: items, raw: setData.data.raw };
108 | } catch (error) {
109 | logger.warn(error);
110 | return false;
111 | }
112 | };
113 |
114 | const getItems = async (playlist = "playlist") => {
115 | try {
116 | const data = await get(playlist);
117 | const items = await parse(data);
118 | return { data: { items: items, raw: data } };
119 | } catch (error) {
120 | logger.warn(error);
121 | return false;
122 | }
123 | };
124 |
125 | module.exports = { getItems: getItems, set: set, add: add, remove: remove };
126 |
--------------------------------------------------------------------------------
/utils/ffmpeg-getcodecs.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const ffmpeg = require("fluent-ffmpeg");
25 | const util = require("util");
26 | const logger = require("@utils/logger")(module);
27 |
28 | module.exports = async (relativePath) => {
29 | ffmpeg.setFfmpegPath("/root/bin/ffmpeg");
30 | const getAvailableCodecs = util.promisify(ffmpeg.getAvailableCodecs);
31 |
32 | try {
33 | const codecs = await getAvailableCodecs();
34 | return codecs;
35 | } catch (error) {
36 | logger.warn(error);
37 | return {};
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/utils/file-delete.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const fs = require("fs").promises;
25 | const path = require("path");
26 | const logger = require("@utils/logger")(module);
27 |
28 | module.exports = async (relativePath) => {
29 | try {
30 | const absolutePath = path.resolve(relativePath);
31 | if (await fs.unlink(absolutePath)) {
32 | return true;
33 | }
34 | return false;
35 | } catch (error) {
36 | logger.warn(error);
37 | return false;
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/utils/file-exists.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const fs = require("fs");
25 | const path = require("path");
26 | const logger = require("@utils/logger")(module);
27 |
28 | module.exports = async (relativePath) => {
29 | try {
30 | const absolutePath = path.resolve(relativePath);
31 | if (await fs.existsSync(absolutePath)) {
32 | return true;
33 | }
34 | return false;
35 | } catch (error) {
36 | logger.warn(error);
37 | return false;
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/utils/file-read-json.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const { promises: fs } = require("fs");
25 |
26 | module.exports = async (filename) => {
27 | const fileJson = await fs.readFile(filename);
28 | return JSON.parse(fileJson);
29 | };
30 |
--------------------------------------------------------------------------------
/utils/file-read.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const { promises: fs } = require("fs");
25 |
26 | module.exports = async (file) => {
27 | const fileContents = await fs.readFile(file);
28 | return fileContents.toString().trim();
29 | };
30 |
--------------------------------------------------------------------------------
/utils/file-upload.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const path = require("path");
25 | const multer = require("multer");
26 |
27 | const storage = multer.diskStorage({
28 | destination: (req, file, cb) => {
29 | cb(null, path.join(__dirname, "..", "data", "media"));
30 | },
31 | filename: (req, file, cb) => {
32 | let extArray = file.mimetype.split("/");
33 | let extension = extArray[extArray.length - 1];
34 | cb(null, `${file.originalname.split(".")[0]}.${extension}`);
35 | },
36 | });
37 |
38 | module.exports = multer({
39 | storage: storage,
40 | }).single("file");
41 |
--------------------------------------------------------------------------------
/utils/filenames-get.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const fs = require("fs");
26 | const fsp = fs.promises;
27 | const path = require("path");
28 |
29 | module.exports = async (dirname) => {
30 | let files = [];
31 | try {
32 | files = await fsp.readdir(path.resolve(dirname));
33 | return files;
34 | } catch (error) {
35 | logger.warn(error);
36 | return files;
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/utils/filter-audio-meter.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const path = require("path");
26 |
27 | module.exports = async (options = {}) => {
28 | let filters = [];
29 | try {
30 | if (options.audioMeter) {
31 | filters = [
32 | {
33 | filter: "amovie",
34 | options: "1:d=0",
35 | outputs: "volume",
36 | },
37 | {
38 | filter: "showvolume",
39 | inputs: "volume",
40 | outputs: "volume_info",
41 | },
42 | {
43 | filter: "drawtext",
44 | options:
45 | "text='Volume: %{metadata=lavfi.showvolume.volume': x=(w-tw-10): y=(h-th-10): fontcolor=white: fontsize=24: box=1: boxcolor=black'",
46 | inputs: "volume_info",
47 | outputs: "output",
48 | },
49 | ];
50 | }
51 | } catch (error) {
52 | logger.warn("Cannot create text filter " + error.message);
53 | }
54 | return filters;
55 | };
56 |
--------------------------------------------------------------------------------
/utils/filter-combine.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 |
26 | module.exports = async (...filter) => {
27 | let filters = [];
28 | try {
29 | const length = filter.length;
30 | for (let i = 0; i < length; i += 1) {
31 | if (Array.isArray(filter[i])) {
32 | filters = filters.concat(filter[i]);
33 | }
34 | }
35 | } catch (error) {
36 | logger.warn("Cannot concatenate filters " + error.message);
37 | }
38 | return filters;
39 | };
40 |
--------------------------------------------------------------------------------
/utils/filter-image.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const getFilepath = require("@utils/get-filepath");
26 |
27 | module.exports = async (command, options) => {
28 | try {
29 | if (options.overlay.image && options.overlay.image.file) {
30 | const filepath = await getFilepath({
31 | file: options.overlay.image.file,
32 | timestamp: false,
33 | format: options.overlay.image.format || "png",
34 | });
35 |
36 | //ffmpeg -y -i video.mp4 -i overlay.png -filter_complex [0]overlay=x=0:y=0[out] -map [out] -map 0:a? test.mp4
37 |
38 | // command.input(filepath);
39 | // command.complexFilter(
40 | // [
41 | // {
42 | // filter: "overlay",
43 | // options: { x: 0, y: 0 },
44 | // inputs: ["0:v"],
45 | // outputs: "output",
46 | // },
47 | // ],
48 | // "output"
49 | // );
50 | }
51 | } catch (error) {
52 | logger.warn("Cannot create image overlay filter");
53 | logger.warn(error);
54 | }
55 | return command;
56 | };
57 |
--------------------------------------------------------------------------------
/utils/filter-interlace.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const path = require("path");
26 | const parse = require("@utils/parse");
27 |
28 | module.exports = async (interlace = false, fieldorder = "tff") => {
29 | const filters = [];
30 | try {
31 | if (interlace) {
32 | filters.push({
33 | filter: `yadif`,
34 | // options: { mode: 1, parity: "t", deint: 0 },
35 | });
36 | }
37 | } catch (error) {
38 | logger.warn("Cannot create interalcing filter " + error.message);
39 | }
40 | return filters;
41 | };
42 |
--------------------------------------------------------------------------------
/utils/filter-qr.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const path = require("path");
26 | const qr = require("@utils/qr");
27 | const imageFilter = require("@utils/filter-image");
28 |
29 | module.exports = async (command, options) => {
30 | try {
31 | if (options.overlay.qr && options.overlay.qr.data) {
32 | const data = await qr(options.overlay.qr);
33 |
34 | options.overlay.image.file = path.join(__dirname, "..", "data", "qr", qrData?.file);
35 | options.overlay.image.format = options.overlay.qr?.type || "png";
36 | options.overlay.image.size = options.overlay.qr?.size || 20;
37 | options.overlay.image.location = {
38 | x: options?.overlay?.qr?.location?.x || 0,
39 | y: options?.overlay?.qr?.location?.y || 0,
40 | };
41 |
42 | command = imageFilter(command, options);
43 | }
44 | } catch (error) {
45 | logger.warn("Cannot create QR code filter ");
46 | logger.warn(error);
47 | }
48 | return command;
49 | };
50 |
--------------------------------------------------------------------------------
/utils/get-extension.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = (format = "h264") => {
25 | if (format === "prores") {
26 | return ".mov";
27 | }
28 |
29 | if (format === "h264") {
30 | return ".mp4";
31 | }
32 |
33 | if (format === "mjpeg") {
34 | return ".mov";
35 | }
36 |
37 | return `.${format}`;
38 | };
39 |
--------------------------------------------------------------------------------
/utils/get-filepath.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const path = require("path");
26 | const { format } = require("date-fns");
27 | const getFileExtension = require("@utils/get-extension");
28 |
29 | const defaultOptions = {
30 | format: "h264",
31 | includePath: true,
32 | format: "h264",
33 | timestamp: "MM-dd-yyyy-HH-mm",
34 | chunks: false,
35 | };
36 |
37 | module.exports = async (options = {}) => {
38 | options = { ...defaultOptions, ...options };
39 |
40 | let filePath = "";
41 | let mediaPath = "";
42 |
43 | if (options?.includePath) {
44 | mediaPath = process.env.MEDIA_PATH || path.join(__dirname, "..", "data", "media");
45 | }
46 |
47 | if (options?.chunks && options?.timestamp) {
48 | const dateTimeString = format(new Date(), options?.timestamp);
49 | filePath = path.join(mediaPath, `${options?.file}-${dateTimeString}-%03d${getFileExtension(options?.format)}`);
50 | } else if (options?.chunks) {
51 | filePath = path.join(mediaPath, `${options?.file}-%03d${getFileExtension(options?.format)}`);
52 | } else if (options?.timestamp) {
53 | const dateTimeString = format(new Date(), options?.timestamp);
54 | filePath = path.join(mediaPath, `${options?.file}-${dateTimeString}${getFileExtension(options?.format)}`);
55 | } else {
56 | filePath = path.join(mediaPath, `${options?.file}${getFileExtension(options?.format)}`);
57 | }
58 |
59 | return filePath;
60 | };
61 |
--------------------------------------------------------------------------------
/utils/git-commit.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const { execSync } = require("child_process");
25 |
26 | module.exports = async (directory) => {
27 | const revision = await execSync(
28 | `cd ${directory} && git config --global --add safe.directory ${directory} && git rev-parse HEAD`
29 | )
30 | .toString()
31 | .trim();
32 | return revision;
33 | };
34 |
--------------------------------------------------------------------------------
/utils/hash-response.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const md5 = require("md5");
25 |
26 | module.exports = (res, req, contents) => {
27 | const response = contents;
28 | const meta = {
29 | hash: md5(response),
30 | request_url: `${req.protocol}://${req.hostname}${req.originalUrl}`,
31 | request_method: req.method,
32 | request_body: req.body,
33 | user: req.user,
34 | };
35 |
36 | response.meta = meta;
37 | res.header("Content-Type", "application/json");
38 | res.json(response);
39 | };
40 |
--------------------------------------------------------------------------------
/utils/http-logger.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const morgan = require("morgan");
25 | const logger = require("@utils/logger")(module);
26 |
27 | logger.stream = {
28 | write: (message) => {
29 | message = message.substring(0, message.lastIndexOf("\n"));
30 | const items = message.split(" ");
31 | logger.http(message, { remoteAddress: items[0] });
32 | },
33 | };
34 |
35 | module.exports = morgan(`:remote-addr :method :url :status :res[content-length] :response-time ms`, {
36 | stream: logger.stream,
37 | });
38 |
--------------------------------------------------------------------------------
/utils/job-load.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const jobManager = require("@utils/jobManager");
26 | const pidusage = require("pidusage");
27 |
28 | module.exports = async () => {
29 | let usage = {};
30 | const pids = [];
31 | const jobs = jobManager.getAll();
32 |
33 | for (let [jobId, job] of Object.entries(jobs)) {
34 | pids.push(job?.pid);
35 | }
36 |
37 | if (pids.length > 0) {
38 | usage = await pidusage(pids);
39 | }
40 |
41 | for (let [jobId, job] of Object.entries(jobs)) {
42 | usage[jobId] = usage[job?.pid];
43 | usage[jobId].cpu = usage[jobId].cpu / 100;
44 | jobManager.update(jobId, { load: usage[job?.pid] });
45 | delete usage[job?.pid];
46 | }
47 |
48 | return usage;
49 | };
50 |
--------------------------------------------------------------------------------
/utils/jobManager.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const crypto = require("crypto");
25 | const fileDelete = require("@utils/file-delete");
26 | const thumbnailCache = require("@utils/thumbnail-cache");
27 |
28 | let maxQueueSize = process.env.QUEUE_SIZE || 5;
29 | let jobs = {};
30 |
31 | const start = (output, name = "FFmpeg Process", type = ["default"]) => {
32 | const queueSize = Object.keys(jobs).length;
33 | if (queueSize < maxQueueSize) {
34 | const hash = crypto.createHash("md5").update(output).digest("hex");
35 | if (!jobs[hash]) {
36 | jobs[hash] = {
37 | jobNumber: Object.keys(jobs).length + 1,
38 | jobId: hash,
39 | started: new Date(),
40 | jobName: name,
41 | type: type,
42 | };
43 | return jobs[hash];
44 | } else {
45 | throw new Error("Job is already running.");
46 | }
47 | } else {
48 | throw new Error("Job queue is full, cancel a job or wait to one is finished before starting another.");
49 | }
50 | };
51 |
52 | const update = (hash, update) => {
53 | if (jobs[hash]) {
54 | jobs[hash] = { ...jobs[hash], ...update };
55 | return jobs[hash];
56 | } else {
57 | return { error: "Job does not exist." };
58 | }
59 | };
60 |
61 | const end = (hash, kill = true) => {
62 | if (jobs[hash]) {
63 | const job = jobs[hash];
64 |
65 | if (kill) {
66 | process.kill(jobs[hash].pid, "SIGINT");
67 | }
68 |
69 | job.ended = new Date();
70 | job.duration = job.ended - job.started;
71 | delete jobs[hash];
72 |
73 | fileDelete(`data/thumbnail/${job.jobId}.png`);
74 | thumbnailCache.del(job.jobId);
75 |
76 | return job;
77 | } else {
78 | return { error: "Job does not exist." };
79 | }
80 | };
81 |
82 | const get = (output) => {
83 | const hash = crypto.createHash("md5").update(output).digest("hex");
84 | if (jobs[hash]) {
85 | return jobs[hash];
86 | } else {
87 | return false;
88 | }
89 | };
90 |
91 | const getbyId = (hash) => {
92 | if (jobs[hash]) {
93 | return jobs[hash];
94 | } else {
95 | return false;
96 | }
97 | };
98 |
99 | const getAll = () => {
100 | return jobs;
101 | };
102 |
103 | module.exports = { end: end, update: update, start: start, get: get, getbyId: getbyId, getAll: getAll };
104 |
--------------------------------------------------------------------------------
/utils/logger.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const winston = require("winston");
25 | const path = require("path");
26 | require("winston-daily-rotate-file");
27 | const logFolder = process.env.LOG_FOLDER || "logs";
28 | const logName = process.env.LOG_NAME || "ffmpeg";
29 | const logLevel = process.env.LOG_LEVEL || "info";
30 |
31 | const customLevels = {
32 | levels: {
33 | error: 0,
34 | warn: 1,
35 | info: 2,
36 | http: 3,
37 | debug: 4,
38 | },
39 | colors: {
40 | error: "red",
41 | warn: "yellow",
42 | info: "blue",
43 | http: "magenta",
44 | debug: "gray",
45 | },
46 | };
47 |
48 | const customLogFormat = winston.format.combine(
49 | winston.format.errors({ stack: true }),
50 | winston.format.timestamp(),
51 | winston.format.splat(),
52 | winston.format.printf((log) => `${log.timestamp} ${log.level}: ${log.message}`)
53 | );
54 |
55 | winston.addColors(customLevels.colors);
56 |
57 | const loggerInstance = winston.createLogger({
58 | levels: customLevels.levels,
59 | handleExceptions: false,
60 | transports: [
61 | new winston.transports.DailyRotateFile({
62 | level: logLevel,
63 | format: customLogFormat,
64 | filename: path.join(logFolder, logName + "-%DATE%.log"),
65 | datePattern: "YYYY-MM-DD",
66 | zippedArchive: true,
67 | maxSize: "100m",
68 | maxFiles: "1d",
69 | }),
70 | new winston.transports.Console({
71 | level: logLevel,
72 | handleExceptions: true,
73 | colorize: true,
74 | format: winston.format.combine(customLogFormat, winston.format.colorize({ all: true })),
75 | }),
76 | ],
77 | });
78 |
79 | const logger = (module) => {
80 | const filename = path.basename(module.filename);
81 | const loggers = {};
82 |
83 | for (let level in customLevels.levels) {
84 | loggers[level] = (message, metadata) => {
85 | loggerInstance[level](message, { metadata: { ...{ filename: filename }, ...metadata } });
86 | };
87 | }
88 |
89 | return loggers;
90 | };
91 |
92 | module.exports = logger;
93 |
--------------------------------------------------------------------------------
/utils/markdown.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const swaggerJsdoc = require("swagger-jsdoc");
25 | const YAML = require("yaml");
26 | const fs = require("fs");
27 | const path = require("path");
28 |
29 | const host = process.env.HOST || "localhost";
30 | const port = process.env.PORT || "80";
31 | const url = `http://${host}:${port}/api/`;
32 |
33 | const options = {
34 | definition: {
35 | openapi: "3.0.0",
36 | info: {
37 | title: "FFmpeg Docker API",
38 | version: "0.1.0",
39 | description: "Common FFmpeg functions from a RESTful API",
40 | license: {
41 | name: "GPLv3",
42 | url: "https://www.gnu.org/licenses/gpl-3.0.en.html",
43 | },
44 | contact: {
45 | name: "Ryan McCartney",
46 | url: "https://ryan.mccartney.info/ffmpeg-docker",
47 | email: "ryan@mccartney.info",
48 | },
49 | },
50 | servers: [
51 | {
52 | url: url,
53 | },
54 | ],
55 | },
56 | apis: ["./routes/*.js", "./modules/*.js"],
57 | };
58 |
59 | const main = async () => {
60 | const swaggerJsonSpec = swaggerJsdoc(options);
61 | const swaggerYamlSpec = YAML.stringify(swaggerJsonSpec);
62 | fs.writeFileSync(path.join("docs", "assets", "api-spec.yml"), swaggerYamlSpec);
63 | };
64 |
65 | main();
66 |
--------------------------------------------------------------------------------
/utils/node-version.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const { execSync } = require("child_process");
25 |
26 | module.exports = async () => {
27 | const revision = await execSync(`node --version`).toString().trim();
28 | return revision;
29 | };
30 |
--------------------------------------------------------------------------------
/utils/os-version.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const { execSync } = require("child_process");
25 |
26 | module.exports = async () => {
27 | const osObject = {};
28 | const os = await execSync(`cat /etc/os-release`).toString().trim();
29 |
30 | for (let line of os.split("\n")) {
31 | const item = line.split("=");
32 | osObject[item[0].toLowerCase()] = item[1].replace(/"/g, ``).trim();
33 | }
34 |
35 | return osObject;
36 | };
37 |
--------------------------------------------------------------------------------
/utils/parse.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const Mustache = require("mustache");
26 |
27 | const host = process.env.HOST || "localhost";
28 | const queueSize = process.env.QUEUE_SIZE || "10";
29 |
30 | const port = process.env.PORT || "80";
31 |
32 | module.exports = async (inputString, options = {}) => {
33 | let parsedString = "";
34 | try {
35 | const view = {
36 | ...{
37 | date: new Date(),
38 | host: host,
39 | port: port,
40 | queueSize: queueSize.toString(),
41 | },
42 | ...options,
43 | };
44 |
45 | parsedString = await Mustache.render(inputString, view);
46 | } catch (error) {
47 | logger.warn(error);
48 | }
49 | return parsedString;
50 | };
51 |
--------------------------------------------------------------------------------
/utils/qr.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 | const util = require("util");
26 | const path = require("path");
27 | const QRCode = require("qrcode");
28 | const parse = require("@utils/parse");
29 |
30 | module.exports = async (qr) => {
31 | const response = { status: true, data: {} };
32 | try {
33 | const QrType = qr?.type || "png";
34 | const qrCodePath = path.join(__dirname, "..", "data", "qr", qr?.file + "." + QrType);
35 |
36 | response.data = await QRCode.toFile(qrCodePath, await parse(qr?.text, qr), {
37 | type: QrType,
38 | color: {
39 | dark: `${qr.color || "#FFF"}`,
40 | light: `${qr.background || "#000"}`,
41 | },
42 | });
43 | } catch (error) {
44 | logger.warn(error);
45 | response.status = false;
46 | response.error = error;
47 | }
48 | };
49 |
--------------------------------------------------------------------------------
/utils/rtmp-address.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = (address, path = "", key) => {
25 | let fullAddress = `rtmp://${address}${path}`;
26 | if (key) {
27 | fullAddress += `/${key}`;
28 | }
29 | return fullAddress;
30 | };
31 |
--------------------------------------------------------------------------------
/utils/set-codec.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const defaultOutput = { audioCodec: "aac", videoCodec: "h264", encodePreset: "ultrafast" };
25 |
26 | module.exports = (command, output = {}) => {
27 | output = { ...defaultOutput, ...output };
28 |
29 | if (output?.videoCodec === "prores") {
30 | command.videoCodec("prores_ks").outputOptions("-profile:v", "3").outputOptions("-c:a", "pcm_s16le");
31 | }
32 |
33 | if (output?.videoCodec === "h264") {
34 | command
35 | .videoCodec("libx264")
36 | .outputOptions("-preset", output?.encodePreset || "ultrafast")
37 | .outputOptions("-pass", "1")
38 | .outputOptions("-tune zerolatency")
39 | .outputOptions("-max_delay", "100");
40 | }
41 |
42 | if (output?.videoCodec === "mjpeg") {
43 | command
44 | .videoCodec("mjpeg")
45 | .outputOptions("-q:v", "10")
46 | .outputOptions("-c:a", "copy")
47 | .addOutputOptions("-pix_fmt", "yuvj422p");
48 | }
49 |
50 | if (output?.videoCodec === "mjpeg2") {
51 | command.videoCodec("mpeg2video").addOutputOptions("-pix_fmt", "yuv420p");
52 | }
53 |
54 | if (!output?.videoCodec) {
55 | command
56 | .videoCodec("libx264")
57 | .videoCodec("libx264")
58 | .outputOptions("-crf", "23")
59 | .outputOptions("-preset", output?.encodePreset || "ultrafast");
60 | }
61 |
62 | if (output?.audioCodec === "aac") {
63 | command.audioCodec("aac");
64 | }
65 |
66 | if (output?.audioCodec === "mp3") {
67 | command.audioCodec("mp3");
68 | }
69 |
70 | if (!output?.audioCodec) {
71 | command.audioCodec("mp3");
72 | }
73 |
74 | return command;
75 | };
76 |
--------------------------------------------------------------------------------
/utils/strategies.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const passport = require("passport");
25 | const logger = require("@utils/logger")(module);
26 | const JwtStrategy = require("passport-jwt").Strategy;
27 | const ExtractJwt = require("passport-jwt").ExtractJwt;
28 |
29 | const jwtStrategy = (settings) => {
30 | const options = {
31 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
32 | secretOrKey: process.env.AUTH_KEY || "averysecretkey",
33 | issuer: "accounts.examplesoft.com",
34 | audience: "yoursite.net",
35 | };
36 |
37 | return new JwtStrategy(options, function (jwt_payload, done) {
38 | User.findOne({ id: jwt_payload.sub }, function (err, user) {
39 | if (err) {
40 | return done(err, false);
41 | }
42 | if (user) {
43 | return done(null, user);
44 | } else {
45 | return done(null, false);
46 | }
47 | });
48 | });
49 | };
50 |
51 | module.exports = {
52 | local: jwtStrategy,
53 | };
54 |
--------------------------------------------------------------------------------
/utils/thumbnail-cache.js:
--------------------------------------------------------------------------------
1 | const NodeCache = require("node-cache");
2 | const thumbnailCache = new NodeCache({ stdTTL: 100, checkperiod: 120 });
3 |
4 | module.exports = thumbnailCache;
5 |
--------------------------------------------------------------------------------
/utils/validator-isiporfqdn.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const validator = require("validator");
25 |
26 | module.exports = (value, { req, location, path }) => {
27 | return validator.isIP(value) || validator.isFQDN(value);
28 | };
29 |
--------------------------------------------------------------------------------
/utils/vmaf-json-csv.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const logger = require("@utils/logger")(module);
25 |
26 | // "frameNum": 0,
27 | // "metrics": {
28 | // "integer_adm2": 0.972270,
29 | // "integer_adm_scale0": 0.970884,
30 | // "integer_adm_scale1": 0.964849,
31 | // "integer_adm_scale2": 0.977850,
32 | // "integer_adm_scale3": 0.971833,
33 | // "integer_motion2": 0.000000,
34 | // "integer_motion": 0.000000,
35 | // "integer_vif_scale0": 0.570051,
36 | // "integer_vif_scale1": 0.889042,
37 | // "integer_vif_scale2": 0.930582,
38 | // "integer_vif_scale3": 0.952735,
39 | // "psnr": 37.205054,
40 | // "ssim": 0.987119,
41 | // "ms_ssim": 0.984290,
42 | // "vmaf": 84.659084
43 |
44 | module.exports = async (json = { frames: [] }) => {
45 | let csvData = "Frame Number,PSNR,SSIM,VMAF\n";
46 | try {
47 | for (let frame of json?.frames) {
48 | const csvLine = `${frame?.frameNum},${frame?.metrics?.psnr},${frame?.metrics?.ssim},${frame?.metrics?.vmaf}\n`;
49 | csvData += csvLine;
50 | }
51 | } catch (error) {
52 | logger.warn(error);
53 | }
54 | return csvData;
55 | };
56 |
--------------------------------------------------------------------------------
/utils/watcher.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | fs.watch("/path/to/folder", (eventType, filename) => {
25 | console.log(eventType);
26 | // could be either 'rename' or 'change'. new file event and delete
27 | // also generally emit 'rename'
28 | console.log(filename);
29 | });
30 |
--------------------------------------------------------------------------------
/validators/audio.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const barsType = require("@utils/barsTypes");
25 |
26 | module.exports = (direction = "input") => {
27 | return {
28 | [`${direction}.type`]: {
29 | optional: true,
30 | isIn: {
31 | options: [barsType],
32 | default: barsType[0],
33 | errorMessage: `Bars type must be one of ${barsType.toString()}`,
34 | },
35 | },
36 | [`${direction}.file`]: {
37 | exists: {
38 | errorMessage: "Input filename required.",
39 | },
40 | isString: { errorMessage: "Filename must be a string." },
41 | },
42 | [`${direction}.repeat`]: {
43 | optional: true,
44 | isBoolean: { default: false, errorMessage: "Repear must be a boolean value." },
45 | },
46 | };
47 | };
48 |
--------------------------------------------------------------------------------
/validators/auth.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = {
25 | username: {
26 | exists: {
27 | errorMessage: "Username is required.",
28 | },
29 | isString: { errorMessage: "Username must be a string" },
30 | },
31 | password: {
32 | exists: {
33 | errorMessage: "Password is required.",
34 | },
35 | isString: { errorMessage: "Password must be a string" },
36 | },
37 | };
38 |
--------------------------------------------------------------------------------
/validators/bars.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const barsType = require("@utils/barsTypes");
25 |
26 | module.exports = (direction = "input") => {
27 | return {
28 | [`${direction}.type`]: {
29 | optional: true,
30 | isIn: {
31 | options: [barsType],
32 | default: barsType[0],
33 | errorMessage: `Bars type must be one of ${barsType.toString()}`,
34 | },
35 | },
36 | [`${direction}.frequency`]: {
37 | optional: true,
38 | isInt: {
39 | min: 100,
40 | max: 18000,
41 | default: 1000,
42 | errorMessage: "Audio frequency must be between 100Hz and 18,000 Hz",
43 | },
44 | },
45 | [`${direction}.duration`]: {
46 | optional: true,
47 | isInt: {
48 | min: 1,
49 | max: 3600,
50 | default: 10,
51 | errorMessage: "Duration of bars must be between 1 and 3,600 seconds as an integar",
52 | },
53 | },
54 | };
55 | };
56 |
--------------------------------------------------------------------------------
/validators/decklink.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const encodePresets = require("@utils/encodePresets");
25 |
26 | module.exports = (direction = "input") => {
27 | return {
28 | [`${direction}.cardName`]: {
29 | exists: {
30 | errorMessage: "Decklink card name required",
31 | },
32 | isString: { errorMessage: "Decklink card name must be a string" },
33 | },
34 | [`${direction}.volume`]: {
35 | optional: true,
36 | isFloat: { min: 0, max: 1, default: 0.25, errorMessage: "Volume must be a float between 0 and 1" },
37 | },
38 | [`${direction}.duplexMode`]: {
39 | optional: true,
40 | isIn: {
41 | options: [["full", "half"]],
42 | default: "unset",
43 | errorMessage: "Decklink card name must one of 'full', 'half' or 'unset'",
44 | },
45 | },
46 | [`${direction}.encodePreset`]: {
47 | optional: true,
48 | isIn: {
49 | options: [encodePresets],
50 | default: encodePresets[0],
51 | errorMessage: `Encode preset must be one of ${encodePresets.toString()}.`,
52 | },
53 | },
54 | };
55 | };
56 |
--------------------------------------------------------------------------------
/validators/file.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = (direction = "input") => {
25 | const validator = {
26 | [`${direction}.file`]: {
27 | isString: { errorMessage: "Filename must be a string." },
28 | },
29 | [`${direction}.repeat`]: {
30 | optional: true,
31 | isBoolean: { default: false, errorMessage: "Repear must be a boolean value." },
32 | },
33 | [`${direction}.chunkSize`]: {
34 | optional: true,
35 | isInt: { min: 5, max: 1800, errorMessage: "Chunks must be between 5 and 1800 seconds." },
36 | },
37 | };
38 |
39 | if (direction === "output") {
40 | validator[`${direction}.file`].optional = true;
41 | } else {
42 | validator[`${direction}.file`].exists = {
43 | errorMessage: "Input filename required.",
44 | };
45 | }
46 |
47 | return validator;
48 | };
49 |
--------------------------------------------------------------------------------
/validators/hls.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const encodePresets = require("@utils/encodePresets");
25 |
26 | module.exports = (direction = "input") => {
27 | return {
28 | [`${direction}.file`]: {
29 | optional: true,
30 | isString: { errorMessage: "HLS filename must be a string" },
31 | },
32 | [`${direction}.chunkDuration`]: {
33 | optional: true,
34 | isFloat: {
35 | min: 0,
36 | max: 10,
37 | default: 0.5,
38 | errorMessage: "Chunk duration must be a float between 0 and 10 seconds",
39 | },
40 | },
41 | [`${direction}.chunks`]: {
42 | optional: true,
43 | isInt: {
44 | min: 1,
45 | max: 50,
46 | default: 5,
47 | errorMessage: "Number of chunks must be an integar between 1 and 50",
48 | },
49 | },
50 | [`${direction}.encodePreset`]: {
51 | optional: true,
52 | isIn: {
53 | options: [encodePresets],
54 | default: encodePresets[0],
55 | errorMessage: `Encode preset must be one of ${encodePresets.toString()}.`,
56 | },
57 | },
58 | };
59 | };
60 |
--------------------------------------------------------------------------------
/validators/overlay.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = (direction = "input") => {
25 | return {
26 | "overlay.line1": {
27 | optional: true,
28 | isString: { default: "", errorMessage: "Line 1 must be a String" },
29 | },
30 | "overlay.line2": {
31 | optional: true,
32 | isString: { default: "", errorMessage: "Line 2 must be a String" },
33 | },
34 | "overlay.fontSize": {
35 | optional: true,
36 | isInt: { min: 10, max: 200, default: 120, errorMessage: "Font size must be between 10 and 200" },
37 | },
38 | "overlay.timecode": {
39 | optional: true,
40 | isBoolean: { default: false, errorMessage: "Timecode must be a Boolean value" },
41 | },
42 | "overlay.offset": {
43 | optional: true,
44 | isInt: { min: -12, max: 12, default: 0, errorMessage: "Time offset must be between -12 and +12 hours" },
45 | },
46 | "overlay.font": {
47 | optional: true,
48 | isString: { default: "swansea-bold.ttf", errorMessage: "Fonts must be in the fonts folder" },
49 | },
50 | "overlay.scrolling": {
51 | optional: true,
52 | isBoolean: { default: false, errorMessage: "Scrolling must be a boolean type" },
53 | },
54 | "overlay.image.file": {
55 | optional: true,
56 | isString: { default: "", errorMessage: "Image file must be a string" },
57 | },
58 | "overlay.image.size": {
59 | optional: true,
60 | isInt: {
61 | min: 0,
62 | max: 100,
63 | default: 50,
64 | errorMessage: "Size between 0 and 100, relative to view height",
65 | },
66 | },
67 | "overlay.image.location.x": {
68 | optional: true,
69 | isInt: { min: -100, max: 100, default: 0, errorMessage: "X-axis location between -100 and 100" },
70 | },
71 | "overlay.image.location.y": {
72 | optional: true,
73 | isInt: { min: -100, max: 100, default: 0, errorMessage: "Y-axis location between -100 and 100" },
74 | },
75 | };
76 | };
77 |
78 | // "topRight": {
79 | // "line1": "%{pts\\:hms}",
80 | // "line2": "Frame %{n}"
81 | // }
82 |
--------------------------------------------------------------------------------
/validators/rtmp.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const encodePresets = require("@utils/encodePresets");
25 | const isIPorFQDN = require("@utils/validator-isiporfqdn");
26 |
27 | module.exports = (direction = "input") => {
28 | return {
29 | [`${direction}.address`]: {
30 | exists: { errorMessage: "Must provide and address required." },
31 | custom: {
32 | options: isIPorFQDN,
33 | errorMessage: "Address must be a valid IP Address or FQDN",
34 | },
35 | },
36 | [`${direction}.path`]: {
37 | optional: true,
38 | isString: { default: "", errorMessage: "Path must be a valid string" },
39 | },
40 | [`${direction}.port`]: {
41 | optional: true,
42 | exists: { errorMessage: "Must provide a port number as an integar" },
43 | isInt: {
44 | min: 1024,
45 | max: 65535,
46 | default: 1935,
47 | errorMessage: "Must be a valid port number between 1024 to 65535",
48 | },
49 | },
50 | [`${direction}.key`]: {
51 | optional: true,
52 | isString: {
53 | default: "",
54 | errorMessage: "RTMP key must be a string.",
55 | },
56 | },
57 | [`${direction}.ttl`]: {
58 | optional: true,
59 | isInt: {
60 | min: 0,
61 | max: 255,
62 | default: 64,
63 | errorMessage: "Time to Live of SRT Packets must be between 0 and 255",
64 | },
65 | },
66 | [`${direction}.tos`]: {
67 | optional: true,
68 | isInt: { min: 0, max: 255, default: 104, errorMessage: "ToS of SRT Packets must be between 0 and 255" },
69 | },
70 | [`${direction}.bitrate`]: {
71 | optional: true,
72 | isString: {
73 | default: "5000k",
74 | errorMessage: "Bitrate must be a string.",
75 | },
76 | },
77 | [`${direction}.encodePreset`]: {
78 | optional: true,
79 | isIn: {
80 | options: [encodePresets],
81 | default: encodePresets[0],
82 | errorMessage: `Encode preset must be one of ${encodePresets.toString()}.`,
83 | },
84 | },
85 | };
86 | };
87 |
--------------------------------------------------------------------------------
/validators/rtp.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const encodePresets = require("@utils/encodePresets");
25 | const isIPorFQDN = require("@utils/validator-isiporfqdn");
26 |
27 | module.exports = (direction = "input") => {
28 | return {
29 | [`${direction}.address`]: {
30 | exists: { errorMessage: "Must provide and address required." },
31 | custom: {
32 | options: isIPorFQDN,
33 | errorMessage: "Address must be a valid IP Address or FQDN",
34 | },
35 | },
36 | [`${direction}.port`]: {
37 | exists: { errorMessage: "Must provide a port number as an integar" },
38 | isInt: { min: 1024, max: 65535, errorMessage: "Must be a valid port number between 1024 to 65535" },
39 | },
40 | [`${direction}.packetSize`]: {
41 | optional: true,
42 | isInt: {
43 | min: 0,
44 | max: 65535,
45 | default: 1316,
46 | errorMessage: "RTP Packet size must be between 0 and 65535 bytes",
47 | },
48 | },
49 | [`${direction}.buffer`]: {
50 | optional: true,
51 | isInt: { min: 0, max: 255, default: 65535, errorMessage: "RTP buffer must be between 0 and 65535 bytes" },
52 | },
53 | [`${direction}.bitrate`]: {
54 | optional: true,
55 | isString: {
56 | default: "5000k",
57 | errorMessage: "Bitrate must be a string.",
58 | },
59 | },
60 | [`${direction}.encodePreset`]: {
61 | optional: true,
62 | isIn: {
63 | options: [encodePresets],
64 | default: encodePresets[0],
65 | errorMessage: `Encode preset must be one of ${encodePresets.toString()}.`,
66 | },
67 | },
68 | };
69 | };
70 |
--------------------------------------------------------------------------------
/validators/srt.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const encodePresets = require("@utils/encodePresets");
25 | const isIPorFQDN = require("@utils/validator-isiporfqdn");
26 |
27 | module.exports = (direction = "input") => {
28 | return {
29 | [`${direction}.address`]: {
30 | exists: { errorMessage: "Must provide and address required." },
31 | custom: {
32 | options: isIPorFQDN,
33 | errorMessage: "Address must be a valid IP Address or FQDN",
34 | },
35 | },
36 | [`${direction}.port`]: {
37 | exists: { errorMessage: "Must provide a port number as an integar" },
38 | isInt: { min: 1024, max: 65535, errorMessage: "Must be a valid port number between 1024 to 65535" },
39 | },
40 | [`${direction}.latency`]: {
41 | optional: true,
42 | isInt: { min: 20, max: 10000, default: 250, errorMessage: "SRT Latency must be between 20ms and 10000ms" },
43 | },
44 | [`${direction}.packetSize`]: {
45 | optional: true,
46 | isInt: {
47 | min: 0,
48 | max: 65535,
49 | default: 1316,
50 | errorMessage: "SRT Packet size must be between 0 and 65535 bytes",
51 | },
52 | },
53 | [`${direction}.ttl`]: {
54 | optional: true,
55 | isInt: {
56 | min: 0,
57 | max: 255,
58 | default: 64,
59 | errorMessage: "Time to Live of SRT Packets must be between 0 and 255",
60 | },
61 | },
62 | [`${direction}.tos`]: {
63 | optional: true,
64 | isInt: { min: 0, max: 255, default: 104, errorMessage: "ToS of SRT Packets must be between 0 and 255" },
65 | },
66 | [`${direction}.mode`]: {
67 | optional: true,
68 | isIn: {
69 | options: [["listener", "caller"]],
70 | default: "caller",
71 | errorMessage: "SRT mode must be 'Caller' or 'Listener'",
72 | },
73 | },
74 | [`${direction}.bitrate`]: {
75 | optional: true,
76 | isString: {
77 | default: "5000k",
78 | errorMessage: "Bitrate must be a string.",
79 | },
80 | },
81 | [`${direction}.encodePreset`]: {
82 | optional: true,
83 | isIn: {
84 | options: [encodePresets],
85 | default: encodePresets[0],
86 | errorMessage: `Encode preset must be one of ${encodePresets.toString()}.`,
87 | },
88 | },
89 | };
90 | };
91 |
--------------------------------------------------------------------------------
/validators/thumbnail.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = (direction = "input") => {
25 | return {
26 | "thumbnail.frequency": {
27 | optional: true,
28 | isInt: {
29 | min: 1,
30 | max: 200,
31 | default: 25,
32 | errorMessage: "Thumbnail frequency must be between 1 and 200 frames.",
33 | },
34 | },
35 | };
36 | };
37 |
--------------------------------------------------------------------------------
/validators/udp.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | const encodePresets = require("@utils/encodePresets");
25 | const isIPorFQDN = require("@utils/validator-isiporfqdn");
26 |
27 | module.exports = (direction = "input") => {
28 | return {
29 | [`${direction}.address`]: {
30 | exists: { errorMessage: "Must provide and address required." },
31 | custom: {
32 | options: isIPorFQDN,
33 | errorMessage: "Address must be a valid IP Address or FQDN",
34 | },
35 | },
36 | [`${direction}.port`]: {
37 | exists: { errorMessage: "Must provide a port number as an integar" },
38 | isInt: { min: 1024, max: 65535, errorMessage: "Must be a valid port number between 1024 to 65535" },
39 | },
40 | [`${direction}.packetSize`]: {
41 | optional: true,
42 | isInt: {
43 | min: 0,
44 | max: 65535,
45 | default: 1316,
46 | errorMessage: "UDP packet size must be between 0 and 65535 bytes",
47 | },
48 | },
49 | [`${direction}.buffer`]: {
50 | optional: true,
51 | isInt: { min: 0, max: 255, default: 65535, errorMessage: "UDP buffer must be between 0 and 65535 bytes" },
52 | },
53 | [`${direction}.bitrate`]: {
54 | optional: true,
55 | isString: {
56 | default: "5000k",
57 | errorMessage: "Bitrate must be a string.",
58 | },
59 | },
60 | [`${direction}.encodePreset`]: {
61 | optional: true,
62 | isIn: {
63 | options: [encodePresets],
64 | default: encodePresets[0],
65 | errorMessage: `Encode preset must be one of ${encodePresets.toString()}.`,
66 | },
67 | },
68 | };
69 | };
70 |
--------------------------------------------------------------------------------
/validators/vmaf.js:
--------------------------------------------------------------------------------
1 | /*
2 | FFmpeg Docker, an API wrapper around FFmpeg running in a configurable docker container
3 | Copyright (C) 2022 Ryan McCartney
4 |
5 | This file is part of the FFmpeg Docker (ffmpeg-docker).
6 |
7 | FFmpeg Docker is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | "use strict";
23 |
24 | module.exports = (direction = "input") => {
25 | return {
26 | "vmaf.reference": {
27 | isString: {
28 | errorMessage: "VMAF reference file must be a string",
29 | },
30 | },
31 | "vmaf.model": {
32 | optional: true,
33 | isString: {
34 | default: "vmaf_v0.6.1.json",
35 | errorMessage: "VMAF model must be a string",
36 | },
37 | },
38 | "vmaf.threads": {
39 | optional: true,
40 | isInt: { min: 1, max: 20, default: 1, errorMessage: "VMAF threads must be a integar" },
41 | },
42 | };
43 | };
44 |
--------------------------------------------------------------------------------
/views/chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{> head}}
4 |
5 |
6 |
7 |
8 |
9 | {{> header }}
10 |
11 |
12 |
13 |
14 |
15 | {{> footer }}
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/views/clock.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{> head}}
4 |
5 |
6 |
42 |
43 |
44 |
45 | {{> header }}
46 |
47 |
48 |