如何逐帧阅读视频?

时间:2014-07-03 11:27:29

标签: java video image-processing

我想逐帧读取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()) };

谢谢!

3 个答案:

答案 0 :(得分:9)

您可以使用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);
    }

答案 1 :(得分:3)

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

enter image description here

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

可以检查源代码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();
    }
}

答案 2 :(得分:1)

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

请参阅此问题:ffmpeg split avi into frames with known frame rate

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