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



更新:

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

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

背景

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

归根结底,在它工作的同时,如果有另一种更容易的解决方案,那么使用多个虚拟机并稳定地桥接它们需要大量的维护和麻烦。VLC确实对玩任何东西都有着传奇般的支持,这就是为什么我到目前为止一直使用它的原因,我很想看看我是否能在JavaFX中获得类似的结果,或者至少它是否能以跨平台的方式提供这样做的手段。

研究

JavaFX2.0支持视频-很棒!但目前官方的说法是,它支持"包含VP6视频和MP3音频的FLV"。有没有一种方法可以扩展它,增加对更多编解码器的支持?没有我想支持的硬编解码器,它更多的是一种尽可能多的情况,所以我正在寻找一种可扩展的方法来实现上述功能。

我想知道它是否会为本机安装的编解码器播放视频,而且它只是不宣传自己(因为该功能显然是依赖于机器的,而不是跨平台的。

从JavaFX1.3来看,它还支持其他依赖于平台的编解码器,具体取决于它的安装位置。有没有办法用JavaFX2实现这种行为?还是计划在以后的版本中发布?我还没能在路线图上找到任何关于它的信息,也没能从甲骨文那里得到任何评论

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

就用JavaFX播放DVD而言,我完全没有任何进展,所以我认为这只是目前的一个障碍。如果有人真的有任何想法或信息,我会洗耳恭听。

其他方法

我有点想知道的一种方法可能是从这里描述的旧JavaFX中撬出JMC jar,并尝试将其与JavaFX2一起使用。我想没有人在这种方法或类似的方法上运气好吧?

所有失败的事情,如果有人有任何关于是否/何时支持额外编解码器的信息或链接,那么我也很想听听。或者,如果有人有甲骨文公司的任何联系方式,我可以问一下,也将不胜感激!一段时间以来,我一直渴望在Java中获得像样的视频支持,我想这归根结底是想弄清楚JavaFX是解决这个问题的办法,还是只是另一个三心二意的尝试,它永远不会比现在播放得更多!我希望不是后者,但我还没有看到太多证据表明情况确实如此。

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

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

  1. Docs表示,WebView与HTML5配合使用,后者播放平台上支持的视频(尽管遗憾的是,它不是flash(。如果使用网络视图播放视频对你有用,你可以尝试一下。您甚至可以使用其他节点绘制它。

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

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

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

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

以下是我在认真考虑在中汇编其他媒体支持之前的简短调查,不过我将把它留在这里供参考

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

魔术从Media构造函数开始,它最终是MediaException弹出的地方(如果你试图播放不受支持的格式,则使用MEDIA_UNSUPPORTED标志。(从那里它创建了Locator,其构造函数确保URL是受支持的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源代码,使用上面提出的对新内容类型的更改进行构建,然后查看本机级别上发生了哪些错误(如果有的话(,然后从中进行处理。

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

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

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

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

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

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

注意,对于基于InputStream的媒体API,JavaFX开发人员稍后的评论之一是"我建议我们考虑将其用于JDK 10",因此我认为这可能是未来的一种可能性。。。

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

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

  • 在JavaFX客户端中播放h265 HEVC

相关内容

最新更新