GStreamer.cc 7.65 KB
Newer Older
1
/****************************************************************************
2
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/
9 10 11 12 13


/**
 * @file
 *   @brief QGC Video Streaming Initialization
Gus Grubba's avatar
Gus Grubba committed
14
 *   @author Gus Grubba <gus@auterion.com>
15 16 17 18
 */

#include <QDebug>

19 20
#include "GStreamer.h"
#include "GstVideoReceiver.h"
21

22
QGC_LOGGING_CATEGORY(GStreamerLog, "GStreamerLog")
23 24 25 26 27 28 29 30 31

static void qt_gst_log(GstDebugCategory * category,
                       GstDebugLevel      level,
                       const gchar      * file,
                       const gchar      * function,
                       gint               line,
                       GObject          * object,
                       GstDebugMessage  * message,
                       gpointer           data)
32
{
33 34
    Q_UNUSED(data);

35 36
    if (level > gst_debug_category_get_threshold(category)) {
        return;
37
    }
38 39 40 41 42 43 44 45

    QMessageLogger log(file, line, function);

    char* object_info = gst_info_strdup_printf("%" GST_PTR_FORMAT, static_cast<void*>(object));

    switch (level) {
    default:
    case GST_LEVEL_ERROR:
46
        log.critical(GStreamerLog, "%s %s", object_info, gst_debug_message_get(message));
47 48
        break;
    case GST_LEVEL_WARNING:
49
        log.warning(GStreamerLog, "%s %s", object_info, gst_debug_message_get(message));
50 51 52
        break;
    case GST_LEVEL_FIXME:
    case GST_LEVEL_INFO:
53
        log.info(GStreamerLog, "%s %s", object_info, gst_debug_message_get(message));
54 55 56 57 58
        break;
    case GST_LEVEL_DEBUG:
    case GST_LEVEL_LOG:
    case GST_LEVEL_TRACE:
    case GST_LEVEL_MEMDUMP:
59
        log.debug(GStreamerLog, "%s %s", object_info, gst_debug_message_get(message));
60 61 62 63 64
        break;
    }

    g_free(object_info);
    object_info = nullptr;
65
}
66 67

#if defined(__ios__)
68 69
#include "gst_ios_init.h"
#endif
70

71
#include "VideoReceiver.h"
72

73 74
G_BEGIN_DECLS
// The static plugins we use
75
#if defined(__android__) || defined(__ios__)
76
    GST_PLUGIN_STATIC_DECLARE(coreelements);
77
    GST_PLUGIN_STATIC_DECLARE(playback);
78 79
    GST_PLUGIN_STATIC_DECLARE(libav);
    GST_PLUGIN_STATIC_DECLARE(rtp);
80
    GST_PLUGIN_STATIC_DECLARE(rtsp);
81 82 83
    GST_PLUGIN_STATIC_DECLARE(udp);
    GST_PLUGIN_STATIC_DECLARE(videoparsersbad);
    GST_PLUGIN_STATIC_DECLARE(x264);
84
    GST_PLUGIN_STATIC_DECLARE(rtpmanager);
85 86
    GST_PLUGIN_STATIC_DECLARE(isomp4);
    GST_PLUGIN_STATIC_DECLARE(matroska);
87
    GST_PLUGIN_STATIC_DECLARE(mpegtsdemux);
88
    GST_PLUGIN_STATIC_DECLARE(opengl);
89
    GST_PLUGIN_STATIC_DECLARE(tcp);
90 91
#if defined(__android__)
    GST_PLUGIN_STATIC_DECLARE(androidmedia);
92 93 94
#elif defined(__ios__)
    GST_PLUGIN_STATIC_DECLARE(applemedia);
#endif
95
#endif
96
    GST_PLUGIN_STATIC_DECLARE(qmlgl);
97
    GST_PLUGIN_STATIC_DECLARE(qgc);
98
G_END_DECLS
99

100
#if (defined(Q_OS_MAC) && defined(QGC_INSTALL_RELEASE)) || defined(Q_OS_WIN)
dogmaphobic's avatar
dogmaphobic committed
101 102 103 104 105 106 107
static void qgcputenv(const QString& key, const QString& root, const QString& path)
{
    QString value = root + path;
    qputenv(key.toStdString().c_str(), QByteArray(value.toStdString().c_str()));
}
#endif

Andrew Voznytsa's avatar
Andrew Voznytsa committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
static void
blacklist()
{
    GstRegistry* reg;

    if ((reg = gst_registry_get()) == nullptr) {
        return;
    }

    GstPluginFeature* plugin;

    if ((plugin = gst_registry_lookup_feature(reg, "bcmdec")) != nullptr) {
        qCCritical(GStreamerLog) << "Disable bcmdec";
        gst_plugin_feature_set_rank(plugin, GST_RANK_NONE);
    }
}

125 126
void
GStreamer::initialize(int argc, char* argv[], int debuglevel)
127
{
128 129
    qRegisterMetaType<VideoReceiver::STATUS>("STATUS");

130 131
#ifdef Q_OS_MAC
    #ifdef QGC_INSTALL_RELEASE
Don Gagne's avatar
Don Gagne committed
132
        QString currentDir = QCoreApplication::applicationDirPath();
133 134 135 136 137 138 139
        qgcputenv("GST_PLUGIN_SCANNER",           currentDir, "/../Frameworks/GStreamer.framework/Versions/1.0/libexec/gstreamer-1.0/gst-plugin-scanner");
        qgcputenv("GTK_PATH",                     currentDir, "/../Frameworks/GStreamer.framework/Versions/Current");
        qgcputenv("GIO_EXTRA_MODULES",            currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gio/modules");
        qgcputenv("GST_PLUGIN_SYSTEM_PATH_1_0",   currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0");
        qgcputenv("GST_PLUGIN_SYSTEM_PATH",       currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0");
        qgcputenv("GST_PLUGIN_PATH_1_0",          currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0");
        qgcputenv("GST_PLUGIN_PATH",              currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0");
140
    #endif
141 142 143 144
#elif defined(Q_OS_WIN)
    QString currentDir = QCoreApplication::applicationDirPath();
    qgcputenv("GST_PLUGIN_PATH", currentDir, "/gstreamer-plugins");
#endif
145

146
    //-- If gstreamer debugging is not configured via environment then use internal QT logging
147
    if (qEnvironmentVariableIsEmpty("GST_DEBUG")) {
148
        gst_debug_set_default_threshold(static_cast<GstDebugLevel>(debuglevel));
149 150
        gst_debug_remove_log_function(gst_debug_log_default);
        gst_debug_add_log_function(qt_gst_log, nullptr, nullptr);
151 152 153
    }

    // Initialize GStreamer
154
#if defined(__ios__)
155 156 157
    //-- iOS specific initialization
    gst_ios_pre_init();
#endif
158

159 160
    GError* error = nullptr;
    if (!gst_init_check(&argc, &argv, &error)) {
161
        qCCritical(GStreamerLog) << "gst_init_check() failed: " << error->message;
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
        g_error_free(error);
    }

    // The static plugins we use
#if defined(__android__) || defined(__ios__)
    GST_PLUGIN_STATIC_REGISTER(coreelements);
    GST_PLUGIN_STATIC_REGISTER(playback);
    GST_PLUGIN_STATIC_REGISTER(libav);
    GST_PLUGIN_STATIC_REGISTER(rtp);
    GST_PLUGIN_STATIC_REGISTER(rtsp);
    GST_PLUGIN_STATIC_REGISTER(udp);
    GST_PLUGIN_STATIC_REGISTER(videoparsersbad);
    GST_PLUGIN_STATIC_REGISTER(x264);
    GST_PLUGIN_STATIC_REGISTER(rtpmanager);
    GST_PLUGIN_STATIC_REGISTER(isomp4);
    GST_PLUGIN_STATIC_REGISTER(matroska);
178
    GST_PLUGIN_STATIC_REGISTER(mpegtsdemux);
179
    GST_PLUGIN_STATIC_REGISTER(opengl);
180
    GST_PLUGIN_STATIC_REGISTER(tcp);
181 182 183 184 185 186 187 188 189 190

#if defined(__android__)
    GST_PLUGIN_STATIC_REGISTER(androidmedia);
#elif defined(__ios__)
    GST_PLUGIN_STATIC_REGISTER(applemedia);
#endif
#endif

#if defined(__ios__)
    gst_ios_post_init();
191
#endif
192

Andrew Voznytsa's avatar
Andrew Voznytsa committed
193 194
    blacklist();

195 196 197 198
    /* the plugin must be loaded before loading the qml file to register the
     * GstGLVideoItem qml item
     * FIXME Add a QQmlExtensionPlugin into qmlglsink to register GstGLVideoItem
     * with the QML engine, then remove this */
199 200 201 202 203 204 205 206
    GstElement *sink = gst_element_factory_make("qmlglsink", nullptr);

    if (sink == nullptr) {
        GST_PLUGIN_STATIC_REGISTER(qmlgl);
        sink = gst_element_factory_make("qmlglsink", nullptr);
    }

    if (sink != nullptr) {
207
        gst_object_unref(sink);
208
        sink = nullptr;
209
    } else {
210
        qCCritical(GStreamerLog) << "unable to find qmlglsink - you need to build it yourself and add to GST_PLUGIN_PATH";
211
    }
212 213

    GST_PLUGIN_STATIC_REGISTER(qgc);
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
}

void*
GStreamer::createVideoSink(QObject* parent, QQuickItem* widget)
{
    Q_UNUSED(parent)

    GstElement* sink;

    if ((sink = gst_element_factory_make("qgcvideosinkbin", nullptr)) != nullptr) {
        g_object_set(sink, "widget", widget, NULL);
    } else {
        qCritical() << "gst_element_factory_make('qgcvideosinkbin') failed";
    }

    return sink;
}

void
GStreamer::releaseVideoSink(void* sink)
{
    if (sink != nullptr) {
        gst_object_unref(GST_ELEMENT(sink));
    }
}

VideoReceiver*
GStreamer::createVideoReceiver(QObject* parent)
{
    Q_UNUSED(parent)
    return new GstVideoReceiver(nullptr);
245
}