Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
860d317330 | ||
|
|
bab11a731e | ||
|
|
df9e7bead0 | ||
|
|
962dc847e7 | ||
|
|
566181e8d7 | ||
|
|
5f5f835b2e | ||
|
|
c0e697eb58 | ||
|
|
d3c2f50b20 | ||
|
|
f1ee1eeb63 | ||
|
|
bb18519e44 | ||
|
|
8e2ad133ea | ||
|
|
5e82e8413f | ||
|
|
917f6e5ee9 | ||
|
|
e1ca6e644e | ||
|
|
f1e89242cb | ||
|
|
91145cde0f | ||
|
|
8ae01fae3f | ||
|
|
4e60ccb2ff | ||
|
|
186052f21d | ||
|
|
0fb3bb0727 | ||
|
|
8f61a11452 | ||
|
|
4b1d3b0125 | ||
|
|
3f81d055af | ||
|
|
c61182bcb2 | ||
|
|
2fdfb3e998 |
@@ -0,0 +1,8 @@
|
||||
# ProBot No Response (https://probot.github.io/apps/no-response/)
|
||||
|
||||
daysUntilClose: 7
|
||||
responseRequiredLabel: 'need more info'
|
||||
closeComment: >
|
||||
This issue has been automatically closed because there was no response to a
|
||||
request for more information from the issue opener. Please leave a comment or
|
||||
open a new issue if you have additional information related to this issue.
|
||||
@@ -0,0 +1,14 @@
|
||||
# ProBot Stale (https://probot.github.io/apps/stale/)
|
||||
|
||||
daysUntilStale: 90
|
||||
daysUntilClose: 7
|
||||
exemptLabels:
|
||||
- accepted
|
||||
- bug
|
||||
- enhancement
|
||||
- meta
|
||||
staleLabel: stale
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs.
|
||||
closeComment: false
|
||||
@@ -22,6 +22,9 @@ matrix:
|
||||
- qt59svg
|
||||
- libesd0-dev
|
||||
- libgl-dev
|
||||
- libegl1-mesa-dev
|
||||
- libxkbcommon-dev
|
||||
- wayland-protocols
|
||||
- libopus-dev
|
||||
- libavcodec-dev
|
||||
- libavutil-dev
|
||||
|
||||
@@ -21,7 +21,10 @@ You can follow development on our [Discord server](https://discord.gg/6ERtzFY).
|
||||
- Gamepad support with SDL gamepad mappings
|
||||
|
||||
## Building
|
||||
1. Install the latest Qt SDK (and optionally, the Qt Creator IDE) from https://www.qt.io/download (select MSVC toolchain on Windows)
|
||||
1. Install the latest Qt SDK (and optionally, the Qt Creator IDE) from https://www.qt.io/download
|
||||
- On Windows, install Visual Studio 2017 and select MSVC 2017 toolchain during Qt installation
|
||||
- On Mac, install the latest version of XCode
|
||||
- On Linux, install your distro equivalents of: `openssl-devel qt5-devel SDL2-devel ffmpeg-devel qt5-qtquickcontrols2-devel libva-devel libvdpau-devel`
|
||||
2. Run `git submodule update --init --recursive` from within `moonlight-qt/`
|
||||
3. Open the project in Qt Creator or build from qmake on the command line
|
||||
|
||||
|
||||
+4
-2
@@ -17,13 +17,15 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.10</string>
|
||||
<string>10.11</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1.0</string>
|
||||
<string>0.2.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.2.0</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Moonlight</string>
|
||||
</dict>
|
||||
|
||||
+25
-4
@@ -44,13 +44,18 @@ macx {
|
||||
unix:!macx {
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += openssl sdl2 opus
|
||||
LIBS += -ldl
|
||||
|
||||
packagesExist(libavcodec) {
|
||||
PKGCONFIG += libavcodec libavutil
|
||||
CONFIG += ffmpeg
|
||||
|
||||
packagesExist(libva) {
|
||||
packagesExist(libva-x11) {
|
||||
CONFIG += libva-x11
|
||||
}
|
||||
packagesExist(libva-wayland) {
|
||||
CONFIG += libva-wayland
|
||||
}
|
||||
CONFIG += libva
|
||||
}
|
||||
|
||||
@@ -82,7 +87,8 @@ SOURCES += \
|
||||
streaming/audio.cpp \
|
||||
gui/computermodel.cpp \
|
||||
gui/appmodel.cpp \
|
||||
streaming/streamutils.cpp
|
||||
streaming/streamutils.cpp \
|
||||
backend/autoupdatechecker.cpp
|
||||
|
||||
HEADERS += \
|
||||
utils.h \
|
||||
@@ -97,7 +103,8 @@ HEADERS += \
|
||||
gui/computermodel.h \
|
||||
gui/appmodel.h \
|
||||
streaming/video/decoder.h \
|
||||
streaming/streamutils.h
|
||||
streaming/streamutils.h \
|
||||
backend/autoupdatechecker.h
|
||||
|
||||
# Platform-specific renderers and decoders
|
||||
ffmpeg {
|
||||
@@ -114,10 +121,23 @@ ffmpeg {
|
||||
libva {
|
||||
message(VAAPI renderer selected)
|
||||
|
||||
PKGCONFIG += libva
|
||||
DEFINES += HAVE_LIBVA
|
||||
SOURCES += streaming/video/ffmpeg-renderers/vaapi.cpp
|
||||
HEADERS += streaming/video/ffmpeg-renderers/vaapi.h
|
||||
}
|
||||
libva-x11 {
|
||||
message(VAAPI X11 support enabled)
|
||||
|
||||
PKGCONFIG += libva-x11
|
||||
DEFINES += HAVE_LIBVA_X11
|
||||
}
|
||||
libva-wayland {
|
||||
message(VAAPI Wayland support enabled)
|
||||
|
||||
PKGCONFIG += libva-wayland
|
||||
DEFINES += HAVE_LIBVA_WAYLAND
|
||||
}
|
||||
libvdpau {
|
||||
message(VDPAU renderer selected)
|
||||
|
||||
@@ -202,4 +222,5 @@ macx {
|
||||
QMAKE_BUNDLE_DATA += APP_BUNDLE_RESOURCES
|
||||
}
|
||||
|
||||
VERSION = 0.1.0
|
||||
VERSION = 0.2.0
|
||||
DEFINES += VERSION_STR=\\\"0.2.0\\\"
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
#include "autoupdatechecker.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
AutoUpdateChecker::AutoUpdateChecker(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_Nam(this)
|
||||
{
|
||||
// Never communicate over HTTP
|
||||
m_Nam.setStrictTransportSecurityEnabled(true);
|
||||
|
||||
connect(&m_Nam, SIGNAL(finished(QNetworkReply*)),
|
||||
this, SLOT(handleUpdateCheckRequestFinished(QNetworkReply*)));
|
||||
|
||||
QString currentVersion(VERSION_STR);
|
||||
qDebug() << "Current Moonlight version:" << currentVersion;
|
||||
parseStringToVersionQuad(currentVersion, m_CurrentVersionQuad);
|
||||
|
||||
// Should at least have a 1.0-style version number
|
||||
Q_ASSERT(m_CurrentVersionQuad.count() > 1);
|
||||
}
|
||||
|
||||
void AutoUpdateChecker::start()
|
||||
{
|
||||
#if defined(Q_OS_WIN32) || defined(Q_OS_DARWIN) // Only run update checker on platforms without auto-update
|
||||
// We'll get a callback when this is finished
|
||||
QUrl url("https://moonlight-stream.com/updates/qt.json");
|
||||
m_Nam.get(QNetworkRequest(url));
|
||||
#endif
|
||||
}
|
||||
|
||||
void AutoUpdateChecker::parseStringToVersionQuad(QString& string, QVector<int>& version)
|
||||
{
|
||||
QStringList list = string.split('.');
|
||||
for (const QString& component : list) {
|
||||
version.append(component.toInt());
|
||||
}
|
||||
}
|
||||
|
||||
void AutoUpdateChecker::handleUpdateCheckRequestFinished(QNetworkReply* reply)
|
||||
{
|
||||
Q_ASSERT(reply->isFinished());
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QTextStream stream(reply);
|
||||
stream.setCodec("UTF-8");
|
||||
|
||||
// Read all data and queue the reply for deletion
|
||||
QString jsonString = stream.readAll();
|
||||
reply->deleteLater();
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8(), &error);
|
||||
if (jsonDoc.isNull()) {
|
||||
qWarning() << "Update manifest malformed:" << error.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonArray array = jsonDoc.array();
|
||||
if (array.isEmpty()) {
|
||||
qWarning() << "Update manifest doesn't contain an array";
|
||||
return;
|
||||
}
|
||||
|
||||
for (QJsonValueRef updateEntry : array) {
|
||||
if (updateEntry.isObject()) {
|
||||
QJsonObject updateObj = updateEntry.toObject();
|
||||
if (!updateObj.contains("platform") ||
|
||||
!updateObj.contains("arch") ||
|
||||
!updateObj.contains("version") ||
|
||||
!updateObj.contains("browser_url")) {
|
||||
qWarning() << "Update manifest entry missing vital field";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!updateObj["platform"].isString() ||
|
||||
!updateObj["arch"].isString() ||
|
||||
!updateObj["version"].isString() ||
|
||||
!updateObj["browser_url"].isString()) {
|
||||
qWarning() << "Update manifest entry has unexpected vital field type";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (updateObj["arch"] == QSysInfo::buildCpuArchitecture() &&
|
||||
updateObj["platform"] == QSysInfo::productType()) {
|
||||
qDebug() << "Found update manifest match for current platform";
|
||||
|
||||
QString latestVersion = updateObj["version"].toString();
|
||||
qDebug() << "Latest version of Moonlight for this platform is:" << latestVersion;
|
||||
|
||||
QVector<int> latestVersionQuad;
|
||||
|
||||
parseStringToVersionQuad(latestVersion, latestVersionQuad);
|
||||
|
||||
for (int i = 0;; i++) {
|
||||
int latestVer = 0;
|
||||
int currentVer = 0;
|
||||
|
||||
// Treat missing decimal places as 0
|
||||
if (i < latestVersionQuad.count()) {
|
||||
latestVer = latestVersionQuad[i];
|
||||
}
|
||||
if (i < m_CurrentVersionQuad.count()) {
|
||||
currentVer = m_CurrentVersionQuad[i];
|
||||
}
|
||||
if (i >= latestVersionQuad.count() && i >= m_CurrentVersionQuad.count()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentVer < latestVer) {
|
||||
qDebug() << "Update available";
|
||||
|
||||
emit onUpdateAvailable(updateObj["browser_url"].toString());
|
||||
return;
|
||||
}
|
||||
else if (currentVer > latestVer) {
|
||||
qDebug() << "Update manifest version lower than current version";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Update manifest version equal to current version";
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
qWarning() << "Update manifest contained unrecognized entry:" << updateEntry.toString();
|
||||
}
|
||||
}
|
||||
|
||||
qWarning() << "No entry in update manifest found for current platform: "
|
||||
<< QSysInfo::buildCpuArchitecture() << QSysInfo::productType();
|
||||
}
|
||||
else {
|
||||
qWarning() << "Update checking failed with error: " << reply->error();
|
||||
reply->deleteLater();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class AutoUpdateChecker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AutoUpdateChecker(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
signals:
|
||||
void onUpdateAvailable(QString url);
|
||||
|
||||
private slots:
|
||||
void handleUpdateCheckRequestFinished(QNetworkReply* reply);
|
||||
|
||||
private:
|
||||
void parseStringToVersionQuad(QString& string, QVector<int>& version);
|
||||
|
||||
QVector<int> m_CurrentVersionQuad;
|
||||
QNetworkAccessManager m_Nam;
|
||||
};
|
||||
@@ -33,6 +33,18 @@
|
||||
</screenshots>
|
||||
|
||||
<releases>
|
||||
<release version="0.2.0" date="2018-08-12">
|
||||
<description>
|
||||
<p>Bugfixes:</p>
|
||||
<ul>
|
||||
<li>Fixed functionality of '=', 'Numpad Dot', and 'Numpad Enter' keys</li>
|
||||
<li>Fixed uninitialized variable causing strange gamepad behavior</li>
|
||||
<li>Added a warning for incompatible configs and decoder failures</li>
|
||||
<li>Added a warning for Wayland performance issues</li>
|
||||
<li>Stopped capturing the mouse by default for windowed streams</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.1.0" date="2018-08-05">
|
||||
<description>
|
||||
<p>New features:</p>
|
||||
|
||||
@@ -28,14 +28,24 @@ GridView {
|
||||
// routine to run, but only if we start as invisible
|
||||
visible: false
|
||||
|
||||
function computerLost()
|
||||
{
|
||||
// Go back to the PC view on PC loss
|
||||
stackView.pop()
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
// Start polling when this view is shown
|
||||
ComputerManager.startPolling()
|
||||
|
||||
appModel.computerLost.connect(computerLost)
|
||||
}
|
||||
else {
|
||||
// Stop polling when this view is not on top
|
||||
ComputerManager.stopPollingAsync()
|
||||
|
||||
appModel.computerLost.disconnect(computerLost)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-1
@@ -34,7 +34,10 @@ GridView {
|
||||
// Setup signals on CM
|
||||
ComputerManager.computerAddCompleted.connect(addComplete)
|
||||
|
||||
if (!prefs.hasAnyHardwareAcceleration()) {
|
||||
if (prefs.isRunningWayland()) {
|
||||
waylandDialog.open()
|
||||
}
|
||||
else if (!prefs.hasAnyHardwareAcceleration()) {
|
||||
noHwDecoderDialog.open()
|
||||
}
|
||||
}
|
||||
@@ -224,6 +227,18 @@ GridView {
|
||||
}
|
||||
}
|
||||
|
||||
MessageDialog {
|
||||
id: waylandDialog
|
||||
modality:Qt.WindowModal
|
||||
icon: StandardIcon.Warning
|
||||
standardButtons: StandardButton.Ok | StandardButton.Help
|
||||
text: "Moonlight does not support hardware acceleration on Wayland. Continuing on Wayland may result in poor streaming performance. " +
|
||||
"Please switch to an X session for optimal performance."
|
||||
onHelp: {
|
||||
Qt.openUrlExternally("https://github.com/moonlight-stream/moonlight-docs/wiki/Fixing-Hardware-Decoding-Problems");
|
||||
}
|
||||
}
|
||||
|
||||
MessageDialog {
|
||||
id: pairDialog
|
||||
// don't allow edits to the rest of the window while open
|
||||
|
||||
@@ -108,6 +108,14 @@ void AppModel::handleComputerStateChanged(NvComputer* computer)
|
||||
return;
|
||||
}
|
||||
|
||||
// If the computer has gone offline or we've been unpaired,
|
||||
// signal the UI so we can go back to the PC view.
|
||||
if (m_Computer->state == NvComputer::CS_OFFLINE ||
|
||||
m_Computer->pairState == NvComputer::PS_NOT_PAIRED) {
|
||||
emit computerLost();
|
||||
return;
|
||||
}
|
||||
|
||||
// First, process additions/removals from the app list. This
|
||||
// is required because the new game may now be running, so
|
||||
// we can't check that first.
|
||||
|
||||
@@ -42,6 +42,9 @@ private slots:
|
||||
|
||||
void handleBoxArtLoaded(NvComputer* computer, NvApp app, QUrl image);
|
||||
|
||||
signals:
|
||||
void computerLost();
|
||||
|
||||
private:
|
||||
NvComputer* m_Computer;
|
||||
BoxArtManager m_BoxArtManager;
|
||||
|
||||
+53
-3
@@ -4,6 +4,8 @@ import QtQuick.Layouts 1.3
|
||||
|
||||
import QtQuick.Controls.Material 2.1
|
||||
|
||||
import AutoUpdateChecker 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
visible: true
|
||||
@@ -66,14 +68,54 @@ ApplicationWindow {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
property string browserUrl: ""
|
||||
|
||||
id: updateButton
|
||||
icon.source: "qrc:/res/update.svg"
|
||||
icon.color: "#0BF200"
|
||||
|
||||
ToolTip.delay: 1000
|
||||
ToolTip.timeout: 3000
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: "Update available for Moonlight"
|
||||
|
||||
// Invisible until we get a callback notifying us that
|
||||
// an update is available
|
||||
visible: false
|
||||
|
||||
onClicked: Qt.openUrlExternally(browserUrl);
|
||||
|
||||
Menu {
|
||||
x: parent.width
|
||||
transformOrigin: Menu.TopRight
|
||||
}
|
||||
|
||||
|
||||
function updateAvailable(url)
|
||||
{
|
||||
updateButton.browserUrl = url
|
||||
updateButton.visible = true
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
AutoUpdateChecker.onUpdateAvailable.connect(updateAvailable)
|
||||
AutoUpdateChecker.start()
|
||||
}
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
icon.source: "qrc:/res/question_mark.svg"
|
||||
|
||||
ToolTip.delay: 1000
|
||||
ToolTip.timeout: 3000
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: "Help"
|
||||
|
||||
// TODO need to make sure browser is brought to foreground.
|
||||
onClicked: Qt.openUrlExternally("https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide");
|
||||
|
||||
Menu {
|
||||
id: helpButton
|
||||
x: parent.width
|
||||
transformOrigin: Menu.TopRight
|
||||
}
|
||||
@@ -83,11 +125,15 @@ ApplicationWindow {
|
||||
// TODO: Implement gamepad mapping then unhide this button
|
||||
visible: false
|
||||
|
||||
ToolTip.delay: 1000
|
||||
ToolTip.timeout: 3000
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: "Gamepad Mapper"
|
||||
|
||||
icon.source: "qrc:/res/ic_videogame_asset_white_48px.svg"
|
||||
onClicked: navigateTo("qrc:/gui/GamepadMapper.qml", "Gamepad Mapping")
|
||||
|
||||
Menu {
|
||||
id: gamepadMappingMenu
|
||||
x: parent.width
|
||||
transformOrigin: Menu.TopRight
|
||||
}
|
||||
@@ -97,8 +143,12 @@ ApplicationWindow {
|
||||
icon.source: "qrc:/res/settings.svg"
|
||||
onClicked: navigateTo("qrc:/gui/SettingsView.qml", "Settings")
|
||||
|
||||
ToolTip.delay: 1000
|
||||
ToolTip.timeout: 3000
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: "Settings"
|
||||
|
||||
Menu {
|
||||
id: optionsMenu
|
||||
x: parent.width
|
||||
transformOrigin: Menu.TopRight
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "gui/computermodel.h"
|
||||
#include "gui/appmodel.h"
|
||||
#include "backend/autoupdatechecker.h"
|
||||
#include "streaming/session.hpp"
|
||||
#include "settings/streamingpreferences.h"
|
||||
|
||||
@@ -131,7 +132,13 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef USE_CUSTOM_LOGGER
|
||||
#ifdef LOG_TO_FILE
|
||||
#ifdef Q_OS_DARWIN
|
||||
// On macOS, $TMPDIR is some random folder under /var/folders/ that nobody can
|
||||
// easily find, so use the system's global tmp directory instead.
|
||||
QDir tempDir("/tmp");
|
||||
#else
|
||||
QDir tempDir(QDir::tempPath());
|
||||
#endif
|
||||
s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch())));
|
||||
if (s_LoggerFile->open(QIODevice::WriteOnly)) {
|
||||
qInfo() << "Redirecting log output to " << s_LoggerFile->fileName();
|
||||
@@ -172,6 +179,11 @@ int main(int argc, char *argv[])
|
||||
[](QQmlEngine*, QJSEngine*) -> QObject* {
|
||||
return new ComputerManager();
|
||||
});
|
||||
qmlRegisterSingletonType<AutoUpdateChecker>("AutoUpdateChecker", 1, 0,
|
||||
"AutoUpdateChecker",
|
||||
[](QQmlEngine*, QJSEngine*) -> QObject* {
|
||||
return new AutoUpdateChecker();
|
||||
});
|
||||
|
||||
QQuickStyle::setStyle("Material");
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M21,10.12H14.22L16.96,7.3C14.23,4.6 9.81,4.5 7.08,7.2C4.35,9.91 4.35,14.28 7.08,17C9.81,19.7 14.23,19.7 16.96,17C18.32,15.65 19,14.08 19,12.1H21C21,14.08 20.12,16.65 18.36,18.39C14.85,21.87 9.15,21.87 5.64,18.39C2.14,14.92 2.11,9.28 5.62,5.81C9.13,2.34 14.76,2.34 18.27,5.81L21,3V10.12M12.5,8V12.25L16,14.33L15.28,15.54L11,13V8H12.5Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 484 B |
@@ -13,5 +13,6 @@
|
||||
<file>res/arrow_left.svg</file>
|
||||
<file>res/question_mark.svg</file>
|
||||
<file>res/moonlight.svg</file>
|
||||
<file>res/update.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -67,6 +67,11 @@ bool StreamingPreferences::hasAnyHardwareAcceleration()
|
||||
1920, 1080, 60);
|
||||
}
|
||||
|
||||
bool StreamingPreferences::isRunningWayland()
|
||||
{
|
||||
return qgetenv("XDG_SESSION_TYPE") == QByteArray("wayland");
|
||||
}
|
||||
|
||||
int StreamingPreferences::getMaximumStreamingFrameRate()
|
||||
{
|
||||
// Never let the maximum drop below 60 FPS
|
||||
|
||||
@@ -17,6 +17,8 @@ public:
|
||||
|
||||
Q_INVOKABLE static bool hasAnyHardwareAcceleration();
|
||||
|
||||
Q_INVOKABLE static bool isRunningWayland();
|
||||
|
||||
Q_INVOKABLE static int getMaximumStreamingFrameRate();
|
||||
|
||||
Q_INVOKABLE QRect getDisplayResolution(int displayIndex);
|
||||
|
||||
+11
-3
@@ -41,6 +41,10 @@ SdlInputHandler::SdlInputHandler(bool multiController)
|
||||
// Player 1 is always present in non-MC mode
|
||||
m_GamepadMask = 0x1;
|
||||
}
|
||||
else {
|
||||
// Otherwise, detect gamepads on the fly
|
||||
m_GamepadMask = 0;
|
||||
}
|
||||
|
||||
SDL_zero(m_GamepadState);
|
||||
}
|
||||
@@ -158,6 +162,7 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event)
|
||||
case SDL_SCANCODE_CLEAR:
|
||||
keyCode = 0x0C;
|
||||
break;
|
||||
case SDL_SCANCODE_KP_ENTER: // FIXME: Is this correct?
|
||||
case SDL_SCANCODE_RETURN:
|
||||
keyCode = 0x0D;
|
||||
break;
|
||||
@@ -235,7 +240,7 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event)
|
||||
case SDL_SCANCODE_KP_MINUS:
|
||||
keyCode = 0x6D;
|
||||
break;
|
||||
case SDL_SCANCODE_KP_DECIMAL:
|
||||
case SDL_SCANCODE_KP_PERIOD:
|
||||
keyCode = 0x6E;
|
||||
break;
|
||||
case SDL_SCANCODE_KP_DIVIDE:
|
||||
@@ -289,6 +294,9 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event)
|
||||
case SDL_SCANCODE_SEMICOLON:
|
||||
keyCode = 0xBA;
|
||||
break;
|
||||
case SDL_SCANCODE_EQUALS:
|
||||
keyCode = 0xBB;
|
||||
break;
|
||||
case SDL_SCANCODE_COMMA:
|
||||
keyCode = 0xBC;
|
||||
break;
|
||||
@@ -382,8 +390,8 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
|
||||
}
|
||||
|
||||
if (event->xrel != 0 || event->yrel != 0) {
|
||||
LiSendMouseMoveEvent((unsigned short)event->xrel,
|
||||
(unsigned short)event->yrel);
|
||||
LiSendMouseMoveEvent((short)event->xrel,
|
||||
(short)event->yrel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -361,9 +361,9 @@ bool Session::validateLaunch()
|
||||
m_StreamConfig.width,
|
||||
m_StreamConfig.height,
|
||||
m_StreamConfig.fps) &&
|
||||
m_Preferences.videoDecoderSelection != StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
||||
m_Preferences.videoDecoderSelection == StreamingPreferences::VDS_AUTO) {
|
||||
if (hevcForced) {
|
||||
emitLaunchWarning("Using software decoding due to your selection to force HEVC. This may cause poor streaming performance.");
|
||||
emitLaunchWarning("Using software decoding due to your selection to force HEVC without GPU support. This may cause poor streaming performance.");
|
||||
}
|
||||
else {
|
||||
emitLaunchWarning("This PC's GPU doesn't support HEVC decoding.");
|
||||
@@ -375,6 +375,11 @@ bool Session::validateLaunch()
|
||||
if (m_Computer->maxLumaPixelsHEVC == 0) {
|
||||
emitLaunchWarning("Your host PC GPU doesn't support HEVC. "
|
||||
"A GeForce GTX 900-series (Maxwell) or later GPU is required for HEVC streaming.");
|
||||
|
||||
// Moonlight-common-c will handle this case already, but we want
|
||||
// to set this explicitly here so we can do our hardware acceleration
|
||||
// check below.
|
||||
m_StreamConfig.supportsHevc = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,7 +431,23 @@ bool Session::validateLaunch()
|
||||
}
|
||||
}
|
||||
|
||||
// Always allow the launch to proceed for now
|
||||
if (m_Preferences.videoDecoderSelection == StreamingPreferences::VDS_FORCE_HARDWARE &&
|
||||
!isHardwareDecodeAvailable(m_Preferences.videoDecoderSelection,
|
||||
m_StreamConfig.supportsHevc ? VIDEO_FORMAT_H265 : VIDEO_FORMAT_H264,
|
||||
m_StreamConfig.width,
|
||||
m_StreamConfig.height,
|
||||
m_StreamConfig.fps)) {
|
||||
if (m_Preferences.videoCodecConfig == StreamingPreferences::VCC_AUTO) {
|
||||
emit displayLaunchError("Your selection to force hardware decoding cannot be satisfied due to missing hardware decoding support on this PC's GPU.");
|
||||
}
|
||||
else {
|
||||
emit displayLaunchError("Your codec selection and force hardware decoding setting are not compatible. This PC's GPU lacks support for decoding your chosen codec.");
|
||||
}
|
||||
|
||||
// Fail the launch, because we won't manage to get a decoder for the actual stream
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -721,7 +742,9 @@ void Session::exec()
|
||||
// Capture the mouse by default on release builds only.
|
||||
// This prevents the mouse from becoming trapped inside
|
||||
// Moonlight when it's halted at a debug break.
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
if (m_Preferences.fullScreen) {
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Stop text input. SDL enables it by default
|
||||
@@ -803,6 +826,7 @@ void Session::exec()
|
||||
SDL_AtomicUnlock(&m_DecoderLock);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to recreate decoder after reset");
|
||||
emit displayLaunchError("Unable to initialize video decoder. Please check your streaming settings and try again.");
|
||||
goto DispatchDeferredCleanup;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
#include "vaapi.h"
|
||||
#include <streaming/streamutils.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
VAAPIRenderer::VAAPIRenderer()
|
||||
: m_HwContext(nullptr),
|
||||
m_X11VaLibHandle(nullptr),
|
||||
m_vaPutSurface(nullptr)
|
||||
: m_HwContext(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -16,11 +12,17 @@ VAAPIRenderer::VAAPIRenderer()
|
||||
VAAPIRenderer::~VAAPIRenderer()
|
||||
{
|
||||
if (m_HwContext != nullptr) {
|
||||
av_buffer_unref(&m_HwContext);
|
||||
}
|
||||
AVHWDeviceContext* deviceContext = (AVHWDeviceContext*)m_HwContext->data;
|
||||
AVVAAPIDeviceContext* vaDeviceContext = (AVVAAPIDeviceContext*)deviceContext->hwctx;
|
||||
|
||||
if (m_X11VaLibHandle != nullptr) {
|
||||
dlclose(m_X11VaLibHandle);
|
||||
// Hold onto this VADisplay since we'll need it to uninitialize VAAPI
|
||||
VADisplay display = vaDeviceContext->display;
|
||||
|
||||
av_buffer_unref(&m_HwContext);
|
||||
|
||||
if (display) {
|
||||
vaTerminate(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,31 +40,53 @@ VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height)
|
||||
SDL_VERSION(&info.version);
|
||||
|
||||
if (!SDL_GetWindowWMInfo(window, &info)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_GetWindowWMInfo() failed: %s",
|
||||
SDL_GetError());
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_GetWindowWMInfo() failed: %s",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_assert(info.subsystem == SDL_SYSWM_X11);
|
||||
m_HwContext = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
|
||||
if (!m_HwContext) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to allocate VAAPI context");
|
||||
return false;
|
||||
}
|
||||
|
||||
AVHWDeviceContext* deviceContext = (AVHWDeviceContext*)m_HwContext->data;
|
||||
AVVAAPIDeviceContext* vaDeviceContext = (AVVAAPIDeviceContext*)deviceContext->hwctx;
|
||||
|
||||
m_WindowSystem = info.subsystem;
|
||||
if (info.subsystem == SDL_SYSWM_X11) {
|
||||
#ifdef HAVE_LIBVA_X11
|
||||
m_XWindow = info.info.x11.window;
|
||||
|
||||
m_X11VaLibHandle = dlopen("libva-x11.so", RTLD_LAZY);
|
||||
if (!m_X11VaLibHandle) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"dlopen(libva.so) failed: %s",
|
||||
dlerror());
|
||||
vaDeviceContext->display = vaGetDisplay(info.info.x11.display);
|
||||
if (!vaDeviceContext->display) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Unable to open X11 display for VAAPI");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_vaPutSurface = (vaPutSurface_t)dlsym(m_X11VaLibHandle, "vaPutSurface");
|
||||
#else
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Moonlight not compiled with VAAPI X11 support!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else if (info.subsystem == SDL_SYSWM_WAYLAND) {
|
||||
#ifdef HAVE_LIBVA_WAYLAND
|
||||
m_WaylandSurface = info.info.wl.surface;
|
||||
m_WaylandDisplay = info.info.wl.display;
|
||||
vaDeviceContext->display = vaGetDisplayWl(info.info.wl.display);
|
||||
if (!vaDeviceContext->display) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Unable to open Wayland display for VAAPI");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"VAAPI backend does not currently support Wayland");
|
||||
"Moonlight not compiled with VAAPI Wayland support!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
@@ -71,18 +95,31 @@ VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height)
|
||||
return false;
|
||||
}
|
||||
|
||||
err = av_hwdevice_ctx_create(&m_HwContext,
|
||||
AV_HWDEVICE_TYPE_VAAPI,
|
||||
nullptr, nullptr, 0);
|
||||
int major, minor;
|
||||
VAStatus status;
|
||||
status = vaInitialize(vaDeviceContext->display, &major, &minor);
|
||||
if (status != VA_STATUS_SUCCESS) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to initialize VAAPI: %d",
|
||||
status);
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Initialized VAAPI %d.%d",
|
||||
major, minor);
|
||||
|
||||
// This will populate the driver_quirks
|
||||
err = av_hwdevice_ctx_init(m_HwContext);
|
||||
if (err < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to create VAAPI context: %d",
|
||||
"Failed to initialize VAAPI context: %d",
|
||||
err);
|
||||
return false;
|
||||
}
|
||||
|
||||
// This quirk is set for the VDPAU wrapper which doesn't work with our VAAPI renderer
|
||||
if (((AVVAAPIDeviceContext*)((AVHWDeviceContext*)(m_HwContext->data))->hwctx)->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES) {
|
||||
if (vaDeviceContext->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES) {
|
||||
// Fail and let our VDPAU renderer pick this up
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Avoiding VDPAU wrapper for VAAPI decoding");
|
||||
@@ -98,7 +135,8 @@ VAAPIRenderer::prepareDecoderContext(AVCodecContext* context)
|
||||
context->hw_device_ctx = av_buffer_ref(m_HwContext);
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Using VAAPI accelerated renderer");
|
||||
"Using VAAPI accelerated renderer on %s",
|
||||
m_WindowSystem == SDL_SYSWM_X11 ? "X11" : "Wayland");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -120,14 +158,45 @@ VAAPIRenderer::renderFrame(AVFrame* frame)
|
||||
|
||||
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
||||
|
||||
m_vaPutSurface(vaDeviceContext->display,
|
||||
surface,
|
||||
m_XWindow,
|
||||
0, 0,
|
||||
m_VideoWidth, m_VideoHeight,
|
||||
dst.x, dst.y,
|
||||
dst.w, dst.h,
|
||||
NULL, 0, 0);
|
||||
if (m_WindowSystem == SDL_SYSWM_X11) {
|
||||
#ifdef HAVE_LIBVA_X11
|
||||
vaPutSurface(vaDeviceContext->display,
|
||||
surface,
|
||||
m_XWindow,
|
||||
0, 0,
|
||||
m_VideoWidth, m_VideoHeight,
|
||||
dst.x, dst.y,
|
||||
dst.w, dst.h,
|
||||
NULL, 0, 0);
|
||||
#endif
|
||||
}
|
||||
else if (m_WindowSystem == SDL_SYSWM_WAYLAND) {
|
||||
#ifdef HAVE_LIBVA_WAYLAND
|
||||
struct wl_buffer* buffer;
|
||||
VAStatus status;
|
||||
|
||||
status = vaGetSurfaceBufferWl(vaDeviceContext->display,
|
||||
surface,
|
||||
VA_FRAME_PICTURE,
|
||||
&buffer);
|
||||
if (status == VA_STATUS_SUCCESS) {
|
||||
wl_surface_attach(m_WaylandSurface, buffer, 0, 0);
|
||||
wl_surface_damage(m_WaylandSurface, dst.x, dst.y, dst.w, dst.h);
|
||||
|
||||
wl_display_flush(m_WaylandDisplay);
|
||||
wl_surface_commit(m_WaylandSurface);
|
||||
}
|
||||
else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"vaGetSurfaceBufferWl failed(): %d",
|
||||
status);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// We don't accept anything else in initialize().
|
||||
SDL_assert(false);
|
||||
}
|
||||
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
// Avoid X11 if SDL was built without it
|
||||
#ifndef SDL_VIDEO_DRIVER_X11
|
||||
#warning Unable to use libva-x11 without SDL support
|
||||
#undef HAVE_LIBVA_X11
|
||||
#endif
|
||||
|
||||
// Avoid Wayland if SDL was built without it
|
||||
#ifndef SDL_VIDEO_DRIVER_WAYLAND
|
||||
#warning Unable to use libva-wayland without SDL support
|
||||
#undef HAVE_LIBVA_WAYLAND
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <va/va.h>
|
||||
#ifdef HAVE_LIBVA_X11
|
||||
#include <va/va_x11.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBVA_WAYLAND
|
||||
#include <va/va_wayland.h>
|
||||
#endif
|
||||
#include <libavutil/hwcontext_vaapi.h>
|
||||
}
|
||||
|
||||
class VAAPIRenderer : public IFFmpegRenderer
|
||||
{
|
||||
typedef VAStatus (*vaPutSurface_t)(
|
||||
VADisplay dpy,
|
||||
VASurfaceID surface,
|
||||
Drawable draw, /* X Drawable */
|
||||
short srcx,
|
||||
short srcy,
|
||||
unsigned short srcw,
|
||||
unsigned short srch,
|
||||
short destx,
|
||||
short desty,
|
||||
unsigned short destw,
|
||||
unsigned short desth,
|
||||
VARectangle *cliprects,
|
||||
unsigned int number_cliprects,
|
||||
unsigned int flags
|
||||
);
|
||||
|
||||
public:
|
||||
VAAPIRenderer();
|
||||
virtual ~VAAPIRenderer();
|
||||
@@ -38,10 +38,18 @@ public:
|
||||
virtual void renderFrame(AVFrame* frame);
|
||||
|
||||
private:
|
||||
Window m_XWindow;
|
||||
int m_WindowSystem;
|
||||
AVBufferRef* m_HwContext;
|
||||
void* m_X11VaLibHandle;
|
||||
vaPutSurface_t m_vaPutSurface;
|
||||
|
||||
#ifdef HAVE_LIBVA_X11
|
||||
Window m_XWindow;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBVA_WAYLAND
|
||||
struct wl_surface* m_WaylandSurface;
|
||||
struct wl_display* m_WaylandDisplay;
|
||||
#endif
|
||||
|
||||
int m_VideoWidth;
|
||||
int m_VideoHeight;
|
||||
int m_DisplayWidth;
|
||||
|
||||
@@ -97,9 +97,9 @@ bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height)
|
||||
SDL_VERSION(&info.version);
|
||||
|
||||
if (!SDL_GetWindowWMInfo(window, &info)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_GetWindowWMInfo() failed: %s",
|
||||
SDL_GetError());
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_GetWindowWMInfo() failed: %s",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
// This is gross but it allows us to use sizeof()
|
||||
#include "ffmpeg_videosamples.cpp"
|
||||
|
||||
#define FAILED_DECODES_RESET_THRESHOLD 20
|
||||
|
||||
bool FFmpegVideoDecoder::isHardwareAccelerated()
|
||||
{
|
||||
return m_HwDecodeCfg != nullptr;
|
||||
@@ -50,7 +52,8 @@ FFmpegVideoDecoder::FFmpegVideoDecoder()
|
||||
: m_VideoDecoderCtx(nullptr),
|
||||
m_DecodeBuffer(1024 * 1024, 0),
|
||||
m_HwDecodeCfg(nullptr),
|
||||
m_Renderer(nullptr)
|
||||
m_Renderer(nullptr),
|
||||
m_ConsecutiveFailedDecodes(0)
|
||||
{
|
||||
av_init_packet(&m_Pkt);
|
||||
SDL_AtomicSet(&m_QueuedFrames, 0);
|
||||
@@ -317,7 +320,20 @@ int FFmpegVideoDecoder::submitDecodeUnit(PDECODE_UNIT du)
|
||||
char errorstring[512];
|
||||
av_strerror(err, errorstring, sizeof(errorstring));
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Decoding failed: %s", errorstring);
|
||||
"avcodec_send_packet() failed: %s", errorstring);
|
||||
|
||||
// If we've failed a bunch of decodes in a row, the decoder/renderer is
|
||||
// clearly unhealthy, so let's generate a synthetic reset event to trigger
|
||||
// the event loop to destroy and recreate the decoder.
|
||||
if (++m_ConsecutiveFailedDecodes == FAILED_DECODES_RESET_THRESHOLD) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Resetting decoder due to consistent failure");
|
||||
|
||||
SDL_Event event;
|
||||
event.type = SDL_RENDER_DEVICE_RESET;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
return DR_NEED_IDR;
|
||||
}
|
||||
|
||||
@@ -332,12 +348,29 @@ int FFmpegVideoDecoder::submitDecodeUnit(PDECODE_UNIT du)
|
||||
|
||||
err = avcodec_receive_frame(m_VideoDecoderCtx, frame);
|
||||
if (err == 0) {
|
||||
// Reset failed decodes count if we reached this far
|
||||
m_ConsecutiveFailedDecodes = 0;
|
||||
|
||||
// Queue the frame for rendering from the main thread
|
||||
SDL_AtomicIncRef(&m_QueuedFrames);
|
||||
queueFrame(frame);
|
||||
}
|
||||
else {
|
||||
av_frame_free(&frame);
|
||||
|
||||
char errorstring[512];
|
||||
av_strerror(err, errorstring, sizeof(errorstring));
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"avcodec_receive_frame() failed: %s", errorstring);
|
||||
|
||||
if (++m_ConsecutiveFailedDecodes == FAILED_DECODES_RESET_THRESHOLD) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Resetting decoder due to consistent failure");
|
||||
|
||||
SDL_Event event;
|
||||
event.type = SDL_RENDER_DEVICE_RESET;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
return DR_OK;
|
||||
|
||||
@@ -42,6 +42,7 @@ private:
|
||||
const AVCodecHWConfig* m_HwDecodeCfg;
|
||||
IFFmpegRenderer* m_Renderer;
|
||||
SDL_atomic_t m_QueuedFrames;
|
||||
int m_ConsecutiveFailedDecodes;
|
||||
|
||||
static const uint8_t k_H264TestFrame[];
|
||||
static const uint8_t k_HEVCTestFrame[];
|
||||
|
||||
Submodule moonlight-common-c/moonlight-common-c updated: fc124b60ce...feb46b978e
@@ -1,3 +1,4 @@
|
||||
# This script requires create-dmg to be installed from https://github.com/sindresorhus/create-dmg
|
||||
BUILD_CONFIG=$1
|
||||
|
||||
fail()
|
||||
@@ -40,12 +41,12 @@ echo Copying frameworks dependencies
|
||||
mkdir $BUILD_FOLDER/app/Moonlight.app/Contents/Frameworks
|
||||
cp -R $SOURCE_ROOT/libs/mac/Frameworks/ $BUILD_FOLDER/app/Moonlight.app/Contents/Frameworks/ || fail "Framework copy failed!"
|
||||
|
||||
echo Creating DMG
|
||||
echo Creating app bundle
|
||||
EXTRA_ARGS=
|
||||
if [ "$BUILD_CONFIG" == "Debug" ]; then EXTRA_ARGS="$EXTRA_ARGS -use-debug-libs"; fi
|
||||
if [ "$SIGNING_KEY" != "" ]; then EXTRA_ARGS="$EXTRA_ARGS -codesign=$SIGNING_KEY"; fi
|
||||
echo Extra deployment arguments: $EXTRA_ARGS
|
||||
macdeployqt $BUILD_FOLDER/app/Moonlight.app -dmg $EXTRA_ARGS -qmldir=$SOURCE_ROOT/app/gui -appstore-compliant || fail "macdeployqt failed!"
|
||||
macdeployqt $BUILD_FOLDER/app/Moonlight.app $EXTRA_ARGS -qmldir=$SOURCE_ROOT/app/gui -appstore-compliant || fail "macdeployqt failed!"
|
||||
|
||||
echo Deploying DMG
|
||||
mv $BUILD_FOLDER/app/Moonlight.dmg $INSTALLER_FOLDER/
|
||||
echo Creating DMG
|
||||
create-dmg $BUILD_FOLDER/app/Moonlight.app $INSTALLER_FOLDER || fail "create-dmg failed!"
|
||||
|
||||
@@ -31,6 +31,7 @@ if /I "%ARCH%" NEQ "x86" (
|
||||
)
|
||||
|
||||
set VS_PATH=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community
|
||||
set VCREDIST_PATH=%VS_PATH%\VC\Redist\MSVC\14.14.26405
|
||||
set SIGNTOOL_PARAMS=sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /sha1 1B3C676E831A94EC0327C3347EB32C68C26B3A67 /v
|
||||
|
||||
call "%VS_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %ARCH%
|
||||
@@ -88,10 +89,18 @@ if "%SIGN%"=="1" (
|
||||
)
|
||||
|
||||
echo Building installer
|
||||
set VCREDIST_INSTALLER=%VS_PATH%\VC\Redist\MSVC\14.14.26405\vcredist_%ARCH%.exe
|
||||
set VCREDIST_INSTALLER=%VCREDIST_PATH%\vcredist_%ARCH%.exe
|
||||
msbuild %SOURCE_ROOT%\wix\Moonlight.sln /p:Configuration=%BUILD_CONFIG% /p:Platform=%ARCH%
|
||||
if !ERRORLEVEL! NEQ 0 goto Error
|
||||
|
||||
echo Building portable package
|
||||
rem This must be done after WiX harvesting and signing, since the VCRT dlls are MS signed
|
||||
rem and should not be harvested for inclusion in the full installer
|
||||
copy "%VCREDIST_PATH%\%ARCH%\Microsoft.VC141.CRT\*.dll" %DEPLOY_FOLDER%
|
||||
if !ERRORLEVEL! NEQ 0 goto Error
|
||||
7z a %INSTALLER_FOLDER%\MoonlightPortable.zip %DEPLOY_FOLDER%\*
|
||||
if !ERRORLEVEL! NEQ 0 goto Error
|
||||
|
||||
if "%SIGN%"=="1" (
|
||||
echo Signing installer binary
|
||||
"%WIX%\bin\insignia" -ib %INSTALLER_FOLDER%\MoonlightSetup.exe -o %BUILD_FOLDER%\engine.exe
|
||||
@@ -108,6 +117,8 @@ if /i "%APPVEYOR%"=="true" (
|
||||
echo Pushing artifacts
|
||||
appveyor PushArtifact %INSTALLER_FOLDER%\MoonlightSetup.exe -FileName MoonlightSetup-%ARCH%-%BUILD_CONFIG%.exe
|
||||
if !ERRORLEVEL! NEQ 0 goto Error
|
||||
appveyor PushArtifact %INSTALLER_FOLDER%\MoonlightPortable.zip -FileName MoonlightPortable-%ARCH%-%BUILD_CONFIG%.zip
|
||||
if !ERRORLEVEL! NEQ 0 goto Error
|
||||
)
|
||||
|
||||
echo Build successful!
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<Package InstallerVersion="500" Compressed="yes" InstallScope="perMachine" />
|
||||
|
||||
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
||||
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." Schedule="afterInstallInitialize" />
|
||||
<MediaTemplate CompressionLevel="high" />
|
||||
|
||||
<?if $(var.Platform) = x64 ?>
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
</bal:Condition>
|
||||
<?endif ?>
|
||||
|
||||
<!-- HACK: Force replacement of lower versioned files too. This is only safe because we don't install any shared files -->
|
||||
<Variable Name="REINSTALLMODE" bal:Overridable="yes" Value="dmus" />
|
||||
|
||||
<?if $(env.ARCH) ~= x64 ?>
|
||||
<Variable Name="InstallFolder" Type="string" Value="[ProgramFiles64Folder]Moonlight Game Streaming" />
|
||||
<?elseif $(env.ARCH) ~= x86 ?>
|
||||
@@ -71,6 +74,7 @@
|
||||
</ExePackage>
|
||||
<MsiPackage Id="Moonlight" SourceFile="$(var.Moonlight.TargetPath)" Vital="yes">
|
||||
<MsiProperty Name="INSTALLFOLDER" Value="[InstallFolder]" />
|
||||
<MsiProperty Name="REINSTALLMODE" Value="[REINSTALLMODE]" />
|
||||
</MsiPackage>
|
||||
</Chain>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user