I want to get a frame sample (jpeg) from a video file (mov) with java. Is there an easy way to do this. When I search in google all I can find is to make mov from multiple jpgs. I dont know maybe I cannot find the right keywords.
Press ALT+PRINT SCREEN. Play the video and pause it at the point you want to take a still from it. Press PRINT SCREEN or ALT+PRINT SCREEN, depending on whether the video is playing full screen or in an active window.
On the Selection and media controls toolbar, click the Extract Frames button and select Extract Current Frame. In the Extract Current Frame dialog box, select a folder in which to save your file. In the File name field, type a filename. Click the Save as type drop-down list and select a file format.
I know that the original question is solved, nevertheless, I am posting this answer in case anyone else got stuck like I did.
Since yesterday, I have tried everything, and I mean everything to do this. All available Java libraries are either out of date, not maintained anymore or lack any kind of usable documentation (seriously??!?!)
I tried JFM (old and useless), JCodec (no documentation whatsoever), JJMpeg (looks promising but is very difficult and cumbersome to use due to lack of Java-class documentation), OpenCV auto-Java builds and a few bunch of other libraries that I cannot remember.
Finally, I decided to take a look at JavaCV's (Github link) classes and voila! It contains FFMPEG bindings with detailed documentations.
<dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv</artifactId> <version>1.0</version> </dependency>
Turns out there is a very easy way to extract video frames from a video file to a BufferedImage
and by extension a JPEG file. The class FFmpegFrameGrabber could be easily used for grabbing individual frames and converting them to BufferedImage
. A code sample is as follows:
FFmpegFrameGrabber g = new FFmpegFrameGrabber("textures/video/anim.mp4"); g.start(); for (int i = 0 ; i < 50 ; i++) { ImageIO.write(g.grab().getBufferedImage(), "png", new File("frame-dump/video-frame-" + System.currentTimeMillis() + ".png")); } g.stop();
Basically, this code dumps the first 50 frames of the video and saves them as a PNG file. The good thing is that the internal seek function, works on actual frames not keyframes (a problem that I had with JCodec)
You can refer to the JavaCV's homepage to find out more about other classes that can be used for capturing frames from WebCams etc. Hope this answer helps :-)
Xuggler does the job. They even give a sample code which does exactly what I need. Link is below
http://xuggle.googlecode.com/svn/trunk/java/xuggle-xuggler/src/com/xuggle/mediatool/demos/DecodeAndCaptureFrames.java
And I've modified the code in this link such that it saves only the first frame of the video.
import javax.imageio.ImageIO;
import java.io.File;
import java.awt.image.BufferedImage;
import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.MediaListenerAdapter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.xuggler.Global;
/**
* * @author aclarke
* @author trebor
*/
public class DecodeAndCaptureFrames extends MediaListenerAdapter
{
private int mVideoStreamIndex = -1;
private boolean gotFirst = false;
private String saveFile;
private Exception e;
/** Construct a DecodeAndCaptureFrames which reads and captures
* frames from a video file.
*
* @param filename the name of the media file to read
*/
public DecodeAndCaptureFrames(String videoFile, String saveFile)throws Exception
{
// create a media reader for processing video
this.saveFile = saveFile;
this.e = null;
IMediaReader reader = ToolFactory.makeReader(videoFile);
// stipulate that we want BufferedImages created in BGR 24bit color space
reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
// note that DecodeAndCaptureFrames is derived from
// MediaReader.ListenerAdapter and thus may be added as a listener
// to the MediaReader. DecodeAndCaptureFrames implements
// onVideoPicture().
reader.addListener(this);
// read out the contents of the media file, note that nothing else
// happens here. action happens in the onVideoPicture() method
// which is called when complete video pictures are extracted from
// the media source
while (reader.readPacket() == null && !gotFirst);
if (e != null)
throw e;
}
/**
* Called after a video frame has been decoded from a media stream.
* Optionally a BufferedImage version of the frame may be passed
* if the calling {@link IMediaReader} instance was configured to
* create BufferedImages.
*
* This method blocks, so return quickly.
*/
public void onVideoPicture(IVideoPictureEvent event)
{
try
{
// if the stream index does not match the selected stream index,
// then have a closer look
if (event.getStreamIndex() != mVideoStreamIndex)
{
// if the selected video stream id is not yet set, go ahead an
// select this lucky video stream
if (-1 == mVideoStreamIndex)
mVideoStreamIndex = event.getStreamIndex();
// otherwise return, no need to show frames from this video stream
else
return;
}
ImageIO.write(event.getImage(), "jpg", new File(saveFile));
gotFirst = true;
}
catch (Exception e)
{
this.e = e;
}
}
}
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.bytedeco.javacpp.opencv_core.IplImage;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FrameGrabber.Exception;
public class Read{
public static void main(String []args) throws IOException, Exception
{
FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber("C:/Users/Digilog/Downloads/Test.mp4");
frameGrabber.start();
IplImage i;
try {
i = frameGrabber.grab();
BufferedImage bi = i.getBufferedImage();
ImageIO.write(bi,"png", new File("D:/Img.png"));
frameGrabber.stop();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With