向 JavaFX 2.2 添加其他视频编解码器/DVD 支持背景研究其他方法

2022-09-03 05:08:59

更新:

由于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方面,我绝对无处可去,所以我假设目前这只是一个禁忌。如果有人有任何想法或信息,我全都听见了。

其他方法

我半信半疑的一种方法是将JMC jar从旧的JavaFX中撬开,如这里所述,并试图使其与JavaFX 2一起工作。我不认为有人对这种方法或类似的东西有任何运气?

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


答案 1

相信我,我感受到并知道你的挫折。我已经考虑了一段时间,但我不得不使用不直接的手段来解决我的问题。

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

  1. 文档说,WebView与HTML5一起使用,HTML5播放平台上支持的视频(尽管遗憾的是不是flash)。如果使用Web视图播放视频对您有用,您可以尝试一下。您甚至可以使用其他节点在其上绘制。

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

  3. 如果您需要在javafx 2.0应用程序中利用闪存的强大功能,请使用基于swt的浏览器(如果您是Swinger,则可以使用DJ项目之类的浏览器),因为它们支持本机浏览器的所有功能。


答案 2

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

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

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

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

魔术从Media构造函数开始,它最终是从弹出的地方(如果您尝试播放不受支持的格式,则带有标志)。从那里,它将创建定位器,其构造函数确保 URL 是受支持的 URL。然后,在单独的线程中调用它的方法,该线程对URL字符串执行一些健全性检查,读取文件,然后继续尝试找出格式。MediaExceptionMEDIA_UNSUPPORTEDinit()

因此,该方法的这一部分的相关代码是:

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;
}

由此,我们可以看到第一次“愚蠢”尝试根据其名称获取文件内容(这就是这样做的)。然后有一些特殊情况可以检查不同类型的wav文件,但如果失败,那么我们就会回到更聪明的检查中,查看实际的文件签名。这两个检查都在MediaUtils中。后一种检查要广泛得多,它会查看文件的前几个字节,看看它是否可以以这种方式计算出格式。如果它不能,那么它就会救助并抛出异常,然后弹出作为我们可怕的旗帜。MediaUtils.filenameToContentType()MEDIA_UNSUPPORTED

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

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

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

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

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

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

但是,我不是GStreamer方面的专家,所以虽然我知道JavaFX目前拒绝处理和播放的还有更多格式,但我不确定他们究竟是如何删除这个容量的。他们肯定在上面的Java层中做到了这一点,但他们也可能在原生GStreamer级别上做到了这一点 - 在这一点上我不确定。

我假设他们已经对JFX8的GStreamer进行了一些更改 - 但目前它们没有列在相关的项目页面上,因此很难确切地确定他们为此版本更改了什么。

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


推荐