2012-05-21 36 views
2

我正在开发使用GStreamer和OpenCV进行视频处理的应用程序。其任务是从OpenCV源码获取图像,并将它们拖入GStreamer管道(转换和解码,稍后必须流式传输视频数据)并在Java语言环境中处理图像。是否可以使用调用Java方法的JNI本地线程(回调函数)来更新Swing UI组件?

所以我在C中构建了一个本地框架来管理这个任务。现在我使用JNI访问我的C库,并且将执行GStreamer主循环附加到JVM。有一些线程与我使用SDL库的图像处理无关,但没有调用任何Java方法。显然它到目前为止工作。我将原始图像转换为Java,并且我还可以使用ByteBuffer(本机创建)get方法和System.err.println显示其字节数据。

问题是在GUI中以某种方式显示这些图像。我为我的图形环境使用Swing框架。

所以我做了一个快速和肮脏的图像视图通过扩展JPanel,因为我通常会和我的时候只使用Java通常工作。

我重写paint方法使用Graphics.drawImage方法来绘制图像。通过将原生回调传递的原始数据复制到整数数组中,然后将此整数数组分配给MemoryImageSource来生成图像。我使用(JFrame的)createImage方法得到一个Image对象。一切都返回显然是有效的参考。没有例外抛出和所有。至少没有可见的我。

试了几种方法,以及只使用一个字节数组的MemoryImageSource没有生成的图像为止。数据却在那里,我可以阅读它!

我可以复制数据,显示字节的数据,但我无法得到显示我的自定义视图JPanel面积达一个显示图像。这就像图像是完全黑色或透明或什么的。

这个问题真的打我,我不知道如何说服这个东西的工作。我认为这里的线程有几个问题。但是我没有为这个特定场景提供更多资源。

我在做什么错,或者如何以正确的方式做得更好。

附加: 应用程序也有时只是崩溃,或者如果我改变大小的窗口中的GUI冻结,所以我避免这样做的时刻。所以本地线程有问题。

+1

对UI的任何更新都应发生在事件派发线程上,通常通过调用SwingUtilities.invokeLater(Runnable)来实现。这意味着您的图像数据必须存在于生产线程和事件分派线程可用的范围内。 – technomage

+0

我在最后一次测试中做到了这一点......没有成功...... – kneo

+1

除非您每次*测试都做到这一点,否则您一定没有成功。 – technomage

回答

1

我使用OpenCV-Library访问安装在系统上的相机。我从每个抓取的帧中获取尺寸,颜色信息和BGR-Samples,并根据整个事件初始化的帧速率让GStreamer AppSrc将图像拖入视频处理流水线。最初的管道是这样的:

的OpenCV,摄像机 - > AppSrc - > VideoRate - > ffmpegcolorspace - > AppSink

它去很快,但比较复杂,现在这是怎么看起来像。

的AppSink呼吁GStreamer的“新缓冲区”信号的功能(其它一些没有涉及到我的问题,其中重要)。这些回调实现调用提供图像颜色和维度的Java对象函数以及其示例缓冲区。所以这是关于我在做什么的简要信息。

现在我的问题:

看来我解决了我的问题。我现在使用另一种方式来创建我的图像,现在它的工作。

//constructor, callback whatever 
imageSource = new MemoryImageSource(data.width,data.height,rawdata,0,data.width); 
... 
//Paint method of a JFrame or what ever ... 
... 
image img = createImage(imageSource); 
setBounds(100,100,img.getWidth(null),img.getHeight(null)); 
createBufferStrategy(2); 

BufferStrategy strategy = getBufferStrategy(); 

Graphics gr = strategy.getDrawGraphics();   
gr.drawImage(img, 0, 0, null); 
gr.dispose(); 

strategy.show(); 

我使用这些几行,其工作为我现在::

int[] nBits = {8, 8, 8}; 
ComponentSampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, channels, width * channels, new int[] {2, 1, 0}); 
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); 
ColorModel colorModel = new ComponentColorModel(colorSpace, nBits, false, false,Transparency.OPAQUE,DataBuffer.TYPE_BYTE); 

DataBufferByte db = new DataBufferByte(new byte[][] {buffer}, buffer.length); 

WritableRaster raster = Raster.createWritableRaster(sampleModel, db, new Point(0, 0)); 
BufferedImage image = new BufferedImage(colorModel, raster, false, null); 

缓冲器在本文表示原始字节样本阵列I得到throught

代替使用存储器中的图像源,像这样的我的方法从本地调用。

我也遇到了其他几个问题,利用摆动像冻结UI或崩溃抛出这些错误消息:

[xcb] Unknown request in queue while dequeuing 
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called 
[xcb] Aborting, sorry about that. 
java: ../../src/xcb_io.c:178: dequeue_pending_request: assertion »!xcb_xlib_unknown_req_in_deq« failed. 

这是因为我用了UIManager.setLookAndFeel()方法来设置窗口外观到系统默认值。我没有将此与问题联系起来,因为如果您使用默认系统“Look And Feels”,我不知道Swing使用本机UI框架。删除这可以解决问题。我的研究将我带到论坛post(德文),它描述了Linux(Ubuntu)机器上仅发生在Java上(不是本机部分)的情况,而同一应用程序在未经修改的情况下在Windows机器上运行。所以删除它解决了我的问题。我认为我的“形象没有出现问题”与此有某种关系,但我不知道,因为我现在工作,所以我不在乎。

相关问题