使用gstreamer / gstreamer-java解析mjpeg流的两个jpeg帧之间的文本数据

时间:2011-08-31 14:35:37

标签: java gstreamer

我创建了一个mjpeg流。我在两个jpeg帧之间嵌入了内容长度[在第一帧的页脚和下一帧的标题之间]。

[MJPEG STREAM]
      |
      V
...
----------
JPEG FRAME
(Image)
----------
Content-length
(Text)
----------
JPEG FRAME
(Image)
----------
Content-length
(Text)
----------
JPEG FRAME
(Image)
----------
...
      |
      V

我可以使用gstreamer-java,gstreamer C API和gst-launch播放视频。但是我试图解析gstreamer-java中的内容长度文本。我尝试了“元标记”,但这并没有产生我需要的任何结果

我播放我创建的mjpeg流如下

gst-launch -v souphttpsrc location="<ip>:<port>/<cgi_bin folder>/<name>.cgi" do-timestamp=true is_live=true ! multipartdemux ! jpegdec ! ffmpegcolorspace ! autovideosink

我使用

尝试了元标记
gst-launch -v souphttpsrc location="<ip>:<port>/<cgi_bin folder>/<name>.cgi" do-timestamp=true is_live=true ! multipartdemux ! jpegdec ! fakesink -t

和这个

gst-launch -v souphttpsrc location="<ip>:<port>/<cgi_bin folder>/<name>.cgi" do-timestamp=true is_live=true ! fakesink -t

然而,此媒体管道的输出类似于以下

/GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain   ******* < (557568   
bytes, timestamp: 0:00:06.895505695, duration: none, offset: -1, offset_end: -1, flags: 
0) 0x9a82818"
/GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain   ******* < (557568 
bytes, timestamp: 0:00:06.941328354, duration: none, offset: -1, offset_end: -1, flags: 
0) 0x9a6f6e0"

因为可以看出没有内容长度。 :(。我使用WireShark并查看包含内容长度的数据包。随后我写了一个单独的Java代码(没有gstreamer插件),我可以解析流来获取内容长度。但这不是我想要的理想方法内容长度对应于保持查看同步的精确帧。

我之前为C API代码编写过 tees 。我想知道 tee 是否适合这种情况!

1 个答案:

答案 0 :(得分:0)

Appsink 派上用场了。管道看起来像

                         _ queue -> appsink -> parser 
                       /  
        video -> tee ->
                       \_ demux -> decoder -> ffmpegcolorspace -> autovideosink 

Java Code代码段看起来像

首先定义appsink bin

final AppSink appsink = (AppSink) ElementFactory.make("appsink", "appsink");

然后它的属性......

appsink.set("emit-signals",true);
appsink.set("max-buffers",1);
//appsink.set("drop",true); //Make this non-blocking. 
                            //Meaning drop frames when queue is full

然后它的功能......

appsink.connect(new AppSink.NEW_BUFFER() {
@Override public void newBuffer(Element elem, Pointer userData) {
AppSink appsink = (AppSink) elem;
Buffer buffer = appsink.pullBuffer();  //get the stream data as an input to external 
                                       //applications

/*
// Create a character ByteBuffer
CharBuffer cbuf = byteBuffer.asCharBuffer();
*/

ByteBuffer byteBuffer = buffer.getByteBuffer();
byte[] bytearray = new byte[byteBuffer.remaining()];
byteBuffer.get(bytearray);
String s = new String(bytearray);
//InputStream is = new ByteArrayInputStream(bytearray);
// System.out.print(buffer.getSize()+"\n");
//  System.out.print(s+"\n");

//Do whatever with this buffer inside string here e.g. parsing text content

...

byteBuffer.clear();
buffer.dispose();
buffer = null;

}
});           

// ============================================= ==============================

C代码段看起来像

...
sink = gst_element_factory_make ("appsink", "Output");
g_assert (sink);

则...

...
gst_app_sink_set_max_buffers((GstAppSink*)sink, 100);
gst_app_sink_set_emit_signals ((GstAppSink*)sink, TRUE);
g_signal_connect (sink, "new-buffer",  G_CALLBACK(new_buffer), NULL);

则...

static GstFlowReturn new_buffer (GstAppSink *app_sink, gpointer user_data)
{
  char* pipe_name = (char*) user_data;
  GstBuffer* buffer = gst_app_sink_pull_buffer(app_sink);

//  g_debug("appsink buffer timestamp(%lli) size(%d)",
//          GST_BUFFER_TIMESTAMP(buffer),
//          GST_BUFFER_SIZE(buffer));

  g_print((char*)buffer);

  gst_buffer_unref(buffer);
  return GST_FLOW_OK;
}