【发布时间】:2014-04-10 14:01:04
【问题描述】:
我刚刚使用 java fx 创建了一个应用程序,可以循环文件夹中的视频。 我必须设置下一个视频触发 setonendofmedia 事件,所以它们处于一个循环中,但问题是应用程序在开始时加载每个视频,所以过了一会儿它会填满内存并崩溃。 是否有其他方法可以循环播放视频而不预先加载它们或每隔一段时间刷新内存?
这是我的代码:
package application;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBoxBuilder;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
class SceneGenerator {
private int xSize;
private int ySize;
public SceneGenerator(int xSize,int ySize){
this.xSize=xSize;
this.ySize=ySize;
}
public Scene createScene() {
final StackPane layout = new StackPane();
// determine the source directory for the playlist
final File dir = new File(System.getProperty("user.dir")+"\\video");
if (!dir.exists() || !dir.isDirectory()) {
JOptionPane.showMessageDialog(null,"Cannot find video source directory: " + dir);
Platform.exit();
System.exit(0);
return null;
}
//inizializzo il toolkit
// create some media players.
final List<MediaPlayer> players = new ArrayList<MediaPlayer>();
for (String file : dir.list(new FilenameFilter() {
@Override public boolean accept(File dir, String name) {
return name.endsWith(".mp4")||name.endsWith(".flv");
}
})) players.add(createPlayer("file:///" + (dir + "\\" + file).replace("\\", "/").replaceAll(" ", "%20")));
if (players.isEmpty()) {
System.out.println("No video found in " + dir);
Platform.exit();
System.exit(0);
return null;
}
// create a view to show the mediaplayers.
final MediaView mediaView = new MediaView(players.get(0));
mediaView.setPreserveRatio(false);
mediaView.setFitHeight(ySize-((ySize/100)*(JavaPlayer.panelSouthYDimension+1)-JavaPlayer.pixelAdattamento));
mediaView.setFitWidth(xSize);
// play each audio file in turn.
for (int i = 0; i < players.size(); i++) {
final MediaPlayer player = players.get(i);
final MediaPlayer nextPlayer = players.get((i + 1) % players.size());
player.setOnEndOfMedia(new Runnable() {
@Override public void run() {
mediaView.setMediaPlayer(nextPlayer);
nextPlayer.seek(nextPlayer.getStartTime());
nextPlayer.play();
}
});
}
// start playing the first track.
mediaView.setMediaPlayer(players.get(0));
mediaView.getMediaPlayer().play();
// layout the scene.
layout.setStyle("-fx-background-color: black; -fx-font-size: 20; -fx-padding: 0; -fx-alignment: center;");
layout.getChildren().addAll(
VBoxBuilder.create().spacing(10).alignment(Pos.CENTER).children(
mediaView).build()
);
return new Scene(layout);
}
/** sets the currently playing label to the label of the new media player and updates the progress monitor. */
/** @return a MediaPlayer for the given source which will report any errors it encounters */
private MediaPlayer createPlayer(String aMediaSrc) {
// System.out.println("Creating player for: " + aMediaSrc);
final MediaPlayer player = new MediaPlayer(new Media(aMediaSrc));
player.setOnError(new Runnable() {
@Override public void run() {
System.out.println("Media error occurred: " + player.getError());
}
});
return player;
}
}
您好,感谢您的代码,我目前使用的是 java 7,一切正常,但是一旦加载了视频,它就永远不会释放,因此内存消耗仍然很高。 我尝试使用 system.gc,但似乎还不够。有什么建议吗?提前致谢。
class SceneGenerator {
private int xSize;
private int ySize;
public SceneGenerator(int xSize,int ySize){
this.xSize=xSize;
this.ySize=ySize;
}
公共场景 createScene() { 最终 StackPane 布局 = new StackPane();
// determine the source directory for the playlist
final File dir = new File(System.getProperty("user.dir")+"\\video");
if (!dir.exists() || !dir.isDirectory()) {
JOptionPane.showMessageDialog(null,"Cannot find video source directory: " + dir);
Platform.exit();
System.exit(0);
return null;
}
//inizializzo il toolkit
final MediaView mediaView = new MediaView();
mediaView.setPreserveRatio(false);
mediaView.setFitHeight(ySize-((ySize/100)*(JavaPlayer.panelSouthYDimension+1)-JavaPlayer.pixelAdattamento));
mediaView.setFitWidth(xSize);
final int QUEUE_SIZE = 2 ; // should be enough
final BlockingQueue<MediaPlayer> playerQueue = new ArrayBlockingQueue<>(QUEUE_SIZE);
final Thread createPlayerThread = new Thread(new Runnable() {
@Override
public void run() {
// create some media players.
List<String> videoFiles = new ArrayList<String>();
for (String file : dir.list(new FilenameFilter() {
@Override public boolean accept(File dir, String name) {
return name.endsWith(".mp4")||name.endsWith(".flv");
}
})) videoFiles.add("file:///" + (dir + "\\" + file).replace("\\", "/").replaceAll(" ", "%20"));
int nextFileIndex = 0 ;
while (true) {
System.gc();
MediaPlayer player = new MediaPlayer(new Media(videoFiles.get(nextFileIndex).toString())); // create
player.setOnEndOfMedia(new Runnable() {
@Override
public void run() {
final Task<MediaPlayer> nextPlayerTask = new Task<MediaPlayer>() {
@Override
public MediaPlayer call() {
try {
return playerQueue.take();
} catch (InterruptedException e) {
JOptionPane.showMessageDialog(null, "Error in SceneGenerator() : "+e.getMessage());
return null;
}
}
};
nextPlayerTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {
MediaPlayer player = nextPlayerTask.getValue();
mediaView.setMediaPlayer(player);
player.play();
}
});
new Thread(nextPlayerTask).start();
}
});
try {
playerQueue.put(player); // this will block if the queue is full...
} catch (InterruptedException exc ) { // shouldn't happen...
exc.printStackTrace();
return ;
}
nextFileIndex = (nextFileIndex + 1) % videoFiles.size();
}
}
});
createPlayerThread.setDaemon(true); // won't block application exit
// Layout etc
createPlayerThread.start();
// start first player. In theory, this could block, so call it before you show the stage:
MediaPlayer firstPlayer;
try {
firstPlayer = playerQueue.take();
mediaView.setMediaPlayer(firstPlayer);
firstPlayer.play();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
JOptionPane.showMessageDialog(null, "Error in SceneGenerator() : "+e.getMessage());
}
// layout the scene.
layout.setStyle("-fx-background-color: black; -fx-font-size: 20; -fx-padding: 0; -fx-alignment: center;");
layout.getChildren().addAll(
VBoxBuilder.create().spacing(10).alignment(Pos.CENTER).children(
mediaView).build()
);
return new Scene(layout);
}
}
【问题讨论】:
-
我对 javaFX 不是很熟悉,但是我非常熟悉垃圾收集的工作原理。乍一看(也许我只是错过了它),但看起来你并没有摆脱玩家数组列表中的项目。我想这些项目会占用大量内存,并且通过在数组列表中保留对它们的引用,可以防止 GC 释放内存。也许您也可以等待创建播放器(并且只存储文件路径),直到它准备好播放(或队列中的下一个)。对不起,如果这没有帮助,就像我说的那样,我对 javaFX 不是很熟悉。