Code your own video converter

There are millions of great apps out there, but there is nothing more empowering than being able to write your own. That doesn’t always mean ‘from scratch’, either.

Previously, we showed you how to make use of Java threads to boss external apps. This time, we continue our look at the FFmpeg video transcoding tool and how to build a more complex user interface that supports popular video compression options, including the new High Efficiency Video Coding (HEVC) codec also known as ‘H.265’.

Codecs 101

The popular MX Player now supports hardware decoding of H.265 video.

The popular MX Player now supports hardware decoding of H.265 video.

A codec is short for ‘encoder-decoder’ and it’s the algorithm used to specify how your favourite video and audio files are compressed.

Raw audio and especially raw video files are immense in size by comparison with the compressed versions we use today.

H.264, also known as ‘AVC’, is the defacto standard — it’s supported in all iOS devices, Android since forever and most Windows, Mac OS X and Linux computers. It’s also used in new broadcast free-to-air digital TV and many Blu-ray movies.

But if it’s this common, why would you need a video converter? Well, for starters, DVD movies use the older MPEG-2 video codec, which isn’t natively supported in iOS, Android or Windows since Windows Media Center was given the axe.

The majority of free-to-air digital TV in Australia is still MPEG2-TS (transport stream), which is a slight but important variation on the form used in DVDs.

However, despite the universal love for H.264, nothing in tech stands still and, today, H.264 is beginning to lose its crown to the new kid on the block, H.265 or HEVC. So what’s so good about it?

Basically, it can do anything H.264 can do but in half the file size. So more or less, a 1GB video with H.264 compression becomes a 500MB H.265 file.

Devices supporting H.265?

vlc

Don’t have Windows 10? VLC media player has native support for H.265.

But having files encoded with H.265, you need something to play them back again. The good news is H.265 is native to Windows 10 and, for anything older, there’s always our favourite fallback option — VLC Media Player.

VLC also comes in versions for Mac OS X and Linux, so there’s really no excuse.

As for mobile devices, Android has supported H.265 natively since Lollipop (Android 5.0) and there are H.265 players on the App Store that work with iOS 6.0 or later.

Secret Source

comp

Our GUI app’s five main sections for file selection through to FFmeg output.

It’s important to point out the app we’re making does none of that — it’s simply a graphical user interface. The heavy lifting is done by the open-source command-line audio-video transcoding app called ‘FFmpeg’.

This is normally available as source-code that you compile, but as we saw last time, it’s also available as a ready-to-run executable app, something Java can still happily control.

FFmpeg runs on the command prompt, so for a very simple task, you could run:

ffmpeg –i input.avi output.mp4

Here, ‘ffmpeg’ is the name of the executable file, which always comes first and it’s followed by parameters or ‘switches’ that tell the app what you want it to do.

The ‘-i’ parameter stands for ‘input’ and indicates that the immediately following text is the name of the input video file. The only other part of the command is the ‘output.mp4’. FFmpeg always assumes the very last splash of text is the output filepath and name.

set

Many FFmpeg parameters can be set by combobox, checkbox or slide.

However, while this command works, it makes an awful lot of assumptions that aren’t always appropriate. For instance, we’re not actually setting the audio or video codecs, or their bit rates.

FFmpeg always finds the required codecs to decode the input file, but unless you specify otherwise, it makes assumptions on what it thinks you want for the output codecs — and it does that based on the output file extension.

Here, the output is an MP4 file, so it assumes you want H.264 video encoding and AAC (Advanced Audio Codec) audio encoding at default quality rates. But you can also encode H.265 video into an MP4 file container, even use MP3 audio.

Let’s try something more complex:

ffmpeg –i input.avi –c:v libx265 –preset fast –x265-params crf=29 –c:a libmp3lame –b:a 128k output.mp4

You’ll recognise the input file from before, but now, ‘-c:v’ means ‘codec:video’ and the name of the codec in this case is the built-in FFmpeg library file ‘libx265’ (x265 is the open-source version of H.265).

Next comes the ‘-preset’ parameter, which sets the encoding profile, determining the overall encoding speed and compactness of the output file. For this, we’ve chosen the mid-range ‘fast’ profile (more on that later).

Next, the ‘-x265-params’ code is FFmpeg’s way of interacting with specific libx265 library parameters and, here, we set CRF to a value of 29.

CRF stands for Constant Rate Factor. We could go on for hours on this but, instead, just briefly, CRF is a way to set a variable bit rate (and, largely, the file size) using a simple integer number based on a particular video quality level.

In CRF-speak, ‘0’ is perfection but big files, while ‘51’ is mostly rubbish and tiny files. A CRF of 29 is a good compromise between quality and file size, leaning slightly towards smaller file sizes.

Similarly, ‘-c:a’ is ‘codec:audio’ and here, we’re using libmp3lame to provide MP3 audio encoding.

Lastly, the ‘–b:a’ code indicates ‘bitrate:audio’ and sets the audio bitrate to 128Kbps. Note, we’re making the common assumption the audio stream is stereo only and ‘128k’ is the total audio bit rate, so it’ll be 64Kbps per channel, similar to your average music file.

Java's jComboBox is ideal for letting users pick FFmpeg profile options.

Java’s jComboBox is ideal for letting users pick FFmpeg profile options.

Now this code works, but it’s a safe bet you’d never remember that command-line code in a million years.

It’d be much simpler to just pull a slider control across to set the CRF or audio bit rate, use a couple of comboboxes to set the audio and video codecs and, finally, some file dialog boxes to set the input and output files.

That’s exactly what we do with our GUI app and there are many benefits from this.

First, you can effectively code your own converter to do what you want, without relying on someone else to hopefully code what you need.

Second, you can change the GUI code any time you want — you’re not waiting for an app update.

Third, you don’t need to cop bundled bloatware, nagware, malware or suck-your-CPU-dry-ware that often finds its way into popular free apps and into your computer.

How we built it

gui

Using NetBeans’ Swing GUI Builder makes creating a user interface easy.

As we’ve done previously in this masterclass, we’ve deliberately kept the user interface as simple as possible to cap the number of code lines and enable you to follow what’s going on.

The user interface is the one we built using NetBeans’ built-in Swing GUI Builder. Components such as text boxes and even file dialog boxes, we’ve looked at before, but the new component this time is the jSlider.

You’ve used them in apps galore, but here’s how you create your own in Java.

jSlider is a GUI component, and like almost every other GUI component, you attach a listener to it, enabling Java to lie in wait for your ‘click and drag’ before firing a method to perform some function in your code.

Normally, you’d get the listener to update a variable with a numeric value based on the slider’s position.

Let’s look:

class Slider1Listener implements ChangeListener {
@Override
public void stateChanged(ChangeEvent e) {
crf = jSlider1.getValue();
jLabel2.setText(crf+””);
}
}

To create the jSlider, just grab it from the palette in the Design panel and drag it onto the app window.

NetBeans automatically sets up a ‘free design’ platform, allow you to position components almost wherever you want.

slide

ChangeListeners make auto-adjusting jSlider controls very simple.

But to get our code to listen for the slider, we have to use the ChangeListener class.

Here, we’ve created our own version called ‘Slider1Listener’ that implements the ChangeListener class.

The ‘@override’ statement says, ‘Thanks, Java, we’ll take it from here!’ and we carry out the code in the ‘stateChanged’ method.

Here, the first thing we do is get the current value of jSlider1 using the ‘getValue()’ method and assign it to the variable ‘crf’ we’ve initialised earlier.

We then take ‘crf’ and add the value to jLabel2 using the setText() method so you can see it on the screen.

However, ‘crf’ is an integer variable and you normally can’t use one with setText() because it’s expecting a string. The proper way to fix this is to convert ‘crf’ to a string variable, but the cheat way is to simply concatenate an empty string (“”) to the end of it.

Java knows to convert the integer variable first before adding it to the empty string and the whole thing works.

Just be aware that this stateChanged() method fires every time the value of the slider changes — that means it’ll automatically continue to update as you pull the slider across from one side to the other.

As for how we launch the FFmpeg executable from within Java, that’s easy.

Take a look at this:

processFfmpeg = new ProcessBuilder(ffmpegPath, “-i”, infile,
“-c:v”, vcodec, preset1, preset2, preset3, preset4,
“-c:a”, acodec,”-b:a” ,apreset1, “-y”, outfile).start();

This is the key code. We create a new Java code stream or ‘thread’ that runs separately from the thread running the GUI app, and inside this new thread, we run the FFmpeg app and our series of parameters.

ProcessBuilder is Java’s preferred method for creating a thread and you’ll notice a couple of parameters we spoke of right at the start (e.g. ‘-c:a’, ‘-b:a’ and so on).

Using the app

Our GUI app makes driving FFmpeg simpler and easier to manage.

Our GUI app makes driving FFmpeg simpler and easier to manage.

As for how to use the app, launch it, hit the ‘ffmpeg path’ button and locate the ‘ffmpeg.exe’ binary executable file from the download earlier (it’ll be in the ‘bin’ subfolder).

Next, press the ‘Source’ button and load in your input file. After that, press the ‘Save file’ button and choose where you want to save the output file. If you don’t give it an ‘.mp4’ extension, the GUI app will do it automatically.

Following that, make your adjustments to the audio and video codec settings. Once you’re done adjusting, press the ‘Convert’ button and away it goes.

The app continuously captures the return data from FFmpeg and updates the big jTextArea as the conversion process continues.

When it’s complete, you’ll find your output file located in your folder of choice.

Video tests

Ffmpeg is the engine for many freeware video converters on the web.

FFmpeg is the engine for many freeware video converters on the web.

I love the whole concept of video compression, so what better way to test out a new GUI for FFmpeg than trying it out with a bunch of tests?

Remember we talked about the two key parameters being CRF and the Profile? You can see what effect each has on the encoding time and file size in the table — the smaller the CRF number (meaning the higher the quality), the larger the encoded file size.

The ‘slower’ the profile, the longer it takes, but typically, the smaller the file size. So you can have a situation where you use a CRF of 30 and a ‘fastest’ profile for a given file size, but a CRF/profile combo of 29/fast actually produces better quality with a smaller file size.

The downside is it takes longer to encode.

Using X.265, a CRF of 29 and the ‘fast’ profile, you can compress a 10-minute low-action 1080p (1920 x 1080-pixel) full-HD video clip at good quality into as little as 60MB. That’s pretty good going.

And now, doing these tests is just a matter of moving some sliders and choosing from a couple of comboboxes. Much easier than mucking around with command-line parameters!

Add your own features

But here’s the thing — now that you’ve seen how FFmpeg and its parameter options work, by learning to code, you can now choose any option you want and create your own personalised GUI app.

FFmpeg has a truckload of different parameter options — just read through the documentation to get an idea.

And FFmpeg is just one app — imagine the other apps awaiting you!

Learning to code is such an incredibly valuable skill, you’ll never look at another app the same way again.