java JavaFX 不支持 MP4?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16322983/
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
MP4 unsupported in JavaFX?
提问by Chaos
So I've recently started working with JavaFX to try and insert video and audio into my java programs. Audio has worked just fine, but for some reason every time I try and play a video file, it returns a MEDIA_UNSUPPORTED exception. I've read around and saw that the video file needed to be MP4 (which it is), so I tried converting it to a different type then re-converting it to MP4 (H.264 & AAC) with a few different converters and nothing changes.
所以我最近开始使用 JavaFX 尝试将视频和音频插入到我的 Java 程序中。音频工作得很好,但由于某种原因,每次我尝试播放视频文件时,它都会返回 MEDIA_UNSUPPORTED 异常。我已经阅读并看到视频文件需要是 MP4(它是),所以我尝试将它转换为不同的类型,然后使用几个不同的转换器将其重新转换为 MP4(H.264 和 AAC)和没有什么变化。
Here's the code I'm working with:
这是我正在使用的代码:
import java.net.URL;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.util.Duration;
public class CallVideo extends JFrame{
public static final String VID_URL = "file:/C:/Users/Public/Videos/Videos/testCon.mp4"; //http://static.clipcanvas.com/sample/clipcanvas_14348_H264_320x180.mp4
private JFXPanel panel;
public CallVideo(String url)
{
panel = new JFXPanel();
Platform.runLater(new Runnable()
{
public void run()
{
final Media clip = new Media(VID_URL);
final MediaPlayer player = new MediaPlayer(clip);
final MediaView viewer = new MediaView(player);
viewer.setFitHeight(200);
viewer.setFitWidth(200);
final Button button = new Button("Bing Zzzzt!");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event)
{
viewer.getMediaPlayer().seek(Duration.ZERO);
viewer.getMediaPlayer().play();
}
});
setMediaEventHandlers(viewer);
VBox vid = new VBox();
vid.getChildren().addAll(viewer, button);
Scene aScene = new Scene(vid, 200, 200);
panel.setScene(aScene);
}
});
this.add(panel);
this.setSize(500, 500);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
private void setMediaEventHandlers(final MediaView view) {
final MediaPlayer player = view.getMediaPlayer();
System.out.println("Initial: " + player.getStatus());
player.statusProperty().addListener(new ChangeListener<MediaPlayer.Status>() {
@Override
public void changed(ObservableValue<? extends MediaPlayer.Status> observable, MediaPlayer.Status oldStatus, MediaPlayer.Status curStatus) {
System.out.println("Current: " + curStatus);
}
});
if (player.getError() != null) {
System.out.println("Initial Error: " + player.getError());
}
player.setOnError(new Runnable() {
@Override public void run() {
System.out.println("Current Error: " + player.getError());
}
});
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new CallVideo(VID_URL);
}
});
}
}
}
The error occurs on the line where the "Media" object is initialized (beginning of constructor). I'm at a total loss to see what the problem is. I've seen questions about the audio playing but the video not showing up, but it doesn't even do that for me...
错误发生在初始化“媒体”对象的行(构造函数的开头)。我完全不知道问题出在哪里。我已经看到有关音频播放的问题,但视频没有出现,但它甚至对我来说都没有......
In case someone needs it:
如果有人需要它:
Eclipse
蚀
JDK 7
JDK 7
JavaFX 2.0
JavaFX 2.0
Windows 7 Pro
视窗 7 专业版
EDIT:
编辑:
First off, I noticed I'm actually using JavaFX 2.0... Might that be the problem?
首先,我注意到我实际上使用的是 JavaFX 2.0 ......这可能是问题所在吗?
I've tested both versions provided in the answer, and both return this error (called by the statusListener) when using the URL provided by that answer:
我已经测试了答案中提供的两个版本,并且在使用该答案提供的 URL 时都返回此错误(由 statusListener 调用):
Current Error: MediaException: MEDIA_UNSUPPORTED : com.sun.media.jfxmedia.MediaException: "Error enter code herelocator unsupported media format" : com.sun.media.jfxmedia.MediaException: "Error locator unsupported media format"
When using my own file, the program returns this error immediately upon calling the Media constructor, as before:
使用我自己的文件时,程序在调用 Media 构造函数时立即返回此错误,就像以前一样:
Exception in thread "AWT-EventQueue-0" MediaException: MEDIA_UNSUPPORTED : Unrecognized file signature!
at javafx.scene.media.Media.<init>(Media.java:382)
at CallVideo.<init>(CallVideo.java:27)
at CallVideo.run(CallVideo.java:90)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.accessimport javax.swing.*;
import javafx.application.Platform;
import javafx.beans.value.*;
import javafx.embed.swing.JFXPanel;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.media.*;
import javafx.util.Duration;
public class VideoPlayer extends JFrame {
public static final String VID_URL =
"http://static.clipcanvas.com/sample/clipcanvas_14348_H264_320x180.mp4";
private static final int VID_WIDTH = 320;
private static final int VID_HEIGHT = 180;
private static final int PLAYER_WIDTH = 320;
private static final int PLAYER_HEIGHT = 265;
private void play(final String url) {
final JFXPanel panel = new JFXPanel();
Platform.runLater(new Runnable() {
@Override public void run() {
initFX(panel, url);
}
});
this.add(panel);
this.setSize(PLAYER_WIDTH, PLAYER_HEIGHT);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
private void initFX(JFXPanel panel, String url) {
MediaView mediaView = createMediaView(url);
final Scene playerScene = new Scene(
createPlayerLayout(mediaView),
PLAYER_WIDTH,
PLAYER_HEIGHT
);
setMediaEventHandlers(
mediaView
);
panel.setScene(playerScene);
}
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;
}
private VBox createPlayerLayout(final MediaView view) {
final Button button = new Button("Play From Start");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
view.getMediaPlayer().seek(Duration.ZERO);
view.getMediaPlayer().play();
}
});
final VBox layout = new VBox(8);
layout.setAlignment(Pos.CENTER);
layout.getChildren().addAll(
view,
button
);
layout.setStyle("-fx-background-color: linear-gradient(to bottom, derive(lightseagreen, -20%), lightseagreen);");
return layout;
}
private void setMediaEventHandlers(final MediaView view) {
final MediaPlayer player = view.getMediaPlayer();
System.out.println("Initial: " + player.getStatus());
player.statusProperty().addListener(new ChangeListener<MediaPlayer.Status>() {
@Override
public void changed(ObservableValue<? extends MediaPlayer.Status> observable, MediaPlayer.Status oldStatus, MediaPlayer.Status curStatus) {
System.out.println("Current: " + curStatus);
}
});
if (player.getError() != null) {
System.out.println("Initial Error: " + player.getError());
}
player.setOnError(new Runnable() {
@Override public void run() {
System.out.println("Current Error: " + player.getError());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
VideoPlayer player = new VideoPlayer();
player.play(VID_URL);
}
});
}
}
0(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
I've updated the code I'm using above.
我已经更新了我上面使用的代码。
SOLVED!The reason is really I was using an inappropriate JavaFX (and possibly JDK) for the job. I'm not really in control of that stuff since these are school computers, but that messed me up something good... Thanks for the help! I updated it with my final code.
解决了!原因真的是我在工作中使用了不合适的 JavaFX(可能还有 JDK)。我不能真正控制那些东西,因为这些是学校电脑,但这让我搞砸了一些好事……谢谢你的帮助!我用我的最终代码更新了它。
回答by jewelsea
This worked for me after I modified your program a little bit to fix a couple of issues.
在我稍微修改了您的程序以解决几个问题后,这对我有用。
Some changes I applied:
我应用的一些更改:
- A MediaViewis necessary to view the video, so one needs to be created and added to an active JavaFX scene in order for the video to be seen.
- Some JavaFX controls need to be created on the JavaFX application thread rather than the main thread, otherwise you get
java.lang.IllegalStateException: Toolkit not initialized
. - Monitoring media error events and adding some diagnostic logs helps troubleshoot media encoding issues.
- MediaView是查看视频所必需的,因此需要创建一个MediaView并将其添加到活动的 JavaFX 场景中,以便观看视频。
- 一些 JavaFX 控件需要在 JavaFX 应用程序线程而不是主线程上创建,否则您将获得
java.lang.IllegalStateException: Toolkit not initialized
. - 监控媒体错误事件并添加一些诊断日志有助于解决媒体编码问题。
A JavaFX only solution
仅限 JavaFX 的解决方案
Your program embeds JavaFX in a Swing application which is a bit more complex then just playing Media in a standard JavaFX application. Corresponding code for playback of an mp4 in a standard JavaFX application is supplied in my answer to: Can't play mp4 converted file - JavaFX 2.1. Using just JavaFX is recommended unless you have a specific need for Swing (such as embedding your JavaFX based media player inside an existing large Swing application).
您的程序将 JavaFX 嵌入到 Swing 应用程序中,这比在标准 JavaFX 应用程序中播放媒体要复杂一些。在我的回答中提供了在标准 JavaFX 应用程序中播放 mp4 的相应代码:无法播放 mp4 转换文件 - JavaFX 2.1。建议仅使用 JavaFX,除非您对 Swing 有特定需求(例如将基于 JavaFX 的媒体播放器嵌入到现有的大型 Swing 应用程序中)。
Oracle provide a good tutorial for Incorporating Media Assets Into JavaFX Applications.
Oracle 为将媒体资产合并到 JavaFX 应用程序提供了一个很好的教程。
The JavaFX media package descriptiondocuments the media playback encodings, containers and protocols which JavaFX supports.
的JavaFX的媒体包描述文件的媒体播放编码,容器和其中的JavaFX支撑协议。
Sample for playing back mp4 video from a Swing App using a JavaFX MediaPlayer
使用 JavaFX MediaPlayer 从 Swing 应用程序播放 mp4 视频的示例
Note the sample only catches a subset of the possible media errors. For a code template which can catch and log all media errors see the JavaFX media error handling documentation.
请注意,示例仅捕获了可能的媒体错误的一个子集。有关可以捕获和记录所有媒体错误的代码模板,请参阅JavaFX 媒体错误处理文档。
##代码##SOLVED!
解决了!
Nice to see that original poster was able to get video playback working and the final error was just using an old JavaFX version (2.0) which does not support mp4 playback. Updating to JavaFX 2.2+ (which does support mp4 playback) fixed the issue.
很高兴看到原始海报能够播放视频,而最终的错误只是使用了不支持 mp4 播放的旧 JavaFX 版本 (2.0)。更新到 JavaFX 2.2+(支持 mp4 播放)修复了这个问题。