我正在使用 JavaFX 媒体播放器使用以下代码播放 mp3 文件
new MediaPlayer(new Media(FileObject.toURI().toString())).play();
但是现在我要求我在内存中保存 mp3 字节数据而不是文件对象。原因是 mp3 文件被加密,然后随程序一起提供。因此我需要解密内存或输入流中的 mp3 文件。
我可以将 mp3 文件解密为 temp 目录中的临时文件,但这会产生性能开销并且音频内容不安全。
仅支持 HTTP、FILE 和 JAR URL。如果提供的 URL 无效,则会引发异常。如果发生异步错误,将设置 error 属性。收听此属性以收到任何此类错误的通知。
我个人对 JavaFX 并不熟悉,但这会告诉我,如果不诉诸讨厌的 hack,您将无法直接从内存中读取媒体。通常对于这种仅 URI 的接口,我建议注册一个自定义UrlStreamHandler和一个从内存读取的自定义协议。但是假设 JavaDoc 是正确的,JavaFX 使用它自己的分辨率,所以大概这不起作用。
鉴于此,我怀疑完成这项工作的唯一方法是通过 HTTP 提供对内存中 MP3 的访问。您可以使用Jetty或任何类似的可嵌入 servlet 容器来执行此操作。大致如下:
1) 根据快速入门指南启动 Jetty
2) 注册一个如下所示的 servlet。此 servlet 将公开您的内存中数据:
public class MagicAccessServlet extends HttpServlet {
private static final Map<String, byte[]> mediaMap = new ConcurrentHashMap();
public static String registerMedia(byte[] media) {
String key = UUID.randomUUID().toString();
mediaMap.put(key, media);
return key;
}
public static deregisterMedia(String key) {
mediaMap.remove(key);
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
String key = req.get("key");
byte[] media = mediaMap.get(key);
resp.setContentLength(media.length);
resp.getOutputStream().write(media);
}
}
然后,您可以使用 http url 从您的应用程序中访问。例如像
MagicAccessServlet.registerMedia(decodedMp3);
new MediaPlayer(new Media("http://localhost:<port>/<context>/<servlet>?key=" + key)).play();
不幸的是,作为 Media 构造函数,除了临时文件方法之外,我没有其他简单的方法可以做到这一点。请注意,虽然我同意性能会有开销,但如果文件不是太大(大多数 mp3 文件通常不是),那么从这个意义上说开销应该是最小的。从技术上讲,将内容解码到内存也会使其不安全(尽管公认更难提取。)
我确实想到的一种有点疯狂的方法是使用套接字。您可以设置应用程序的一个单独部分来解密未加密的内容,然后通过 localhost 上的某个端口流式传输原始 mp3 字节。然后,您可以将其作为 HTTP URI 提供给 Media 构造函数。