为JavaFX 2.2添加其他视频编解码器/ DVD支持

时间:2011-11-16 14:27:12

标签: java video javafx codec vlcj

更新

由于JFX的媒体方面已经开源,我自己研究了这个问题,确实可以,但需要更改和重建JFX源(Java和C部分)。 here对于任何想要去的人 - 我在该示例中添加了MKV支持,但对于其他插件应该非常相似。

问题的其余部分因此主要是历史性的,但我会留在这里作为参考。

背景

到目前为止,我一直在使用VLCJ在我的应用程序中播放视频。它可以工作,但是如果可能的话,我想看看我是否可以通过迁移到JavaFX来实现对常见编解码器的类似级别的支持,并为多个虚拟机节省了很多麻烦,以及VLCJ需要可靠地播放多个视频。我不会在这里讨论,但如果您对细节感兴趣,请查看我对this问题的回答。还有跨平台兼容性的问题,它适用于Mac和Linux,但我还没有弄清楚如何让它在Mac上显示(我相信有一些安全措施可以防止一个进程获得对另一个本机的访问权限)组件,但这又超出了这个问题的范围。)

归结为这样一个事实:虽然它有效,但是如果有另一种解决方案更容易,那么很多维护和麻烦都可以使用多个虚拟机并稳定地进行桥接。 VLC对于播放几乎任何东西都有相当的传奇支持,这就是为什么我到目前为止已经使用它了,我有兴趣看看我是否可以在JavaFX中得到类似的结果 - 或者至少它是否可以以跨平台的方式提供这样做的手段。

研究

JavaFX 2.0支持视频 - 太棒了!但目前官方的产品线支持“包含VP6视频和MP3音频的FLV”。有没有办法扩展它以增加对更多编解码器的支持?没有我想支持的硬编解码器,它更多的是尽我所能,所以我正在寻找一种可扩展的方法来解决上述问题。

我想知道它是否会播放本机安装在机器上的编解码器的视频,并且它不会自己宣传自己(因为该功能显然是依赖于机器而不是跨平台的。)但是没有骰子,我已经尝试了许多常见的格式,它确实拒绝播放除了它所声明的内容以外的任何内容。

从JavaFX 1.3开始also supports other platform dependant codecs depending on where it's installed。有没有办法在JavaFX 2中获得这种行为?或者是否计划随后发布?我无法在路线图上找到任何有关它的信息,也无法从Oracle那里得到关于它的任何评论。

我唯一能从广泛搜索中找到的东西是here,这意味着它可能是可能的,但似乎没有人知道如何。我也有兴趣知道它是否基于GStreamer,为什么GStreamer支持的所有格式都不包含在默认值中?

在使用JavaFX播放DVD方面,我绝对无处可去,所以我认为目前这只是一个禁忌。如果有人确实有任何想法或信息,我会全力以赴。

其他方法

我想知道的一种方法可能是将JMC jar从旧的JavaFX中删除,如here所述,并尝试将其与JavaFX 2一起使用。我不认为任何人都有运气用这种方法或类似的东西?

所有事情都失败了,如果有任何信息或链接关于是否/当支持其他编解码器将支持开箱即用,那么我也有兴趣听到这一点。或者,如果有人在Oracle有任何联系方式,我可以要求也会感激!我一直渴望在Java中获得不错的视频支持,我想这可归结为是试图弄清楚JavaFX是否是这个的答案,或者只是另一个半心半意的尝试,它永远不会超过它此刻呢!我希望它不是后者,但我还没有看到很多东西来表明情况。

5 个答案:

答案 0 :(得分:10)

相信我,我觉得并且知道你的沮丧。我已经思考了一段时间,但我不得不使用非直接的方法来解决我的问题。

有很多方法可以解决这个问题,每种方法都有局限性,但取决于对您有用的方法:

  1. 文档说WebView可以与HTML5一起使用,HTML5播放平台支持的视频(虽然很遗憾不闪存)。如果使用webview为您播放视频,您可以试一试。您甚至可以使用其他节点绘制它。

  2. 便携式VLC播放器!如果您正在开发某种投影仪/导演应用程序并且您想要全屏视频,那么您可以让便携式VLC播放器在一个屏幕中全屏播放视频,并在另一个屏幕中播放控件。使用此解决方案,它适用于Mac和Windows。 :) 唯一的问题是你不能在视频上绘制节点,因为它是一个外部应用程序,只是你的应用程序全屏视频的错觉。

  3. 如果您需要在javafx 2.0应用程序中使用闪存的强大功能,那么请使用基于swt的浏览器(如果您是Swinger,则使用DJ Project之类的东西),因为它们支持所有您的原生浏览器的功能。

答案 1 :(得分:9)

我现在成功地将MKV支持成功编译到JavaFX中,并且它确实需要一些,但在本机层上也需要付出很多努力。有关此问题的讨论,请参阅here;有关作为补丁/ JIRA票据提交的结果,请参见here

我已经撰写了一份更为全面的流程here指南,其中任何人都可能会对这条路线感兴趣。

在我真正认真考虑编写其他媒体支持之前,接下来是我的简短调查,不过我会留在这里作为参考。

现在JFX8已经发布并且是完全开源的,我花了一些时间来研究如何做到这一点,以及是否可以在不修补JFX源的情况下完成。不幸的是,后一点的答案几乎是肯定的,至少不是没有可怕的字节码操作黑客。我可能会在以后更实际地研究这个问题,但是我会记录我迄今为止从可用来源得到的内容。

魔法从Media constructor开始,MediaException最终会弹出MEDIA_UNSUPPORTED(如果您尝试播放不受支持的格式,则带有init()标记。)从那里创建Locator,其构造函数确保URL是支持的URL。然后在一个单独的线程中调用它的if (scheme.equals("file") || scheme.equals("jar")) { InputStream stream = getInputStream(uri); stream.close(); isConnected = true; contentType = MediaUtils.filenameToContentType(uriString); // We need to provide at least something } if (isConnected) { // Check whether content may be played. // For WAV use file signature, since it can detect audio format // and we can fail sooner, then doing it at runtime. // This is important for AudioClip. if (MediaUtils.CONTENT_TYPE_WAV.equals(contentType)) { contentType = getContentTypeFromFileSignature(uri); if (!MediaManager.canPlayContentType(contentType)) { isMediaSupported = false; } } else { if (contentType == null || !MediaManager.canPlayContentType(contentType)) { // Try content based on file name. contentType = MediaUtils.filenameToContentType(uriString); if (Locator.DEFAULT_CONTENT_TYPE.equals(contentType)) { // Try content based on file signature. contentType = getContentTypeFromFileSignature(uri); } if (!MediaManager.canPlayContentType(contentType)) { isMediaSupported = false; } } } // Break as connection has been made and media type checked. break; } 方法,该线程对URL字符串执行一些健全性检查,读取文件,然后继续尝试找出格式是什么。

这部分方法的相关代码是:

MediaUtils.filenameToContentType()

从这里我们可以看到第一个"哑巴"尝试根据其名称获取文件内容(这是MEDIA_UNSUPPORTED所做的。)然后有一些特殊情况用于检查不同类型的wav文件,但如果失败那么我们会回退在一个更聪明的检查,看看实际的文件签名。这两项检查都在MediaUtils。后一种检查要广泛得多,并查看文件的前几个字节,看它是否能以这种方式计算出格式。如果它不能,则它会退出并抛出异常,然后弹出我们可怕的CONTENT_TYPES标志。

如果类型被正确识别,那么还有另一个障碍 - 它必须得到当前平台的支持。某些平台根据环境动态加载,但GSTPlatform始终存在,因此我们需要在此处添加任何其他(通用)格式。这相对简单,存在一个filenameToContentType()数组,它只包含支持格式的数组。

不幸的是,目前克隆JavaFX repo对我来说似乎失败了,否则我会尝试将其中的一部分付诸实践。但是代替上述内容,实际需要添加对更多格式的支持?它实际上看起来并不困难。

  1. MediaUtils中,需要将支持添加到fileSignatureToContentType()方法以处理新的文件扩展名。这是微不足道的。

  2. 在同一个类中,需要将支持添加到{{1}}方法,以根据其签名计算文件类型。这有点复杂,但仍然不是太糟糕。这甚至可以是可选的,因为如果格式没有从文件扩展名中正确识别(或根本没有),则当前代码似乎只将其用作后备。可以找到不同格式的文件签名的完整列表here,这有助于完成此任务。

  3. 在GSTPlatform中,new content type需要添加到支持的内容类型列表中。

  4. 在Java方面,这似乎是让它接受内容类型并至少尝试将其传递给本地Gstreamer layer所必需的。

    但是,我不是GStreamer的专家,所以虽然我知道JavaFX目前拒绝的还有更多可以处理和播放的格式,但我不确定是什么如何确切地说他们已经删除了这个容量。他们肯定是在上面的Java层中完成的,但他们也可能在原生的GStreamer级别上完成它 - 此时我不确定。

    我认为他们已经为JFX8对GStreamer进行了一些更改 - 但是目前他们还没有在relevant project page上列出,因此很难确切地确定他们为这个版本改变了什么。

    下一步是获取JFX8源代码,使用上面提出的针对新内容类型的更改进行构建,然后查看本机级别上发生的错误(如果有),然后从那里获取。

答案 2 :(得分:6)

现在,Javafx2.1最终支持mp4 H.264,所以你现在应该没有上面发布的特技。 :)

答案 3 :(得分:5)

API设计似乎不支持滚动您自己的编解码器。几乎所有课程都是最终的(例如VideoTrack,Media,MediaPlayer等)。我假设实际的视频解码是在目前使用内部类完成的,这意味着无法覆盖它们。

有一个plan to Open Source JavaFX 2.0,我怀疑当我们接近JDK8的发布时。希望当他们这样做时,我们可以看到他们如何从Media(String source)构造函数中解析他们的编解码器,看看我们是否可以以某种方式挂钩。

答案 4 :(得分:2)

JavaFX错误跟踪系统中的当前打开功能请求:

阅读链接的功能请求及其相关注释,以了解您正在使用的JavaFX分发版本的当前状态(或缺少;-)。

注意,对于基于InputStream的Media API,JavaFX开发人员后来的一条评论是"我建议我们考虑将其用于JDK 10",所以我想这可能是未来的可能性。 ..

另请注意,如果您不确定JavaFX当前是否具有对给定编码类型的内置支持,则javadoc for the javafx.media package中提供了对支持的媒体编码和媒体容器类型的全面概述(只需确保您查看了与您的JavaFX版本匹配的javadoc版本。

那些可能对其他解决方案感兴趣的人至少可以从JavaFX获取视频,即使它是JavaFX本身不支持的媒体类型,并且您也不想破解本机JavaFX媒体支持让你的视频播放,也可以看到我对相关问题的回答: