在 JavaFX 中渲染 YUV

Render YUV in JavaFX

我需要在 JavaFX 中以最小延迟渲染 yuyv422 流。如果我将它转换为 RGB,我可以使用带有 PixelFormat 实例的 WritableImage 的 ImageView,它可以工作,但是 RGB 转换消耗大量 CPU,特别是在高分辨率下。我看到了这个确切的功能请求

https://bugs.openjdk.java.net/browse/JDK-8091933

但似乎不会在 Java 9 中实现。如果实现了,我想知道它是否会引入延迟或需求过多 CPU。还有其他使用 JavaFX 的方法吗?

总的来说:
图像处理总是很昂贵,这就是矢量化或硬件加速用于这些任务的原因。仅用一个线程简单地循环图像已经非常慢,尤其是在 java 中。最重要的是,人们倾向于使用 Color 对象进行颜色修改,这非常慢。

纯Java:
如果你想让你的代码保持纯粹 Java。您应该通过调用

检查 WriteableImage 使用的是哪种内部格式
myImage.getPixelWriter().getPixelFormat().getType() 

如果内部格式不是 RGB,请将颜色转换调整为给定格式以避免双重转换。 另外请确保您的代码已尽可能优化:
- 不要使用数组以外的任何对象
- 尽量减少局部变量的使用
您也可以尝试通过并行循环对转换过程进行多线程处理。

JNI:
远离 Java 开辟了很多可能性。有几个独立于平台的库用于将 YUV 转换为 RGB 并返回:

OpenCV:
易于使用,并且已经带有 java API:

byte[] myYuvImage = null; //your image here
byte[] myRgbImage = new byte[width * height * 3]; //the output image
Mat yuvMat = new Mat(height, width, CvType.CV_8UC2); //YUV422 should be 2 channel
Mat rgbMat = new Mat(height, width, CvType.CV_8UC3);
yuvMat.put(0,0, myYuvImage);
Imgproc.cvtColor(yuvMat, rgbMat, Imgproc.COLOR_YUV2RGB_Y422);
rgbMat.get(0, 0, myRgbImage);

Intel IPP:
只能通过 JNI 获得。您将使用 ippiRGBToYUV422_8u_C3C2R 有关详细信息,请参阅 RGBToYUV422

SwScale as part of FFmpeg:
只能通过 JNI 获得。请参阅此 answer 并调整示例。

我个人的经验是,即使在 AMD 机器上,IPP 也能提供迄今为止最好的性能。然而,它附带的许可证可能是免费的,但它禁止反编译,这可能与 LGPL 库不兼容。