Sunday, March 29, 2015

JCodec - Grabbing and saving picture frames from video

JCodec is an open source pure java implementation of video and audio codecs and formats (this statement was ripped from the website (http://jcodec.org/index.html). It's a nifty API, with a nice license (BSD), but sadly, as with open source software, the documentation can get a little bit stale.

The code listed on the website (as of Mar 29, 2015) to get a single frame works on v0.1.5, but as usual, being a person who wants to work with the latest and greatest piece of API, I got the v0.1.9 version from Maven (http://search.maven.org/#search%7Cga%7C1%7Cjcodec) and tried to run the code sample.

Alas, it didn't compile. After searching high and low for a remedy with the javadocs, and sidetracked to trying Apache Imaging (still in incubation), and took a look on OpenIMAJ (www.openimaj.org/), I still can't find a way to get a single frame with v0.1.9.

I finally got frustrated and just downloaded the v0.1.5 sources and see how it was implemented then. I realised that v0.1.9 removed the dependency on javax.imageio. That's why the example code didn't work. So I took some code out in v0.1.5 and reapplied to v0.1.9 just to test it out:



import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;

import javax.imageio.ImageIO;

import org.jcodec.api.FrameGrab;
import org.jcodec.common.FileChannelWrapper;
import org.jcodec.common.NIOUtils;
import org.jcodec.common.model.ColorSpace;
import org.jcodec.common.model.Picture;
import org.jcodec.scale.ColorUtil;
import org.jcodec.scale.Transform;
import org.junit.Test;

public class JCodecTests {

 @Test
 public void testSingleFrame_v019() throws Exception {
  int frameNumber = 150;
  Picture frame = FrameGrab.getNativeFrame(new File("D:/yk/mymovie.mp4"), frameNumber);

        Transform transform = ColorUtil.getTransform(frame.getColor(), ColorSpace.RGB);
        Picture rgb = Picture.create(frame.getWidth(), frame.getHeight(), ColorSpace.RGB);
        transform.transform(frame, rgb);
        BufferedImage bi = toBufferedImage(rgb);
        ImageIO.write(bi, "png", new File("frame_150.png"));
 }
}


It's a little bit 'exposed', but this would work, for now.

Lesson learnt: Go directly to the source! Long live open source!