如何写gstreamer管道opencv mat?
我想添加一些opencv进程到gstreamer管道,然后通过udpsink发送它。
我能够像这样从gstreamer读取帧:
// may add some plugins to the pipeline later
cv::VideoCapture cap("v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! appsink");
cv::Mat frame;
while(ture){
cap >> frame;
// do some processing to the frame
}
但是无法弄清楚的是如何将处理后的帧传递给下面的管道: appsrc ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000
appsrc ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000
我试过了
cv::VideoWriter writer = cv::VideoWriter("appsrc ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000", 0, (double)30, cv::Size(640, 480), true);
writer << processedFrame;
但是,接收方没有收到任何信息。 (我使用管道$gst-launch-1.0 udpsrc port=5000 ! tsparse ! tsdemux ! h264parse ! avdec_h264 ! videoconvert ! ximagesink sync=false
作为接收器)
我的问题是, 我可以将处理过的opencv Mat传递给gstreamer管道,让它执行一些编码,然后通过udpsink通过网络发送? 如果是的话,我该如何做到这一点?
旁边的问题,有没有什么办法可以调试VideoWriter? 比如检查帧是否实际写入了它。
请注意,我在ubuntu 14.04上使用了opencv 2.4.12和gstreamer 1.2。
任何帮助都很棒!
编辑:提供更多的信息,我测试了下面的代码,它给了GStreamer Plugin: Embedded video playback halted; module appsrc0 reported: Internal data flow error.
GStreamer Plugin: Embedded video playback halted; module appsrc0 reported: Internal data flow error.
#include <stdio.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
int main(int argc, char *argv[]){
cv::VideoCapture cap("v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! appsink");
if (!cap.isOpened()) {
printf("=ERR= can't create capturen");
return -1;
}
cv::VideoWriter writer;
// problem here
writer.open("appsrc ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! autovideoconvert ! ximagesink sync=false", 0, (double)30, cv::Size(640, 480), true);
if (!writer.isOpened()) {
printf("=ERR= can't create writern");
return -1;
}
cv::Mat frame;
int key;
while (true) {
cap >> frame;
if (frame.empty()) {
printf("no framen");
break;
}
writer << frame;
key = cv::waitKey( 30 );
}
cv::destroyWindow( "video" );
}
显然,appsrc管道有问题,但我不知道哪里出了问题,因为管道gst-launch-1.0 v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! ximagesink sync=false
gst-launch-1.0 v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! ximagesink sync=false
gst-launch-1.0 v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! ximagesink sync=false
正常工作。
经过几个小时的搜索和测试,我终于得到了答案。 关键是在appsrc
之后只使用videoconvert
,不需要设置上限。 因此,一个appsrc ! videoconvert ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000
管道将看起来像appsrc ! videoconvert ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000
appsrc ! videoconvert ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000
appsrc ! videoconvert ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000
。
以下是从gstreamer管道读取图像的示例代码,执行一些opencv图像处理并将其写回管道。
使用这种方法,您可以轻松地将任何opencv进程添加到gstreamer管道。
// Compile with: $ g++ opencv_gst.cpp -o opencv_gst `pkg-config --cflags --libs opencv`
#include <stdio.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
int main(int argc, char** argv) {
// Original gstreamer pipeline:
// == Sender ==
// gst-launch-1.0 v4l2src
// ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB
// ! videoconvert
// ! x264enc noise-reduction=10000 tune=zerolatency byte-stream=true threads=4
// ! mpegtsmux
// ! udpsink host=localhost port=5000
//
// == Receiver ==
// gst-launch-1.0 -ve udpsrc port=5000
// ! tsparse ! tsdemux
// ! h264parse ! avdec_h264
// ! videoconvert
// ! ximagesink sync=false
// first part of sender pipeline
cv::VideoCapture cap("v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! appsink");
if (!cap.isOpened()) {
printf("=ERR= can't create video capturen");
return -1;
}
// second part of sender pipeline
cv::VideoWriter writer;
writer.open("appsrc ! videoconvert ! x264enc noise-reduction=10000 tune=zerolatency byte-stream=true threads=4 ! mpegtsmux ! udpsink host=localhost port=9999"
, 0, (double)30, cv::Size(640, 480), true);
if (!writer.isOpened()) {
printf("=ERR= can't create video writern");
return -1;
}
cv::Mat frame;
int key;
while (true) {
cap >> frame;
if (frame.empty())
break;
/* Process the frame here */
writer << frame;
key = cv::waitKey( 30 );
}
}
希望这可以帮助。 ;)
好的,这是很长的评论..它不是答案,但很少提示:
1a,使用网播来检查接收方收到什么。它的简单:
shell> nc -l 5000 -u
当你发送一些东西给接收者时,检查打印什么。nc设置为将所有内容转储到屏幕上。
1b,您可以尝试vlc for reciever并检查调试消息(位于工具>消息 - 或者按Ctrl + M)。 将日志杆设置为2调试。然后打开网络流并使用udp://@:5000
作为URL ..
顺便说一句,你可以用rtp用管道测试它:
appsrc ! x264enc ! mpegtsmux ! rtpmp2tpay ! udpsink host=localhost port=5000
这是在vlc rtp://@:5000
然后..
2,使用标识元素检查appsrc之后流动的东西(非常有用..我经常用它来调试管道问题):
改变你的管道(注意标识元素和-v为udpsink):
cv::VideoWriter writer = cv::VideoWriter("appsrc ! identity silent=false ! x264enc ! mpegtsmux ! udpsink -v host=localhost port=5000", 0, (double)30, cv::Size(640, 480), true);
然后运行你的代码并检查它的输出结果。它将列出来自appsrc的输入缓冲区
3,对于你发布的代码更新 - 不,我打算使用caps=
属性作为更新,但也许没有区别:
writer.open("appsrc caps="video/x-raw, framerate=30/1, width=640, height=480, format=RGB" ! autovideoconvert ! ximagesink sync=false", 0, (double)30, cv::Size(640, 480), true);
链接地址: http://www.djcxy.com/p/25427.html