Recommended Java library for creating a video programmatically

24,046

Solution 1

I've used the code mentioned below to successfully perform items 1, 2, and 4 on your requirements list in pure Java. It's worth a look and you could probably figure out how to include #3.

http://www.randelshofer.ch/blog/2010/10/writing-quicktime-movies-in-pure-java/

Solution 2

I found a tool called ffmpeg which can convert multimedia files form one format to another. There is a filter called libavfilter in ffmpeg which is the substitute for vhook which allows the video/audio to be modified or examined between the decoder and the encoder. I think it should be possible to input raw frames and generate video. I researched on any java implementation of ffmpeg and found the page titled "Getting Started with FFMPEG-JAVA" which is a JAVA wrapper around FFMPEG using JNA.

Solution 3

You can try a pure Java codec library called JCodec.
It has a very basic H.264 ( AVC ) encoder and MP4 muxer. Here's a full sample code taken from the their samples -- TranscodeMain.

private static void png2avc(String pattern, String out) throws IOException {
    FileChannel sink = null;
    try {
        sink = new FileOutputStream(new File(out)).getChannel();
        H264Encoder encoder = new H264Encoder();
        RgbToYuv420 transform = new RgbToYuv420(0, 0);

        int i;
        for (i = 0; i < 10000; i++) {
            File nextImg = new File(String.format(pattern, i));
            if (!nextImg.exists())
                continue;
            BufferedImage rgb = ImageIO.read(nextImg);
            Picture yuv = Picture.create(rgb.getWidth(), rgb.getHeight(), ColorSpace.YUV420);
            transform.transform(AWTUtil.fromBufferedImage(rgb), yuv);
            ByteBuffer buf = ByteBuffer.allocate(rgb.getWidth() * rgb.getHeight() * 3);

            ByteBuffer ff = encoder.encodeFrame(buf, yuv);
            sink.write(ff);
        }
        if (i == 1) {
            System.out.println("Image sequence not found");
            return;
        }
    } finally {
        if (sink != null)
            sink.close();
    }
}

This sample is more sophisticated and actually shows muxing of encoded frames into MP4 file:

private static void prores2avc(String in, String out, ProresDecoder decoder, RateControl rc) throws IOException {
    SeekableByteChannel sink = null;
    SeekableByteChannel source = null;
    try {
        sink = writableFileChannel(out);
        source = readableFileChannel(in);

        MP4Demuxer demux = new MP4Demuxer(source);
        MP4Muxer muxer = new MP4Muxer(sink, Brand.MOV);

        Transform transform = new Yuv422pToYuv420p(0, 2);

        H264Encoder encoder = new H264Encoder(rc);

        MP4DemuxerTrack inTrack = demux.getVideoTrack();
        CompressedTrack outTrack = muxer.addTrackForCompressed(TrackType.VIDEO, (int) inTrack.getTimescale());

        VideoSampleEntry ine = (VideoSampleEntry) inTrack.getSampleEntries()[0];
        Picture target1 = Picture.create(ine.getWidth(), ine.getHeight(), ColorSpace.YUV422_10);
        Picture target2 = null;
        ByteBuffer _out = ByteBuffer.allocate(ine.getWidth() * ine.getHeight() * 6);

        ArrayList<ByteBuffer> spsList = new ArrayList<ByteBuffer>();
        ArrayList<ByteBuffer> ppsList = new ArrayList<ByteBuffer>();
        Packet inFrame;
        int totalFrames = (int) inTrack.getFrameCount();
        long start = System.currentTimeMillis();
        for (int i = 0; (inFrame = inTrack.getFrames(1)) != null && i < 100; i++) {
            Picture dec = decoder.decodeFrame(inFrame.getData(), target1.getData());
            if (target2 == null) {
                target2 = Picture.create(dec.getWidth(), dec.getHeight(), ColorSpace.YUV420);
            }
            transform.transform(dec, target2);
            _out.clear();
            ByteBuffer result = encoder.encodeFrame(_out, target2);
            if (rc instanceof ConstantRateControl) {
                int mbWidth = (dec.getWidth() + 15) >> 4;
                int mbHeight = (dec.getHeight() + 15) >> 4;
                result.limit(((ConstantRateControl) rc).calcFrameSize(mbWidth * mbHeight));
            }
            spsList.clear();
            ppsList.clear();
            H264Utils.encodeMOVPacket(result, spsList, ppsList);
            outTrack.addFrame(new MP4Packet((MP4Packet) inFrame, result));
            if (i % 100 == 0) {
                long elapse = System.currentTimeMillis() - start;
                System.out.println((i * 100 / totalFrames) + "%, " + (i * 1000 / elapse) + "fps");
            }
        }
        outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList, ppsList));

        muxer.writeHeader();
    } finally {
        if (sink != null)
            sink.close();
        if (source != null)
            source.close();
    }
}
Share:
24,046
Neil Coffey
Author by

Neil Coffey

I am a UK-based software engineer specialising in Java development, but have had my finger in a number of pies over the last 30 or so years :) My regular working languages are Java, C/C++, C#, Objective C and (with a greater degree of hatred) Javascript. My recent interests and activities include: development of enterprise applications used by local government and healthcare organisations in the UK development of various web sites in the fields of software development and language learning internationally specialist focus on Java performance and algorithms mobile development (primarily iOS) French/Spanish/English translation of specialist IT material for a range of international companies and organisations

Updated on May 13, 2020

Comments

  • Neil Coffey
    Neil Coffey about 4 years

    Can anyone recommend a Java library that would allow me to create a video programmatically? Specifically, it would do the following:

    • take a series of BufferedImages as the frames
    • allow a background WAV/MP3 to be added
    • allow 'incidental' WAV/MP3s to be added at arbitrarily, programmatically specified points
    • output the video in a common format (MPEG etc)

    Can anybody recommend anything? For the picture/sound mixing, I'd even live with something that took a series of frames, and for each frame I had to supply the raw bytes of uncompressed sound data associated with that frame.

    P.S. It doesn't even have to be a "third party library" as such if the Java Media Framework has the calls to achieve the above, but from my sketchy memory I have a feeling it doesn't.