Post

Exporting a video with an alpha channel using JavaCV.

Exporting a video with an alpha channel using JavaCV.

Transparency

A video with an alpha channel is convenient when we’re doing some clip editing. For me, I’d like to use that for karaoke videos, which has a karaoke animation video source on the top layer, and the background images on the bottom layer. When we overlay them in editing software, it’d look like this: a karaoke video frame

Things about video codecs

Only some special video codecs support alpha channels. The most used are:

CodecsThe pixel format that includes alphaAvailable ContainersSupported by PowerDirector
ffv1 (FFmpeg video codec #1)bgraAVI, MKV, MOV, NUT, …
qtrle (QuickTime Animation (RLE) video)argbMOV
PNGrgbaMOV

Above is the information I got on the Internet, not sure if there are more available containers, but the MOV is tested and is sure to work. (find more info here)

To see what pixel formats a codec supports with ffmpeg, run this command: (for the qtrle case)

1
ffmpeg -h encoder=qtrle

I’m using PowerDirector as the editing software, and it doesn’t support the ffv1 and qtrle transparent videos. After my test, it seems like PowerDirector only supports the PNG codec.

PNG?

Yes, PNG could be a video codec. Unlike others, PNG codec simply stores every single frame’s data without compression, which makes the file size huge compared to common codecs like h.265.

Implementation

Let’s output a video with a PNG codec and MOV format using the FFmpegFrameRecorder in JavaCV, and I’ll show you how to do it with Java BufferedImage.

Other codecs can be applied easily, just be careful to use the corresponding pixel formats. (Only the essential part of the code displayed here.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Setup a converter for coverting a buffered image to the accepted Frame format.
Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();

// Setup the buffered image you want to record.
BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

// Draw something on the buffered image.
Graphics2D imgG2d = (Graphics2D) bufferedImage.getGraphics();
imgG2d.fillRect(...);

// Setup the frame recorder.
FFmpegFrameRecorder frameRecorder = new FFmpegFrameRecorder(...);
frameRecorder.setFrameRate(...);
frameRecorder.setVideoBitrate(...);
frameRecorder.setVideoCodec(avcodec.AV_CODEC_ID_PNG);
frameRecorder.setPixelFormat(avutil.AV_PIX_FMT_RGBA);
frameRecorder.setFormat("mov");

try {
   frameRecorder.start();

   for(...){
      Frame frame = java2DFrameConverter.getFrame(bufferedImage);
      frameRecorder.record(frame, AV_PIX_FMT_ARGB);
   } 
} catch(...) {
    ...
}

frameRecorder.close();

It’s done. You can now output your own transparent videos!

Here are screenshots of comparison of our outputted video vs. Sayatoo’s vs. H265 common.

Our Format

ours

Sayatoo’s Format

sayatoo

H265 Common Format

h265

Why I wrote this post?

I am working on a karaoke software project, being confused about exporting a transparent video. In the end, I referenced the Sayatoo, the commercial karaoke software and found that it strangely used PNG as its video input. After a lot of attempts and I finally found that you have to use PNG codec for transparent videos, so that PowerDirector can recognize it.

References

This post is licensed under CC BY 4.0 by the author.