Examples - a-schild/jave2 GitHub Wiki
Examples
Recipes for the conversions people ask for most. See Usage for how to add the library, and Supported formats for what the bundled ffmpeg can read and write.
Every example calls
attrs.setOutputFormat(...). Older examples elsewhere on the internet callattrs.setFormat(...), which has not existed for a long time and will not compile.
Audio
WAV to MP3
File source = new File("source.wav");
File target = new File("target.mp3");
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setBitRate(128000);
audio.setChannels(2);
audio.setSamplingRate(44100);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp3");
attrs.setAudioAttributes(audio);
new Encoder().encode(new MultimediaObject(source), target, attrs);
Extracting the audio from a video, as WAV
File source = new File("source.avi");
File target = new File("target.wav");
AudioAttributes audio = new AudioAttributes();
audio.setCodec("pcm_s16le");
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("wav");
attrs.setAudioAttributes(audio);
new Encoder().encode(new MultimediaObject(source), target, attrs);
Taking the soundtrack off a video, as MP3
Leaving VideoAttributes unset is what drops the picture.
File source = new File("source.mp4");
File target = new File("target.mp3");
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setBitRate(192000);
audio.setChannels(2);
audio.setSamplingRate(44100);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp3");
attrs.setAudioAttributes(audio);
new Encoder().encode(new MultimediaObject(source), target, attrs);
If the source audio is already MP3, audio.setCodec(AudioAttributes.DIRECT_STREAM_COPY)
lifts the stream out unchanged, which is both faster and lossless.
FLAC to MP4, audio only
An MP4 carrying nothing but sound. Same shape as above, a different container, and
setFaststart so it can be streamed.
AudioAttributes audio = new AudioAttributes();
audio.setCodec("aac");
audio.setBitRate(256000);
VideoAttributes video = new VideoAttributes();
video.setFaststart(true);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp4");
attrs.setAudioAttributes(audio);
attrs.setVideoAttributes(video);
Players that insist on a picture want a video stream, so for those, loop a still image
instead. See Encoding Attributes for setLoop.
FLAC to MP3, keeping the album art
Cover art is carried as a video stream, so an audio only encoding drops it. Ask for the video stream and ask for it unchanged.
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setBitRate(320000);
VideoAttributes video = new VideoAttributes();
video.setCodec("copy"); // this is what keeps the cover
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp3");
attrs.setAudioAttributes(audio);
attrs.setVideoAttributes(video);
new Encoder().encode(new MultimediaObject(source), target, attrs);
You can check it survived, since the cover shows up as a video stream:
boolean hasCover = new MultimediaObject(target).getInfo().getVideo() != null;
To AMR, for telephony
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libopencore_amrnb");
audio.setSamplingRate(8000); // amr-nb only does 8 kHz
audio.setChannels(1); // and mono
audio.setBitRate(12200);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("amr");
attrs.setAudioAttributes(audio);
Changing the volume
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setVolume(512); // 256 is unchanged, so this is twice as loud
Video
AVI to FLV
File source = new File("source.avi");
File target = new File("target.flv");
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setBitRate(64000);
audio.setChannels(1);
audio.setSamplingRate(22050);
VideoAttributes video = new VideoAttributes();
video.setCodec("flv");
video.setBitRate(160000);
video.setFrameRate(15);
video.setSize(new VideoSize(400, 300));
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("flv");
attrs.setAudioAttributes(audio);
attrs.setVideoAttributes(video);
new Encoder().encode(new MultimediaObject(source), target, attrs);
To MP4, H.264
AudioAttributes audio = new AudioAttributes();
audio.setCodec("aac");
audio.setBitRate(128000);
VideoAttributes video = new VideoAttributes();
video.setCodec("libx264");
video.setCrf(23); // 0 lossless, 51 worst, 23 is the usual default
video.setPreset(PresetEnum.MEDIUM.getPresetName()); // or just "medium"
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp4");
attrs.setAudioAttributes(audio);
attrs.setVideoAttributes(video);
To MP4 at a fixed size, two pass
When the size of the result matters more than the time it takes, let the encoder look at
the material first. setTwoPass(true) runs ffmpeg twice: once to measure, once to encode
using what it measured, so the bitrate lands where it does the most good.
AudioAttributes audio = new AudioAttributes();
audio.setCodec("aac");
audio.setBitRate(128000);
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.setAudioAttributes(audio);
attrs.setVideoAttributes(video);
attrs.setTwoPass(true);
A video bitrate is required, since that is the budget being planned, and this is the wrong
tool alongside setCrf, which asks for a quality rather than a size. See
Encoding Attributes for the details.
To WebM, VP9
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libopus");
audio.setBitRate(96000);
VideoAttributes video = new VideoAttributes();
video.setCodec("libvpx-vp9");
video.setBitRate(250000);
video.setFrameRate(25);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("webm");
attrs.setAudioAttributes(audio);
attrs.setVideoAttributes(video);
Taking a portion out of the middle
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp4");
attrs.setOffset(30.0f); // start thirty seconds in
attrs.setDuration(10.0f); // and take ten seconds
Videos filmed sideways
Phones record the orientation as metadata rather than rotating the picture, so a video that looks upright in a phone gallery can arrive on its side.
MultimediaInfo info = new MultimediaObject(source).getInfo();
if (info.getRotate() == 90 || info.getRotate() == 270) {
// width and height of info.getVideo().getSize() are the other way round
// once it is played back
}
Several files at once
Joining videos
List<MultimediaObject> sources = new ArrayList<>();
sources.add(new MultimediaObject(new File("part1.mp4")));
sources.add(new MultimediaObject(new File("part2.mp4")));
VideoAttributes video = new VideoAttributes();
video.setCodec("mpeg4");
FilterGraph graph = new FilterGraph();
FilterChain chain = new FilterChain();
chain.addFilter(new MediaConcatFilter(sources.size(), true, true)); // video, audio
graph.addChain(chain);
video.setComplexFiltergraph(graph);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp4");
attrs.setVideoAttributes(video);
new Encoder().encode(sources, target, attrs);
When several sources are joined there is no single source to describe, so
EncoderProgressListener.sourceInfois not called, and progress is reported asPROGRESS_UNKNOWNrather than a percentage.
Joining audio files
The same filter, told to take the audio streams and not the video ones. Note that the
filter graph still hangs off VideoAttributes even though the output has no video, since
that is where setComplexFiltergraph lives.
List<MultimediaObject> sources = new ArrayList<>();
sources.add(new MultimediaObject(new File("1.mp3")));
sources.add(new MultimediaObject(new File("2.mp3")));
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setChannels(2);
audio.setSamplingRate(44100);
FilterGraph graph = new FilterGraph();
FilterChain chain = new FilterChain();
chain.addFilter(new MediaConcatFilter(sources.size(), false, true)); // no video, audio
graph.addChain(chain);
VideoAttributes video = new VideoAttributes();
video.setComplexFiltergraph(graph);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp3");
attrs.setAudioAttributes(audio);
attrs.setVideoAttributes(video);
new Encoder().encode(sources, target, attrs);
The two booleans are which streams to carry: MediaConcatFilter(n, video, audio). Passing
(n, true, false) joins the pictures and drops the sound, and the single argument
constructor takes both, which fails if any source lacks either.
All the sources must have compatible streams. Files with different sample rates or channel counts need converting first, one at a time, and joining afterwards.
Stills
One frame
ScreenExtractor extractor = new ScreenExtractor();
extractor.renderOneImage(new MultimediaObject(source), 320, 240, 2000L, target, 2);
// w h millis file quality
A frame every so many seconds
extractor.render(new MultimediaObject(source), 320, 240, 5,
outputDirectory, "frame", "jpg", 2);
// every 5 seconds, into a directory
Filters
VideoAttributes video = new VideoAttributes();
// text across the picture
video.addFilter(new DrawtextFilter("watermark", "10", "10", "Sans", 24.0,
new Color("ffffff")));
// or scale it
video.addFilter(new ScaleFilter(new VideoSize(1280, 720)));
// or crop it
video.addFilter(new CropFilter(640, 480, 0, 0)); // width, height, x, y
Burning in subtitles takes the file itself, the filter escapes the path for you:
video.addFilter(new AssSubtitlesFilter(new File("subtitles.ass")));
Following along
new Encoder().encode(new MultimediaObject(source), target, attrs,
new EncoderProgressListener() {
public void sourceInfo(MultimediaInfo info) { }
public void progress(int permil) {
if (permil == EncoderProgressListener.PROGRESS_UNKNOWN) {
System.out.println("working");
} else {
System.out.println(permil / 10.0 + "%");
}
}
public void message(String message) { }
@Override public void done() {
System.out.println("finished");
}
});
PROGRESS_UNKNOWN, which is -1, means the source declared no duration, so there is
nothing for the progress to be a proportion of. Live streams, webm files from browser
recorders and concatenations all land there, and an indeterminate progress bar is the
right response.
Stopping a running encoding
encode() blocks, so to be able to abort it, run it on a thread of your own and keep the
Encoder where the other thread can reach it. abortEncoding() kills the ffmpeg process.
Encoder encoder = new Encoder();
Thread thread = new Thread(() -> {
try {
encoder.encode(new MultimediaObject(source), target, attrs, listener);
// finished
} catch (EncoderException ex) {
// failed, or was aborted
}
});
thread.start();
// later, from anywhere
encoder.abortEncoding();
quitEncoding() is the gentler alternative: it sends ffmpeg a q, so ffmpeg finishes
writing what it has and closes the file properly, leaving a shorter but playable result.
abortEncoding() kills the process outright and the partial file is usually unusable.
Neither is any use once the run has ended, and quitEncoding() throws if nothing is
running.
One Encoder runs one encoding at a time, since it keeps a single process, so give each
concurrent conversion its own.
With two pass encoding there are two processes one after the other, and aborting ends whichever is running and abandons the encoding as a whole. Aborting during the measuring pass therefore throws away work without producing anything, which is worth knowing if you abort often.
Something not covered here
If the option you need is not in the typed API, see Custom ffmpeg arguments.
The test sources in
jave-core-test
exercise most of the library against real files, and are worth reading when you want to see
a class used in anger.