GStreamer qmlglsink 管道中的崩溃动态重新绑定到不同的 GstGLVideoItem
Crash in GStreamer qmlglsink pipeline dynamically rebind to different GstGLVideoItem
我使用现有的 qmlglsink 示例之一从 4 个 IP 摄像机流式传输视频源。
4 个管道在引擎加载之前创建。
for(int i = 0; i < maxCameras; ++i) {
GstElement* pipeline = gst_pipeline_new (NULL);
GstElement* src = gst_element_factory_make ("udpsrc", NULL);
GstElement* parse = gst_element_factory_make ("jpegparse", NULL);
GstElement* decoder = gst_element_factory_make ("jpegdec", NULL);
GstElement* glcolorconvert = gst_element_factory_make ("glcolorconvert", NULL);
GstElement* glupload = gst_element_factory_make ("glupload", NULL);
GstElement *sink = gst_element_factory_make ("qmlglsink", NULL);
g_assert (src && parse && decoder && glupload && glcolorconvert && sink);
g_object_set (G_OBJECT (src), "port", startingPort + i, NULL);
g_object_set (G_OBJECT (sink), "sync", FALSE, NULL);
gst_bin_add_many (GST_BIN (pipeline), src, parse, decoder, glupload, glcolorconvert, sink, NULL);
if (!gst_element_link_many ( src, parse, decoder, glupload, glcolorconvert, sink, NULL)) {
qDebug() << "Linking GStreamer pipeline elements failed";
}
sinks.insert(std::make_pair(QString::number(startingPort+i), sink));
pipelines.insert(std::make_pair(QString::number(startingPort+i), pipeline));
}
在 Qml sink 中连接并处理
import QtQuick 2.15
import QtQuick.Layouts 1.15
import CustomProject 1.0
import org.freedesktop.gstreamer.GLVideoItem 1.0
Item {
id: root
signal clicked()
required property int udpPort
property var camConnect: undefined
onUdpPortChanged: { setupConnection(); }
onVisibleChanged: {
if (visible) { setupConnection();
} else { camConnect = undefined }
}
GstGLVideoItem {
id: videoItem
anchors.fill: parent
function connect() {
CameraSinksFactory.connectSink(this, udpPort)
}
}
MouseArea {
anchors.fill: parent
onClicked: {
CameraSinksFactory.stopPipeline(udpPort)
root.clicked()
}
}
function setupConnection() {
if (udpPort <= 0 || !root.visible) return;
videoItem.connect()
root.camConnect = CameraSinksFactory.getCamConnection(udpPort);
root.camConnect.resolutionX =// - 15 root.width
root.camConnect.resolutionY = root.height
root.camConnect.bitrate = 15000000
root.camConnect.streaming = root.visible
CameraSinksFactory.startPipeline(udpPort)
}
}
问题:主屏幕使用模型(提供 udpPort 作为唯一 ID)显示 4(2x2 网格)项目。当用户点击一个项目时 - 来自该摄像头的画面应该填满整个屏幕。在示例中,他们使用 4/6 显式项目创建 GridLayout 并仅操纵它们的可见性(实际上,单击的项目只剩下一个并占据整个屏幕)。
就我而言 - 我正在使用单独的项目进行全屏查看。所以我禁用流式传输(CamConnection class 与相机通信并发送命令)并隐藏 GridView。新 GstGLVideoItem 绑定到管道中的 qmlglsink。
一切正常,直到我重复单击序列(返回到 GridView 和全视图)。每次结束时:
Bail out! ERROR:../ext/qt/gstqsgtexture.cc:134:virtual void
GstQSGTexture::bind(): code should not be reached
** (KMS:20495): CRITICAL **: 15:47:36.937: gst_video_frame_map_id: assertion 'info->width <= meta->width' failed
** ERROR:../ext/qt/gstqsgtexture.cc:134:virtual void GstQSGTexture::bind(): code should not be reached
根据插件代码分析,当 INFO(从 CAPS 读取的图像大小)大于提供缓冲区中元数据的大小时,就会发生这种情况。这是可以理解的 - 缓冲区太小。
我使用 GST_DEBUG=4/5/6/7 并且日志确认自动检测到的上限与发送到相机的命令中的请求匹配。
我可以使用示例,但项目假设另一个面板带有这些摄像头 - 所以上述问题将在不久的将来出现。
如何使整个设置工作?如何安全地将管道 qmlglsink 重新绑定到新的 QML VideoItem?
两种可能的解决方案:
- 设置
gst_element_set_state (pipeline, GST_STATE_NULL);
,将接收器小部件更改为新项目并启动管道 gst_element_set_state (pipeline, GST_STATE_PLAYING);
- 使用带有 gst-pipeline 的 Qt 5 MediaPlayer 作为源。当可见时设置 source 并执行 start()。当不可见时,将 source 重置为 empty (重要)并执行 stop().
总的来说 - 当我们将新的 QML 项动态分配给管道接收器时,每次不创建管道可能带来的好处不值得麻烦。
我使用现有的 qmlglsink 示例之一从 4 个 IP 摄像机流式传输视频源。 4 个管道在引擎加载之前创建。
for(int i = 0; i < maxCameras; ++i) {
GstElement* pipeline = gst_pipeline_new (NULL);
GstElement* src = gst_element_factory_make ("udpsrc", NULL);
GstElement* parse = gst_element_factory_make ("jpegparse", NULL);
GstElement* decoder = gst_element_factory_make ("jpegdec", NULL);
GstElement* glcolorconvert = gst_element_factory_make ("glcolorconvert", NULL);
GstElement* glupload = gst_element_factory_make ("glupload", NULL);
GstElement *sink = gst_element_factory_make ("qmlglsink", NULL);
g_assert (src && parse && decoder && glupload && glcolorconvert && sink);
g_object_set (G_OBJECT (src), "port", startingPort + i, NULL);
g_object_set (G_OBJECT (sink), "sync", FALSE, NULL);
gst_bin_add_many (GST_BIN (pipeline), src, parse, decoder, glupload, glcolorconvert, sink, NULL);
if (!gst_element_link_many ( src, parse, decoder, glupload, glcolorconvert, sink, NULL)) {
qDebug() << "Linking GStreamer pipeline elements failed";
}
sinks.insert(std::make_pair(QString::number(startingPort+i), sink));
pipelines.insert(std::make_pair(QString::number(startingPort+i), pipeline));
}
在 Qml sink 中连接并处理
import QtQuick 2.15
import QtQuick.Layouts 1.15
import CustomProject 1.0
import org.freedesktop.gstreamer.GLVideoItem 1.0
Item {
id: root
signal clicked()
required property int udpPort
property var camConnect: undefined
onUdpPortChanged: { setupConnection(); }
onVisibleChanged: {
if (visible) { setupConnection();
} else { camConnect = undefined }
}
GstGLVideoItem {
id: videoItem
anchors.fill: parent
function connect() {
CameraSinksFactory.connectSink(this, udpPort)
}
}
MouseArea {
anchors.fill: parent
onClicked: {
CameraSinksFactory.stopPipeline(udpPort)
root.clicked()
}
}
function setupConnection() {
if (udpPort <= 0 || !root.visible) return;
videoItem.connect()
root.camConnect = CameraSinksFactory.getCamConnection(udpPort);
root.camConnect.resolutionX =// - 15 root.width
root.camConnect.resolutionY = root.height
root.camConnect.bitrate = 15000000
root.camConnect.streaming = root.visible
CameraSinksFactory.startPipeline(udpPort)
}
}
问题:主屏幕使用模型(提供 udpPort 作为唯一 ID)显示 4(2x2 网格)项目。当用户点击一个项目时 - 来自该摄像头的画面应该填满整个屏幕。在示例中,他们使用 4/6 显式项目创建 GridLayout 并仅操纵它们的可见性(实际上,单击的项目只剩下一个并占据整个屏幕)。
就我而言 - 我正在使用单独的项目进行全屏查看。所以我禁用流式传输(CamConnection class 与相机通信并发送命令)并隐藏 GridView。新 GstGLVideoItem 绑定到管道中的 qmlglsink。
一切正常,直到我重复单击序列(返回到 GridView 和全视图)。每次结束时:
Bail out! ERROR:../ext/qt/gstqsgtexture.cc:134:virtual void GstQSGTexture::bind(): code should not be reached
** (KMS:20495): CRITICAL **: 15:47:36.937: gst_video_frame_map_id: assertion 'info->width <= meta->width' failed
** ERROR:../ext/qt/gstqsgtexture.cc:134:virtual void GstQSGTexture::bind(): code should not be reached
根据插件代码分析,当 INFO(从 CAPS 读取的图像大小)大于提供缓冲区中元数据的大小时,就会发生这种情况。这是可以理解的 - 缓冲区太小。
我使用 GST_DEBUG=4/5/6/7 并且日志确认自动检测到的上限与发送到相机的命令中的请求匹配。
我可以使用示例,但项目假设另一个面板带有这些摄像头 - 所以上述问题将在不久的将来出现。
如何使整个设置工作?如何安全地将管道 qmlglsink 重新绑定到新的 QML VideoItem?
两种可能的解决方案:
- 设置
gst_element_set_state (pipeline, GST_STATE_NULL);
,将接收器小部件更改为新项目并启动管道gst_element_set_state (pipeline, GST_STATE_PLAYING);
- 使用带有 gst-pipeline 的 Qt 5 MediaPlayer 作为源。当可见时设置 source 并执行 start()。当不可见时,将 source 重置为 empty (重要)并执行 stop().
总的来说 - 当我们将新的 QML 项动态分配给管道接收器时,每次不创建管道可能带来的好处不值得麻烦。