This program allows you to execute transcoding operation via an API using gstreamer.
What you can do with it :
- Predefine your encoding / muxing presets in a json configuration file
- Post result(s) to another http(s) server (upload sample)
- Follow transcoding progression and send notification to another http(s) server
- Stop a transcoding operation
- Transcode subtitles except image based subtitles
- Verify if the transcoder will be able to transcode media before adding media to queue
What you can't do with it :
- Define demuxing / decoding operation in the json configuration file.
- Muxing subtitles in the final container
- (opt) Query the endpoint
/support
to verify that your media is supported - Query endpoint
/transcode
to add the media. It will re-test if the media can be transcoded (like/support
endpoint). When all is successful it will add the media to transcoding queue in redis. - Worker start transcoding using gstreamer
- During the process, if
progress
url was sent to/transcode
, it will periodically notify it with the progression data ({ "status": "progress", "jobId": 123, "progress": 10.2 }
or if it failed{ "status": "failed", "jobId": 123 }
) - Once transcoding is completed / cancelled, if
end
url was sent to/transcode
, it will notify this url with media information as body andcancelled
(=0|1) in query string.
First define .env
file in the project, then docker-compose -f ./docker-compose.dev.yml up
.
Use npm run warmup
to create cache.json
if needed.
Sample basic .env :
STORAGE_PATH=.data
DEBUG=app:*
PRESET_FILE=./example_presets/presets-full.json
PORT=3000
ARENA_PORT=3001
ALLOW_QUERY_FILE_PATH=1
ALLOWED_API_KEYS=test
In dev env, before querying /transcode
, please verify that the user 1000 has the permission to read / write in
$STORAGE_PATH/virtual_storage
folder.
You can import api definition (<rootDir>/insomnia/transcoder.yml
) with insomnia
name | example | description |
---|---|---|
PORT | 3000 | Exposed api listen port (mapped to 4000 in dev docker-compose) |
REDIS_HOST | redis.host | Redis address |
REDIS_PORT | 6379 | Redis port (this variable is used only by the app and don't change redis service in dev docker-compose) |
REDIS_PASSWORD | Redis password (this variable is used only by the app and don't change redis service in dev docker-compose) | |
REDIS_PREFIX | transco | Redis queue prefix |
DEBUG | app:* | Used to activate debug output see debug for usage |
ARENA_PORT | 3001 | Exposed arena port (mapped to 4001 in dev docker-compose) |
ARENA_HOST | 0.0.0.0 | Listen address for arena |
ALLOWED_API_KEYS | Api keys used by the API, you can use alphanum char, to define multiple api keys use , separator. Theses api keys are case insensitive. To disable api key auth, let this variable empty |
|
PRESET_FILE | ./example_presets/presets-full.json | Preset filepath (see example dir for some presets sample) |
VERSION | Version used by sentry | |
SENTRY_DSN | Sentry DSN | |
PROXIED | To define if this application is behind a reverse proxy | |
SENTRY_ENV | dev | Sentry env |
ALLOW_QUERY_FILE_PATH | Set value to 1 if you want to allow filepath in api queries | |
STORAGE_PATH | .data | Docker volumes path |
DISCOVER_TIMEOUT | 60 | Timeout for discovering media's metadata (in seconds) |
JOB_TIMEOUT | 300000 | Job timeout (max duration without progress in ms) |
Key | Type | Required | Description |
---|---|---|---|
constraints | object | n | Plugins whitelist section |
constraints.audio | object | n | Plugins whitelist for audio |
constraints.audio.parsers | string[] | n | Plugins whitelist for audio parsers (unused if empty) |
constraints.audio.decoders | string[] | n | Plugins whitelist for audio decoders (unused if empty) |
constraints.video | object | n | Plugins whitelist for video |
constraints.video.parsers | string[] | n | Plugins whitelist for video parsers (unused if empty) |
constraints.video.decoders | string[] | n | Plugins whitelist for video decoders (unused if empty) |
constraints.demuxers | string[] | n | Demuxers whitelist |
queueProps | object | n | Queue element props |
src | object | n | Src element section |
src.http | object | n | Http src element section |
src.http.element | string | n | Element name for http(s) links |
src.http.props | object | n | Element props for http(s) links |
src.file | object | n | File src element section |
src.file.element | string | n | Element name for files |
src.file.props | object | n | Element props for files |
sink | object | n | Sink element section |
sink.http | object | n | Http sink element section |
sink.http.element | string | n | Element name |
sink.http.props | object | Element props | |
sink.file | object | n | File sink element section |
sink.file.element | string | n | Element name |
sink.file.props | object | n | Element props |
subtitles | object | n | Subtitles section (/!\ this feature has his decoding pipeline mostly hardcoded and can have hazardous behavior) |
subtitles.accept | regex | y | Accepted subtitles mimetype |
subtitles.filename | string | n | Output filename, %i will be remplaced by the stream offset |
subtitles.encoder | object | y | Subtitles encoder section |
subtitles.encoder.instance | string | y | Subtitle element name |
subtitles.encoder.params | string | n | Subtitle element props |
presets | object | y | Presets section |
presets.<name> | object | y | Preset section, you can use whatever you want as |
presets.<name>.minHeight | int | n | Min media height for this preset, it the original media is lower than this height, the preset will be ignored except if media's width is greater than minWidth |
presets.<name>.minWidth | int | n | Min media width for this preset, it the original media is lower than this width, the preset will be ignored except if media's height is greater than minHeight |
presets.<name>.muxer | object | y | Muxer section |
presets.<name>.muxer.type | string | y | Muxer element name |
presets.<name>.muxer.filename | string | y | Output filename |
presets.<name>.muxer.params | object | n | Muxer element properties, ex : { "streamable": true } |
presets.<name>.video | array | n | Video pipeline |
presets.<name>.video[X] | object | n | Element / Caps definition |
presets.<name>.video[X].removeIfStreamHeight | int | n | Remove this element / caps if media's height equals removeIfStreamHeight |
presets.<name>.video[X].instance | string(element,caps) | y | Element type |
presets.<name>.video[X].params | object | y | Element or caps parameters |
presets.<name>.video[X].params.type | string | y | Element or caps type ex: video/x-raw or videoscale |
presets.<name>.video[X].params.props | object | n | Element or caps properties, ex: { "height": 480 } . bitrate property is specific, you must define the unit associated to this value with bitrateUnit field. It will be used to keep the original bitrate if media's bitrate is lower than the one you wrote |
presets.<name>.audio | array | n | Audio pipeline |
presets.<name>.audio[X] | object | n | Element / Caps definition |
presets.<name>.audio[X].instance | string(element,caps) | y | Element type |
presets.<name>.audio[X].params | object | y | Element or caps parameters |
presets.<name>.audio[X].params.type | string | y | Element or caps type ex: audio/x-raw or audioconvert |
presets.<name>.audio[X].params.props | object | n | Element or caps properties, ex: { "bitrate": 160000, "bitrateUnit": "b" } . bitrate property is specific, you must define the unit associated to this value with bitrateUnit field. It will be used to keep the original bitrate if media's bitrate is lower than the one you wrote |