我想直接将 Gstreamer 管道与 OpenCV 结合使用来管理来自相机的图像采集。目前我没有相机,所以我一直在尝试从 URI 和本地文件获取视频。我正在使用带有 L4T 的 Jetson AGX Xavier(ubuntu 18.04),我的 OpenCV 版本包括 Gstreamer,并且两个库似乎都可以独立工作。
我遇到的问题是,当我使用 cv2.CAP_GSTREAMER 将定义管道的字符串传递给 VideoCapture 类时,我收到一些如下警告:
[ WARN:0] global /home/nvidia/opencv/modules/videoio/src/cap_gstreamer.cpp (854) open OpenCV | GStreamer warning: Error opening bin: could not link playbin0 to whatever sink I've defined
[ WARN:0] global /home/nvidia/opencv/modules/videoio/src/cap_gstreamer.cpp (597) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
我尝试了几个选项,您可以在下面的代码中看到它们:
bool receiver(const char* context)
{
VideoCapture cap(context, CAP_GSTREAMER);
int fail = 0;
while(!cap.isOpened())
{
cout<<"VideoCapture not opened"<<endl;
fail ++;
if (fail > 10){
return false;
}
continue;
}
Mat frame;
while(true) {
cap.read(frame);
if(frame.empty())
return true;
imshow("Receiver", frame);
if(waitKey(1) == 'r')
return false;
}
destroyWindow("Receiver");
return true;
}
int main(int argc, char *argv[])
{
GstElement *pipeline;
const char* context = "gstlaunch v udpsrc port=5000 caps=\"application/xrtp\" ! rtph264depay ! ffdec_h264 ! ffmpegcolorspace ! ximagesink sync=false"; //Command for the camera that I don't have yet
const char* test_context = "gstlaunch playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm";
const char* thermal_context = "playbin uri=file:///home/nvidia/repos/vidtest/thermalVideo.avi ! appsink name=thermalsink";
const char* local_context = "playbin uri=file:///home/nvidia/repos/flir/Video.avi";
// gst_init(&argc, &argv);
// pipeline = gst_parse_launch(test_context, NULL);
bool correct_execution = receiver(thermal_context);
if(correct_execution){
cout << "openCV - gstreamer works!" << endl;
} else {
cout << "openCV - gstreamer FAILED" << endl;
}
}
对于我测试过的命令,错误isPipelinePlaying OpenCV | GStreamer 警告:GStreamer:尚未创建管道 是持久的,如果我没有定义 AppSink,则上面显示的错误将针对 open OpenCV | 进行更改。 GStreamer 警告:在手动管道中找不到 appsink。 从警告中我可以了解到管道不完整或未正确创建,但我不知道为什么,我按照我在网上找到的示例进行操作,它们不包含任何其他步骤。
此外,当直接使用 Gstreamer 管道可视化流时,当我尝试打开本地视频时,一切似乎都工作正常,但第一帧被卡住并且不显示视频,它只是停留在第一帧框架。你知道为什么会发生这种情况吗? playbin uri 指向互联网地址,一切正常...代码如下:
#include <gst/gst.h>
#include <unistd.h> // for sleep function
#include <iostream>
using namespace std;
int main (int argc, char *argv[])
{
GstElement *pipeline;
GstBus *bus;
GstMessage *msg;
const char* context = "gstlaunch v udpsrc port=5000 caps=\"application/xrtp\" ! rtph264depay ! ffdec_h264 ! ffmpegcolorspace ! ximagesink sync=false";
const char* local_context = "gst-launch-1.0 -v playbin uri=file:///home/nvidia/repos/APPIDE/vidtest/THERMAL/thermalVideo.avi";
const char* test_context = "gstlaunch playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm";
// Initialize gstreamer
gst_init (&argc, &argv);
// Create C pipeline from terminal command (context)
pipeline = gst_parse_launch(local_context, NULL);
// Start the pipeline
gst_element_set_state(pipeline, GST_STATE_PLAYING);
// Wait until error or EOS
bus = gst_element_get_bus (pipeline);
gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
/* Free resources */
if (msg != NULL)
gst_message_unref (msg);
// g_print(msg);
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
}
最佳答案
为了使用 gstreamer 后端,opencv VideoCapture 需要从源到 appsink 的有效管道字符串(BGR 颜色格式)。
您的管道字符串不正确,主要是因为它们以二进制命令(gSTLaunch for gst-launch-1.0、playbin)开头,您将在 shell 中使用该命令来运行这些命令。
您可以尝试使用此管道从 RTP/UDP 读取 H264 编码视频,使用专用 HW NVDEC 进行解码,然后从 NVMM 内存复制到系统内存,同时转换为 BGRx 格式,然后使用基于 CPU 的 videoconvert 转换 BGR 格式正如 opencv appsink 所期望的:
const char* context = "udpsrc port=5000 caps=application/x-rtp,media=video,encoding-name=H264 ! rtph264depay ! h264parse ! nvv4l2decoder ! nvvidconv ! video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1";
或者对于 uridecodebin,如果选择了 NV 解码器,输出可能位于 NVMM 内存中,否则位于系统内存中,因此以下 nvvidconv 实例首先复制到 NVMM 内存,然后第二个 nvvidconv 转换为带有 HW 的 BGRx 并输出进入系统内存:
const char* local_context = "uridecodebin uri=file:///home/nvidia/repos/APPIDE/vidtest/THERMAL/thermalVideo.avi ! nvvidconv ! video/x-raw(memory:NVMM) ! nvvidconv ! video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1";
请注意高分辨率:
- 基于 CPU 的 videoconvert 可能是一个瓶颈。启用所有内核并提升时钟。
- OpenCv imshow 可能不会那么快,具体取决于您的 OpenCv 构建的图形后端(GTK、QT4、QT5..)。在这种情况下,解决方案是使用 OpenCv Videowriter,使用 gstreamer 后端输出到 gstreamer 视频接收器。
关于c++ - Gstreamer 流不适用于 OpenCV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70753630/