有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何逐帧读取视频?

我想逐帧读取java8-64位格式的Mp4文件,并将每个帧作为jpg写入硬盘。我的第一次尝试是使用JavaFX2.2媒体播放器来播放文件 在视图组件上。我想可能会有一个选项,在每次加载新帧并准备在组件表面上绘制时注册一个观察者以获取事件,但似乎没有这样的方法。 只抓取在组件上绘制的帧/像素就足够了

这可以通过使用媒体播放器来完成吗?我使用媒体播放器的原因是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()) };

谢谢


共 (3) 个答案

  1. # 2 楼答案

    您可以使用MediaView的快照()。 首先将mediaPlayer连接到MediaView组件,然后使用mediaPlayer。seek()查找视频位置。然后可以使用以下代码提取图像帧:

        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);
        }
    
  2. # 3 楼答案

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

    enter image description here

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

    可以检查源代码here和视频here

    下面是使用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();
        }
    }