У меня есть небольшая программа на qt / c ++, которая использует gstreamer. Он работает правильно на Debian 64bit и не будет работать на Raspberry Pi 3, работающем с Rasbian.
Программа отображает веб-камеру USB по адресу / dev / video0 и передает ее по указанному IP-адресу. (для тестирования я использую адрес обратной связи и имею программу RTP-приемника на том же компьютере для отображения потока)
У меня установлен qt creator на обеих машинах, а программы собраны на целевой машине. (без кросс-компиляции)
При запуске на Raspberry Pi "GstStateChangeReturn" возвращается как "GST_STATE_CHANGE_FAILURE"
Вот полный код:
gstreamer_stream_and_display_test.pro
#-------------------------------------------------
#
# Project created by QtCreator 2018-10-25T19:06:04
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = gstreamer_stream_and_display_test
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
CONFIG += link_pkgconfig
PKGCONFIG += gstreamer-1.0 glib-2.0 gobject-2.0 gstreamer-video-1.0
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <glib.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
GstElement *pipeline0;
GstStateChangeReturn sret0;
};
#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <glib.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
gst_init (&argc, &argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>
#include <QWidget>
#include <QDebug>
#include <glib.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setFixedSize(1280,720);
setWindowTitle("Stream and Display Test");
WId xwinid = winId();
pipeline0 = gst_pipeline_new("myPipeline");
GstElement *v4l2src = gst_element_factory_make("v4l2src", "v4l2src");
GstElement *capsfilter = gst_element_factory_make("capsfilter", "capsfilter");
GstElement *tee = gst_element_factory_make("tee", "tee");
GstElement *encoder = gst_element_factory_make("jpegenc", "encoder");
GstElement *videoConverter = gst_element_factory_make("videoconvert", "videoConverter");
GstElement *rtp = gst_element_factory_make("rtpjpegpay", "rtp");
GstElement *queueDisplay = gst_element_factory_make("queue", "queueDisplay");
GstElement *queueStreamer = gst_element_factory_make("queue", "queueStreamer");
GstElement *udpsink = gst_element_factory_make("udpsink", "udpsink");
GstElement *videoSink = gst_element_factory_make("xvimagesink", "videoSink");
// jpegenc -> rtpjpegpay -> udpsink
//v4l2src -> capsfilter -> tee <
// videoconvert -> queue -> xvimagesink
g_object_set(udpsink, "port", 5200, NULL);
g_object_set(udpsink, "host", "127.0.0.1", NULL);
GstCaps *caps = gst_caps_from_string("video/x-raw, width=(int)1280, height=(int)720");
g_object_set(capsfilter, "caps", caps, NULL);
//add elements to bin
gst_bin_add_many(GST_BIN(pipeline0), v4l2src, capsfilter, tee, encoder, queueDisplay, queueStreamer, videoConverter, rtp, udpsink, videoSink, NULL);
//Link source elements
if(!gst_element_link_many(v4l2src, capsfilter, tee, NULL))
{
qDebug()<<"Unable to link source elements";
}
//Link streaming elements
if(!gst_element_link_many(queueStreamer, encoder, rtp, udpsink, NULL))
{
qDebug()<<"Unable to link streaming elements";
}
//Link display elements
if(!gst_element_link_many(queueDisplay, videoConverter, videoSink, NULL))
{
qDebug()<<"Unable to link display elements";
}
//Create Tee Pads
GstPad *teeStreamerPad = gst_element_get_request_pad(tee, "src_%u");
GstPad *queueStreamerPad = gst_element_get_static_pad(queueStreamer, "sink");
GstPad *teeDisplayPad = gst_element_get_request_pad(tee, "src_%u");
GstPad *queueDisplayPad= gst_element_get_static_pad(queueDisplay, "sink");
//Link Tee and Queue Pads
if(gst_pad_link(teeStreamerPad, queueStreamerPad) != GST_PAD_LINK_OK)
{
qDebug()<<"Unable to link streamer pads";
}
if(gst_pad_link(teeDisplayPad, queueDisplayPad) != GST_PAD_LINK_OK)
{
qDebug()<<"Unable to link display pads";
}
gst_object_unref(queueStreamerPad);
gst_object_unref(queueDisplayPad);
//Setup Gui Display Area
gint viewX = 0;
gint viewY = 0;
gint camResX = 1280;
gint camResY = 720;
gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY (videoSink), xwinid);
gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY (videoSink), viewX, viewY, camResX, camResY);
//start pipeline
sret0 = gst_element_set_state(pipeline0, GST_STATE_PLAYING);
if(sret0 == GST_STATE_CHANGE_FAILURE)
{
qDebug()<<"Error: GST_STATE_CHANGE_FAILURE";
close();
}
else
{
qDebug()<<sret0;
}
}
MainWindow::~MainWindow()
{
gst_element_set_state (pipeline0, GST_STATE_NULL);
gst_object_unref(pipeline0);
delete ui;
qDebug()<<"Closed correctly";
}