Encoding Attributes - a-schild/jave2 GitHub Wiki
Encoding Attributes
Every encoding is described by one EncodingAttributes, which carries an
AudioAttributes and a VideoAttributes. Anything left unset is left to ffmpeg, which
generally means "keep what the source had" or "use the codec default", so you only need to
set what you actually want to change.
All three classes are in ws.schild.jave.encode, and their setters return this, so they
chain.
EncodingAttributes
| Method | What it does |
|---|---|
setOutputFormat(String) |
The container to write, "mp4", "webm", "mp3". Must be one the ffmpeg in use can write, see Encoder.getSupportedEncodingFormats() |
setInputFormat(String) |
Force how the source is read, for sources whose container cannot be guessed |
setAudioAttributes(AudioAttributes) |
Audio settings. Leave unset and the result has no audio |
setVideoAttributes(VideoAttributes) |
Video settings. Leave unset and the result has no video, including album art, which is carried as a video stream |
setOffset(Float) |
Start this many seconds into the source |
setDuration(Float) |
Encode only this many seconds |
setStreamLoop(Integer) |
Repeat the input this many extra times, -1 for endlessly |
setLoop(boolean) |
Loop the input, ffmpeg's -loop 1. This is how a still image becomes a video of some length, paired with setDuration |
setMapMetaData(boolean) |
Carry the source metadata across into the output |
setSafe(Integer) |
The concat demuxer's -safe, for joining via a list file |
setTwoPass(boolean) |
Encode twice, measuring the material before spending the bitrate. Needs VideoAttributes.setBitRate, see below |
setFilterThreads(int) |
Threads for filtering |
setDecodingThreads(int) |
Threads for decoding |
setEncodingThreads(Integer) |
Threads for encoding |
setExtraContext(Map<String, String>) |
Values your own EncodingArguments can read, see Custom ffmpeg arguments |
Limiting the CPU an encoding may use is the thread trio:
EncodingAttributes attrs = new EncodingAttributes();
attrs.setDecodingThreads(2);
attrs.setEncodingThreads(2);
attrs.setFilterThreads(2);
Two pass encoding
With setTwoPass(true) ffmpeg is run twice over the same input. The first run encodes the
video only to measure it, writing what it learns to a statistics file and throwing the
pictures away. The second encodes for real and uses those measurements to decide where the
bitrate is worth spending. On material that is not uniformly difficult, a quiet scene
followed by a busy one, a fixed budget buys noticeably better quality that way. It costs
roughly twice the time.
VideoAttributes video = new VideoAttributes();
video.setCodec("libx264");
video.setBitRate(1200000); // the budget the two passes exist to spend well
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp4");
attrs.setVideoAttributes(video);
attrs.setAudioAttributes(audio);
attrs.setTwoPass(true);
Two things follow from what it is for:
- A video bitrate is required. Without one there is no budget to plan, and
validate()says so rather than running ffmpeg twice for nothing. - It does not go with
setCrf. Constant rate factor asks for a quality and accepts whatever bitrate that takes, so there is nothing to allocate and one pass already gives the same answer. Use one or the other.
The statistics file is written to the temporary directory under a name of the library's choosing and removed afterwards, so nothing is left beside your output.
Two passes are reported to an EncoderProgressListener as one encoding: the progress runs
from 0 to 1000 once across both, with each pass taking half the range, sourceInfo is
called once at the start and done() once at the end. The halves are equal, which is a
simplification, since measuring is usually quicker than encoding.
AudioAttributes
| Method | What it does |
|---|---|
setCodec(String) |
The encoder to use, from Encoder.getAudioEncoders(). AudioAttributes.DIRECT_STREAM_COPY ("copy") takes the source stream unchanged, which is much faster and lossless, but only works when the target container accepts that codec |
setBitRate(Integer) |
Bits per second, so 128 kb/s is setBitRate(128000) |
setSamplingRate(Integer) |
Hertz, so CD rate is setSamplingRate(44100) |
setChannels(Integer) |
1 mono, 2 stereo |
setVolume(Integer) |
256 leaves the volume alone, below quietens, above amplifies |
setQuality(Integer) |
Codec dependent variable bitrate quality, for encoders that take one |
Volume used to be passed to ffmpeg as
-vol, which ffmpeg removed. Since 4.0.0 the library applies it as a volume filter instead, so the same256scale keeps working on current binaries. It occupies the-afslot, so if you also want audio filters of your own, put the volume into your own filter chain rather than setting both.
VideoAttributes
| Method | What it does |
|---|---|
setCodec(String) |
The encoder to use, from Encoder.getVideoEncoders(). VideoAttributes.DIRECT_STREAM_COPY ("copy") takes the source stream unchanged |
setBitRate(Integer) |
Bits per second, so 360 kb/s is setBitRate(360000) |
setFrameRate(Integer) |
Frames per second |
setSize(VideoSize) |
Output dimensions, setSize(new VideoSize(512, 384)). ws.schild.jave.info.VideoSize |
setTag(String) |
The fourcc written into the container, "DIVX" and friends, which is how some players decide which decoder to run |
setPixelFormat(String) |
"yuv420p" and the like. Worth setting for H.264 that must play on older devices |
setCrf(Integer) |
Constant rate factor, 0 lossless to 51 worst, 23 is the usual x264 default. An alternative to a bitrate rather than an addition to one |
setPreset(String) |
How hard the encoder works, "ultrafast" through "placebo". Takes a String, so use PresetEnum.MEDIUM.getPresetName() if you want the enum |
setTune(TuneEnum) |
FILM, ANIMATION, GRAIN, STILLIMAGE, FASTDECODE, ZEROLATENCY, PSNR, SSIM |
setX264Profile(X264_PROFILE) |
BASELINE, MAIN, HIGH, HIGH10, HIGH422, HIGH444 |
setQuality(Integer) |
Codec dependent quality scale |
setFaststart(boolean) |
Move the mp4 index to the front, so the file can start playing before it has fully downloaded |
setVsync(VsyncMethod) |
PASSTHROUGH, CFR, VFR, DROP, AUTO |
setComplexFiltergraph(FilterGraph) |
A whole filter graph, which is how several inputs are joined, see Examples |
addFilter(VideoFilter) |
One filter onto the chain, scaling, cropping, text, subtitles |
setVsyncis named after ffmpeg's old-vsync, which ffmpeg removed in favour of-fps_mode. Since 4.0.0 the library asks the executable in front of it which spelling it takes and sends that one, so this setter works on both old and new binaries and the name is kept only for compatibility.
Related
- Usage -- putting these together into an encoding
- Examples -- settings that suit particular formats
- Custom ffmpeg arguments -- when the option you want is not here