Commit ae8ea3bf authored by Don Gagne's avatar Don Gagne

Merge pull request #1710 from dogmaphobic/gstRelocation

Initial setup for Mac Installer (Video Steaming)
parents d115de8a fc83d5fd
libs/lib/Frameworks/GStreamer.framework
*.swp
*.nfs
CMakeFiles
......
......@@ -122,18 +122,6 @@ include(libs/qextserialport/src/qextserialport.pri)
include(QGCExternalLibs.pri)
#
# Post link configuration
#
include(QGCSetup.pri)
#
# Installer targets
#
include(QGCInstaller.pri)
#
# Main QGroundControl portion of project file
#
......@@ -702,3 +690,16 @@ AndroidBuild {
$$PWD/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java \
$$PWD/android/src/org/qgroundcontrol/qgchelper/UsbIoManager.java
}
#-------------------------------------------------------------------------------------
#
# Post link configuration
#
include(QGCSetup.pri)
#
# Installer targets
#
include(QGCInstaller.pri)
......@@ -18,7 +18,21 @@
# -------------------------------------------------
installer {
DEFINES += QGC_INSTALL_RELEASE
MacBuild {
VideoEnabled {
# Install the gstreamer framework
# This will:
# Copy from the original distibution into libs/lib/Framworks (if not already there)
# Prune the framework, removing stuff we don't need
# Relocate all dylibs so they can work under @executable_path/...
# Copy the result into the app bundle
# Make sure qgroundcontrol can find them
message("Preparing GStreamer Framework")
QMAKE_POST_LINK += && $$BASEDIR/tools/prepare_gstreamer_framework.sh $$BASEDIR/libs/lib/Frameworks/ $$DESTDIR/$${TARGET}.app $${TARGET}
} else {
message("Skipping GStreamer Framework")
}
# We cd to release directory so we can run macdeployqt without a path to the
# qgroundcontrol.app file. If you specify a path to the .app file the symbolic
# links to plugins will not be created correctly.
......@@ -27,7 +41,6 @@ installer {
QMAKE_POST_LINK += && cd ..
QMAKE_POST_LINK += && hdiutil create -layout SPUD -srcfolder $${DESTDIR}/qgroundcontrol.app -volname QGroundControl $${DESTDIR}/qgroundcontrol.dmg
}
WindowsBuild {
# The pdb moving command are commented out for now since we are including the .pdb in the installer. This makes it much
# easier to debug user crashes.
......
......@@ -55,9 +55,10 @@ WindowsBuild {
#
MacBuild {
# Copy non-standard libraries and frameworks into app package
QMAKE_POST_LINK += && $$QMAKE_COPY_DIR $$BASEDIR/libs/lib/mac64/lib $$DESTDIR/$${TARGET}.app/Contents/libs
QMAKE_POST_LINK += && $$QMAKE_COPY_DIR -L $$BASEDIR/libs/lib/Frameworks $$DESTDIR/$${TARGET}.app/Contents
QMAKE_POST_LINK += && rsync -a --delete $$BASEDIR/libs/lib/Frameworks $$DESTDIR/$${TARGET}.app/Contents/
# Fix library paths inside executable
......
......@@ -131,6 +131,20 @@ static QObject* mavManagerSingletonFactory(QQmlEngine*, QJSEngine*)
return mavManager;
}
#if defined(QGC_GST_STREAMING)
#ifdef Q_OS_MAC
#ifndef __ios__
#ifdef QGC_INSTALL_RELEASE
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
#endif
#endif
#endif
/**
* @brief Constructor for the main application.
*
......@@ -141,7 +155,6 @@ static QObject* mavManagerSingletonFactory(QQmlEngine*, QJSEngine*)
* @param argv The string array of parameters
**/
QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
: QApplication(argc, argv)
, _runningUnitTests(unitTesting)
......@@ -266,8 +279,30 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
//----------------------------------------------------------------
//-- Video Streaming
#if defined(QGC_GST_STREAMING)
#ifdef Q_OS_MAC
#ifndef __ios__
#ifdef QGC_INSTALL_RELEASE
QString currentDir = QCoreApplication::applicationDirPath();
qgcputenv("GST_PLUGIN_SCANNER", currentDir, "/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");
// QStringList env = QProcessEnvironment::systemEnvironment().keys();
// foreach(QString key, env) {
// qDebug() << key << QProcessEnvironment::systemEnvironment().value(key);
// }
#endif
#endif
#endif
#endif
qmlRegisterType<VideoItem>("QGroundControl.QgcQtGStreamer", 1, 0, "VideoItem");
qmlRegisterUncreatableType<VideoSurface>("QGroundControl.QgcQtGStreamer", 1, 0, "VideoSurface", QLatin1String("VideoSurface from QML is not supported"));
#if defined(QGC_GST_STREAMING)
GError* error = NULL;
if (!gst_init_check(&argc, &argv, &error)) {
......
......@@ -87,34 +87,41 @@ void VideoReceiver::start()
do {
if ((_pipeline = gst_pipeline_new("receiver")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_pipeline_new()";
break;
}
if ((dataSource = gst_element_factory_make("udpsrc", "udp-source")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('udpsrc')";
break;
}
if ((caps = gst_caps_from_string("application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_caps_from_string()";
break;
}
g_object_set(G_OBJECT(dataSource), "uri", qPrintable(_uri), "caps", caps, NULL);
if ((demux = gst_element_factory_make("rtph264depay", "rtp-h264-depacketizer")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('rtph264depay')";
break;
}
if ((parser = gst_element_factory_make("h264parse", "h264-parser")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('h264parse')";
break;
}
if ((decoder = gst_element_factory_make("avdec_h264", "h264-decoder")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('avdec_h264')";
break;
}
gst_bin_add_many(GST_BIN(_pipeline), dataSource, demux, parser, decoder, _videoSink, NULL);
if (gst_element_link_many(dataSource, demux, parser, decoder, _videoSink, NULL) != (gboolean)TRUE) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_link_many()";
break;
}
......
......@@ -27,7 +27,6 @@
LinuxBuild {
CONFIG += link_pkgconfig
packagesExist(gstreamer-1.0) {
message("Including support for video streaming")
PKGCONFIG += gstreamer-1.0 gstreamer-video-1.0
CONFIG += VideoEnabled
}
......@@ -35,7 +34,6 @@ LinuxBuild {
#- gstreamer framework installed by the gstreamer devel installer
GST_ROOT = /Library/Frameworks/GStreamer.framework
exists($$GST_ROOT) {
message("Including support for video streaming")
CONFIG += VideoEnabled
INCLUDEPATH += $$GST_ROOT/Headers
LIBS += -F/Library/Frameworks -framework GStreamer
......@@ -44,7 +42,6 @@ LinuxBuild {
#- gstreamer framework installed by the gstreamer iOS SDK installer (default to home directory)
GST_ROOT = $$(HOME)/Library/Developer/GStreamer/iPhone.sdk/GStreamer.framework
exists($$GST_ROOT) {
message("Including support for video streaming")
CONFIG += VideoEnabled
INCLUDEPATH += $$GST_ROOT/Headers
LIBS += -F$$(HOME)/Library/Developer/GStreamer/iPhone.sdk -framework GStreamer
......@@ -53,7 +50,6 @@ LinuxBuild {
#- gstreamer installed by default under c:/gstreamer
GST_ROOT = c:/gstreamer/1.0/x86
exists($$GST_ROOT) {
message("Including support for video streaming")
CONFIG += VideoEnabled
LIBS += -L$$GST_ROOT/lib/gstreamer-1.0/static -lgstreamer-1.0 -lgstvideo-1.0 -lgstbase-1.0
LIBS += -L$$GST_ROOT/lib -lglib-2.0 -lintl -lgobject-2.0
......@@ -67,6 +63,8 @@ LinuxBuild {
VideoEnabled {
message("Including support for video streaming")
DEFINES += \
QGC_GST_STREAMING \
GST_PLUGIN_BUILD_STATIC \
......@@ -123,6 +121,25 @@ VideoEnabled {
$$PWD/gstqtvideosink/utils/utils.cpp \
} else {
LinuxBuild|MacBuild|iOSBuild|WindowsBuild {
message("Skipping support for video streaming (GStreamer libraries not installed)")
MacBuild {
message(" You can download it from http://gstreamer.freedesktop.org/data/pkg/osx/")
message(" Select the devel package and install it (gstreamer-1.0-devel-1.x.x-x86_64.pkg)")
message(" It will be installed in /Libraries/Frameworks")
}
LinuxBuild {
message(" You can install it using apt-get")
message(" sudo apt-get install gstreamer1.0*")
message(" sudo apt-get install libgstreamer1.0*")
}
WindowsBuild {
message(" You can download it from http://gstreamer.freedesktop.org/data/pkg/windows/")
message(" Select the devel AND runtime packages and install them (x86, not the 64-Bit)")
message(" It will be installed in C:/gstreamer. You need to update you PATH to point to the bin directory.")
}
} else {
message("Skipping support for video streaming (Unsupported platform)")
}
}
......@@ -28,12 +28,13 @@ This file is part of the QGROUNDCONTROL project
*
*/
#include <QtGlobal>
#include <QApplication>
#include <QSslSocket>
#ifndef __mobile__
#include <QSerialPortInfo>
#endif
#include <QProcessEnvironment>
#include "QGCApplication.h"
#include "MainWindow.h"
#include "configuration.h"
......
#!/usr/bin/env python
# cerbero - a multi-platform build system for Open Source software
# Copyright (C) 2012 Andoni Morales Alastruey <ylatuya@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
import os
import subprocess
INT_CMD = 'install_name_tool'
OTOOL_CMD = 'otool'
def shell_call(cmd, cmd_dir='.', fail=True):
print "call", cmd
try:
ret = subprocess.check_call(
cmd, cwd=cmd_dir,
env=os.environ.copy())
except subprocess.CalledProcessError:
if fail:
raise SystemError("Error running command: {}".format(cmd))
else:
ret = 0
return ret
def shell_check_call(cmd):
print "ccall", cmd
try:
process = subprocess.Popen(
cmd, stdout=subprocess.PIPE)
output, _ = process.communicate()
except Exception:
raise SystemError("Error running command: {}".format(cmd))
return output
class OSXRelocator(object):
'''
Wrapper for OS X's install_name_tool and otool commands to help
relocating shared libraries.
It parses lib/ /libexec and bin/ directories, changes the prefix path of
the shared libraries that an object file uses and changes it's library
ID if the file is a shared library.
'''
def __init__(self, root, lib_prefix, new_lib_prefix, recursive):
self.root = root
self.lib_prefix = self._fix_path(lib_prefix)
self.new_lib_prefix = self._fix_path(new_lib_prefix)
self.recursive = recursive
def relocate(self):
self.parse_dir(self.root, filters=['', '.dylib', '.so', '0'])
def relocate_file(self, object_file, id=None):
self.change_libs_path(object_file)
self.change_id(object_file, id)
def change_id(self, object_file, id=None):
id = id or object_file.replace(self.lib_prefix, self.new_lib_prefix)
filename = os.path.basename(object_file)
if not (filename.endswith('so') or filename.endswith('dylib')):
return
cmd = [INT_CMD, "-id", id, object_file]
shell_call(cmd, fail=False)
def change_libs_path(self, object_file):
for lib in self.list_shared_libraries(object_file):
if self.lib_prefix in lib:
new_lib = lib.replace(self.lib_prefix, self.new_lib_prefix)
cmd = [INT_CMD, "-change", lib, new_lib, object_file]
shell_call(cmd)
def parse_dir(self, dir_path, filters=None):
for dirpath, dirnames, filenames in os.walk(dir_path):
for f in filenames:
if filters is not None and \
os.path.splitext(f)[1] not in filters:
continue
fn = os.path.join(dirpath, f)
if os.path.islink(fn):
continue
if not os.path.isfile(fn):
continue
self.relocate_file(fn)
if not self.recursive:
break
@staticmethod
def list_shared_libraries(object_file):
cmd = [OTOOL_CMD, "-L", object_file]
res = shell_check_call(cmd).split('\n')
# We don't use the first line
libs = res[1:]
# Remove the first character tabulation
libs = [x[1:] for x in libs]
# Remove the version info
libs = [x.split(' ', 1)[0] for x in libs]
return libs
@staticmethod
def library_id_name(object_file):
cmd = [OTOOL_CMD, "-D", object_file]
res = shell_check_call(cmd).split('\n')[0]
# the library name ends with ':'
lib_name = res[:-1]
return lib_name
def _fix_path(self, path):
if path.endswith('/'):
return path[:-1]
return path
class Main(object):
def run(self):
# We use OptionParser instead of ArgumentsParse because this script
# might be run in OS X 10.6 or older, which do not provide the argparse
# module
import optparse
usage = "usage: %prog [options] directory old_prefix new_prefix"
description = 'Rellocates object files changing the dependant '\
' dynamic libraries location path with a new one'
parser = optparse.OptionParser(usage=usage, description=description)
parser.add_option('-r', '--recursive', action='store_true',
default=False, dest='recursive',
help='Scan directories recursively')
options, args = parser.parse_args()
if len(args) != 3:
parser.print_usage()
exit(1)
relocator = OSXRelocator(args[0], args[1], args[2], options.recursive)
relocator.relocate()
exit(0)
def main():
main = Main()
main.run()
if __name__ == "__main__":
main()
#!/bin/bash
#
# Author: Gus Grubba <mavlink@grubba.com>
#
# Copies the regular distribution of the gstreamer framework
# into the libs directory (to be used for creating the Mac OS
# bundle). It also prunes unnecessary files and relocates the
# dynamic libraries.
#
# This script is run by the build process and should not be
# executed manually.
#
# Usage: $script [framework destination path] [app bundle path] [qgc executable name]
#
# destination is usually: ../libs/lib/Frameworks/
# app bundle is something like: /path/qgroundcontrol.app
# executable name is usually: qgroundcontrol
die () {
echo "$@" 1>&2
exit 1
}
GST_VER=1.0
GST_ROOT=/Library/Frameworks/GStreamer.framework
GST_BASE=$GST_ROOT/Versions/$GST_VER
RELOC=$(dirname $0)/osxrelocator.py
echo "GST Installer"
[ "$#" -eq 3 ] || die "3 arguments required, $# provided"
[ -d "$1" ] || die "Could not find $1"
[ -d "$2" ] || die "Could not find $2"
FMWORK_TARGET=$1
BUNDLE_TARGET=$2
GST_SOURCE=${1%/}/GStreamer.framework
GST_TARGET=$GST_SOURCE/Versions/$GST_VER
QGC_BINARY=$BUNDLE_TARGET/Contents/MacOS/$3
[ -e "$QGC_BINARY" ] || die "Could not find $QGC_BINARY"
process_framework() {
#-- Start looking for the source framework
[ -d "$GST_ROOT" ] || die "Could not find gstreamer framework in $GST_ROOT"
[ -d "$GST_BASE" ] || die "Wrong version of gstreamer framework found in $GST_ROOT"
[ -e $RELOC ] || die "Cannot find $RELOC"
echo "GST Installer: Copying $GST_ROOT to $FMWORK_TARGET"
rsync -a --delete "$GST_ROOT" "$FMWORK_TARGET" || die "Error copying $GST_ROOT to $FMWORK_TARGET"
#-- Prune unused stuff
rm -rf $GST_TARGET/bin/*
rm -rf $GST_TARGET/Headers/*
rm -rf $GST_TARGET/include/*
rm -rf $GST_TARGET/lib/*.a
rm -rf $GST_TARGET/lib/*.la
rm -rf $GST_TARGET/lib/gio/modules/static
rm -rf $GST_TARGET/lib/glib-2.0
rm -rf $GST_TARGET/lib/gst-validate-launcher
rm -rf $GST_TARGET/lib/gstreamer-1.0/static
rm -rf $GST_TARGET/lib/libffi-3.0.13
rm -rf $GST_TARGET/lib/pkgconfig
#-- Some dylibs are dupes instead of symlinks.
#-- This will do a minimum job in trying to clean those.
#-- Doesn't work. The stupid thing can't load a dlyb symlink.
#for f in $GST_TARGET/lib/*.dylib
#do
# foo=$(basename "$f")
# bar="${foo%.*}"
# for i in `seq 0 9`;
# do
# if [ -e $GST_TARGET/lib/$bar.$i.dylib ]; then
# DUPES="$DUPES
#rm -f $GST_TARGET/lib/$bar.$i.dylib"
# DUPES="$DUPES
#ln -s $f $GST_TARGET/lib/$bar.$i.dylib"
# fi
# done
#done
#IFS=$'\n'
#for c in $DUPES
#do
# eval $c
#done
#-- Now relocate the embeded paths
echo "GST Installer: Relocating"
python $RELOC -r $GST_TARGET/lib /Library/Frameworks/GStreamer.framework/ @executable_path/../Frameworks/GStreamer.framework/ > /dev/null || die "Error relocating binaries in $GST_TARGET/lib"
python $RELOC -r $GST_TARGET/libexec /Library/Frameworks/GStreamer.framework/ @executable_path/../Frameworks/GStreamer.framework/ > /dev/null || die "Error relocating binaries in $GST_TARGET/libexec"
}
#-- Check and see if we've already processed the framework
echo "GST Installer: Checking $GST_TARGET"
[ -d $GST_TARGET ] || process_framework
#-- Now copy the framework to the app bundle
echo "GST Installer: Copying $GST_SOURCE to $BUNDLE_TARGET/Contents/Frameworks/"
rsync -a --delete $GST_SOURCE $BUNDLE_TARGET/Contents/Frameworks/ || die "Error copying framework into app bundle"
#-- Move this gst binary to MacOS
mv $BUNDLE_TARGET/Contents/Frameworks/GStreamer.framework/Versions/1.0/libexec/gstreamer-1.0/gst-plugin-scanner $BUNDLE_TARGET/Contents/MacOS/ || die "Error moving gst-plugin-scanner"
#-- Fix main binary
python $RELOC $QGC_BINARY /Library/Frameworks/GStreamer.framework/ @executable_path/../Frameworks/GStreamer.framework/ > /dev/null || die "Error relocating $QGC_BINARY"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment