如何在 Java 中有效渲染视频(AWT??)
在我的项目中,我有一个类 FrameProducer
,每次创建视频帧时都会触发事件。每个帧都是作为 java.awt.Image.BufferedImage 对象返回的图像。
我有 2 个 FrameProducer 对象,希望在屏幕上同时渲染它们生成的 BufferedImage。我希望屏幕上渲染的图片可缩放(也就是说,当我拖动应用程序窗口的角落时,渲染的视频会变小或变大)。
您认为如何最好地实现这一目标?
我考虑过使用嵌入在 java.awt.Frame
中的 java.awt.Graphics2D
,但我不知道如何做到这一点,或者如果这是最好的选择。我只需要这个来实现算法可视化,它不需要漂亮和闪亮,只需快速和简单即可。我可以使用哪些建议或一些现成的代码?
编辑: 好的,我按照 Rekin 的建议实施了该解决方案,并且它有效。但由于我不是 Java 专家,也绝对不是 Swing 专家,我我想请您对我的代码提出善意的评论 - 我相信将来很多人都会从中受益。
正如我所说,有一个 FrameProducer
(不用介意实现):
public abstract class FrameProducer extends Observable {
public abstract BufferedImage getFrame();
public void fireEvent() {
setChanged();
notifyObservers();
}
}
然后还有一个 FrameRenderer
等待来自 FrameProducer
的事件(一个使用 java.util
实现简单的观察者模式):
public class FrameRenderer extends JPanel implements Observer {
private BufferedImage frame;
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(frame, null, 0, 0);
g2d.dispose();
}
@Override
public void update(Observable observable, Object arg) {
System.out.println("Cought an event from " + observable.getClass());
if (observable instanceof FrameProducer) {
frame = ((FrameProducer) observable).getFrame();
paint(getGraphics());
}
}
}
然后还有需要返工的部分:MainFrame
。
public class MainFrame extends JFrame {
FrameProducer[] producers;
public MainFrame(FrameProducer[] producers) {
this.setTitle("Playing what you feed.");
this.producers = producers;
initContents();
setVisible(true);
}
private void initContents() {
FrameRenderer renderer = new FrameRenderer();
renderer.setLocation(0, 0);
this.add(renderer);
producers[0].addObserver(renderer);
}
}
这一切都在 main 方法中初始化:
public class FrameAccessTest {
public static void main(String[] args) {
final FrameProducer frameGrabber = new CameraFrameGrabber("vfw://0");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
MainFrame mainFrame =
new MainFrame(new FrameProducer[] {frameGrabber});
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
如何以这样的方式实现 initContents(),即 MainFrame's
构造函数中提供的所有视频流作为 FrameProducer[]
连续渲染并且它们是可扩展的?
In my project I've got a class FrameProducer
firing events each time a video frame has been created. Each frame is an image returned as an java.awt.Image.BufferedImage
object.
I've got 2 FrameProducer
objects and would like to render BufferedImage's
produced by them simultaneously on the screen. I would like the picture rendered on the screen to be scalable (that is, when I drag the application-window's corner the rendered video gets smaller or bigger).
How do you think this is best to be achieved?
I've considered using java.awt.Graphics2D
embedded in an java.awt.Frame
, but I don't know how such a thing can be done, or if this is the best choice. I just need this for algorithm visualisation, it doesn't need to be nice and shiny, just fast and easy. What would some suggestions or some ready code be that I could use?
Edit:
OK, I implemented the solution as Rekin suggested, and it works. But as I'm not an Java expert and definitely not a Swing expert, I'd like to ask you for kind remarks on my code - I'm sure many will benefit from that in the future.
As I said, there is a FrameProducer
(never mind the implementation):
public abstract class FrameProducer extends Observable {
public abstract BufferedImage getFrame();
public void fireEvent() {
setChanged();
notifyObservers();
}
}
Then there is also a FrameRenderer
waiting for events from the FrameProducer
(a simple observer-pattern implementation using java.util
):
public class FrameRenderer extends JPanel implements Observer {
private BufferedImage frame;
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(frame, null, 0, 0);
g2d.dispose();
}
@Override
public void update(Observable observable, Object arg) {
System.out.println("Cought an event from " + observable.getClass());
if (observable instanceof FrameProducer) {
frame = ((FrameProducer) observable).getFrame();
paint(getGraphics());
}
}
}
And then there is also the thing that needs rework: the MainFrame
.
public class MainFrame extends JFrame {
FrameProducer[] producers;
public MainFrame(FrameProducer[] producers) {
this.setTitle("Playing what you feed.");
this.producers = producers;
initContents();
setVisible(true);
}
private void initContents() {
FrameRenderer renderer = new FrameRenderer();
renderer.setLocation(0, 0);
this.add(renderer);
producers[0].addObserver(renderer);
}
}
It all gets initialised in the main method:
public class FrameAccessTest {
public static void main(String[] args) {
final FrameProducer frameGrabber = new CameraFrameGrabber("vfw://0");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
MainFrame mainFrame =
new MainFrame(new FrameProducer[] {frameGrabber});
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
How do I implement initContents() in such a way, that all the video streams provided in MainFrame's
constructor as FrameProducer[]
get rendered in a row and that they are scalable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会使用 JPanel 并重写
paintComponent
方法。在其中,我将使用Graphics2D.drawImage()
将容器的宽度和高度作为其参数。AWT 方法似乎更接近裸机,但由于 JDK 6 在 Swing 渲染管道方面带来了很多改进,所以我会选择 Swing 和 AWT 方法。 Java2D 方法。它由可用硬件加速(尽可能使用 Windows 上的 DirectDraw 或 OpenGL),并在良好的 API 后面隐藏大量低级细节。例如,您可以免费获得双缓冲。
I'd go with JPanel and overriding
paintComponent
method. In it I'd useGraphics2D.drawImage()
giving width and height of container as a parameters to it.The AWT approach seems closer to bare metal, but since JDK 6 brought a lot of improvements in Swing rendering pipeline, I would go the Swing & Java2D approach. It's accelerated by available hardware (using DirectDraw on Windows or OpenGL wherever possible) and hides a lot of low level details behind a nice API. For example You get double buffering for free.
重写
paintComponent
方法并使用 Graphics2D 使用drawImage
绘制缓冲图像。此方法已重载,也可用于缩放图像。Override the
paintComponent
method and use Graphics2D to draw your buffered image usingdrawImage
. This method is overloaded and can be used to scale the image as well.