License
This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) License. To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
Copyright 2021 Sveriges Television AB
Introduction
This documentation is in a work-in-progress state. Not all features are yet described. |
This is a living, breathing guide. If you’d like to contribute, fork us on GitHub!
What is Encore?
Encore is a scalable video transcoding[1] tool, built on Open Source giants like FFmpeg and Redisson.
Why does it exist?
Encore was created to scale, and abstract the transcoding power of FFmpeg, and to offer a simple solution for Transcoding - Transcoding-as-a-Service.
See the Project History for more about that.
Who is it for?
Encore is aimed at the advanced technical user that needs a scalable video transcoding tool - for example, as a part of their VOD (Video On Demand) transcoding pipeline.
How can you use it?
For example, you could deploy a number of Encore instances within your existing Kubernetes/Docker/other container solution and let the running instances communicate with a Redis cluster (as a Queue message broker). Every instance can than pick the next job lot, and you can scale your transcoding as needed.
Features
-
Scalable - queuing and concurrency options
-
Flexible profile configuration
-
Possibility to extend FFmpeg functionality
-
Tested and tried in production
Encore is not
-
A live/stream transcoder
-
A Video packager (see Frequently Asked Questions)
-
A GUI application
Built with
-
Kotlin
-
Gradle
-
Spring Boot
-
FFmpeg
-
Redisson
-
and many other great projects
API, Profiles, and other formats will change now and then before we reach version 1.0.0 - Encore is currently considered a work-in-progress tool. It is used in daily production though. |
Encore - built on Open Source Giants
The User Guide
This part of the documentation describes how to build the project, and/or just use the pre-built jar to run it directly.
The appendix gives a few other examples of how you can run Encore |
Building the project
Note: This step is not needed if you are trying out Encore with the Docker Compose example.
-
Requires:
-
JDK 11 or later
-
An available Redis instance (default configuration: locally installed port 6379)
-
FFmpeg and Mediainfo (we recommend the versions present in Homebrew-AVTools repository, which has been tested to work with Encore).
-
To build Encore, with all tests, do:
$ ./gradlew clean build
$ ./gradlew clean build -x test
Run Encore as a runnable jar
You can run Encore on your local machine by starting up a local developer Application Profile. Get the pre-built encore jar, or first build the project and get the jar from ./build/libs/
foobar@foo:~$ SPRING_PROFILES_ACTIVE=local java -jar encore-x.y.z.jar
This will use the src/main/resources/application-local.yml configuration profile in Encore. |
If the startup fails, verify that you are fulfilling the requirements
Next, Continue to Posting your first EncoreJob
Posting your first EncoreJob
-
This step requires:
-
A running instance of Encore
-
A inputdir - where you put source files
-
A outputdir - where you want the encoded files to end up
-
1) Use one of the files from the test resources in the Encore project and copy this to your inputdir (Verify that you have access permissions to the inputdir and outputdir.)
$ cp src/test/resources/input/test.mp4 /tmp/input
2) Fire up a browser and http://<ENCORE_IP>:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/ - i.e directly to the Encore Swagger Interface for Posting an EncoreJob.
3) Finally, Under POST, hit the "Try it out" button and POST this example. (Replace the outputFolder and uri with your outputdir and inputdir/filename.)
{
"profile": "program",
"outputFolder": "/tmp/output",
"baseName": "quicktest_",
"inputs": [{
"uri": "/tmp/input/test.mp4",
"useFirstAudioStreams": 2,
"type": "AudioVideo"
}]
}
You can now see some output in your terminal, and after a while you should see a couple of encoded files in the outputdir. Congratulations, you did your first encoding with Encore!
Now, find out more about specific options, see Dynamically generated Endpoint documentation, or see the Concepts.
The Concept/Technical Guide
If you are looking for concepts, structures and API descriptions, this part of the documentation is for you.
Concepts
Workflow
The workflow for an Encore Job
-
An Encore Job is created
-
It is offered to a Queue[2]. At some point, the Encore Job is picked up from the Queue
-
Metadata needed for the coming transcoding task is gathered - for example, the input file is analyzed, the Profile is read.
-
The transcoding is started - (FFmpeg transcoding starts)
-
Output files are written to the configured destination
The Encore Job status field will roughly tell the observer where in the workflow it is currently (click to expand)
// SPDX-FileCopyrightText: 2020 Sveriges Television AB
//
// SPDX-License-Identifier: EUPL-1.2
package se.svt.oss.encore.model
enum class Status(val isCompleted: Boolean) {
NEW(false),
QUEUED(false),
IN_PROGRESS(false),
SUCCESSFUL(true),
FAILED(true),
CANCELLED(true);
val isCancelled: Boolean
get() = this == CANCELLED
}
Encore Job
An Encore Job is the aggregate for the information needed to transcode an input file - information like input files, profile and priority.
-
An Encore Job describes how an input file should be processed.
-
An Encore Job can have several output files, and one input file.
-
An Encore Job has a profile, which essentially describes how the job should configure it’s transcoding.
-
An Encore Job has a priority, which essentially describes how the job should be prioritized.
Profile
A Profile can be seen as a general abstraction of an FFmpeg configuration - example, bitrate to use, thumbnail generation, the codec to use.
-
A Profile specifies a big part of the configuration used by an Encore Job - metadata, FFmpeg configuration and specific codec configuration.
-
A Profile is specified in the yaml-format.
Scaling, distribution and queues
By using Redis (as a message broker/queue handler) and an internal concurrency scheduler, Encore can be scaled by setting up more instances, and allowing more concurrency.
-
An Encore instance uses Redis through Redisson’s Priority Blocking Queue. Jobs are scheduled on an Encore instance according to a given priority.
-
Furthermore, The Encore concurrency setting affects how many transcoding jobs be run on the same instance at once.
So, From an Encore instance’s point of view, the next Encore Job is chosen for transcoding according to its priority and according to how many concurrent tasks that are allowed on that instance.
API/Endpoints
Encore is built using the framework Spring Rest Data offering the default endpoints generated from the usage of this framework. However, other custom Endpoints exist.
Encore’s endpoints are described and self-documented in the OpenAPIv3 format.
Dynamically generated Endpoint documentation
To see and interact with the endpoints live, consult your
for example, if you ran it on your localhost:
This is the recommended way - dynamic, powerful and always up-to-date. |
Statically generated Endpoint documentation
To see a static version, refer to the Static Endpoints documentation.
The statically generated documentation needs to be cleaned up, as it is autogenerated, with quite a few quirks. This will happen when the project is mature. |
Models
Encore Job
The Encore Job is a central object in Encore. The Encore Job fields are described in the Dynamically generated Endpoint documentation, but also in the
The Encore Job class in Kotlin (click to expand)
// SPDX-FileCopyrightText: 2020 Sveriges Television AB
//
// SPDX-License-Identifier: EUPL-1.2
package se.svt.oss.encore.model
import com.fasterxml.jackson.annotation.JsonIgnore
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.data.annotation.Id
import org.springframework.data.redis.core.RedisHash
import org.springframework.data.redis.core.index.Indexed
import org.springframework.validation.annotation.Validated
import se.svt.oss.encore.model.input.Input
import se.svt.oss.mediaanalyzer.file.MediaFile
import java.net.URI
import java.time.OffsetDateTime
import java.util.UUID
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
import javax.validation.constraints.NotEmpty
import javax.validation.constraints.Positive
@Validated
@RedisHash("encore-jobs", timeToLive = (60 * 60 * 24 * 7).toLong()) // 1 week ttl
@Tag(name = "encorejob")
data class EncoreJob(
@Schema(
description = "The Encore Internal EncoreJob Identity", example = "fb2baa17-8972-451b-bb1e-1bc773283476",
accessMode = Schema.AccessMode.READ_ONLY, hidden = false, defaultValue = "A random UUID"
)
@Id val id: UUID = UUID.randomUUID(),
@Schema(
description = "External id - for external backreference", example = "any-string",
nullable = true
)
val externalId: String? = null,
@Schema(
description = "The name of the encoding profile to use",
example = "x264-animated", required = true
)
@NotBlank
val profile: String,
@Schema(
description = "A directory path to where the output should be written",
example = "/an/output/path/dir", required = true
)
@NotBlank
val outputFolder: String,
@Schema(
description = "Base filename of output files",
example = "any_file", required = true
)
@NotBlank
val baseName: String,
@Schema(
description = "The Creation date for the EncoreJob",
example = "2021-04-22T03:00:48.759168+02:00", accessMode = Schema.AccessMode.READ_ONLY,
defaultValue = "now()"
)
@Indexed
val createdDate: OffsetDateTime = OffsetDateTime.now(),
@Schema(
description = "An url to which the progress status callback should be directed",
example = "http://projectx/encorecallback", nullable = true
)
val progressCallbackUri: URI? = null,
@Schema(
description = "The queue priority of the EncoreJob",
defaultValue = "0", minimum = "0", maximum = "100"
)
@Min(0)
@Max(100)
val priority: Int = 0,
@Schema(
description = "The exception message, if the EncoreJob failed",
example = "input/output error", accessMode = Schema.AccessMode.READ_ONLY, nullable = true
)
var message: String? = null,
@Schema(
description = "The EncoreJob progress",
example = "57", accessMode = Schema.AccessMode.READ_ONLY, defaultValue = "0"
)
var progress: Int = 0,
@Schema(
description = "The Encoding speed of the job (compared to it's play speed/input duration)",
example = "0.334", accessMode = Schema.AccessMode.READ_ONLY, nullable = true
)
var speed: Double? = null,
@Schema(
description = "The time for when the EncoreJob was picked from the queue)",
example = "2021-04-19T07:20:43.819141+02:00", accessMode = Schema.AccessMode.READ_ONLY, nullable = true
)
var startedDate: OffsetDateTime? = null,
@Schema(
description = "The time for when the EncoreJob was completed (fail or success)",
example = "2021-04-19T07:20:43.819141+02:00", accessMode = Schema.AccessMode.READ_ONLY, nullable = true
)
var completedDate: OffsetDateTime? = null,
@Schema(
description = "Instruct Encore to overlay encoding metadata on the encoded video stream",
defaultValue = "false"
)
val debugOverlay: Boolean = false,
@Schema(
description = "Key/Values to append to the MDC log context", defaultValue = "{}"
)
val logContext: Map<String, String> = emptyMap(),
@Schema(description = "Seek to given time in seconds before encoding output.", nullable = true, example = "60.0")
val seekTo: Double? = null,
@Schema(description = "Limit output to given duration.", nullable = true, example = "60.0")
val duration: Double? = null,
@Schema(
description = "Time in seconds for when the thumbnail should be picked. Overrides profile configuration for thumbnails",
example = "1800.5", nullable = true
)
@Positive
val thumbnailTime: Double? = null,
@NotEmpty
val inputs: List<Input> = emptyList()
) {
@Schema(
description = "Analyzed models of the output files",
accessMode = Schema.AccessMode.READ_ONLY
)
var output = emptyList<MediaFile>()
@Schema(
description = "The Job Status",
accessMode = Schema.AccessMode.READ_ONLY
)
@Indexed
var status = Status.NEW
set(value) {
field = value
if (value.isCompleted) {
completedDate = OffsetDateTime.now()
}
if (value == Status.IN_PROGRESS) {
startedDate = OffsetDateTime.now()
}
}
val contextMap: Map<String, String>
@JsonIgnore
get() = mapOf(
"id" to id.toString(),
"file" to baseName,
"externalId" to (externalId ?: ""),
"profile" to profile
) + logContext
}
Profile
A Profile consists of toplevel metadata, and a list of encoding configuration types - encodes.
Field | Description | Constraint | Default |
---|---|---|---|
name |
profile name |
||
description |
a helpful description of the profile |
||
scaling |
directly matching the FFmpeg scaling algorithm options |
if given, one of the FFmpeg Scaling algorithm options |
lanczos |
encodes |
a list of encode types (configurations) for the profile |
AudioEncode X264Encode X265Encode ThumbnailEncode ThumbnailMapEncode |
Profile Encode Types
Audio
The AudioEncode type is, as the name implies, for audio encoding.
The AudioEncode type can exist at two levels in a Profile configuration:
-
As a field, audioEncode, in encodes: VideoEncode - the audio stream will be embedded in the output video container.
-
As a separate Encode type in the encodes list - the audio stream will be written to a separate output filestream.
TODO: Describe the new mapping logic
Field | Description | Constraint | Default |
---|---|---|---|
codec |
|||
bitrate |
optional |
||
samplerate |
The audio sample rate in hz |
48000 |
|
channels |
number of channels |
2 |
|
suffix |
suffix for the audio output file |
{codec]_{nrofchannels}.ch |
|
params |
map of FFmpeg parameters to the given codec - cutoff etc |
||
filters |
any optional filters to FFmpeg. |
||
audioMixPreset |
the name of the default AudioMixPreset to use, if any |
"default" |
|
skipIfNoAudioMixPreset |
don’t encode audio if no mix was found |
boolean |
false |
format |
output file extension |
mp4 |
Video
The VideoEncode type is, as the name implies, for video encoding.
VideoEncode is a base type, for building concrete (n)Encode type implementations on. Existing examples are X264Encode and X265Encode. It is not intended for direct usage.
Field | Description | Constraint | Default |
---|---|---|---|
width |
adds the scale filter (if scaling enabled) |
null, or -2 if only height is given |
|
height |
adds the scale filter (if scaling enabled) |
null, or -2 if only height is given |
|
twoPass |
true, false |
If FFmpeg transcoding should be twoPass |
true |
params |
general FFmpeg Encoding parameters (see examples, vsync etc) |
||
filters |
for adding extra FFmpeg Filters |
||
audioEncode |
AudioEncode or null |
||
suffix |
suffix added to the output filename |
||
format |
The file output format |
||
codec |
codec library to use |
example: libx264 |
The X264Encode will encode to AVC (H.264) video using libx264.
Field | Description | Constraint | Default |
---|---|---|---|
fields from VideoEncode |
|||
x264-params |
map of specific x264 codec library parameters |
deblock, keyint, etc, see Overwriting default preset settings - FFmpeg x264 and Profiles for examples |
|
format |
mp4 |
||
codec |
The X265Encode will encode to HEVC (H.265) video using libx265.
Field | Description | Constraint | Default |
---|---|---|---|
fields from VideoEncode |
|||
x265-params |
map of specific x265 codec library parameters |
deblock, scenecut, etc, see Passing Options for FFmpeg x265 and Profiles for examples |
|
format |
mp4 |
||
codec |
Image
ThumbnailMapEncode generates a thumbnailmap from the input video.
Field | Description | Constraint | Default |
---|---|---|---|
aspectWidth |
16 |
||
aspectHeight |
9 |
||
tileHeight |
90 |
||
cols |
12 |
||
rows |
20 |
ThumbnailEncode generates an image/images from the video. The extraction point/points are given as either a specific time, or, a list of percentages.
Field | Description | Constraint | Default |
---|---|---|---|
percentages |
[25, 50, 75] |
||
thumbnailWidth |
-2 |
||
thumbnailHeight |
1080 |
||
thumbnailTime |
1080 |
The Community Guide
General community information like the F.A.Q and links to Encore mentions.
Frequently Asked Questions
How can I package my transcoded media for online streaming (DASH and HLS)?
You could have a look at Shaka Packager, Bento4, and configure them to process the output of Encore.
How can I generate my own OpenAPI documentation, for import into X
To create your own OpenAPI-export from Encore so that you can transform it as you wish:
$ SPRING_PROFILES_ACTIVE=local ./gradlew clean generateOpenApiDocs
which will give you a build/openapi.json file for further processing.
For further information on how you can configure the API-generation, see the Springdoc Project |
I have great idea/bugfix/improvement to Encore, how do I submit it?
Can I write a plugin/extension for doing X in Encore?
Currently, there are no extensions interface endpoints, but you could, for example, add transcoding functionality by writing an FFMpeg filter - some examples of how that can done can be found at FFmpeg proxy filters - have a peek at the Homebrew AVTools for how to build an FFmpeg with them.
Also, open a discussion issue if you have any ideas regarding contributions about extensions to Encore that you want to discuss.
How can I create a profile doing X?
Have a look at a few profiles from the documentation or project test examples to learn how you can set different options. Also, see if you can do what you can do what you want with pure FFmpeg. It should then be doable to map that configuration to a custom profile.
Articles and talks
Article: 2021 - Encore - licensed to once again transcode - an article about how, and why, we released Encore as Open Source and an introduction to how it basically works.
Video: 2019 - FOSS made us do it - How Encore and FOSS tools enables the Video Encoding at SVT
Article: 2018 Encore - video transcoding at it’s core - while interesting for the project origins, it contains partially non-valid information as the code has been largely rewritten since then.
Third-party extensions
Eyevinn IAF plugin: An IAF plugin for SVT Encore
Support
There is no formal support - none, nada, nothing - for Encore directly from the main contributors / maintainers - but we would love if people use and improve the project, so here are some suggestions if you are stuck.
File an Issue on GitHub
You can always file an issue, ask a question, open a discussion issue, and we will most likely respond to that, when time allows.
Stack Overflow
If your question does not contain sensitive information, please ask a question on Stack Overflow and use the tag 'svtencore'. Maybe some other users will help you.
Project History
The initiative
It was around 2018, and it was time to yet again update the license and the hardware for our proprietary non-flexible transcoding solution. Although that unnamed solution had served us very well, we also had a history of less than optimal transcoding, flexibility and support when things went wrong. Around that period, it happened that, our organisation was preparing the next "Tekniksprint". A "Tekniksprint" is an "innovate for an entire sprint" period, which happens two times a year at our organisation. That time, a small team gathered, with the purpose of seeing how much of a video transcoding solution that could be built in two weeks. So, with warts, hacks and shortcuts, we had a fun Sprint period, and also ended up with something almost usable, see links. And, yes, it even had GUI, so that we could make it pretty demo friendly. However, it was not very robust, and something we could build further upon.
By having a Proof-of-Concept project, we now could now walk the long and winding internal organisation road of convincing everyone that we could, and that we should re-write the project seriously - considering flexibility, features and support in comparison with others.
The development
It almost became a meme for us, but in 2019 we wrote ut, tested it, and ran it in production, with so good results, that we could ditch out proprietary solution. In fact, Encore helped us achieve better quality, better flexibility, and saved us money - the costs for developing the Encore solution was multitudes less than buying just another new stack.
We now had an easier way to work with new codecs and transcoding features that would be impossible, had we chosen another proprietary solution.
The Open Source Encore
We always had the intention to Open Source the solution, as we heard that others, mainly friends in Public Broadcast organisations, had an interest in the product. So during 2019/20 , with almost every Sprint-period, we tried to have at least a task that was directly prepared with Open Sourcing Encore. Slowly, but determined.
From license research, documentation, basic code cleanups, removing the most SVT-specific code, and releasing libraries that would make it possible to release the project itself. Warts and all, finally we got there.
So far, Encore has been a success story for us at SVT. We sincerely hope that it can benefit you, and with time grow to be an even greater transcoding solution.
/The Videocore Team at SVT
The Contributor Guide
We gratefully accept contributions via pull requests.
Use the issue tracker to suggest feature requests, report bugs, and ask questions. This is also a great way to connect with the developers of the project as well as others who are interested in this solution.
Changing the code-base
Generally speaking, you should fork this repository, make changes in your own fork, and then submit a pull-request. This is often called the Fork-and-Pull model
-
All contributions to this project will be released under the inbound=outbound norm, that is, they are submitted under the projects main license.
-
By submitting a pull request or filing a bug, issue, or feature request, you agree to comply with this waiver of copyright interest. Details can be found in the EUPL 1.2 or later.
-
All new code should have associated unit tests that validate implemented features and the presence or lack of defects.
-
Additionally, the code should follow any stylistic and architectural guidelines prescribed by the project. In the absence of such guidelines, mimic the styles and patterns in the existing code-base.
Sign-off and optionally Sign each Commit
As part of filing a pull request you agree to the DCO, Developer Certificate of Origin
A DCO is a lightweight way for a contributor to confirm that they wrote or otherwise have the right to submit code or documentation to a project.
To confirm that you agree to the DCO, you need to sign off your commits when sending us a pull request.
Technically, this is done by supplying the -s
/--signoff
flag to git when committing:
$ git commit -s -m "add fix for the bug"
Optionally, you can also sign the commit with -S
which also gives your commit a nice verified button on GitHub,
but, it requires that you have a GPG keypair set up.
For mor information, see Sign commit on GitHub with GPG key
$ git commit -s -S -m "add fix for the bug"
For the difference in signoff and signing, see Git signoff vs signing
Git History
In order to maintain a high software quality standard, contributions should aim to follow these rules:
-
We pay more attention to the quality of commit messages. In general, we share the view on how commit messages should be written with the Git project itself:
-
Make separate commits for logically separate changes. For example, pure formatting changes that do not affect software behaviour usually do not belong in the same commit as changes to program logic.
-
Describe your changes well. Do not just repeat in prose what is "obvious" from the code, but provide a rationale explaining why you believe your change is necessary.
-
Describe your changes in the imperative. Instead of writing "Fixes an issue with transcoding" prefer "Fix an transcoding issue". Think about it like the commit only does something if it is applied. This usually results in more concise commit messages.
-
We are picky about whitespaces. Trailing whitespace and duplicate blank lines are simply a superfluous annoyance, and most Git tools flag them red in the diff anyway.
Have a look at basically any of Jeff King’s commits in the Git project.
Thank you for reading and happy contributing!
There are no more guides. You are now on your own. Thank you!.
Appendix
Application Properties
Beside the rich configuration possibilities of Spring Boot and friends, a few custom properties can be specified inside your application.properties file, inside your application.yml file, or as command line switches.
Key | Default | Description |
---|---|---|
local-temporary-encode |
false |
if true, encoding is done in a temporary folder on the Encore instance currently running the job. When done, the results are moved to the where the Encore Job’s output folder path is pointing. |
audio-mix-presets |
a default AudioMixPreset is created |
a list of AudioMixPresets to use |
concurrency |
2 |
Max nr of currently running encoding tasks (property starts at 0, so 0 gives 1 task). |
poll-initial-delay |
10 |
initial wait time in seconds before task starts. |
poll-delay |
5 |
wait before polling, in seconds, for next task after compilation of the current task. |
redis-key-prefix |
encore |
the prefix to identify your redis queue. Redis keys are named "$redisKeyPrefix-queue-$queueNo" |
security.enabled |
false |
enables basic auth, TODO: describe basic security logic |
security.user-password |
password for regular user |
|
security.admin-password |
password for the admin user |
|
open-api.title |
SVT Encore OpenAPI |
title shown in the OpenAPI url summary header |
open-api.description |
"Endpoints for Encore" |
description shown in the OpenAPI url summary header |
open-api.contact-name |
contact name shown in the OpenAPI gui summary header |
|
open-api.contact-email |
contact email shown in the OpenAPI gui summary header |
|
open-api.contact-url |
contact url shown in the OpenAPI gui summary header |
Field | Description | Constraint | Default |
---|---|---|---|
fallback-to-auto |
if true, sets the output audio channels to the number given by the AudioEncode field channel. |
the following conditions needs to apply for it to take effect: set to true nr of audio channels in input file > 0 AudioEncode channels = 2 OR between 1 and the "nr of audio channels in input file" |
true |
default-pan |
if configured, maps "autofound input audio channels" to the configured output channel configuration |
input file channels: configured AudioEncode channel: the pan filter configuration to use See the concrete Profiles for yaml example. Any configuration found in pan-mapping would take precedence over this configuration |
|
pan-mapping |
if configured, maps "found input audio channels" to the configured matching output channel configurations |
input file channels: configured AudioEncode channel: the pan filter configuration which should be used. See the concrete encore-settings configuration example for yaml-examples. Any configuration here takes precedence over configurations in default-pan |
For, clarity, here is how an encore-setting configuration with audio-mix-presets could look like in real life.
spring:
jackson:
time-zone: Europe/Stockholm
profile:
location: url:http://YOURPROFILESERVERURL/encore/prod/master/profiles.yml
encore-settings:
local-temporary-encode: true
audio-mix-presets:
default:
fallback-to-auto: false
default-pan:
2: stereo| c0 = c0 + 0.707*c2 + 0.707*c4 | c1 = c1 + 0.707*c2 + 0.707*c5
pan-mapping:
6:
2: stereo|c0=1.0*c0+0.707*c2+0.707*c4|c1=1.0*c1+0.707*c2+0.707*c5
de:
fallback-to-auto: false
pan-mapping:
6:
2: stereo|c0<0.25*c0+1.5*c2+0.25*c4|c1<0.25*c1+1.5*c2+0.25*c5
redis:
subscription-connection-pool-size: 25
connection-pool-size: 32
connection-minimum-idle-size: 5
uri: redis://YOURINSTANCE:6379
db: 1
Running Encore
As a complement to the UserGuide, here is a few more examples on how you can try out Encore.
-
Using Docker-Compose
-
Using Spring Boot BootRun
-
Building an Docker Image and run Encore in a Docker Container
Example: using Docker Compose
-
This step requires:
-
-
Use a docker-compose.yml
-
-
version: "3.7"
services:
redis:
image: redis:alpine
networks:
- encorenet
encore:
image: ghcr.io/svt/encore-debian:latest
depends_on:
- redis
environment:
- SPRING_PROFILES_ACTIVE=local
- SPRING_REDIS_HOST=redis
- PROFILE_LOCATION=url:https://raw.githubusercontent.com/svt/encore-doc/main/src/docs/asciidoc/examples/profile/profiles.yml
ports:
- "8080:8080"
volumes:
- /tmp/input:/tmp/input:rw # where your put your source files
- /tmp/output:/tmp/output:rw #put your output here
networks:
- encorenet
networks:
encorenet:
driver: bridge
and then
Linux
$ ./docker-compose up
Mac
$ ./docker compose up
and you should see Encore starting up.
By default, there are two folders mapped to your host system by using the example docker-compose file. /tmp/input and /tmp/output, which we will refer to as the inputdir and the outputdir Change these (in the docker-compose file) to something that suits your environment if you are not running on Linux. For example /Users/<YOURUSER>/input:/tmp/input should be fine on macos. |
Get the IP
On Linux: - To find the IP Docker-Compose creates (so that you can access Encore’s api).
$ docker inspect <nameOfDirectoryYouAreRunningFrom>_encorenet
By design Docker-compose creates a network called <nameOfDirectoryYouAreRunningFrom>_encorenet |
On macos: Use 'localhost'
Got the IP? - great! Continue to Posting your first EncoreJob
Example: run Encore with Spring Boot bootRun
You can run Encore on your local machine by starting up a local developer Application Profile:
foobar@foo:~$ SPRING_PROFILES_ACTIVE=local ./gradlew clean bootRun
This will use the src/main/resources/application-local.yml configuration profile in Encore. |
If the startup fails, verify that you are fulfilling the requirements
Continue to Posting your first EncoreJob
Example: run Encore in a Docker Image
-
Create or find a base FFmpeg/Mediainfo Docker image.
The given example installs a recent version of FFmpeg, with a few FFmpeg filters, and mediainfo. Modify as needed, using a tap of Homebrew as an installation base.
A FFmpeg Dockerfile example (click to expand)
FROM ubuntu:20.04
ENV LC_ALL C.UTF-8
ENV LANG C.UTF-8
ENV TZ Europe/Stockholm
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ARG USR="user"
RUN apt-get update && apt-get -y --no-install-recommends install \
build-essential \
curl \
sudo \
file \
locales \
ruby \
git \
expect \
openssh-client \
ca-certificates \
openjdk-11-jre-headless \
zip \
unzip
RUN localedef -i en_US -f UTF-8 en_US.UTF-8 && \
useradd -ms /bin/bash ${USR} && \
echo '${USR} ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers && \
echo 'Set disable_coredump false' >> /etc/sudo.conf
RUN mkdir -m777 /ffmpeg-filters
RUN bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
ENV PATH=/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH
ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk-amd64/
RUN brew tap svt/avtools && \
brew install openssl@1.1 && \
brew unlink openssl@1.1 && \
brew install openssl@3 && \
brew install ffmpeg-encore libsvg-proxy-filter libsrf-proxy-filter mediainfo && \
sudo rm -rf "$(brew --cache)"
RUN cp $(brew --prefix)/lib/libsvg_filter.so $(brew --prefix)/lib/libsrf_filter.so /ffmpeg-filters/
USER ${USR}
CMD ["ffmpeg", "-version"]
foobar@foo:~$ docker build -t encore-docker --build-arg DOCKER_BASE_IMAGE=<yourdockerbaseimage:youjustbuilt> .
foobar@foo:~$ docker run --network=host -v /tmp/input:/tmp/input -v /tmp/output:/tmp/output -e SPRING_PROFILES_ACTIVE='local' encore-docker
Continue to Posting your first EncoreJob
Homebrew AVTools
So you noticed that the FFmpeg Docker Example in the quickstart used the Repository Manager Brew? The creators of Encore, have released their Brew Formulas on GitHub: Homebrew AVTools.
For example, here is the Encore FFmpeg Brew Formula that with minor modifications, uses formulas for X264, X265, and SVT’s subtitle filter.
To use and install this version of FFmpeg locally, follow the examples given at the Homebrew AVTools README. |
# SPDX-FileCopyrightText: 2009-present, Homebrew contributors
# SPDX-FileCopyrightText: 2021 Sveriges Television AB
#
# SPDX-License-Identifier: BSD-2-Clause
class FfmpegEncore < Formula
desc "Play, record, convert, and stream audio and video"
homepage "https://ffmpeg.org/"
url "https://ffmpeg.org/releases/ffmpeg-4.3.1.tar.xz"
sha256 "ad009240d46e307b4e03a213a0f49c11b650e445b1f8be0dda2a9212b34d2ffb"
license "GPL-3.0-or-later"
revision 1
head "https://github.com/FFmpeg/FFmpeg.git"
option "with-ffplay", "Enable ffplay"
depends_on "nasm" => :build
depends_on "pkg-config" => :build
depends_on "aom"
depends_on "fdk-aac" => :recommended
depends_on "fontconfig"
depends_on "freetype"
depends_on "lame"
depends_on "libass"
depends_on "libsoxr"
depends_on "libssh"
depends_on "libvmaf"
depends_on "libvorbis"
depends_on "libvpx"
depends_on "openssl@3"
depends_on "x264-encore"
depends_on "x265-encore"
uses_from_macos "bzip2"
uses_from_macos "zlib"
conflicts_with "ffmpeg", because: "it also ships with ffmpeg binary"
resource "proxy_filter" do
url "https://github.com/SVT/ffmpeg-filter-proxy/archive/v1.0.tar.gz"
sha256 "9a9ddfe248ea299ffa5bf9643bed95913f00b3a9d4e03f402aebc3224e4f82f3"
end
if build.with? "ffplay"
depends_on "libxv" unless OS.mac?
depends_on "sdl2"
end
def install
args = %W[
--prefix=#{prefix}
--enable-shared
--enable-pthreads
--enable-version3
--enable-hardcoded-tables
--enable-avresample
--cc=#{ENV.cc}
--host-cflags=#{ENV.cflags}
--host-ldflags=#{ENV.ldflags}
--enable-gpl
--enable-libaom
--enable-libmp3lame
--enable-libvorbis
--enable-libvpx
--enable-libx264
--enable-libx265
--enable-lzma
--enable-libass
--enable-libfontconfig
--enable-libfreetype
--disable-libjack
--disable-indev=jack
--enable-libaom
--enable-openssl
--enable-libssh
--enable-libvmaf
--enable-nonfree
]
if !build.without? "fdk-aac"
args << "--enable-libfdk-aac"
end
args << "--enable-ffplay" if build.with? "ffplay"
args << "--enable-videotoolbox" if OS.mac?
# GPL-incompatible libraries, requires ffmpeg to build with "--enable-nonfree" flag, (unredistributable libraries)
# Openssl IS GPL compatible since 3, but due to this patch
# https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200609001340.52369-1-rcombs@rcombs.me/
# not being in this version we build from, we have to enable non-free anyway.
# When FFmpeg base is upgraded (including that patch), we should only enable-nonfree when
# fdk-aac is enabled (the default option)
# args << "--enable-nonfree" if !build.without?("fdk-aac")
resource("proxy_filter").stage do |stage|
@proxyfilterpath = Dir.pwd
stage.staging.retain!
end
cp_r Dir.glob("#{@proxyfilterpath}/*.c"), "libavfilter", verbose: true
inreplace "libavfilter/allfilters.c",
"extern AVFilter ff_vf_yadif;",
"extern AVFilter ff_vf_yadif;\nextern AVFilter ff_vf_proxy;\n"
inreplace "libavfilter/Makefile",
"# video filters",
"# video filters\nOBJS-\$(CONFIG_PROXY_FILTER) += vf_proxy.o\n"
system "./configure", *args
system "make", "install"
# Build and install additional FFmpeg tools
system "make", "alltools"
bin.install Dir["tools/*"].select { |f| File.executable? f }
# Fix for Non-executables that were installed to bin/
mv bin/"python", pkgshare/"python", force: true
end
test do
# Create an example mp4 file
mp4out = testpath/"video.mp4"
system bin/"ffmpeg", "-filter_complex", "testsrc=rate=1:duration=1", mp4out
assert_predicate mp4out, :exist?
end
end
If you use Homebrew-AVTools, the version of FFmpeg in use might be updated without any notice. |
Profiles
program: withforcekeyframe.yml
youtube: video.yml
name: program
description: Program profile
scaling: bicubic
encodes:
- type: X264Encode
suffix: 3100
twoPass: true
height: 1080
params:
b:v: 3100k
maxrate: 4700k
bufsize: 6200k
r: 25
vsync: 1
pix_fmt: yuv420p
force_key_frames: expr:not(mod(n,96))
profile:v: high
level: 4.1
x264-params:
deblock: 0,0
aq-mode: 1
bframes: 6
keyint: 192
keyint_min: 96
ref: 4
audioEncode:
type: AudioEncode
codec: aac
bitrate: 192k
suffix: STEREO
- type: X264Encode
suffix: 2069
twoPass: true
height: 720
params:
b:v: 2069k
maxrate: 3104k
bufsize: 4138k
r: 25
vsync: 1
pix_fmt: yuv420p
force_key_frames: expr:not(mod(n,96))
profile:v: main
level: 3.1
x264-params:
deblock: 0,0
aq-mode: 1
bframes: 6
keyint: 192
keyint_min: 96
ref: 4
audioEncode:
type: AudioEncode
codec: aac
bitrate: 128k
suffix: STEREO
- type: X264Encode
suffix: 1312
twoPass: true
height: 540
params:
b:v: 1312k
maxrate: 1968k
bufsize: 2524k
r: 25
vsync: 1
pix_fmt: yuv420p
force_key_frames: expr:not(mod(n,96))
level: 3.1
profile:v: main
x264-params:
deblock: 0,0
aq-mode: 1
bframes: 6
keyint: 192
keyint_min: 96
ref: 4
audioEncode:
type: AudioEncode
codec: aac
bitrate: 96k
suffix: STEREO
- type: X264Encode
suffix: 806
twoPass: true
height: 360
params:
b:v: 806121
maxrate: 1209182
bufsize: 1612242
r: 25
vsync: 1
pix_fmt: yuv420p
force_key_frames: expr:not(mod(n,96))
profile:v: main
level: 3.1
x264-params:
deblock: 0,0
aq-mode: 1
bframes: 6
keyint: 192
keyint_min: 96
ref: 4
audioEncode:
type: AudioEncode
codec: aac
bitrate: 96k
suffix: STEREO
- type: X264Encode
suffix: 320
twoPass: true
height: 234
params:
b:v: 324051
maxrate: 486077
bufsize: 648102
r: 25
vsync: 1
pix_fmt: yuv420p
force_key_frames: expr:not(mod(n,96))
profile:v: baseline
level: 3.1
x264-params:
deblock: 0,0
aq-mode: 1
keyint: 192
keyint_min: 96
ref: 3
audioEncode:
type: AudioEncode
codec: aac
bitrate: 96k
suffix: STEREO
- type: AudioEncode
codec: aac
bitrate: 192k
suffix: STEREO
params:
cutoff: 20000
- type: AudioEncode
codec: aac
bitrate: 64k
suffix: STEREO_LB
params:
cutoff: 14000
- type: ThumbnailMapEncode
- type: ThumbnailEncode
name: youtube
description: Youtube upload
encodes:
- type: X264Encode
suffix: 10000
twoPass: false
height: 1080
params:
crf: 15
r: 25
vsync: 1
pix_fmt: yuv420p
profile:v: high
level: 5.1
x264-params:
vbv-maxrate: 10000
vbv-bufsize: 20000
deblock: 0,0
aq-mode: 1
bframes: 4
keyint: 202
keyint_min: 100
ref: 8
audioEncode:
type: AudioEncode
codec: aac
bitrate: 256k
suffix: STEREO
The Future
We have a few ideas where we would like to go with Encore. We are focusing on the features we need, but we are always open to suggestion and discussion, if you would like to contribute to the project.
Asciidoc Debug
- asciidoctor-version
-
2.0.10
- safe-mode-name
-
unsafe
- docdir
-
/home/runner/work/encore-doc/encore-doc/src/docs/asciidoc
- docfile
-
/home/runner/work/encore-doc/encore-doc/src/docs/asciidoc/encore-documentation.adoc
- imagesdir
-
{imagesdir}