Search code examples
javaandroidimagevideo-encodingandroid-image

Video encode from sequence of images from java android


I would like to encode video from sequence of images with java only in my current android project. I mean without any use of external tools such as NDK.
Also is there any availability of java libraries for encoding video from sequence of images ?


Solution

  • You can use a pure java library called JCodec ( http://jcodec.org ). It contains a primitive yet working H.264 ( AVC ) encoder and a fully functioning MP4 ( ISO BMF ) muxer.
    Here's a CORRECTED code sample that uses low-level API:

    public void imageToMP4(BufferedImage bi) {
        // A transform to convert RGB to YUV colorspace
        RgbToYuv420 transform = new RgbToYuv420(0, 0);
    
        // A JCodec native picture that would hold source image in YUV colorspace
        Picture toEncode = Picture.create(bi.getWidth(), bi.getHeight(), ColorSpace.YUV420);
    
        // Perform conversion
        transform.transform(AWTUtil.fromBufferedImage(bi), yuv);
    
        // Create MP4 muxer
        MP4Muxer muxer = new MP4Muxer(sink, Brand.MP4);
    
        // Add a video track
        CompressedTrack outTrack = muxer.addTrackForCompressed(TrackType.VIDEO, 25);
    
        // Create H.264 encoder
        H264Encoder encoder = new H264Encoder(rc);
    
        // Allocate a buffer that would hold an encoded frame
        ByteBuffer _out = ByteBuffer.allocate(ine.getWidth() * ine.getHeight() * 6);
    
        // Allocate storage for SPS/PPS, they need to be stored separately in a special place of MP4 file
        List<ByteBuffer> spsList = new ArrayList<ByteBuffer>();
        List<ByteBuffer> ppsList = new ArrayList<ByteBuffer>();
    
        // Encode image into H.264 frame, the result is stored in '_out' buffer
        ByteBuffer result = encoder.encodeFrame(_out, toEncode);
    
        // Based on the frame above form correct MP4 packet
        H264Utils.encodeMOVPacket(result, spsList, ppsList);
    
        // Add packet to video track
        outTrack.addFrame(new MP4Packet(result, 0, 25, 1, 0, true, null, 0, 0));
    
        // Push saved SPS/PPS to a special storage in MP4
        outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList, ppsList));
    
        // Write MP4 header and finalize recording
        muxer.writeHeader();
    
    }
    

    You can download JCodec library from a project web site or via Maven, for this add the below snippet to your pom.xml:

    <dependency>
        <groupId>org.jcodec</groupId>
        <artifactId>jcodec</artifactId>
        <version>0.1.3</version>
    </dependency>
    

    [UPDATE 1] Android users can use something like below to convert Android Bitmap object to JCodec native format:

    public static Picture fromBitmap(Bitmap src) {
        Picture dst = Picture.create((int)src.getWidth(), (int)src.getHeight(), RGB);
        fromBitmap(src, dst);
        return dst;
    }
    
    public static void fromBitmap(Bitmap src, Picture dst) {
        int[] dstData = dst.getPlaneData(0);
        int[] packed = new int[src.getWidth() * src.getHeight()];
    
        src.getPixels(packed, 0, src.getWidth(), 0, 0, src.getWidth(), src.getHeight());
    
        for (int i = 0, srcOff = 0, dstOff = 0; i < src.getHeight(); i++) {
            for (int j = 0; j < src.getWidth(); j++, srcOff++, dstOff += 3) {
                int rgb = packed[srcOff];
                dstData[dstOff]     = (rgb >> 16) & 0xff;
                dstData[dstOff + 1] = (rgb >> 8) & 0xff;
                dstData[dstOff + 2] = rgb & 0xff;
            }
        }
    }