Java 如何逐帧读取视频?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24552486/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to read a video frame by frame?
提问by Chris
i would like to read a Mp4 file in java8-64bit frame by frame and write each frame as a jpg to my harddisk. my first attempt was to use JavaFX 2.2 media player to play the file on a View component. i thought maybe there would be an option to register an observer to get an event each time a new frame was loaded and ready to be painted on the component surface but seems there is no such method. it would be enough to grab just those frames/pixels that got painted on the component.
我想逐帧读取 java8-64bit 中的 Mp4 文件,并将每一帧作为 jpg 写入我的硬盘。我的第一次尝试是使用 JavaFX 2.2 媒体播放器在 View 组件上播放文件。我想也许会有一个选项来注册观察者以在每次加载新帧并准备在组件表面上绘制时获取事件,但似乎没有这样的方法。只抓取在组件上绘制的那些帧/像素就足够了。
Can this be done by using the media player? the reason why i use the media player is bcs it was the simplest solution i got workin. i tryed vlcj, just 32bit, and gstreamer but without luck :(
这可以通过使用媒体播放器来完成吗?我使用媒体播放器的原因是 bcs 这是我工作的最简单的解决方案。我尝试过 vlcj、32 位和 gstreamer,但没有运气:(
what i got so far:
到目前为止我得到了什么:
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;
}
is there somehow a way to do the following:
有没有办法做到以下几点:
player.setOnNextFrameReady(final Event evt) { writeImage(evt.getFrame()) };
Thanks!
谢谢!
采纳答案by Gabriel Ambrósio Archanjo
Marvin Frameworkprovides methods to process media files frame by frame. Below it is shown a simple video processing example that highlights the path of a snooker ball.
Marvin Framework提供了逐帧处理媒体文件的方法。下面是一个简单的视频处理示例,突出显示了斯诺克球的路径。
At the left the video is played frame by frame with an interval of 30ms between frames. At the right the video is played frame by frame, but keeping all positions of the white ball through a simple image processing approach.
在左侧,视频逐帧播放,帧之间的间隔为 30 毫秒。在右侧,视频逐帧播放,但通过简单的图像处理方法保留了白球的所有位置。
The source code can be checked hereand the video here.
Below the essential source code to request media file frames using Marvin:
下面是使用 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();
}
}
回答by Aaron Digulla
Frameworks like ffmpegcome with command line tools to split a video into individual frames (i.e. images in a folder).
ffmpeg等框架带有命令行工具,可将视频拆分为单独的帧(即文件夹中的图像)。
See this question: ffmpeg split avi into frames with known frame rate
看到这个问题:ffmpeg split avi into frames with known frame rate
The answers contains links to Java frameworks which wrap ffmpeg.
答案包含指向包装 ffmpeg 的 Java 框架的链接。
回答by Clement Chen
You can use the snapshot() of MediaView. First connect a mediaPlayer to a MediaView component, then use mediaPlayer.seek() to seek the video position. And then you can use the following code to extract the image frame:
您可以使用 MediaView 的 snapshot()。首先将一个 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);
}