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 same 256 scale keeps working on current binaries. It occupies the -af slot, 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

setVsync is 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