17

更新:

由于 JFX 的媒体端已经开源,我自己研究了一下,这确实是可能的,但需要更改和重建 JFX 源(Java 和 C 部分)。这里为任何想要的人描述了这个过程试一试 - 我在该示例中添加了 MKV 支持,但对于其他插件应该非常相似。

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

背景

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

归结为这样一个事实,虽然它可以工作,但如果有另一种更容易的解决方案,那么使用多个 VM 并稳定地桥接它们会带来很多维护和麻烦。VLC 确实对播放几乎任何东西都有相当传奇的支持水平,这就是我迄今为止一直使用它的原因,我很想看看我是否可以在 JavaFX 中获得类似的结果 - 或者至少是否可以提供以跨平台方式执行此操作的方法。

研究

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

我想知道它是否会播放本机安装在机器上的编解码器的视频,并且它只是不宣传自己(因为该功能显然是机器相关的,而不是跨平台的。)但没有骰子,我尝试了一个数字通用格式,它确实拒绝播放除了它所说的以外的任何东西。

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

我从广泛搜索中唯一能找到的就是这里,这意味着它可能是可能的,但似乎没有人知道如何。我也很想知道它是否基于 GStreamer 为什么默认情况下也不包含 GStreamer 支持的所有格式?

在使用 JavaFX 播放 DVD 方面,我绝对无处可去,所以我假设目前这只是一个不行。如果有人确实有任何想法或信息,我会全神贯注。

其他方法

我想知道的一种方法可能是从旧的 JavaFX 中剔除 JMC jar,如此处所述并试图让它与 JavaFX 2 一起工作。我认为没有人对这种方法或类似的东西有任何运气?

所有事情都失败了,如果有人有任何信息或链接说明是否/何时支持开箱即用的其他编解码器,那么我也很想听听。或者,如果有人有甲骨文某人的任何联系方式,我也可以问一下,我将不胜感激!一段时间以来,我一直渴望在 Java 中提供体面的视频支持,我想这归结为试图弄清楚 JavaFX 是否是这个问题的答案,或者只是另一个半心半意的尝试,它永远不会比它播放更多目前可以!我希望不是后者,但我还没有看到太多可以证明是这样的。

4

5 回答 5

10

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

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

  1. 文档说 WebView 与 HTML5 一起使用,它可以播放平台上支持的视频(但遗憾的是不是 flash)。如果使用 webview 播放视频适合您,您可以尝试一下。您甚至可以使用其他节点对其进行绘制。

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

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

于 2011-11-27T00:06:29.823 回答
10

我现在已经成功地将 MKV 支持编译到 JavaFX 中,这确实需要一些,但在本机层上也不需要太多的努力。有关它的讨论,请参见此处,有关作为补丁/JIRA 票证提交的结果,请参见此处。

我在这里写了一个关于这个过程的更全面的指南,其他任何想要走这条路的人都可能会感兴趣。

以下是我在认真考虑编译其他媒体支持之前的简短调查,尽管我将其留在这里以供参考。

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

魔术从Media constructor开始,最终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中。后一种检查范围更广,它会查看文件的前几个字节,看看它是否能以这种方式计算出格式。如果它不能,那么它会退出并抛出异常,然后作为我们可怕的MEDIA_UNSUPPORTED标志弹出。

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

不幸的是,目前克隆 JavaFX 存储库对我来说似乎失败了,否则我会尝试将其中的一些内容付诸实践。但是代替上述内容,添加对更多格式的支持实际上需要发生什么?其实看起来也不是特别难。

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

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

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

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

但是,我不是 GStreamer 方面的专家,所以虽然我知道它可以处理和播放 JavaFX 目前拒绝的更多格式,但我不确定他们究竟是如何消除这种能力的。他们肯定在上面的 Java 层中完成了它,但他们可能也在本机 GStreamer 级别上完成了它——在这一点上我不确定。

我假设他们已经对 JFX8 的 GStreamer 进行了一些更改 - 但目前它们没有列在相关的项目页面上,因此很难准确计算出他们为此版本所做的更改。

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

于 2014-03-21T16:14:59.527 回答
6

而现在,Javafx2.1 终于支持 mp4 H.264,所以您现在应该可以不用上面发布的特技了。:)

于 2012-03-27T23:19:52.150 回答
5

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

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

于 2011-11-25T06:12:20.480 回答
2

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

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

请注意,对于基于 InputStream 的媒体 API,JavaFX 开发人员后来的评论之一是“我建议我们为 JDK 10 考虑这个”,所以我想这可能在未来......

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

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

于 2018-01-30T00:11:56.127 回答