如何逐帧阅读video?

我想逐帧读取java8-64bit中的Mp4文件,并将每个帧作为jpg写入我的硬盘。 我的第一次尝试是使用JavaFX 2.2媒体播放器在View组件上播放该文件。 我想也许会有一个选项来注册一个观察者来获取一个事件,每次加载一个新的框架并准备在组件表面上绘制,但似乎没有这样的方法。 只抓住在组件上绘制的那些帧/像素就足够了。

这可以通过使用媒体播放器来完成吗? 我使用媒体播放器的原因是bcs这是我工作的最简单的解决方案。 我尝试了vlcj,只有32位,和gstreamer但没有运气:(

到目前为止我得到了什么:

public class VideoGrabber extends extends JFrame { // code for scene setup omitted final MediaView view = createMediaView(...) // some other stuff happens here // now start the video view.getMediaPlayer().seek(Duration.ZERO); view.getMediaPlayer().play(); view.getMediaPlayer().setOnEndOfMedia(new Runnable() { // save image when done BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_BGR view.paint(img.getGraphics()); ImageIO.write(img, "JPEG", new File("pic-"+System.currentTimeMillis()+".jpg")); }); // somewhere else to create private MediaView createMediaView(String url) { final Media clip = new Media(url); final MediaPlayer player = new MediaPlayer(clip); final MediaView view = new MediaView(player); view.setFitWidth(VID_WIDTH); view.setFitHeight(VID_HEIGHT); return view; } 

有什么方法可以做到以下几点:

 player.setOnNextFrameReady(final Event evt) { writeImage(evt.getFrame()) }; 

谢谢!

Marvin Framework提供了逐帧处理媒体文件的方法。 下面是一个简单的video处理示例,突出了斯诺克球的路径。

在此处输入图像描述

在左侧,video逐帧播放,帧间间隔为30ms。 在右侧,video逐帧播放,但通过简单的图像处理方法保持白球的所有位置。

这里可以查看源代码和video。

在使用Marvin请求媒体文件框架的基本源代码下面:

 public class MediaFileExample implements Runnable{ private MarvinVideoInterface videoAdapter; private MarvinImage videoFrame; public MediaFileExample(){ try{ // Create the VideoAdapter used to load the video file videoAdapter = new MarvinJavaCVAdapter(); videoAdapter.loadResource("./res/snooker.wmv"); // Start the thread for requesting the video frames new Thread(this).start(); } catch(MarvinVideoInterfaceException e){e.printStackTrace();} } @Override public void run() { try{ while(true){ // Request a video frame videoFrame = videoAdapter.getFrame(); } }catch(MarvinVideoInterfaceException e){e.printStackTrace();} } public static void main(String[] args) { MediaFileExample m = new MediaFileExample(); } } 

您可以使用MediaView的snapshot()。 首先将mediaPlayer连接到MediaView组件,然后使用mediaPlayer.seek()来搜索video位置。 然后您可以使用以下代码来提取图像框架:

  int width = mediaPlayer.getMedia().getWidth(); int height = mediaPlayer.getMedia().getHeight(); WritableImage wim = new WritableImage(width, height); MediaView mv = new MediaView(); mv.setFitWidth(width); mv.setFitHeight(height); mv.setMediaPlayer(mediaPlayer); mv.snapshot(null, wim); try { ImageIO.write(SwingFXUtils.fromFXImage(wim, null), "png", new File("/test.png")); } catch (Exception s) { System.out.println(s); } 

像ffmpeg这样的框架带有命令行工具,可以将video分成单独的帧(即文件夹中的图像)。

看到这个问题: ffmpeg将avi分成具有已知帧速率的帧

答案包含指向ffmpeg的Java框架的链接。