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

更新:

由于JFX的媒体方面是开源的,我自己也研究过这个问题,但确实有可能,但需要更改和重建JFX源代码(Java和C部分)。 这里描述的过程适用于任何想要的人。有一个去 – 我在这个例子中添加了MKV支持,但它应该与其他插件非常相似。

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

背景

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

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

研究

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

我想知道它是否会播放本机安装在机器上的编解码器的video,并且它本身并不宣传自己(因为该function显然是依赖于机器而不是跨平台。)但是没有骰子,我尝试了一个数字常见的格式,除了它陈述的内容之外,它确实拒绝播放任何其他内容。

从查看JavaFX 1.3开始, 它还支持其他依赖于平台的编解码器,具体取决于它的安装位置 。 有没有办法在JavaFX 2中获得这种行为? 或者是否计划随后发布? 我无法在路线图上找到任何有关它的信息或Oracle的任何评论。

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

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

其他方法

我想知道的一种方法可能是将JMC jar从这里描述的旧JavaFX中撬开,并尝试将其与JavaFX 2一起使用。我不认为任何人对这种方法有什么好运或类似的东西?

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

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

有很多方法可以解决这个问题,每种方法都有局限性,但取决于哪些方法适合您:

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

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

  3. 如果您需要在javafx 2.0应用程序中使用闪存的强大function,那么使用基于swt的浏览器(或类似DJ项目,如果您是Swinger),因为它们支持本机浏览器的所有function。

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

我已经写了一篇关于这个过程的更全面的指南,这可能是其他任何想要沿着这条路走下去的人感兴趣的。

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

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

魔术从Media构造函数开始,它最终弹出MediaException (如果你试图播放不支持的格式,则使用MEDIA_UNSUPPORTED标志。)从那里创建Locator ,其构造函数确保URL是支持的。 然后在一个单独的线程中调用它的init()方法,该线程对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; } 

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

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

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

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

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

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

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

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

我假设他们已经为JFX8的GStreamer做了一些更改 – 但是目前他们没有在相关的项目页面上列出,因此很难确切地知道他们为这个版本改变了什么。

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

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

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

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

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

  • JDK-8091656获取更多媒体格式支持的愿望清单
  • JDK-8091755 Media应支持InputStream

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

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

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

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

  • 在JavaFX客户端中播放h265 HEVC
Interesting Posts