Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb75b3d6d2 | ||
|
|
27708b9ecb | ||
|
|
5443165fce | ||
|
|
dfb006d264 | ||
|
|
4f00f62674 | ||
|
|
cec527ffd5 | ||
|
|
4f2fe5c988 | ||
|
|
2bf552f801 | ||
|
|
477fa8fedf | ||
|
|
f1c7c5f02c | ||
|
|
4e936193c7 | ||
|
|
f9895c22b6 | ||
|
|
6e46537112 | ||
|
|
92b3918b26 | ||
|
|
34c615a5fd | ||
|
|
fa29260e09 | ||
|
|
a05816b495 | ||
|
|
9c5d847dae | ||
|
|
082e330f9d | ||
|
|
8878c4a136 | ||
|
|
00926bac81 | ||
|
|
67b0907e52 | ||
|
|
dba479774b | ||
|
|
5c8a1e632b | ||
|
|
d65e29111f | ||
|
|
ed170b8092 | ||
|
|
ac36fef968 | ||
|
|
10f6b73cad | ||
|
|
13d933fc07 | ||
|
|
3ba98e86f2 | ||
|
|
1dfca525cf | ||
|
|
e51ad1a68a | ||
|
|
9c76700f74 | ||
|
|
773b1af6f1 | ||
|
|
b8b633a6cc | ||
|
|
ada2270bd1 | ||
|
|
25e5175c54 | ||
|
|
9dcd770df2 | ||
|
|
00a1948b73 | ||
|
|
859a5a5e0c | ||
|
|
6783cf57da | ||
|
|
a8dc5ac14a |
@@ -3,11 +3,7 @@ QT -= core gui
|
|||||||
TARGET = AntiHooking
|
TARGET = AntiHooking
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
|
||||||
# Support debug and release builds from command line for CI
|
include(../globaldefs.pri)
|
||||||
CONFIG += debug_and_release
|
|
||||||
|
|
||||||
# Ensure symbols are always generated
|
|
||||||
CONFIG += force_debug_info
|
|
||||||
|
|
||||||
INCLUDEPATH += $$PWD/../libs/windows/include
|
INCLUDEPATH += $$PWD/../libs/windows/include
|
||||||
contains(QT_ARCH, i386) {
|
contains(QT_ARCH, i386) {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ You can follow development on our [Discord server](https://discord.gg/6ERtzFY).
|
|||||||
|
|
||||||
### Windows-specific Build Requirements
|
### Windows-specific Build Requirements
|
||||||
* Windows 7 or later
|
* Windows 7 or later
|
||||||
* [Visual Studio](https://visualstudio.microsoft.com/downloads/) 2015 or later (Community edition is fine)
|
* [Visual Studio](https://visualstudio.microsoft.com/downloads/) 2017 (Community edition is fine)
|
||||||
* Select MSVC Desktop toolchain during Qt installation
|
* Select MSVC Desktop toolchain during Qt installation
|
||||||
* [DirectX SDK](https://www.microsoft.com/en-us/download/details.aspx?id=6812)
|
* [DirectX SDK](https://www.microsoft.com/en-us/download/details.aspx?id=6812)
|
||||||
* [7-Zip](https://www.7-zip.org/) (only if building installers for non-development PCs)
|
* [7-Zip](https://www.7-zip.org/) (only if building installers for non-development PCs)
|
||||||
|
|||||||
+1
-1
Submodule app/SDL_GameControllerDB updated: e411d95fcd...cbebd79740
+25
-5
@@ -8,11 +8,7 @@ unix:!macx {
|
|||||||
TARGET = Moonlight
|
TARGET = Moonlight
|
||||||
}
|
}
|
||||||
|
|
||||||
# Support debug and release builds from command line for CI
|
include(../globaldefs.pri)
|
||||||
CONFIG += debug_and_release
|
|
||||||
|
|
||||||
# Ensure symbols are always generated
|
|
||||||
CONFIG += force_debug_info
|
|
||||||
|
|
||||||
# Precompile QML files to avoid writing qmlcache on portable versions.
|
# Precompile QML files to avoid writing qmlcache on portable versions.
|
||||||
# Since this binds the app against the Qt runtime version, we will only
|
# Since this binds the app against the Qt runtime version, we will only
|
||||||
@@ -94,6 +90,16 @@ unix:!macx {
|
|||||||
packagesExist(vdpau) {
|
packagesExist(vdpau) {
|
||||||
CONFIG += libvdpau
|
CONFIG += libvdpau
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packagesExist(mmal) {
|
||||||
|
PKGCONFIG += mmal
|
||||||
|
CONFIG += mmal
|
||||||
|
}
|
||||||
|
|
||||||
|
packagesExist(libdrm) {
|
||||||
|
PKGCONFIG += libdrm
|
||||||
|
CONFIG += libdrm
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
win32 {
|
win32 {
|
||||||
@@ -213,6 +219,20 @@ libvdpau {
|
|||||||
SOURCES += streaming/video/ffmpeg-renderers/vdpau.cpp
|
SOURCES += streaming/video/ffmpeg-renderers/vdpau.cpp
|
||||||
HEADERS += streaming/video/ffmpeg-renderers/vdpau.h
|
HEADERS += streaming/video/ffmpeg-renderers/vdpau.h
|
||||||
}
|
}
|
||||||
|
mmal {
|
||||||
|
message(MMAL renderer selected)
|
||||||
|
|
||||||
|
DEFINES += HAVE_MMAL
|
||||||
|
SOURCES += streaming/video/ffmpeg-renderers/mmal.cpp
|
||||||
|
HEADERS += streaming/video/ffmpeg-renderers/mmal.h
|
||||||
|
}
|
||||||
|
libdrm {
|
||||||
|
message(DRM renderer selected)
|
||||||
|
|
||||||
|
DEFINES += HAVE_DRM
|
||||||
|
SOURCES += streaming/video/ffmpeg-renderers/drm.cpp
|
||||||
|
HEADERS += streaming/video/ffmpeg-renderers/drm.h
|
||||||
|
}
|
||||||
config_SL {
|
config_SL {
|
||||||
message(Steam Link build configuration selected)
|
message(Steam Link build configuration selected)
|
||||||
|
|
||||||
|
|||||||
@@ -89,10 +89,9 @@ QUrl BoxArtManager::loadBoxArt(NvComputer* computer, NvApp& app)
|
|||||||
|
|
||||||
void BoxArtManager::handleBoxArtLoadComplete(NvComputer* computer, NvApp app, QUrl image)
|
void BoxArtManager::handleBoxArtLoadComplete(NvComputer* computer, NvApp app, QUrl image)
|
||||||
{
|
{
|
||||||
if (image.isEmpty()) {
|
if (!image.isEmpty()) {
|
||||||
image = QUrl("qrc:/res/no_app_image.png");
|
emit boxArtLoadComplete(computer, app, image);
|
||||||
}
|
}
|
||||||
emit boxArtLoadComplete(computer, app, image);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl BoxArtManager::loadBoxArtFromNetwork(NvComputer* computer, int appId)
|
QUrl BoxArtManager::loadBoxArtFromNetwork(NvComputer* computer, int appId)
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#include "systemproperties.h"
|
#include "systemproperties.h"
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
|
||||||
#include "streaming/session.h"
|
#include "streaming/session.h"
|
||||||
#include "streaming/streamutils.h"
|
#include "streaming/streamutils.h"
|
||||||
|
|
||||||
SystemProperties::SystemProperties()
|
SystemProperties::SystemProperties()
|
||||||
{
|
{
|
||||||
isRunningWayland = qgetenv("XDG_SESSION_TYPE") == "wayland";
|
isRunningWayland = qgetenv("XDG_SESSION_TYPE") == "wayland";
|
||||||
|
isRunningXWayland = qgetenv("XDG_SESSION_TYPE") == "wayland" && QGuiApplication::platformName() == "xcb";
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
isWow64 = QSysInfo::currentCpuArchitecture() != QSysInfo::buildCpuArchitecture();
|
isWow64 = QSysInfo::currentCpuArchitecture() != QSysInfo::buildCpuArchitecture();
|
||||||
@@ -51,6 +54,13 @@ void SystemProperties::querySdlVideoInfo()
|
|||||||
// Never let the maximum drop below 60 FPS
|
// Never let the maximum drop below 60 FPS
|
||||||
maximumStreamingFrameRate = 60;
|
maximumStreamingFrameRate = 60;
|
||||||
|
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_DisplayMode bestMode;
|
SDL_DisplayMode bestMode;
|
||||||
for (int displayIndex = 0; displayIndex < SDL_GetNumVideoDisplays(); displayIndex++) {
|
for (int displayIndex = 0; displayIndex < SDL_GetNumVideoDisplays(); displayIndex++) {
|
||||||
SDL_DisplayMode desktopMode;
|
SDL_DisplayMode desktopMode;
|
||||||
@@ -91,6 +101,7 @@ void SystemProperties::querySdlVideoInfo()
|
|||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Failed to create window for hardware decode test: %s",
|
"Failed to create window for hardware decode test: %s",
|
||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,4 +112,6 @@ void SystemProperties::querySdlVideoInfo()
|
|||||||
1920, 1080, 60);
|
1920, 1080, 60);
|
||||||
|
|
||||||
SDL_DestroyWindow(testWindow);
|
SDL_DestroyWindow(testWindow);
|
||||||
|
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public:
|
|||||||
|
|
||||||
Q_PROPERTY(bool hasHardwareAcceleration MEMBER hasHardwareAcceleration CONSTANT)
|
Q_PROPERTY(bool hasHardwareAcceleration MEMBER hasHardwareAcceleration CONSTANT)
|
||||||
Q_PROPERTY(bool isRunningWayland MEMBER isRunningWayland CONSTANT)
|
Q_PROPERTY(bool isRunningWayland MEMBER isRunningWayland CONSTANT)
|
||||||
|
Q_PROPERTY(bool isRunningXWayland MEMBER isRunningXWayland CONSTANT)
|
||||||
Q_PROPERTY(bool isWow64 MEMBER isWow64 CONSTANT)
|
Q_PROPERTY(bool isWow64 MEMBER isWow64 CONSTANT)
|
||||||
Q_PROPERTY(bool hasBrowser MEMBER hasBrowser CONSTANT)
|
Q_PROPERTY(bool hasBrowser MEMBER hasBrowser CONSTANT)
|
||||||
Q_PROPERTY(QString unmappedGamepads MEMBER unmappedGamepads NOTIFY unmappedGamepadsChanged)
|
Q_PROPERTY(QString unmappedGamepads MEMBER unmappedGamepads NOTIFY unmappedGamepadsChanged)
|
||||||
@@ -28,6 +29,7 @@ private:
|
|||||||
|
|
||||||
bool hasHardwareAcceleration;
|
bool hasHardwareAcceleration;
|
||||||
bool isRunningWayland;
|
bool isRunningWayland;
|
||||||
|
bool isRunningXWayland;
|
||||||
bool isWow64;
|
bool isWow64;
|
||||||
bool hasBrowser;
|
bool hasBrowser;
|
||||||
QString unmappedGamepads;
|
QString unmappedGamepads;
|
||||||
|
|||||||
@@ -33,6 +33,23 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="0.10.1" date="2019-04-28">
|
||||||
|
<description>
|
||||||
|
<p>New features:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Video performance optimizations</li>
|
||||||
|
<li>VAAPI support on Wayland</li>
|
||||||
|
</ul>
|
||||||
|
<p>Bugfixes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Fixed a crash when attempting to dismiss the connection terminated dialog</li>
|
||||||
|
<li>Fixed a crash when using the overlay on the software decoder</li>
|
||||||
|
<li>Fixed software decoder not displaying output in some cases</li>
|
||||||
|
<li>Fixed some minor UI issues on the PC grid</li>
|
||||||
|
<li>Improved visibility of toolbar highlights</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="0.10.0" date="2019-04-07">
|
<release version="0.10.0" date="2019-04-07">
|
||||||
<description>
|
<description>
|
||||||
<p>New features:</p>
|
<p>New features:</p>
|
||||||
|
|||||||
@@ -5,5 +5,9 @@
|
|||||||
# pairing data will be lost each reboot.
|
# pairing data will be lost each reboot.
|
||||||
HOME=/usr/local/moonlight
|
HOME=/usr/local/moonlight
|
||||||
|
|
||||||
|
# Renice PE_Single_CPU which seems to host A/V stuff
|
||||||
|
renice -10 -p $(pidof PE_Single_CPU)
|
||||||
|
|
||||||
|
# Renice Moonlight itself to avoid preemption by background tasks
|
||||||
# Write output to a logfile in /tmp
|
# Write output to a logfile in /tmp
|
||||||
exec ./bin/moonlight > /tmp/moonlight.log
|
exec nice -n -10 ./bin/moonlight > /tmp/moonlight.log
|
||||||
|
|||||||
+3
-3
@@ -61,9 +61,9 @@ CenteredGridView {
|
|||||||
source: model.boxart
|
source: model.boxart
|
||||||
|
|
||||||
onSourceSizeChanged: {
|
onSourceSizeChanged: {
|
||||||
if ((width == 130 && height == 180) || // GFE 2.0 placeholder image
|
if ((sourceSize.width == 130 && sourceSize.height == 180) || // GFE 2.0 placeholder image
|
||||||
(width == 628 && height == 888) || // GFE 3.0 placeholder image
|
(sourceSize.width == 628 && sourceSize.height == 888) || // GFE 3.0 placeholder image
|
||||||
(width == 200 && height == 266)) // Our no_app_image.png
|
(sourceSize.width == 200 && sourceSize.height == 266)) // Our no_app_image.png
|
||||||
{
|
{
|
||||||
isPlaceholder = true
|
isPlaceholder = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,27 @@ import QtQuick 2.0
|
|||||||
import QtQuick.Controls 2.2
|
import QtQuick.Controls 2.2
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
|
property string iconSource
|
||||||
|
|
||||||
activeFocusOnTab: true
|
activeFocusOnTab: true
|
||||||
|
|
||||||
|
// FIXME: We're using an Image here rather than icon.source because
|
||||||
|
// icons don't work on Qt 5.9 LTS.
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
source: iconSource
|
||||||
|
anchors.centerIn: parent.background
|
||||||
|
sourceSize {
|
||||||
|
width: parent.background.width * 1.10
|
||||||
|
height: parent.background.height * 1.10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This determines the size of the Material highlight. We increase it
|
||||||
|
// from the default because we use larger than normal icons for TV readability.
|
||||||
|
background.width: (parent.height - parent.anchors.bottomMargin - parent.anchors.topMargin) * 0.60
|
||||||
|
background.height: (parent.height - parent.anchors.bottomMargin - parent.anchors.topMargin) * 0.60
|
||||||
|
|
||||||
Keys.onReturnPressed: {
|
Keys.onReturnPressed: {
|
||||||
clicked()
|
clicked()
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -14,7 +14,7 @@ CenteredGridView {
|
|||||||
activeFocusOnTab: true
|
activeFocusOnTab: true
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
bottomMargin: 5
|
bottomMargin: 5
|
||||||
cellWidth: 310; cellHeight: 350;
|
cellWidth: 310; cellHeight: 330;
|
||||||
objectName: "Computers"
|
objectName: "Computers"
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
@@ -87,7 +87,7 @@ CenteredGridView {
|
|||||||
model: computerModel
|
model: computerModel
|
||||||
|
|
||||||
delegate: NavigableItemDelegate {
|
delegate: NavigableItemDelegate {
|
||||||
width: 300; height: 300;
|
width: 300; height: 320;
|
||||||
grid: pcGrid
|
grid: pcGrid
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
@@ -130,9 +130,11 @@ CenteredGridView {
|
|||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
anchors.top: pcIcon.bottom
|
anchors.top: pcIcon.bottom
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
font.pointSize: 36
|
font.pointSize: 36
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigableMenu {
|
NavigableMenu {
|
||||||
|
|||||||
+8
-16
@@ -20,7 +20,7 @@ Item {
|
|||||||
function stageFailed(stage, errorCode)
|
function stageFailed(stage, errorCode)
|
||||||
{
|
{
|
||||||
// Display the error dialog after Session::exec() returns
|
// Display the error dialog after Session::exec() returns
|
||||||
errorDialog.text = "Starting " + stage + " failed: Error " + errorCode
|
streamSegueErrorDialog.text = "Starting " + stage + " failed: Error " + errorCode
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectionStarted()
|
function connectionStarted()
|
||||||
@@ -38,7 +38,7 @@ Item {
|
|||||||
function displayLaunchError(text)
|
function displayLaunchError(text)
|
||||||
{
|
{
|
||||||
// Display the error dialog after Session::exec() returns
|
// Display the error dialog after Session::exec() returns
|
||||||
errorDialog.text = text
|
streamSegueErrorDialog.text = text
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayLaunchWarning(text)
|
function displayLaunchWarning(text)
|
||||||
@@ -68,9 +68,10 @@ Item {
|
|||||||
SdlGamepadKeyNavigation.enable()
|
SdlGamepadKeyNavigation.enable()
|
||||||
|
|
||||||
if (quitAfter) {
|
if (quitAfter) {
|
||||||
if (errorDialog.text) {
|
if (streamSegueErrorDialog.text) {
|
||||||
// Quit when the error dialog is acknowledged
|
// Quit when the error dialog is acknowledged
|
||||||
errorDialog.open()
|
streamSegueErrorDialog.quitAfter = quitAfter
|
||||||
|
streamSegueErrorDialog.open()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Quit immediately
|
// Quit immediately
|
||||||
@@ -87,8 +88,9 @@ Item {
|
|||||||
// the Qt UI is visible again to prevent losing
|
// the Qt UI is visible again to prevent losing
|
||||||
// focus on the dialog which would impact gamepad
|
// focus on the dialog which would impact gamepad
|
||||||
// users.
|
// users.
|
||||||
if (errorDialog.text) {
|
if (streamSegueErrorDialog.text) {
|
||||||
errorDialog.open()
|
streamSegueErrorDialog.quitAfter = quitAfter
|
||||||
|
streamSegueErrorDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,14 +173,4 @@ Item {
|
|||||||
|
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorMessageDialog {
|
|
||||||
id: errorDialog
|
|
||||||
|
|
||||||
onClosed: {
|
|
||||||
if (quitAfter) {
|
|
||||||
Qt.quit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-59
@@ -138,14 +138,16 @@ ApplicationWindow {
|
|||||||
// onAfterRendering call and potentially reenter this code.
|
// onAfterRendering call and potentially reenter this code.
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
if (SystemProperties.isRunningWayland) {
|
if (SystemProperties.isWow64) {
|
||||||
waylandDialog.open()
|
|
||||||
}
|
|
||||||
else if (SystemProperties.isWow64) {
|
|
||||||
wow64Dialog.open()
|
wow64Dialog.open()
|
||||||
}
|
}
|
||||||
else if (!SystemProperties.hasHardwareAcceleration) {
|
else if (!SystemProperties.hasHardwareAcceleration) {
|
||||||
noHwDecoderDialog.open()
|
if (SystemProperties.isRunningXWayland) {
|
||||||
|
xWaylandDialog.open()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
noHwDecoderDialog.open()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SystemProperties.unmappedGamepads) {
|
if (SystemProperties.unmappedGamepads) {
|
||||||
@@ -173,28 +175,21 @@ ApplicationWindow {
|
|||||||
|
|
||||||
header: ToolBar {
|
header: ToolBar {
|
||||||
id: toolBar
|
id: toolBar
|
||||||
|
height: 60
|
||||||
anchors.topMargin: 5
|
anchors.topMargin: 5
|
||||||
anchors.bottomMargin: 5
|
anchors.bottomMargin: 5
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: 20
|
spacing: 20
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.rightMargin: 10
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
NavigableToolButton {
|
NavigableToolButton {
|
||||||
// Only make the button visible if the user has navigated somewhere.
|
// Only make the button visible if the user has navigated somewhere.
|
||||||
visible: stackView.depth > 1
|
visible: stackView.depth > 1
|
||||||
|
|
||||||
// FIXME: We're using an Image here rather than icon.source because
|
iconSource: "qrc:/res/arrow_left.svg"
|
||||||
// icons don't work on Qt 5.9 LTS.
|
|
||||||
Image {
|
|
||||||
source: "qrc:/res/arrow_left.svg"
|
|
||||||
anchors.centerIn: parent
|
|
||||||
sourceSize {
|
|
||||||
// The icon should be square so use the height as the width too
|
|
||||||
width: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
height: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: stackView.pop()
|
onClicked: stackView.pop()
|
||||||
|
|
||||||
@@ -217,14 +212,7 @@ ApplicationWindow {
|
|||||||
id: addPcButton
|
id: addPcButton
|
||||||
visible: stackView.currentItem.objectName === "Computers"
|
visible: stackView.currentItem.objectName === "Computers"
|
||||||
|
|
||||||
Image {
|
iconSource: "qrc:/res/ic_add_to_queue_white_48px.svg"
|
||||||
source: "qrc:/res/ic_add_to_queue_white_48px.svg"
|
|
||||||
anchors.centerIn: parent
|
|
||||||
sourceSize {
|
|
||||||
width: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
height: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolTip.delay: 1000
|
ToolTip.delay: 1000
|
||||||
ToolTip.timeout: 3000
|
ToolTip.timeout: 3000
|
||||||
@@ -251,14 +239,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
id: updateButton
|
id: updateButton
|
||||||
|
|
||||||
Image {
|
iconSource: "qrc:/res/update.svg"
|
||||||
source: "qrc:/res/update.svg"
|
|
||||||
anchors.centerIn: parent
|
|
||||||
sourceSize {
|
|
||||||
width: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
height: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolTip.delay: 1000
|
ToolTip.delay: 1000
|
||||||
ToolTip.timeout: 3000
|
ToolTip.timeout: 3000
|
||||||
@@ -291,14 +272,7 @@ ApplicationWindow {
|
|||||||
id: helpButton
|
id: helpButton
|
||||||
visible: SystemProperties.hasBrowser
|
visible: SystemProperties.hasBrowser
|
||||||
|
|
||||||
Image {
|
iconSource: "qrc:/res/question_mark.svg"
|
||||||
source: "qrc:/res/question_mark.svg"
|
|
||||||
anchors.centerIn: parent
|
|
||||||
sourceSize {
|
|
||||||
width: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
height: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolTip.delay: 1000
|
ToolTip.delay: 1000
|
||||||
ToolTip.timeout: 3000
|
ToolTip.timeout: 3000
|
||||||
@@ -328,14 +302,7 @@ ApplicationWindow {
|
|||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: "Gamepad Mapper"
|
ToolTip.text: "Gamepad Mapper"
|
||||||
|
|
||||||
Image {
|
iconSource: "qrc:/res/ic_videogame_asset_white_48px.svg"
|
||||||
source: "qrc:/res/ic_videogame_asset_white_48px.svg"
|
|
||||||
anchors.centerIn: parent
|
|
||||||
sourceSize {
|
|
||||||
width: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
height: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: navigateTo("qrc:/gui/GamepadMapper.qml", "Gamepad Mapping")
|
onClicked: navigateTo("qrc:/gui/GamepadMapper.qml", "Gamepad Mapping")
|
||||||
|
|
||||||
@@ -347,14 +314,7 @@ ApplicationWindow {
|
|||||||
NavigableToolButton {
|
NavigableToolButton {
|
||||||
id: settingsButton
|
id: settingsButton
|
||||||
|
|
||||||
Image {
|
iconSource: "qrc:/res/settings.svg"
|
||||||
source: "qrc:/res/settings.svg"
|
|
||||||
anchors.centerIn: parent
|
|
||||||
sourceSize {
|
|
||||||
width: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
height: toolBar.height - toolBar.anchors.bottomMargin - toolBar.anchors.topMargin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: navigateTo("qrc:/gui/SettingsView.qml", "Settings")
|
onClicked: navigateTo("qrc:/gui/SettingsView.qml", "Settings")
|
||||||
|
|
||||||
@@ -385,9 +345,9 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ErrorMessageDialog {
|
ErrorMessageDialog {
|
||||||
id: waylandDialog
|
id: xWaylandDialog
|
||||||
text: "Moonlight does not support hardware acceleration on Wayland. Continuing on Wayland may result in poor streaming performance. " +
|
text: "Hardware acceleration doesn't work on XWayland. Continuing on XWayland may result in poor streaming performance. " +
|
||||||
"Please switch to an X session for optimal performance."
|
"Try running with QT_QPA_PLATFORM=wayland or switch to X11."
|
||||||
helpText: "Click the Help button for more information."
|
helpText: "Click the Help button for more information."
|
||||||
helpUrl: "https://github.com/moonlight-stream/moonlight-docs/wiki/Fixing-Hardware-Decoding-Problems"
|
helpUrl: "https://github.com/moonlight-stream/moonlight-docs/wiki/Fixing-Hardware-Decoding-Problems"
|
||||||
}
|
}
|
||||||
@@ -419,6 +379,29 @@ ApplicationWindow {
|
|||||||
onAccepted: Qt.quit()
|
onAccepted: Qt.quit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HACK: This belongs in StreamSegue but keeping a dialog around after the parent
|
||||||
|
// dies can trigger bugs in Qt 5.12 that cause the app to crash. For now, we will
|
||||||
|
// host this dialog in a QML component that is never destroyed.
|
||||||
|
//
|
||||||
|
// To repro: Start a stream, cut the network connection to trigger the "Connection
|
||||||
|
// terminated" dialog, wait until the app grid times out back to the PC grid, then
|
||||||
|
// try to dismiss the dialog.
|
||||||
|
ErrorMessageDialog {
|
||||||
|
id: streamSegueErrorDialog
|
||||||
|
|
||||||
|
property bool quitAfter: false
|
||||||
|
|
||||||
|
onClosed: {
|
||||||
|
if (quitAfter) {
|
||||||
|
Qt.quit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StreamSegue assumes its dialog will be re-created each time we
|
||||||
|
// start streaming, so fake it by wiping out the text each time.
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NavigableDialog {
|
NavigableDialog {
|
||||||
id: addPcDialog
|
id: addPcDialog
|
||||||
property string label: "Enter the IP address of your GameStream PC:"
|
property string label: "Enter the IP address of your GameStream PC:"
|
||||||
|
|||||||
+25
-13
@@ -290,10 +290,7 @@ int main(int argc, char *argv[])
|
|||||||
// password prompts on macOS.
|
// password prompts on macOS.
|
||||||
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1");
|
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1");
|
||||||
|
|
||||||
// The debug build of ANGLE on Qt 5.12.2 triggers all sorts of asserts
|
#ifdef Q_OS_WIN32
|
||||||
// even simply creating an empty Qt Quick window and then trying to close
|
|
||||||
// the program. Avoid using ANGLE for debug builds until the issue is fixed.
|
|
||||||
#if defined(Q_OS_WIN32) && !defined(QT_DEBUG)
|
|
||||||
if (!qEnvironmentVariableIsSet("QT_OPENGL")) {
|
if (!qEnvironmentVariableIsSet("QT_OPENGL")) {
|
||||||
// On Windows, use ANGLE so we don't have to load OpenGL
|
// On Windows, use ANGLE so we don't have to load OpenGL
|
||||||
// user-mode drivers into our app. OGL drivers (especially Intel)
|
// user-mode drivers into our app. OGL drivers (especially Intel)
|
||||||
@@ -317,17 +314,24 @@ int main(int argc, char *argv[])
|
|||||||
// initializing the SDL video subsystem to have any effect.
|
// initializing the SDL video subsystem to have any effect.
|
||||||
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
|
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
|
||||||
|
|
||||||
// Steam Link requires that we initialize video before creating our
|
if (SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
|
||||||
// QGuiApplication in order to configure the framebuffer correctly.
|
|
||||||
// It's fine to do on other platforms too, and it can save some time
|
|
||||||
// doing initialization and teardown of the video subsystem after streaming.
|
|
||||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) failed: %s",
|
"SDL_InitSubSystem(SDL_INIT_TIMER) failed: %s",
|
||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef STEAM_LINK
|
||||||
|
// Steam Link requires that we initialize video before creating our
|
||||||
|
// QGuiApplication in order to configure the framebuffer correctly.
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Use atexit() to ensure SDL_Quit() is called. This avoids
|
// Use atexit() to ensure SDL_Quit() is called. This avoids
|
||||||
// racing with object destruction where SDL may be used.
|
// racing with object destruction where SDL may be used.
|
||||||
atexit(SDL_Quit);
|
atexit(SDL_Quit);
|
||||||
@@ -342,6 +346,17 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
|
// After the QGuiApplication is created, the platform stuff will be initialized
|
||||||
|
// and we can set the SDL video driver to match Qt.
|
||||||
|
if (qgetenv("XDG_SESSION_TYPE") == "wayland" && QGuiApplication::platformName() == "xcb") {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Detected XWayland. This will probably break hardware decoding! Try running with QT_QPA_PLATFORM=wayland or switch to X11.");
|
||||||
|
}
|
||||||
|
else if (QGuiApplication::platformName().startsWith("wayland")) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Detected Wayland. Performance may be worse than X11.");
|
||||||
|
qputenv("SDL_VIDEODRIVER", "wayland");
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef STEAM_LINK
|
#ifdef STEAM_LINK
|
||||||
// Qt 5.9 from the Steam Link SDK is not able to load any fonts
|
// Qt 5.9 from the Steam Link SDK is not able to load any fonts
|
||||||
// since the Steam Link doesn't include any of the ones it looks
|
// since the Steam Link doesn't include any of the ones it looks
|
||||||
@@ -413,9 +428,6 @@ int main(int argc, char *argv[])
|
|||||||
if (!qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_UNIVERSAL_THEME")) {
|
if (!qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_UNIVERSAL_THEME")) {
|
||||||
qputenv("QT_QUICK_CONTROLS_UNIVERSAL_THEME", "Dark");
|
qputenv("QT_QUICK_CONTROLS_UNIVERSAL_THEME", "Dark");
|
||||||
}
|
}
|
||||||
if (!qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_1_STYLE")) {
|
|
||||||
qputenv("QT_QUICK_CONTROLS_1_STYLE", "Base");
|
|
||||||
}
|
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
QString initialView;
|
QString initialView;
|
||||||
|
|||||||
@@ -111,8 +111,11 @@ void Session::arDecodeAndPlaySample(char* sampleData, int sampleLength)
|
|||||||
{
|
{
|
||||||
int samplesDecoded;
|
int samplesDecoded;
|
||||||
|
|
||||||
// Set this thread to high priority to reduce
|
#ifndef STEAM_LINK
|
||||||
// the chance of missing our sample delivery time
|
// Set this thread to high priority to reduce the chance of missing
|
||||||
|
// our sample delivery time. On Steam Link, this causes starvation
|
||||||
|
// of other threads due to severely restricted CPU time available,
|
||||||
|
// so we will skip it on that platform.
|
||||||
if (s_ActiveSession->m_AudioSampleCount == 0) {
|
if (s_ActiveSession->m_AudioSampleCount == 0) {
|
||||||
if (SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH) < 0) {
|
if (SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH) < 0) {
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
@@ -120,6 +123,7 @@ void Session::arDecodeAndPlaySample(char* sampleData, int sampleLength)
|
|||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// See if we need to drop this sample
|
// See if we need to drop this sample
|
||||||
if (s_ActiveSession->m_DropAudioEndTime != 0) {
|
if (s_ActiveSession->m_DropAudioEndTime != 0) {
|
||||||
|
|||||||
@@ -2,10 +2,18 @@
|
|||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
|
// To reduce CPU load on the Steam Link, we need to accumulate several frames
|
||||||
|
// before submitting for playback. Higher frames per submission saves more CPU
|
||||||
|
// but increases audio latency.
|
||||||
|
#define FRAMES_PER_SUBMISSION 4
|
||||||
|
|
||||||
SLAudioRenderer::SLAudioRenderer()
|
SLAudioRenderer::SLAudioRenderer()
|
||||||
: m_AudioContext(nullptr),
|
: m_AudioContext(nullptr),
|
||||||
m_AudioStream(nullptr)
|
m_AudioStream(nullptr),
|
||||||
|
m_AudioBuffer(nullptr),
|
||||||
|
m_AudioBufferBytesFilled(0)
|
||||||
{
|
{
|
||||||
|
SLAudio_SetLogFunction(SLAudioRenderer::slLogCallback, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SLAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* opusConfig)
|
bool SLAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* opusConfig)
|
||||||
@@ -17,10 +25,11 @@ bool SLAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* o
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_AudioBufferSize = SAMPLES_PER_FRAME * sizeof(short) * opusConfig->channelCount * FRAMES_PER_SUBMISSION;
|
||||||
m_AudioStream = SLAudio_CreateStream(m_AudioContext,
|
m_AudioStream = SLAudio_CreateStream(m_AudioContext,
|
||||||
opusConfig->sampleRate,
|
opusConfig->sampleRate,
|
||||||
opusConfig->channelCount,
|
opusConfig->channelCount,
|
||||||
SAMPLES_PER_FRAME * sizeof(short) * opusConfig->channelCount,
|
m_AudioBufferSize,
|
||||||
1);
|
1);
|
||||||
if (m_AudioStream == nullptr) {
|
if (m_AudioStream == nullptr) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
@@ -36,6 +45,14 @@ bool SLAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* o
|
|||||||
|
|
||||||
SLAudioRenderer::~SLAudioRenderer()
|
SLAudioRenderer::~SLAudioRenderer()
|
||||||
{
|
{
|
||||||
|
if (m_AudioBufferBytesFilled != 0) {
|
||||||
|
// We had a buffer in flight when we quit. Just in case
|
||||||
|
// SLAudio doesn't handle this properly, we'll zero and submit
|
||||||
|
// it just to be safe.
|
||||||
|
memset(m_AudioBuffer, 0, m_AudioBufferSize);
|
||||||
|
SLAudio_SubmitFrame(m_AudioStream);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_AudioStream != nullptr) {
|
if (m_AudioStream != nullptr) {
|
||||||
SLAudio_FreeStream(m_AudioStream);
|
SLAudio_FreeStream(m_AudioStream);
|
||||||
}
|
}
|
||||||
@@ -47,12 +64,52 @@ SLAudioRenderer::~SLAudioRenderer()
|
|||||||
|
|
||||||
bool SLAudioRenderer::submitAudio(short* audioBuffer, int audioSize)
|
bool SLAudioRenderer::submitAudio(short* audioBuffer, int audioSize)
|
||||||
{
|
{
|
||||||
void* outputBuffer = SLAudio_BeginFrame(m_AudioStream);
|
if (m_AudioBufferBytesFilled == 0) {
|
||||||
|
// Get a new audio buffer from SLAudio
|
||||||
|
m_AudioBuffer = (char*)SLAudio_BeginFrame(m_AudioStream);
|
||||||
|
if (m_AudioBuffer == nullptr) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SLAudio_BeginFrame() failed");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (outputBuffer != nullptr) {
|
// Accumulate several frames of audio before submitting to reduce CPU load
|
||||||
memcpy(outputBuffer, audioBuffer, audioSize);
|
SDL_assert(audioSize <= m_AudioBufferSize - m_AudioBufferBytesFilled);
|
||||||
|
memcpy(&m_AudioBuffer[m_AudioBufferBytesFilled], audioBuffer, audioSize);
|
||||||
|
m_AudioBufferBytesFilled += audioSize;
|
||||||
|
|
||||||
|
// Submit the buffer when it's full
|
||||||
|
if (m_AudioBufferBytesFilled == m_AudioBufferSize) {
|
||||||
SLAudio_SubmitFrame(m_AudioStream);
|
SLAudio_SubmitFrame(m_AudioStream);
|
||||||
|
m_AudioBufferBytesFilled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SLAudioRenderer::slLogCallback(void *context, ESLAudioLog logLevel, const char *message)
|
||||||
|
{
|
||||||
|
SDL_LogPriority priority;
|
||||||
|
|
||||||
|
switch (logLevel)
|
||||||
|
{
|
||||||
|
case k_ESLAudioLogError:
|
||||||
|
priority = SDL_LOG_PRIORITY_ERROR;
|
||||||
|
break;
|
||||||
|
case k_ESLAudioLogWarning:
|
||||||
|
priority = SDL_LOG_PRIORITY_WARN;
|
||||||
|
break;
|
||||||
|
case k_ESLAudioLogInfo:
|
||||||
|
priority = SDL_LOG_PRIORITY_INFO;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case k_ESLAudioLogDebug:
|
||||||
|
priority = SDL_LOG_PRIORITY_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
priority,
|
||||||
|
"SLAudio: %s",
|
||||||
|
message);
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ public:
|
|||||||
virtual bool submitAudio(short* audioBuffer, int audioSize);
|
virtual bool submitAudio(short* audioBuffer, int audioSize);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void slLogCallback(void* context, ESLAudioLog logLevel, const char* message);
|
||||||
|
|
||||||
CSLAudioContext* m_AudioContext;
|
CSLAudioContext* m_AudioContext;
|
||||||
CSLAudioStream* m_AudioStream;
|
CSLAudioStream* m_AudioStream;
|
||||||
|
char* m_AudioBuffer;
|
||||||
|
int m_AudioBufferSize;
|
||||||
|
int m_AudioBufferBytesFilled;
|
||||||
};
|
};
|
||||||
|
|||||||
+56
-29
@@ -58,6 +58,14 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s
|
|||||||
prefs.mouseAcceleration ? "1" : "0",
|
prefs.mouseAcceleration ? "1" : "0",
|
||||||
SDL_HINT_OVERRIDE);
|
SDL_HINT_OVERRIDE);
|
||||||
|
|
||||||
|
#ifdef Q_OS_DARWIN
|
||||||
|
// SDL 2.0.9 on macOS has a broken HIDAPI mapping for the older Xbox One S
|
||||||
|
// firmware, so we have to disable HIDAPI for Xbox gamepads on macOS.
|
||||||
|
// https://github.com/moonlight-stream/moonlight-qt/issues/133
|
||||||
|
// https://bugzilla.libsdl.org/show_bug.cgi?id=4395
|
||||||
|
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
|
||||||
|
#endif
|
||||||
|
|
||||||
// We must initialize joystick explicitly before gamecontroller in order
|
// We must initialize joystick explicitly before gamecontroller in order
|
||||||
// to ensure we receive gamecontroller attach events for gamepads where
|
// to ensure we receive gamecontroller attach events for gamepads where
|
||||||
// SDL doesn't have a built-in mapping. By starting joystick first, we
|
// SDL doesn't have a built-in mapping. By starting joystick first, we
|
||||||
@@ -652,41 +660,60 @@ Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param)
|
|||||||
|
|
||||||
void SdlInputHandler::handleControllerAxisEvent(SDL_ControllerAxisEvent* event)
|
void SdlInputHandler::handleControllerAxisEvent(SDL_ControllerAxisEvent* event)
|
||||||
{
|
{
|
||||||
GamepadState* state = findStateForGamepad(event->which);
|
SDL_JoystickID gameControllerId = event->which;
|
||||||
|
GamepadState* state = findStateForGamepad(gameControllerId);
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (event->axis)
|
// Batch all pending axis motion events for this gamepad to save CPU time
|
||||||
{
|
SDL_Event nextEvent;
|
||||||
case SDL_CONTROLLER_AXIS_LEFTX:
|
for (;;) {
|
||||||
state->lsX = event->value;
|
switch (event->axis)
|
||||||
|
{
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTX:
|
||||||
|
state->lsX = event->value;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTY:
|
||||||
|
// Signed values have one more negative value than
|
||||||
|
// positive value, so inverting the sign on -32768
|
||||||
|
// could actually cause the value to overflow and
|
||||||
|
// wrap around to be negative again. Avoid that by
|
||||||
|
// capping the value at 32767.
|
||||||
|
state->lsY = -qMax(event->value, (short)-32767);
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTX:
|
||||||
|
state->rsX = event->value;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTY:
|
||||||
|
state->rsY = -qMax(event->value, (short)-32767);
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
||||||
|
state->lt = (unsigned char)(event->value * 255UL / 32767);
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
||||||
|
state->rt = (unsigned char)(event->value * 255UL / 32767);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Unhandled controller axis: %d",
|
||||||
|
event->axis);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for another event to batch with
|
||||||
|
if (SDL_PeepEvents(&nextEvent, 1, SDL_PEEKEVENT, SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERAXISMOTION) <= 0) {
|
||||||
break;
|
break;
|
||||||
case SDL_CONTROLLER_AXIS_LEFTY:
|
}
|
||||||
// Signed values have one more negative value than
|
|
||||||
// positive value, so inverting the sign on -32768
|
event = &nextEvent.caxis;
|
||||||
// could actually cause the value to overflow and
|
if (event->which != gameControllerId) {
|
||||||
// wrap around to be negative again. Avoid that by
|
// Stop batching if a different gamepad interrupts us
|
||||||
// capping the value at 32767.
|
|
||||||
state->lsY = -qMax(event->value, (short)-32767);
|
|
||||||
break;
|
break;
|
||||||
case SDL_CONTROLLER_AXIS_RIGHTX:
|
}
|
||||||
state->rsX = event->value;
|
|
||||||
break;
|
// Remove the next event to batch
|
||||||
case SDL_CONTROLLER_AXIS_RIGHTY:
|
SDL_PeepEvents(&nextEvent, 1, SDL_GETEVENT, SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERAXISMOTION);
|
||||||
state->rsY = -qMax(event->value, (short)-32767);
|
|
||||||
break;
|
|
||||||
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
|
||||||
state->lt = (unsigned char)(event->value * 255UL / 32767);
|
|
||||||
break;
|
|
||||||
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
|
||||||
state->rt = (unsigned char)(event->value * 255UL / 32767);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Unhandled controller axis: %d",
|
|
||||||
event->axis);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendGamepadState(state);
|
sendGamepadState(state);
|
||||||
|
|||||||
+47
-22
@@ -49,7 +49,12 @@ AUDIO_RENDERER_CALLBACKS Session::k_AudioCallbacks = {
|
|||||||
nullptr,
|
nullptr,
|
||||||
Session::arCleanup,
|
Session::arCleanup,
|
||||||
Session::arDecodeAndPlaySample,
|
Session::arDecodeAndPlaySample,
|
||||||
CAPABILITY_DIRECT_SUBMIT
|
CAPABILITY_DIRECT_SUBMIT |
|
||||||
|
#ifdef STEAM_LINK
|
||||||
|
CAPABILITY_SLOW_OPUS_DECODER
|
||||||
|
#else
|
||||||
|
0
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
Session* Session::s_ActiveSession;
|
Session* Session::s_ActiveSession;
|
||||||
@@ -143,19 +148,28 @@ void Session::clConnectionStatusUpdate(int connectionStatus)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CALL_INITIALIZE(dec) (dec)->initialize(vds, window, videoFormat, width, height, frameRate, enableVsync, enableFramePacing)
|
|
||||||
|
|
||||||
bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
|
bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
|
||||||
SDL_Window* window, int videoFormat, int width, int height,
|
SDL_Window* window, int videoFormat, int width, int height,
|
||||||
int frameRate, bool enableVsync, bool enableFramePacing, bool testOnly, IVideoDecoder*& chosenDecoder)
|
int frameRate, bool enableVsync, bool enableFramePacing, bool testOnly, IVideoDecoder*& chosenDecoder)
|
||||||
{
|
{
|
||||||
|
DECODER_PARAMETERS params;
|
||||||
|
|
||||||
|
params.width = width;
|
||||||
|
params.height = height;
|
||||||
|
params.frameRate = frameRate;
|
||||||
|
params.videoFormat = videoFormat;
|
||||||
|
params.window = window;
|
||||||
|
params.enableVsync = enableVsync;
|
||||||
|
params.enableFramePacing = enableFramePacing;
|
||||||
|
params.vds = vds;
|
||||||
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"V-sync %s",
|
"V-sync %s",
|
||||||
enableVsync ? "enabled" : "disabled");
|
enableVsync ? "enabled" : "disabled");
|
||||||
|
|
||||||
#ifdef HAVE_SLVIDEO
|
#ifdef HAVE_SLVIDEO
|
||||||
chosenDecoder = new SLVideoDecoder(testOnly);
|
chosenDecoder = new SLVideoDecoder(testOnly);
|
||||||
if (CALL_INITIALIZE(chosenDecoder)) {
|
if (chosenDecoder->initialize(¶ms)) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"SLVideo video decoder chosen");
|
"SLVideo video decoder chosen");
|
||||||
return true;
|
return true;
|
||||||
@@ -170,7 +184,7 @@ bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
|
|||||||
|
|
||||||
#ifdef HAVE_FFMPEG
|
#ifdef HAVE_FFMPEG
|
||||||
chosenDecoder = new FFmpegVideoDecoder(testOnly);
|
chosenDecoder = new FFmpegVideoDecoder(testOnly);
|
||||||
if (CALL_INITIALIZE(chosenDecoder)) {
|
if (chosenDecoder->initialize(¶ms)) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"FFmpeg-based video decoder chosen");
|
"FFmpeg-based video decoder chosen");
|
||||||
return true;
|
return true;
|
||||||
@@ -312,12 +326,20 @@ Session::~Session()
|
|||||||
|
|
||||||
bool Session::initialize()
|
bool Session::initialize()
|
||||||
{
|
{
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a hidden window to use for decoder initialization tests
|
// Create a hidden window to use for decoder initialization tests
|
||||||
SDL_Window* testWindow = SDL_CreateWindow("", 0, 0, 1280, 720, SDL_WINDOW_HIDDEN);
|
SDL_Window* testWindow = SDL_CreateWindow("", 0, 0, 1280, 720, SDL_WINDOW_HIDDEN);
|
||||||
if (!testWindow) {
|
if (!testWindow) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Failed to create window for hardware decode test: %s",
|
"Failed to create window for hardware decode test: %s",
|
||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,7 +459,12 @@ bool Session::initialize()
|
|||||||
|
|
||||||
SDL_DestroyWindow(testWindow);
|
SDL_DestroyWindow(testWindow);
|
||||||
|
|
||||||
return ret;
|
if (!ret) {
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::emitLaunchWarning(QString text)
|
void Session::emitLaunchWarning(QString text)
|
||||||
@@ -866,12 +893,14 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||||||
} catch (const GfeHttpResponseException& e) {
|
} catch (const GfeHttpResponseException& e) {
|
||||||
delete m_InputHandler;
|
delete m_InputHandler;
|
||||||
m_InputHandler = nullptr;
|
m_InputHandler = nullptr;
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
emit displayLaunchError("GeForce Experience returned error: " + e.toQString());
|
emit displayLaunchError("GeForce Experience returned error: " + e.toQString());
|
||||||
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
||||||
return;
|
return;
|
||||||
} catch (const QtNetworkReplyException& e) {
|
} catch (const QtNetworkReplyException& e) {
|
||||||
delete m_InputHandler;
|
delete m_InputHandler;
|
||||||
m_InputHandler = nullptr;
|
m_InputHandler = nullptr;
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
emit displayLaunchError(e.toQString());
|
emit displayLaunchError(e.toQString());
|
||||||
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
||||||
return;
|
return;
|
||||||
@@ -902,6 +931,7 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||||||
// listener.
|
// listener.
|
||||||
delete m_InputHandler;
|
delete m_InputHandler;
|
||||||
m_InputHandler = nullptr;
|
m_InputHandler = nullptr;
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -925,6 +955,7 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
delete m_InputHandler;
|
delete m_InputHandler;
|
||||||
m_InputHandler = nullptr;
|
m_InputHandler = nullptr;
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1011,7 +1042,13 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||||||
// blocks this thread too long for high polling rate mice and high
|
// blocks this thread too long for high polling rate mice and high
|
||||||
// refresh rate displays.
|
// refresh rate displays.
|
||||||
if (!SDL_PollEvent(&event)) {
|
if (!SDL_PollEvent(&event)) {
|
||||||
|
#ifndef STEAM_LINK
|
||||||
SDL_Delay(1);
|
SDL_Delay(1);
|
||||||
|
#else
|
||||||
|
// Waking every 1 ms to process input is too much for the low performance
|
||||||
|
// ARM core in the Steam Link, so we will wait 10 ms instead.
|
||||||
|
SDL_Delay(10);
|
||||||
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
@@ -1019,25 +1056,11 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Quit event received");
|
"Quit event received");
|
||||||
goto DispatchDeferredCleanup;
|
goto DispatchDeferredCleanup;
|
||||||
case SDL_USEREVENT: {
|
|
||||||
SDL_Event nextEvent;
|
|
||||||
|
|
||||||
|
case SDL_USEREVENT:
|
||||||
SDL_assert(event.user.code == SDL_CODE_FRAME_READY);
|
SDL_assert(event.user.code == SDL_CODE_FRAME_READY);
|
||||||
|
m_VideoDecoder->renderFrameOnMainThread();
|
||||||
// Drop any earlier frames
|
|
||||||
while (SDL_PeepEvents(&nextEvent,
|
|
||||||
1,
|
|
||||||
SDL_GETEVENT,
|
|
||||||
SDL_USEREVENT,
|
|
||||||
SDL_USEREVENT) == 1) {
|
|
||||||
m_VideoDecoder->dropFrame(&event.user);
|
|
||||||
event = nextEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the last frame
|
|
||||||
m_VideoDecoder->renderFrame(&event.user);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
// Capture mouse cursor when user actives the window by clicking on
|
// Capture mouse cursor when user actives the window by clicking on
|
||||||
@@ -1241,6 +1264,8 @@ DispatchDeferredCleanup:
|
|||||||
SDL_FreeSurface(iconSurface);
|
SDL_FreeSurface(iconSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
// Cleanup can take a while, so dispatch it to a worker thread.
|
// Cleanup can take a while, so dispatch it to a worker thread.
|
||||||
// When it is complete, it will release our s_ActiveSessionSemaphore
|
// When it is complete, it will release our s_ActiveSessionSemaphore
|
||||||
// reference.
|
// reference.
|
||||||
|
|||||||
@@ -26,33 +26,24 @@ typedef struct _VIDEO_STATS {
|
|||||||
uint32_t measurementStartTimestamp;
|
uint32_t measurementStartTimestamp;
|
||||||
} VIDEO_STATS, *PVIDEO_STATS;
|
} VIDEO_STATS, *PVIDEO_STATS;
|
||||||
|
|
||||||
|
typedef struct _DECODER_PARAMETERS {
|
||||||
|
SDL_Window* window;
|
||||||
|
StreamingPreferences::VideoDecoderSelection vds;
|
||||||
|
|
||||||
|
int videoFormat;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int frameRate;
|
||||||
|
bool enableVsync;
|
||||||
|
bool enableFramePacing;
|
||||||
|
} DECODER_PARAMETERS, *PDECODER_PARAMETERS;
|
||||||
|
|
||||||
class IVideoDecoder {
|
class IVideoDecoder {
|
||||||
public:
|
public:
|
||||||
virtual ~IVideoDecoder() {}
|
virtual ~IVideoDecoder() {}
|
||||||
virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds,
|
virtual bool initialize(PDECODER_PARAMETERS params) = 0;
|
||||||
SDL_Window* window,
|
|
||||||
int videoFormat,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
int frameRate,
|
|
||||||
bool enableVsync,
|
|
||||||
bool enableFramePacing) = 0;
|
|
||||||
virtual bool isHardwareAccelerated() = 0;
|
virtual bool isHardwareAccelerated() = 0;
|
||||||
virtual int getDecoderCapabilities() = 0;
|
virtual int getDecoderCapabilities() = 0;
|
||||||
virtual int submitDecodeUnit(PDECODE_UNIT du) = 0;
|
virtual int submitDecodeUnit(PDECODE_UNIT du) = 0;
|
||||||
virtual void renderFrame(SDL_UserEvent* event) = 0;
|
virtual void renderFrameOnMainThread() = 0;
|
||||||
virtual void dropFrame(SDL_UserEvent* event) = 0;
|
|
||||||
|
|
||||||
virtual void queueFrame(void* data1 = nullptr,
|
|
||||||
void* data2 = nullptr)
|
|
||||||
{
|
|
||||||
SDL_Event event;
|
|
||||||
|
|
||||||
event.type = SDL_USEREVENT;
|
|
||||||
event.user.code = SDL_CODE_FRAME_READY;
|
|
||||||
event.user.data1 = data1;
|
|
||||||
event.user.data2 = data2;
|
|
||||||
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
#include "drm.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavutil/hwcontext_drm.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <libdrm/drm_fourcc.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "streaming/streamutils.h"
|
||||||
|
#include "streaming/session.h"
|
||||||
|
|
||||||
|
#include <Limelight.h>
|
||||||
|
|
||||||
|
DrmRenderer::DrmRenderer()
|
||||||
|
: m_DrmFd(-1),
|
||||||
|
m_CrtcId(0),
|
||||||
|
m_PlaneId(0),
|
||||||
|
m_CurrentFbId(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DrmRenderer::~DrmRenderer()
|
||||||
|
{
|
||||||
|
if (m_CurrentFbId != 0) {
|
||||||
|
drmModeRmFB(m_DrmFd, m_CurrentFbId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_DrmFd != -1) {
|
||||||
|
close(m_DrmFd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DrmRenderer::prepareDecoderContext(AVCodecContext*)
|
||||||
|
{
|
||||||
|
/* Nothing to do */
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Using DRM renderer");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DrmRenderer::initialize(PDECODER_PARAMETERS)
|
||||||
|
{
|
||||||
|
const char* device = SDL_getenv("DRM_DEV");
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (device == nullptr) {
|
||||||
|
device = "/dev/dri/card0";
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Opening DRM device: %s",
|
||||||
|
device);
|
||||||
|
|
||||||
|
m_DrmFd = open(device, O_RDWR | O_CLOEXEC);
|
||||||
|
if (m_DrmFd < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Failed to open DRM device: %d",
|
||||||
|
errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeRes* resources = drmModeGetResources(m_DrmFd);
|
||||||
|
if (resources == nullptr) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"drmModeGetResources() failed: %d",
|
||||||
|
errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a connected connector and get the associated encoder
|
||||||
|
uint32_t encoderId = 0;
|
||||||
|
for (i = 0; i < resources->count_connectors && encoderId == 0; i++) {
|
||||||
|
drmModeConnector* connector = drmModeGetConnector(m_DrmFd, resources->connectors[i]);
|
||||||
|
if (connector != nullptr) {
|
||||||
|
if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) {
|
||||||
|
encoderId = connector->encoder_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeConnector(connector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoderId == 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"No connected displays found!");
|
||||||
|
drmModeFreeResources(resources);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now find the CRTC from the encoder
|
||||||
|
m_CrtcId = 0;
|
||||||
|
for (i = 0; i < resources->count_encoders && m_CrtcId == 0; i++) {
|
||||||
|
drmModeEncoder* encoder = drmModeGetEncoder(m_DrmFd, resources->encoders[i]);
|
||||||
|
if (encoder != nullptr) {
|
||||||
|
if (encoder->encoder_id == encoderId) {
|
||||||
|
m_CrtcId = encoder->crtc_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeEncoder(encoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_CrtcId == 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"DRM encoder not found!");
|
||||||
|
drmModeFreeResources(resources);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int crtcIndex = -1;
|
||||||
|
for (int i = 0; i < resources->count_crtcs; i++) {
|
||||||
|
if (resources->crtcs[i] == m_CrtcId) {
|
||||||
|
drmModeCrtc* crtc = drmModeGetCrtc(m_DrmFd, resources->crtcs[i]);
|
||||||
|
crtcIndex = i;
|
||||||
|
m_OutputRect.x = m_OutputRect.y = 0;
|
||||||
|
m_OutputRect.w = crtc->width;
|
||||||
|
m_OutputRect.h = crtc->height;
|
||||||
|
drmModeFreeCrtc(crtc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeResources(resources);
|
||||||
|
|
||||||
|
if (crtcIndex == -1) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Failed to get CRTC!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmSetClientCap(m_DrmFd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
|
||||||
|
|
||||||
|
drmModePlaneRes* planeRes = drmModeGetPlaneResources(m_DrmFd);
|
||||||
|
if (planeRes == nullptr) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"drmGetPlaneResources() failed: %d",
|
||||||
|
errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find an NV12 overlay plane to render on
|
||||||
|
m_PlaneId = 0;
|
||||||
|
for (uint32_t i = 0; i < planeRes->count_planes && m_PlaneId == 0; i++) {
|
||||||
|
drmModePlane* plane = drmModeGetPlane(m_DrmFd, planeRes->planes[i]);
|
||||||
|
if (plane != nullptr) {
|
||||||
|
bool matchingFormat = false;
|
||||||
|
for (uint32_t j = 0; j < plane->count_formats; j++) {
|
||||||
|
if (plane->formats[j] == DRM_FORMAT_NV12) {
|
||||||
|
matchingFormat = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingFormat == false) {
|
||||||
|
drmModeFreePlane(plane);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((plane->possible_crtcs & (1 << crtcIndex)) && plane->crtc_id == 0) {
|
||||||
|
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(m_DrmFd, planeRes->planes[i], DRM_MODE_OBJECT_PLANE);
|
||||||
|
if (props != nullptr) {
|
||||||
|
for (uint32_t j = 0; j < props->count_props && m_PlaneId == 0; j++) {
|
||||||
|
drmModePropertyPtr prop = drmModeGetProperty(m_DrmFd, props->props[j]);
|
||||||
|
if (prop != nullptr) {
|
||||||
|
if (!strcmp(prop->name, "type") && props->prop_values[j] == DRM_PLANE_TYPE_OVERLAY) {
|
||||||
|
m_PlaneId = plane->plane_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeProperty(prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeObjectProperties(props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreePlane(plane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreePlaneResources(planeRes);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AVPixelFormat DrmRenderer::getPreferredPixelFormat(int)
|
||||||
|
{
|
||||||
|
// DRM PRIME buffers
|
||||||
|
return AV_PIX_FMT_DRM_PRIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrmRenderer::renderFrame(AVFrame* frame)
|
||||||
|
{
|
||||||
|
AVDRMFrameDescriptor* drmFrame = (AVDRMFrameDescriptor*)frame->data[0];
|
||||||
|
int err;
|
||||||
|
uint32_t primeHandle;
|
||||||
|
uint32_t handles[4] = {};
|
||||||
|
uint32_t pitches[4] = {};
|
||||||
|
uint32_t offsets[4] = {};
|
||||||
|
|
||||||
|
SDL_Rect src, dst;
|
||||||
|
|
||||||
|
src.x = src.y = 0;
|
||||||
|
src.w = frame->width;
|
||||||
|
src.h = frame->height;
|
||||||
|
dst = m_OutputRect;
|
||||||
|
|
||||||
|
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
||||||
|
|
||||||
|
// Convert the FD in the AVDRMFrameDescriptor to a PRIME handle
|
||||||
|
// that can be used in drmModeAddFB2()
|
||||||
|
SDL_assert(drmFrame->nb_objects == 1);
|
||||||
|
err = drmPrimeFDToHandle(m_DrmFd, drmFrame->objects[0].fd, &primeHandle);
|
||||||
|
if (err < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"drmPrimeFDToHandle() failed: %d",
|
||||||
|
errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_assert(drmFrame->nb_layers == 1);
|
||||||
|
SDL_assert(drmFrame->layers[0].nb_planes == 2);
|
||||||
|
for (int i = 0; i < drmFrame->layers[0].nb_planes; i++) {
|
||||||
|
handles[i] = primeHandle;
|
||||||
|
pitches[i] = drmFrame->layers[0].planes[i].pitch;
|
||||||
|
offsets[i] = drmFrame->layers[0].planes[i].offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the last FB object we created so we can free it
|
||||||
|
// when we are finished rendering this one (if successful).
|
||||||
|
uint32_t lastFbId = m_CurrentFbId;
|
||||||
|
|
||||||
|
// Create a frame buffer object from the PRIME buffer
|
||||||
|
err = drmModeAddFB2(m_DrmFd, frame->width, frame->height,
|
||||||
|
drmFrame->layers[0].format,
|
||||||
|
handles, pitches, offsets, &m_CurrentFbId, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"drmModeAddFB2() failed: %d",
|
||||||
|
errno);
|
||||||
|
m_CurrentFbId = lastFbId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the overlay
|
||||||
|
err = drmModeSetPlane(m_DrmFd, m_PlaneId, m_CrtcId, m_CurrentFbId, 0,
|
||||||
|
dst.x, dst.y,
|
||||||
|
dst.w, dst.h,
|
||||||
|
0, 0,
|
||||||
|
frame->width << 16,
|
||||||
|
frame->height << 16);
|
||||||
|
if (err < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"drmModeSetPlane() failed: %d",
|
||||||
|
errno);
|
||||||
|
drmModeRmFB(m_DrmFd, m_CurrentFbId);
|
||||||
|
m_CurrentFbId = lastFbId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the previous FB object which has now been superseded
|
||||||
|
drmModeRmFB(m_DrmFd, lastFbId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
|
|
||||||
|
class DrmRenderer : public IFFmpegRenderer {
|
||||||
|
public:
|
||||||
|
DrmRenderer();
|
||||||
|
virtual ~DrmRenderer() override;
|
||||||
|
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||||
|
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
||||||
|
virtual void renderFrame(AVFrame* frame) override;
|
||||||
|
virtual enum AVPixelFormat getPreferredPixelFormat(int videoFormat) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_DrmFd;
|
||||||
|
uint32_t m_CrtcId;
|
||||||
|
uint32_t m_PlaneId;
|
||||||
|
uint32_t m_CurrentFbId;
|
||||||
|
SDL_Rect m_OutputRect;
|
||||||
|
};
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ bool DXVA2Renderer::prepareDecoderContext(AVCodecContext* context)
|
|||||||
|
|
||||||
int DXVA2Renderer::ffGetBuffer2(AVCodecContext* context, AVFrame* frame, int)
|
int DXVA2Renderer::ffGetBuffer2(AVCodecContext* context, AVFrame* frame, int)
|
||||||
{
|
{
|
||||||
DXVA2Renderer* me = (DXVA2Renderer*)((FFmpegVideoDecoder*)context->opaque)->getRenderer();
|
DXVA2Renderer* me = (DXVA2Renderer*)((FFmpegVideoDecoder*)context->opaque)->getBackendRenderer();
|
||||||
|
|
||||||
frame->buf[0] = av_buffer_pool_get(me->m_Pool);
|
frame->buf[0] = av_buffer_pool_get(me->m_Pool);
|
||||||
if (!frame->buf[0]) {
|
if (!frame->buf[0]) {
|
||||||
@@ -649,11 +649,11 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, int height, int, bool enableVsync)
|
bool DXVA2Renderer::initialize(PDECODER_PARAMETERS params)
|
||||||
{
|
{
|
||||||
m_VideoFormat = videoFormat;
|
m_VideoFormat = params->videoFormat;
|
||||||
m_VideoWidth = width;
|
m_VideoWidth = params->width;
|
||||||
m_VideoHeight = height;
|
m_VideoHeight = params->height;
|
||||||
|
|
||||||
RtlZeroMemory(&m_Desc, sizeof(m_Desc));
|
RtlZeroMemory(&m_Desc, sizeof(m_Desc));
|
||||||
|
|
||||||
@@ -682,7 +682,7 @@ bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, i
|
|||||||
m_Desc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
|
m_Desc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
|
||||||
m_Desc.Format = (D3DFORMAT)MAKEFOURCC('N','V','1','2');
|
m_Desc.Format = (D3DFORMAT)MAKEFOURCC('N','V','1','2');
|
||||||
|
|
||||||
if (!initializeDevice(window, enableVsync)) {
|
if (!initializeDevice(params->window, params->enableVsync)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,23 +704,6 @@ bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, i
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DXVA2Renderer::needsTestFrame()
|
|
||||||
{
|
|
||||||
// We validate the DXVA2 profiles are supported
|
|
||||||
// in initialize() so no test frame is required
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DXVA2Renderer::getDecoderCapabilities()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
IFFmpegRenderer::FramePacingConstraint DXVA2Renderer::getFramePacingConstraint()
|
|
||||||
{
|
|
||||||
return PACING_ANY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
|
void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|||||||
@@ -15,18 +15,10 @@ class DXVA2Renderer : public IFFmpegRenderer
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DXVA2Renderer();
|
DXVA2Renderer();
|
||||||
virtual ~DXVA2Renderer();
|
virtual ~DXVA2Renderer() override;
|
||||||
virtual bool initialize(SDL_Window* window,
|
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||||
int videoFormat,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
int maxFps,
|
|
||||||
bool enableVsync) override;
|
|
||||||
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
||||||
virtual void renderFrame(AVFrame* frame) override;
|
virtual void renderFrame(AVFrame* frame) override;
|
||||||
virtual bool needsTestFrame() override;
|
|
||||||
virtual int getDecoderCapabilities() override;
|
|
||||||
virtual FramePacingConstraint getFramePacingConstraint() override;
|
|
||||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
#include "mmal.h"
|
||||||
|
|
||||||
|
#include "streaming/streamutils.h"
|
||||||
|
#include "streaming/session.h"
|
||||||
|
|
||||||
|
#include <Limelight.h>
|
||||||
|
|
||||||
|
MmalRenderer::MmalRenderer()
|
||||||
|
: m_Renderer(nullptr),
|
||||||
|
m_InputPort(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MmalRenderer::~MmalRenderer()
|
||||||
|
{
|
||||||
|
if (m_InputPort != nullptr) {
|
||||||
|
mmal_port_disable(m_InputPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Renderer != nullptr) {
|
||||||
|
mmal_component_destroy(m_Renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MmalRenderer::prepareDecoderContext(AVCodecContext*)
|
||||||
|
{
|
||||||
|
/* Nothing to do */
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Using MMAL renderer");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MmalRenderer::initialize(PDECODER_PARAMETERS params)
|
||||||
|
{
|
||||||
|
MMAL_STATUS_T status;
|
||||||
|
|
||||||
|
status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &m_Renderer);
|
||||||
|
if (status != MMAL_SUCCESS) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"mmal_component_create() failed: %x (%s)",
|
||||||
|
status, mmal_status_to_string(status));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_InputPort = m_Renderer->input[0];
|
||||||
|
|
||||||
|
m_InputPort->format->encoding = MMAL_ENCODING_OPAQUE;
|
||||||
|
m_InputPort->format->es->video.width = params->width;
|
||||||
|
m_InputPort->format->es->video.height = params->height;
|
||||||
|
m_InputPort->format->es->video.crop.x = 0;
|
||||||
|
m_InputPort->format->es->video.crop.y = 0;
|
||||||
|
m_InputPort->format->es->video.crop.width = params->width;
|
||||||
|
m_InputPort->format->es->video.crop.height = params->height;
|
||||||
|
status = mmal_port_format_commit(m_InputPort);
|
||||||
|
if (status != MMAL_SUCCESS) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"mmal_port_format_commit() failed: %x (%s)",
|
||||||
|
status, mmal_status_to_string(status));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = mmal_component_enable(m_Renderer);
|
||||||
|
if (status != MMAL_SUCCESS) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"mmal_component_enable() failed: %x (%s)",
|
||||||
|
status, mmal_status_to_string(status));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
MMAL_DISPLAYREGION_T dr;
|
||||||
|
|
||||||
|
dr.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
|
||||||
|
dr.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
|
||||||
|
|
||||||
|
dr.set = MMAL_DISPLAY_SET_LAYER;
|
||||||
|
dr.layer = 128;
|
||||||
|
|
||||||
|
dr.set |= MMAL_DISPLAY_SET_ALPHA;
|
||||||
|
dr.alpha = 255;
|
||||||
|
|
||||||
|
dr.set |= MMAL_DISPLAY_SET_FULLSCREEN;
|
||||||
|
dr.fullscreen = (SDL_GetWindowFlags(params->window) & SDL_WINDOW_FULLSCREEN) != 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
SDL_Rect src, dst;
|
||||||
|
src.x = src.y = 0;
|
||||||
|
src.w = params->width;
|
||||||
|
src.h = params->height;
|
||||||
|
dst.x = dst.y = 0;
|
||||||
|
SDL_GetWindowSize(params->window, &dst.w, &dst.h);
|
||||||
|
|
||||||
|
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
||||||
|
|
||||||
|
dr.set |= MMAL_DISPLAY_SET_DEST_RECT;
|
||||||
|
dr.dest_rect.x = dst.x;
|
||||||
|
dr.dest_rect.y = dst.y;
|
||||||
|
dr.dest_rect.width = dst.w;
|
||||||
|
dr.dest_rect.height = dst.h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = mmal_port_enable(m_InputPort, InputPortCallback);
|
||||||
|
if (status != MMAL_SUCCESS) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"mmal_port_enable() failed: %x (%s)",
|
||||||
|
status, mmal_status_to_string(status));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MmalRenderer::InputPortCallback(MMAL_PORT_T*, MMAL_BUFFER_HEADER_T* buffer)
|
||||||
|
{
|
||||||
|
mmal_buffer_header_release(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AVPixelFormat MmalRenderer::getPreferredPixelFormat(int videoFormat)
|
||||||
|
{
|
||||||
|
// Opaque MMAL buffers
|
||||||
|
SDL_assert(videoFormat == VIDEO_FORMAT_H264);
|
||||||
|
return AV_PIX_FMT_MMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MmalRenderer::needsTestFrame()
|
||||||
|
{
|
||||||
|
// We won't be able to decode if the GPU memory is 64 MB or lower,
|
||||||
|
// so we must test before allowing the decoder to be used.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MmalRenderer::renderFrame(AVFrame* frame)
|
||||||
|
{
|
||||||
|
MMAL_BUFFER_HEADER_T* buffer = (MMAL_BUFFER_HEADER_T*)frame->data[3];
|
||||||
|
MMAL_STATUS_T status;
|
||||||
|
|
||||||
|
status = mmal_port_send_buffer(m_InputPort, buffer);
|
||||||
|
if (status != MMAL_SUCCESS) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"mmal_port_send_buffer() failed: %x (%s)",
|
||||||
|
status, mmal_status_to_string(status));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Prevent the buffer from being freed during av_frame_free()
|
||||||
|
// until rendering is complete. The reference is dropped in
|
||||||
|
// InputPortCallback().
|
||||||
|
mmal_buffer_header_acquire(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
#include <interface/mmal/mmal.h>
|
||||||
|
#include <interface/mmal/util/mmal_util.h>
|
||||||
|
#include <interface/mmal/util/mmal_util_params.h>
|
||||||
|
#include <interface/mmal/util/mmal_default_components.h>
|
||||||
|
|
||||||
|
class MmalRenderer : public IFFmpegRenderer {
|
||||||
|
public:
|
||||||
|
MmalRenderer();
|
||||||
|
virtual ~MmalRenderer() override;
|
||||||
|
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||||
|
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
||||||
|
virtual void renderFrame(AVFrame* frame) override;
|
||||||
|
virtual enum AVPixelFormat getPreferredPixelFormat(int videoFormat) override;
|
||||||
|
virtual bool needsTestFrame() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void InputPortCallback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer);
|
||||||
|
|
||||||
|
MMAL_COMPONENT_T* m_Renderer;
|
||||||
|
MMAL_PORT_T* m_InputPort;
|
||||||
|
};
|
||||||
|
|
||||||
@@ -61,6 +61,24 @@ Pacer::~Pacer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Pacer::renderOnMainThread()
|
||||||
|
{
|
||||||
|
// Ignore this call for renderers that work on a dedicated render thread
|
||||||
|
if (m_RenderThread != nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_FrameQueueLock.lock();
|
||||||
|
|
||||||
|
if (!m_RenderQueue.isEmpty()) {
|
||||||
|
// Releases m_FrameQueueLock
|
||||||
|
renderLastFrameAndUnlock();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_FrameQueueLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int Pacer::renderThread(void* context)
|
int Pacer::renderThread(void* context)
|
||||||
{
|
{
|
||||||
Pacer* me = reinterpret_cast<Pacer*>(context);
|
Pacer* me = reinterpret_cast<Pacer*>(context);
|
||||||
@@ -87,34 +105,61 @@ int Pacer::renderThread(void* context)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dequeue the most recent frame for rendering and free the others.
|
// Render the latest frame and discard the others
|
||||||
// NB: m_FrameQueueLock still held here!
|
// NB: m_FrameQueueLock still held here!
|
||||||
AVFrame* lastFrame = nullptr;
|
me->renderLastFrameAndUnlock();
|
||||||
while (!me->m_RenderQueue.isEmpty()) {
|
|
||||||
if (lastFrame != nullptr) {
|
|
||||||
// Don't hold the frame queue lock across av_frame_free(),
|
|
||||||
// since it could need to talk to the GPU driver. This is safe
|
|
||||||
// because we're guaranteed that the queue will not shrink during
|
|
||||||
// this time (and so dequeue() below will always get something).
|
|
||||||
me->m_FrameQueueLock.unlock();
|
|
||||||
av_frame_free(&lastFrame);
|
|
||||||
me->m_VideoStats->pacerDroppedFrames++;
|
|
||||||
me->m_FrameQueueLock.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
lastFrame = me->m_RenderQueue.dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release the frame queue lock before rendering
|
|
||||||
me->m_FrameQueueLock.unlock();
|
|
||||||
|
|
||||||
// Render and free the mot current frame
|
|
||||||
me->renderFrame(lastFrame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Pacer::enqueueFrameForRenderingAndUnlock(AVFrame *frame)
|
||||||
|
{
|
||||||
|
dropFrameForEnqueue(m_RenderQueue);
|
||||||
|
m_RenderQueue.enqueue(frame);
|
||||||
|
|
||||||
|
m_FrameQueueLock.unlock();
|
||||||
|
|
||||||
|
if (m_RenderThread != nullptr) {
|
||||||
|
m_RenderQueueNotEmpty.wakeOne();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SDL_Event event;
|
||||||
|
|
||||||
|
// For main thread rendering, we'll push an event to trigger a callback
|
||||||
|
event.type = SDL_USEREVENT;
|
||||||
|
event.user.code = SDL_CODE_FRAME_READY;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caller must hold m_FrameQueueLock
|
||||||
|
void Pacer::renderLastFrameAndUnlock()
|
||||||
|
{
|
||||||
|
// Dequeue the most recent frame for rendering and free the others.
|
||||||
|
AVFrame* lastFrame = nullptr;
|
||||||
|
while (!m_RenderQueue.isEmpty()) {
|
||||||
|
if (lastFrame != nullptr) {
|
||||||
|
// Don't hold the frame queue lock across av_frame_free(),
|
||||||
|
// since it could need to talk to the GPU driver. This is safe
|
||||||
|
// because we're guaranteed that the queue will not shrink during
|
||||||
|
// this time (and so dequeue() below will always get something).
|
||||||
|
m_FrameQueueLock.unlock();
|
||||||
|
av_frame_free(&lastFrame);
|
||||||
|
m_VideoStats->pacerDroppedFrames++;
|
||||||
|
m_FrameQueueLock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastFrame = m_RenderQueue.dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the frame queue lock before rendering
|
||||||
|
m_FrameQueueLock.unlock();
|
||||||
|
|
||||||
|
// Render and free the mot current frame
|
||||||
|
renderFrame(lastFrame);
|
||||||
|
}
|
||||||
|
|
||||||
// Called in an arbitrary thread by the IVsyncSource on V-sync
|
// Called in an arbitrary thread by the IVsyncSource on V-sync
|
||||||
// or an event synchronized with V-sync
|
// or an event synchronized with V-sync
|
||||||
void Pacer::vsyncCallback(int timeUntilNextVsyncMillis)
|
void Pacer::vsyncCallback(int timeUntilNextVsyncMillis)
|
||||||
@@ -172,10 +217,7 @@ void Pacer::vsyncCallback(int timeUntilNextVsyncMillis)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Place the first frame on the render queue
|
// Place the first frame on the render queue
|
||||||
dropFrameForEnqueue(m_RenderQueue);
|
enqueueFrameForRenderingAndUnlock(m_PacingQueue.dequeue());
|
||||||
m_RenderQueue.enqueue(m_PacingQueue.dequeue());
|
|
||||||
m_FrameQueueLock.unlock();
|
|
||||||
m_RenderQueueNotEmpty.wakeOne();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enablePacing)
|
bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enablePacing)
|
||||||
@@ -211,7 +253,9 @@ bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enablePacing)
|
|||||||
m_DisplayFps, m_MaxVideoFps);
|
m_DisplayFps, m_MaxVideoFps);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_RenderThread = SDL_CreateThread(Pacer::renderThread, "Pacer Render Thread", this);
|
if (m_VsyncRenderer->isRenderThreadSupported()) {
|
||||||
|
m_RenderThread = SDL_CreateThread(Pacer::renderThread, "Pacer Render Thread", this);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -283,16 +327,10 @@ void Pacer::submitFrame(AVFrame* frame)
|
|||||||
if (m_VsyncSource != nullptr) {
|
if (m_VsyncSource != nullptr) {
|
||||||
dropFrameForEnqueue(m_PacingQueue);
|
dropFrameForEnqueue(m_PacingQueue);
|
||||||
m_PacingQueue.enqueue(frame);
|
m_PacingQueue.enqueue(frame);
|
||||||
}
|
m_FrameQueueLock.unlock();
|
||||||
else {
|
|
||||||
dropFrameForEnqueue(m_RenderQueue);
|
|
||||||
m_RenderQueue.enqueue(frame);
|
|
||||||
}
|
|
||||||
m_FrameQueueLock.unlock();
|
|
||||||
if (m_VsyncSource != nullptr) {
|
|
||||||
m_PacingQueueNotEmpty.wakeOne();
|
m_PacingQueueNotEmpty.wakeOne();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_RenderQueueNotEmpty.wakeOne();
|
enqueueFrameForRenderingAndUnlock(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,15 @@ public:
|
|||||||
|
|
||||||
void vsyncCallback(int timeUntilNextVsyncMillis);
|
void vsyncCallback(int timeUntilNextVsyncMillis);
|
||||||
|
|
||||||
|
void renderOnMainThread();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int renderThread(void* context);
|
static int renderThread(void* context);
|
||||||
|
|
||||||
|
void enqueueFrameForRenderingAndUnlock(AVFrame* frame);
|
||||||
|
|
||||||
|
void renderLastFrameAndUnlock();
|
||||||
|
|
||||||
void renderFrame(AVFrame* frame);
|
void renderFrame(AVFrame* frame);
|
||||||
|
|
||||||
void dropFrameForEnqueue(QQueue<AVFrame*>& queue);
|
void dropFrameForEnqueue(QQueue<AVFrame*>& queue);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#include "streaming/video/decoder.h"
|
||||||
#include "streaming/video/overlaymanager.h"
|
#include "streaming/video/overlaymanager.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -16,17 +17,40 @@ public:
|
|||||||
PACING_ANY
|
PACING_ANY
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual bool initialize(SDL_Window* window,
|
virtual bool initialize(PDECODER_PARAMETERS params) = 0;
|
||||||
int videoFormat,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
int maxFps,
|
|
||||||
bool enableVsync) = 0;
|
|
||||||
virtual bool prepareDecoderContext(AVCodecContext* context) = 0;
|
virtual bool prepareDecoderContext(AVCodecContext* context) = 0;
|
||||||
virtual void renderFrame(AVFrame* frame) = 0;
|
virtual void renderFrame(AVFrame* frame) = 0;
|
||||||
virtual bool needsTestFrame() = 0;
|
|
||||||
virtual int getDecoderCapabilities() = 0;
|
virtual bool needsTestFrame() {
|
||||||
virtual FramePacingConstraint getFramePacingConstraint() = 0;
|
// No test frame required by default
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getDecoderCapabilities() {
|
||||||
|
// No special capabilities by default
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual FramePacingConstraint getFramePacingConstraint() {
|
||||||
|
// No pacing preference
|
||||||
|
return PACING_ANY;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isRenderThreadSupported() {
|
||||||
|
// Render thread is supported by default
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isDirectRenderingSupported() {
|
||||||
|
// The renderer can render directly to the display
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual enum AVPixelFormat getPreferredPixelFormat(int videoFormat) {
|
||||||
|
// Planar YUV 4:2:0
|
||||||
|
SDL_assert(videoFormat != VIDEO_FORMAT_H265_MAIN10);
|
||||||
|
return AV_PIX_FMT_YUV420P;
|
||||||
|
}
|
||||||
|
|
||||||
// IOverlayRenderer
|
// IOverlayRenderer
|
||||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override {
|
virtual void notifyOverlayUpdated(Overlay::OverlayType) override {
|
||||||
|
|||||||
@@ -7,9 +7,16 @@
|
|||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
|
|
||||||
|
const std::vector<int> SdlRenderer::k_SwFormats({
|
||||||
|
AV_PIX_FMT_YUV420P,
|
||||||
|
AV_PIX_FMT_NV12
|
||||||
|
});
|
||||||
|
|
||||||
SdlRenderer::SdlRenderer()
|
SdlRenderer::SdlRenderer()
|
||||||
: m_Renderer(nullptr),
|
: m_Renderer(nullptr),
|
||||||
m_Texture(nullptr)
|
m_Texture(nullptr),
|
||||||
|
m_SwPixelFormat(AV_PIX_FMT_YUV420P),
|
||||||
|
m_FontData(Path::readDataFile("ModeSeven.ttf"))
|
||||||
{
|
{
|
||||||
SDL_assert(TTF_WasInit() == 0);
|
SDL_assert(TTF_WasInit() == 0);
|
||||||
if (TTF_Init() != 0) {
|
if (TTF_Init() != 0) {
|
||||||
@@ -61,17 +68,11 @@ bool SdlRenderer::prepareDecoderContext(AVCodecContext*)
|
|||||||
/* Nothing to do */
|
/* Nothing to do */
|
||||||
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Using SDL software renderer");
|
"Using SDL renderer");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SdlRenderer::needsTestFrame()
|
|
||||||
{
|
|
||||||
// This renderer should always work
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SdlRenderer::getDecoderCapabilities()
|
int SdlRenderer::getDecoderCapabilities()
|
||||||
{
|
{
|
||||||
// The FFmpeg CPU decoder can handle reference frame invalidation,
|
// The FFmpeg CPU decoder can handle reference frame invalidation,
|
||||||
@@ -79,23 +80,18 @@ int SdlRenderer::getDecoderCapabilities()
|
|||||||
return CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC;
|
return CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC;
|
||||||
}
|
}
|
||||||
|
|
||||||
IFFmpegRenderer::FramePacingConstraint SdlRenderer::getFramePacingConstraint()
|
|
||||||
{
|
|
||||||
return PACING_ANY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlRenderer::notifyOverlayUpdated(Overlay::OverlayType type)
|
void SdlRenderer::notifyOverlayUpdated(Overlay::OverlayType type)
|
||||||
{
|
{
|
||||||
// Construct the required font to render the overlay
|
// Construct the required font to render the overlay
|
||||||
if (m_OverlayFonts[type] == nullptr) {
|
if (m_OverlayFonts[type] == nullptr) {
|
||||||
QByteArray fontData = Path::readDataFile("ModeSeven.ttf");
|
if (m_FontData.isEmpty()) {
|
||||||
if (fontData.isEmpty()) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Unable to load SDL overlay font");
|
"SDL overlay font failed to load");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_OverlayFonts[type] = TTF_OpenFontRW(SDL_RWFromConstMem(fontData.constData(), fontData.size()),
|
// m_FontData must stay around until the font is closed
|
||||||
|
m_OverlayFonts[type] = TTF_OpenFontRW(SDL_RWFromConstMem(m_FontData.constData(), m_FontData.size()),
|
||||||
1,
|
1,
|
||||||
Session::get()->getOverlayManager().getOverlayFontSize(type));
|
Session::get()->getOverlayManager().getOverlayFontSize(type));
|
||||||
if (m_OverlayFonts[type] == nullptr) {
|
if (m_OverlayFonts[type] == nullptr) {
|
||||||
@@ -125,20 +121,33 @@ void SdlRenderer::notifyOverlayUpdated(Overlay::OverlayType type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SdlRenderer::initialize(SDL_Window* window,
|
bool SdlRenderer::isRenderThreadSupported()
|
||||||
int,
|
{
|
||||||
int width,
|
SDL_RendererInfo info;
|
||||||
int height,
|
SDL_GetRendererInfo(m_Renderer, &info);
|
||||||
int,
|
|
||||||
bool enableVsync)
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL renderer backend: %s",
|
||||||
|
info.name);
|
||||||
|
|
||||||
|
if (info.name != QString("direct3d")) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL renderer backend requires main thread rendering");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SdlRenderer::initialize(PDECODER_PARAMETERS params)
|
||||||
{
|
{
|
||||||
Uint32 rendererFlags = SDL_RENDERER_ACCELERATED;
|
Uint32 rendererFlags = SDL_RENDERER_ACCELERATED;
|
||||||
|
|
||||||
if ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) {
|
if ((SDL_GetWindowFlags(params->window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) {
|
||||||
// In full-screen exclusive mode, we enable V-sync if requested. For other modes, Windows and Mac
|
// In full-screen exclusive mode, we enable V-sync if requested. For other modes, Windows and Mac
|
||||||
// have compositors that make rendering tear-free. Linux compositor varies by distro and user
|
// have compositors that make rendering tear-free. Linux compositor varies by distro and user
|
||||||
// configuration but doesn't seem feasible to detect here.
|
// configuration but doesn't seem feasible to detect here.
|
||||||
if (enableVsync) {
|
if (params->enableVsync) {
|
||||||
rendererFlags |= SDL_RENDERER_PRESENTVSYNC;
|
rendererFlags |= SDL_RENDERER_PRESENTVSYNC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,7 +160,7 @@ bool SdlRenderer::initialize(SDL_Window* window,
|
|||||||
SDL_SetHintWithPriority(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, "1", SDL_HINT_OVERRIDE);
|
SDL_SetHintWithPriority(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, "1", SDL_HINT_OVERRIDE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_Renderer = SDL_CreateRenderer(window, -1, rendererFlags);
|
m_Renderer = SDL_CreateRenderer(params->window, -1, rendererFlags);
|
||||||
if (!m_Renderer) {
|
if (!m_Renderer) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"SDL_CreateRenderer() failed: %s",
|
"SDL_CreateRenderer() failed: %s",
|
||||||
@@ -161,25 +170,13 @@ bool SdlRenderer::initialize(SDL_Window* window,
|
|||||||
|
|
||||||
// The window may be smaller than the stream size, so ensure our
|
// The window may be smaller than the stream size, so ensure our
|
||||||
// logical rendering surface size is equal to the stream size
|
// logical rendering surface size is equal to the stream size
|
||||||
SDL_RenderSetLogicalSize(m_Renderer, width, height);
|
SDL_RenderSetLogicalSize(m_Renderer, params->width, params->height);
|
||||||
|
|
||||||
// Draw a black frame until the video stream starts rendering
|
// Draw a black frame until the video stream starts rendering
|
||||||
SDL_SetRenderDrawColor(m_Renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
SDL_SetRenderDrawColor(m_Renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||||
SDL_RenderClear(m_Renderer);
|
SDL_RenderClear(m_Renderer);
|
||||||
SDL_RenderPresent(m_Renderer);
|
SDL_RenderPresent(m_Renderer);
|
||||||
|
|
||||||
m_Texture = SDL_CreateTexture(m_Renderer,
|
|
||||||
SDL_PIXELFORMAT_YV12,
|
|
||||||
SDL_TEXTUREACCESS_STREAMING,
|
|
||||||
width,
|
|
||||||
height);
|
|
||||||
if (!m_Texture) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"SDL_CreateRenderer() failed: %s",
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
// For some reason, using Direct3D9Ex breaks this with multi-monitor setups.
|
// For some reason, using Direct3D9Ex breaks this with multi-monitor setups.
|
||||||
// When focus is lost, the window is minimized then immediately restored without
|
// When focus is lost, the window is minimized then immediately restored without
|
||||||
@@ -233,13 +230,109 @@ void SdlRenderer::renderOverlay(Overlay::OverlayType type)
|
|||||||
|
|
||||||
void SdlRenderer::renderFrame(AVFrame* frame)
|
void SdlRenderer::renderFrame(AVFrame* frame)
|
||||||
{
|
{
|
||||||
SDL_UpdateYUVTexture(m_Texture, nullptr,
|
int err;
|
||||||
frame->data[0],
|
AVFrame* swFrame = nullptr;
|
||||||
frame->linesize[0],
|
|
||||||
frame->data[1],
|
if (frame->hw_frames_ctx != nullptr) {
|
||||||
frame->linesize[1],
|
// If we are acting as the frontend for a hardware
|
||||||
frame->data[2],
|
// accelerated decoder, we'll need to read the frame
|
||||||
frame->linesize[2]);
|
// back to render it.
|
||||||
|
|
||||||
|
swFrame = av_frame_alloc();
|
||||||
|
if (swFrame == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
swFrame->width = frame->width;
|
||||||
|
swFrame->height = frame->height;
|
||||||
|
swFrame->format = m_SwPixelFormat;
|
||||||
|
|
||||||
|
err = av_hwframe_transfer_data(swFrame, frame, 0);
|
||||||
|
if (err != 0) {
|
||||||
|
// Try to find a supported format
|
||||||
|
for (uint32_t i = 0; i < k_SwFormats.size(); i++) {
|
||||||
|
swFrame->format = k_SwFormats.at(i);
|
||||||
|
err = av_hwframe_transfer_data(swFrame, frame, 0);
|
||||||
|
if (err == 0) {
|
||||||
|
// The format was supported. Use that automatically in the future.
|
||||||
|
m_SwPixelFormat = swFrame->format;
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Selected read-back format: %d",
|
||||||
|
m_SwPixelFormat);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"av_hwframe_transfer_data() failed: %d",
|
||||||
|
err);
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = swFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Texture == nullptr) {
|
||||||
|
Uint32 sdlFormat;
|
||||||
|
|
||||||
|
switch (frame->format)
|
||||||
|
{
|
||||||
|
case AV_PIX_FMT_YUV420P:
|
||||||
|
sdlFormat = SDL_PIXELFORMAT_YV12;
|
||||||
|
break;
|
||||||
|
case AV_PIX_FMT_NV12:
|
||||||
|
sdlFormat = SDL_PIXELFORMAT_NV12;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SDL_assert(false);
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Texture = SDL_CreateTexture(m_Renderer,
|
||||||
|
sdlFormat,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
|
frame->width,
|
||||||
|
frame->height);
|
||||||
|
if (!m_Texture) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_CreateTexture() failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->format == AV_PIX_FMT_YUV420P) {
|
||||||
|
SDL_UpdateYUVTexture(m_Texture, nullptr,
|
||||||
|
frame->data[0],
|
||||||
|
frame->linesize[0],
|
||||||
|
frame->data[1],
|
||||||
|
frame->linesize[1],
|
||||||
|
frame->data[2],
|
||||||
|
frame->linesize[2]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char* pixels;
|
||||||
|
int pitch;
|
||||||
|
|
||||||
|
err = SDL_LockTexture(m_Texture, nullptr, (void**)&pixels, &pitch);
|
||||||
|
if (err < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_LockTexture() failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pixels,
|
||||||
|
frame->data[0],
|
||||||
|
frame->linesize[0] * frame->height);
|
||||||
|
memcpy(pixels + (frame->linesize[0] * frame->height),
|
||||||
|
frame->data[1],
|
||||||
|
frame->linesize[1] * frame->height / 2);
|
||||||
|
|
||||||
|
SDL_UnlockTexture(m_Texture);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_RenderClear(m_Renderer);
|
SDL_RenderClear(m_Renderer);
|
||||||
|
|
||||||
@@ -252,4 +345,9 @@ void SdlRenderer::renderFrame(AVFrame* frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_RenderPresent(m_Renderer);
|
SDL_RenderPresent(m_Renderer);
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
if (swFrame != nullptr) {
|
||||||
|
av_frame_free(&swFrame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,27 +8,25 @@ class SdlRenderer : public IFFmpegRenderer {
|
|||||||
public:
|
public:
|
||||||
SdlRenderer();
|
SdlRenderer();
|
||||||
virtual ~SdlRenderer() override;
|
virtual ~SdlRenderer() override;
|
||||||
virtual bool initialize(SDL_Window* window,
|
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||||
int videoFormat,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
int maxFps,
|
|
||||||
bool enableVsync) override;
|
|
||||||
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
||||||
virtual void renderFrame(AVFrame* frame) override;
|
virtual void renderFrame(AVFrame* frame) override;
|
||||||
virtual bool needsTestFrame() override;
|
|
||||||
virtual int getDecoderCapabilities() override;
|
virtual int getDecoderCapabilities() override;
|
||||||
virtual FramePacingConstraint getFramePacingConstraint() override;
|
|
||||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
||||||
|
virtual bool isRenderThreadSupported() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void renderOverlay(Overlay::OverlayType type);
|
void renderOverlay(Overlay::OverlayType type);
|
||||||
|
|
||||||
SDL_Renderer* m_Renderer;
|
SDL_Renderer* m_Renderer;
|
||||||
SDL_Texture* m_Texture;
|
SDL_Texture* m_Texture;
|
||||||
|
int m_SwPixelFormat;
|
||||||
|
QByteArray m_FontData;
|
||||||
TTF_Font* m_OverlayFonts[Overlay::OverlayMax];
|
TTF_Font* m_OverlayFonts[Overlay::OverlayMax];
|
||||||
SDL_Surface* m_OverlaySurfaces[Overlay::OverlayMax];
|
SDL_Surface* m_OverlaySurfaces[Overlay::OverlayMax];
|
||||||
SDL_Texture* m_OverlayTextures[Overlay::OverlayMax];
|
SDL_Texture* m_OverlayTextures[Overlay::OverlayMax];
|
||||||
SDL_Rect m_OverlayRects[Overlay::OverlayMax];
|
SDL_Rect m_OverlayRects[Overlay::OverlayMax];
|
||||||
|
|
||||||
|
static const std::vector<int> k_SwFormats;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -29,19 +29,19 @@ VAAPIRenderer::~VAAPIRenderer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height, int, bool)
|
VAAPIRenderer::initialize(PDECODER_PARAMETERS params)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
SDL_SysWMinfo info;
|
SDL_SysWMinfo info;
|
||||||
|
|
||||||
m_VideoWidth = width;
|
m_VideoWidth = params->width;
|
||||||
m_VideoHeight = height;
|
m_VideoHeight = params->height;
|
||||||
|
|
||||||
SDL_GetWindowSize(window, &m_DisplayWidth, &m_DisplayHeight);
|
SDL_GetWindowSize(params->window, &m_DisplayWidth, &m_DisplayHeight);
|
||||||
|
|
||||||
SDL_VERSION(&info.version);
|
SDL_VERSION(&info.version);
|
||||||
|
|
||||||
if (!SDL_GetWindowWMInfo(window, &info)) {
|
if (!SDL_GetWindowWMInfo(params->window, &info)) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"SDL_GetWindowWMInfo() failed: %s",
|
"SDL_GetWindowWMInfo() failed: %s",
|
||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
@@ -76,8 +76,6 @@ VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height, int, b
|
|||||||
}
|
}
|
||||||
else if (info.subsystem == SDL_SYSWM_WAYLAND) {
|
else if (info.subsystem == SDL_SYSWM_WAYLAND) {
|
||||||
#ifdef HAVE_LIBVA_WAYLAND
|
#ifdef HAVE_LIBVA_WAYLAND
|
||||||
m_WaylandSurface = info.info.wl.surface;
|
|
||||||
m_WaylandDisplay = info.info.wl.display;
|
|
||||||
vaDeviceContext->display = vaGetDisplayWl(info.info.wl.display);
|
vaDeviceContext->display = vaGetDisplayWl(info.info.wl.display);
|
||||||
if (!vaDeviceContext->display) {
|
if (!vaDeviceContext->display) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
@@ -116,11 +114,12 @@ VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height, int, b
|
|||||||
"Driver: %s",
|
"Driver: %s",
|
||||||
vendorString ? vendorString : "<unknown>");
|
vendorString ? vendorString : "<unknown>");
|
||||||
|
|
||||||
// AMD's Gallium VAAPI driver has a nasty memory leak
|
// AMD's Gallium VAAPI driver has a nasty memory leak that causes memory
|
||||||
// that causes memory to be leaked for each submitted frame.
|
// to be leaked for each submitted frame. The Flatpak runtime has a VDPAU
|
||||||
// The Flatpak runtime has a VDPAU driver in place that works
|
// driver in place that works well, so use that instead on AMD systems. If
|
||||||
// well, so use that instead on AMD systems.
|
// we're using Wayland, we have no choice but to use VAAPI because VDPAU
|
||||||
if (vendorString && qgetenv("FORCE_VAAPI") != "1") {
|
// is only supported under X11.
|
||||||
|
if (vendorString && qgetenv("FORCE_VAAPI") != "1" && m_WindowSystem == SDL_SYSWM_X11) {
|
||||||
QString vendorStr(vendorString);
|
QString vendorStr(vendorString);
|
||||||
if (vendorStr.contains("AMD", Qt::CaseInsensitive) ||
|
if (vendorStr.contains("AMD", Qt::CaseInsensitive) ||
|
||||||
vendorStr.contains("Radeon", Qt::CaseInsensitive)) {
|
vendorStr.contains("Radeon", Qt::CaseInsensitive)) {
|
||||||
@@ -171,15 +170,12 @@ VAAPIRenderer::needsTestFrame()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
VAAPIRenderer::getDecoderCapabilities()
|
VAAPIRenderer::isDirectRenderingSupported()
|
||||||
{
|
{
|
||||||
return 0;
|
// Many Wayland renderers don't support YUV surfaces, so use
|
||||||
}
|
// another frontend renderer to draw our frames.
|
||||||
|
return m_WindowSystem == SDL_SYSWM_X11;
|
||||||
IFFmpegRenderer::FramePacingConstraint VAAPIRenderer::getFramePacingConstraint()
|
|
||||||
{
|
|
||||||
return PACING_ANY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -212,27 +208,10 @@ VAAPIRenderer::renderFrame(AVFrame* frame)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (m_WindowSystem == SDL_SYSWM_WAYLAND) {
|
else if (m_WindowSystem == SDL_SYSWM_WAYLAND) {
|
||||||
#ifdef HAVE_LIBVA_WAYLAND
|
// We don't support direct rendering on Wayland, so we should
|
||||||
struct wl_buffer* buffer;
|
// never get called there. Many common Wayland compositors don't
|
||||||
VAStatus status;
|
// support YUV surfaces, so direct rendering would fail.
|
||||||
|
SDL_assert(false);
|
||||||
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 {
|
else {
|
||||||
// We don't accept anything else in initialize().
|
// We don't accept anything else in initialize().
|
||||||
|
|||||||
@@ -29,18 +29,12 @@ class VAAPIRenderer : public IFFmpegRenderer
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VAAPIRenderer();
|
VAAPIRenderer();
|
||||||
virtual ~VAAPIRenderer();
|
virtual ~VAAPIRenderer() override;
|
||||||
virtual bool initialize(SDL_Window* window,
|
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||||
int videoFormat,
|
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
||||||
int width,
|
virtual void renderFrame(AVFrame* frame) override;
|
||||||
int height,
|
virtual bool needsTestFrame() override;
|
||||||
int maxFps,
|
virtual bool isDirectRenderingSupported() override;
|
||||||
bool enableVsync);
|
|
||||||
virtual bool prepareDecoderContext(AVCodecContext* context);
|
|
||||||
virtual void renderFrame(AVFrame* frame);
|
|
||||||
virtual bool needsTestFrame();
|
|
||||||
virtual int getDecoderCapabilities();
|
|
||||||
virtual FramePacingConstraint getFramePacingConstraint();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_WindowSystem;
|
int m_WindowSystem;
|
||||||
@@ -50,11 +44,6 @@ private:
|
|||||||
Window m_XWindow;
|
Window m_XWindow;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBVA_WAYLAND
|
|
||||||
struct wl_surface* m_WaylandSurface;
|
|
||||||
struct wl_display* m_WaylandDisplay;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int m_VideoWidth;
|
int m_VideoWidth;
|
||||||
int m_VideoHeight;
|
int m_VideoHeight;
|
||||||
int m_DisplayWidth;
|
int m_DisplayWidth;
|
||||||
|
|||||||
@@ -54,14 +54,14 @@ VDPAURenderer::~VDPAURenderer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height, int, bool)
|
bool VDPAURenderer::initialize(PDECODER_PARAMETERS params)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
VdpStatus status;
|
VdpStatus status;
|
||||||
SDL_SysWMinfo info;
|
SDL_SysWMinfo info;
|
||||||
|
|
||||||
m_VideoWidth = width;
|
m_VideoWidth = params->width;
|
||||||
m_VideoHeight = height;
|
m_VideoHeight = params->height;
|
||||||
|
|
||||||
err = av_hwdevice_ctx_create(&m_HwContext,
|
err = av_hwdevice_ctx_create(&m_HwContext,
|
||||||
AV_HWDEVICE_TYPE_VDPAU,
|
AV_HWDEVICE_TYPE_VDPAU,
|
||||||
@@ -93,11 +93,11 @@ bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height, i
|
|||||||
GET_PROC_ADDRESS(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, &m_VdpVideoSurfaceGetParameters);
|
GET_PROC_ADDRESS(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, &m_VdpVideoSurfaceGetParameters);
|
||||||
GET_PROC_ADDRESS(VDP_FUNC_ID_GET_INFORMATION_STRING, &m_VdpGetInformationString);
|
GET_PROC_ADDRESS(VDP_FUNC_ID_GET_INFORMATION_STRING, &m_VdpGetInformationString);
|
||||||
|
|
||||||
SDL_GetWindowSize(window, (int*)&m_DisplayWidth, (int*)&m_DisplayHeight);
|
SDL_GetWindowSize(params->window, (int*)&m_DisplayWidth, (int*)&m_DisplayHeight);
|
||||||
|
|
||||||
SDL_VERSION(&info.version);
|
SDL_VERSION(&info.version);
|
||||||
|
|
||||||
if (!SDL_GetWindowWMInfo(window, &info)) {
|
if (!SDL_GetWindowWMInfo(params->window, &info)) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"SDL_GetWindowWMInfo() failed: %s",
|
"SDL_GetWindowWMInfo() failed: %s",
|
||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
@@ -241,16 +241,6 @@ bool VDPAURenderer::needsTestFrame()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VDPAURenderer::getDecoderCapabilities()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
IFFmpegRenderer::FramePacingConstraint VDPAURenderer::getFramePacingConstraint()
|
|
||||||
{
|
|
||||||
return PACING_ANY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDPAURenderer::renderFrame(AVFrame* frame)
|
void VDPAURenderer::renderFrame(AVFrame* frame)
|
||||||
{
|
{
|
||||||
VdpStatus status;
|
VdpStatus status;
|
||||||
|
|||||||
@@ -12,18 +12,11 @@ class VDPAURenderer : public IFFmpegRenderer
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VDPAURenderer();
|
VDPAURenderer();
|
||||||
virtual ~VDPAURenderer();
|
virtual ~VDPAURenderer() override;
|
||||||
virtual bool initialize(SDL_Window* window,
|
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||||
int videoFormat,
|
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
||||||
int width,
|
virtual void renderFrame(AVFrame* frame) override;
|
||||||
int height,
|
virtual bool needsTestFrame() override;
|
||||||
int maxFps,
|
|
||||||
bool enableVsync);
|
|
||||||
virtual bool prepareDecoderContext(AVCodecContext* context);
|
|
||||||
virtual void renderFrame(AVFrame* frame);
|
|
||||||
virtual bool needsTestFrame();
|
|
||||||
virtual int getDecoderCapabilities();
|
|
||||||
virtual FramePacingConstraint getFramePacingConstraint();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_VideoWidth, m_VideoHeight;
|
uint32_t m_VideoWidth, m_VideoHeight;
|
||||||
|
|||||||
@@ -106,16 +106,11 @@ public:
|
|||||||
CFRelease(sampleBuffer);
|
CFRelease(sampleBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool initialize(SDL_Window* window,
|
virtual bool initialize(PDECODER_PARAMETERS params) override
|
||||||
int videoFormat,
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
bool) override
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
|
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||||
// Prior to 10.13, we'll just assume everything has
|
// Prior to 10.13, we'll just assume everything has
|
||||||
// H.264 support and fail open to allow VT decode.
|
// H.264 support and fail open to allow VT decode.
|
||||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
|
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
|
||||||
@@ -133,7 +128,7 @@ public:
|
|||||||
"Assuming H.264 HW decode on < macOS 10.13");
|
"Assuming H.264 HW decode on < macOS 10.13");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (videoFormat & VIDEO_FORMAT_MASK_H265) {
|
else if (params->videoFormat & VIDEO_FORMAT_MASK_H265) {
|
||||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
|
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
|
||||||
if (__builtin_available(macOS 10.13, *)) {
|
if (__builtin_available(macOS 10.13, *)) {
|
||||||
if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) {
|
if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) {
|
||||||
@@ -156,7 +151,7 @@ public:
|
|||||||
|
|
||||||
SDL_VERSION(&info.version);
|
SDL_VERSION(&info.version);
|
||||||
|
|
||||||
if (!SDL_GetWindowWMInfo(window, &info)) {
|
if (!SDL_GetWindowWMInfo(params->window, &info)) {
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"SDL_GetWindowWMInfo() failed: %s",
|
"SDL_GetWindowWMInfo() failed: %s",
|
||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
@@ -283,11 +278,6 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int getDecoderCapabilities() override
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual IFFmpegRenderer::FramePacingConstraint getFramePacingConstraint() override
|
virtual IFFmpegRenderer::FramePacingConstraint getFramePacingConstraint() override
|
||||||
{
|
{
|
||||||
// This renderer is inherently tied to V-sync due how we're
|
// This renderer is inherently tied to V-sync due how we're
|
||||||
|
|||||||
+178
-106
@@ -23,6 +23,14 @@
|
|||||||
#include "ffmpeg-renderers/vdpau.h"
|
#include "ffmpeg-renderers/vdpau.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_MMAL
|
||||||
|
#include "ffmpeg-renderers/mmal.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DRM
|
||||||
|
#include "ffmpeg-renderers/drm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
// This is gross but it allows us to use sizeof()
|
// This is gross but it allows us to use sizeof()
|
||||||
#include "ffmpeg_videosamples.cpp"
|
#include "ffmpeg_videosamples.cpp"
|
||||||
|
|
||||||
@@ -32,12 +40,13 @@
|
|||||||
|
|
||||||
bool FFmpegVideoDecoder::isHardwareAccelerated()
|
bool FFmpegVideoDecoder::isHardwareAccelerated()
|
||||||
{
|
{
|
||||||
return m_HwDecodeCfg != nullptr;
|
return m_HwDecodeCfg != nullptr ||
|
||||||
|
(m_VideoDecoderCtx->codec->capabilities & AV_CODEC_CAP_HARDWARE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FFmpegVideoDecoder::getDecoderCapabilities()
|
int FFmpegVideoDecoder::getDecoderCapabilities()
|
||||||
{
|
{
|
||||||
return m_Renderer->getDecoderCapabilities();
|
return m_BackendRenderer->getDecoderCapabilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AVPixelFormat FFmpegVideoDecoder::ffGetFormat(AVCodecContext* context,
|
enum AVPixelFormat FFmpegVideoDecoder::ffGetFormat(AVCodecContext* context,
|
||||||
@@ -65,7 +74,8 @@ FFmpegVideoDecoder::FFmpegVideoDecoder(bool testOnly)
|
|||||||
: m_VideoDecoderCtx(nullptr),
|
: m_VideoDecoderCtx(nullptr),
|
||||||
m_DecodeBuffer(1024 * 1024, 0),
|
m_DecodeBuffer(1024 * 1024, 0),
|
||||||
m_HwDecodeCfg(nullptr),
|
m_HwDecodeCfg(nullptr),
|
||||||
m_Renderer(nullptr),
|
m_BackendRenderer(nullptr),
|
||||||
|
m_FrontendRenderer(nullptr),
|
||||||
m_ConsecutiveFailedDecodes(0),
|
m_ConsecutiveFailedDecodes(0),
|
||||||
m_Pacer(nullptr),
|
m_Pacer(nullptr),
|
||||||
m_LastFrameNumber(0),
|
m_LastFrameNumber(0),
|
||||||
@@ -94,9 +104,9 @@ FFmpegVideoDecoder::~FFmpegVideoDecoder()
|
|||||||
av_log_set_level(AV_LOG_INFO);
|
av_log_set_level(AV_LOG_INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
IFFmpegRenderer* FFmpegVideoDecoder::getRenderer()
|
IFFmpegRenderer* FFmpegVideoDecoder::getBackendRenderer()
|
||||||
{
|
{
|
||||||
return m_Renderer;
|
return m_BackendRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpegVideoDecoder::reset()
|
void FFmpegVideoDecoder::reset()
|
||||||
@@ -115,8 +125,14 @@ void FFmpegVideoDecoder::reset()
|
|||||||
Session::get()->getOverlayManager().setOverlayRenderer(nullptr);
|
Session::get()->getOverlayManager().setOverlayRenderer(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete m_Renderer;
|
// If we have a separate frontend renderer, free that first
|
||||||
m_Renderer = nullptr;
|
if (m_FrontendRenderer != m_BackendRenderer) {
|
||||||
|
delete m_FrontendRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete m_BackendRenderer;
|
||||||
|
|
||||||
|
m_FrontendRenderer = m_BackendRenderer = nullptr;
|
||||||
|
|
||||||
if (!m_TestOnly) {
|
if (!m_TestOnly) {
|
||||||
logVideoStats(m_GlobalVideoStats, "Global video stats");
|
logVideoStats(m_GlobalVideoStats, "Global video stats");
|
||||||
@@ -127,35 +143,57 @@ void FFmpegVideoDecoder::reset()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* window,
|
bool FFmpegVideoDecoder::createFrontendRenderer(PDECODER_PARAMETERS params)
|
||||||
int videoFormat, int width, int height,
|
{
|
||||||
int maxFps, bool enableFramePacing, bool testFrame)
|
if (m_BackendRenderer->isDirectRenderingSupported()) {
|
||||||
|
// The backend renderer can render to the display
|
||||||
|
m_FrontendRenderer = m_BackendRenderer;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The backend renderer cannot directly render to the display, so
|
||||||
|
// we will create an SDL renderer to draw the frames.
|
||||||
|
m_FrontendRenderer = new SdlRenderer();
|
||||||
|
if (!m_FrontendRenderer->initialize(params)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine whether the frontend renderer prefers frame pacing
|
||||||
|
auto vsyncConstraint = m_FrontendRenderer->getFramePacingConstraint();
|
||||||
|
if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_OFF && params->enableFramePacing) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Frame pacing is forcefully disabled by the frontend renderer");
|
||||||
|
params->enableFramePacing = false;
|
||||||
|
}
|
||||||
|
else if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_ON && !params->enableFramePacing) {
|
||||||
|
// FIXME: This duplicates logic in Session.cpp
|
||||||
|
int displayHz = StreamUtils::getDisplayRefreshRate(params->window);
|
||||||
|
if (displayHz + 5 >= params->frameRate) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Frame pacing is forcefully enabled by the frontend renderer");
|
||||||
|
params->enableFramePacing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, PDECODER_PARAMETERS params, bool testFrame)
|
||||||
{
|
{
|
||||||
// In test-only mode, we should only see test frames
|
// In test-only mode, we should only see test frames
|
||||||
SDL_assert(!m_TestOnly || testFrame);
|
SDL_assert(!m_TestOnly || testFrame);
|
||||||
|
|
||||||
auto vsyncConstraint = m_Renderer->getFramePacingConstraint();
|
// Create the frontend renderer based on the capabilities of the backend renderer
|
||||||
if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_OFF && enableFramePacing) {
|
if (!createFrontendRenderer(params)) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
return false;
|
||||||
"Frame pacing is forcefully disabled by the active renderer");
|
|
||||||
enableFramePacing = false;
|
|
||||||
}
|
|
||||||
else if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_ON && !enableFramePacing) {
|
|
||||||
// FIXME: This duplicates logic in Session.cpp
|
|
||||||
int displayHz = StreamUtils::getDisplayRefreshRate(window);
|
|
||||||
if (displayHz + 5 >= maxFps) {
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Frame pacing is forcefully enabled by the active renderer");
|
|
||||||
enableFramePacing = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_StreamFps = maxFps;
|
m_StreamFps = params->frameRate;
|
||||||
|
|
||||||
// Don't bother initializing Pacer if we're not actually going to render
|
// Don't bother initializing Pacer if we're not actually going to render
|
||||||
if (!testFrame) {
|
if (!testFrame) {
|
||||||
m_Pacer = new Pacer(m_Renderer, &m_ActiveWndVideoStats);
|
m_Pacer = new Pacer(m_FrontendRenderer, &m_ActiveWndVideoStats);
|
||||||
if (!m_Pacer->initialize(window, maxFps, enableFramePacing)) {
|
if (!m_Pacer->initialize(params->window, params->frameRate, params->enableFramePacing)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +213,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||||||
m_VideoDecoderCtx->flags2 |= AV_CODEC_FLAG2_SHOW_ALL;
|
m_VideoDecoderCtx->flags2 |= AV_CODEC_FLAG2_SHOW_ALL;
|
||||||
|
|
||||||
// Enable slice multi-threading for software decoding
|
// Enable slice multi-threading for software decoding
|
||||||
if (!m_HwDecodeCfg) {
|
if (!isHardwareAccelerated()) {
|
||||||
m_VideoDecoderCtx->thread_type = FF_THREAD_SLICE;
|
m_VideoDecoderCtx->thread_type = FF_THREAD_SLICE;
|
||||||
m_VideoDecoderCtx->thread_count = qMin(MAX_SLICES, SDL_GetCPUCount());
|
m_VideoDecoderCtx->thread_count = qMin(MAX_SLICES, SDL_GetCPUCount());
|
||||||
}
|
}
|
||||||
@@ -185,13 +223,13 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup decoding parameters
|
// Setup decoding parameters
|
||||||
m_VideoDecoderCtx->width = width;
|
m_VideoDecoderCtx->width = params->width;
|
||||||
m_VideoDecoderCtx->height = height;
|
m_VideoDecoderCtx->height = params->height;
|
||||||
m_VideoDecoderCtx->pix_fmt = AV_PIX_FMT_YUV420P; // FIXME: HDR
|
m_VideoDecoderCtx->pix_fmt = m_FrontendRenderer->getPreferredPixelFormat(params->videoFormat);
|
||||||
m_VideoDecoderCtx->get_format = ffGetFormat;
|
m_VideoDecoderCtx->get_format = ffGetFormat;
|
||||||
|
|
||||||
// Allow the renderer to attach data to this decoder
|
// Allow the backend renderer to attach data to this decoder
|
||||||
if (!m_Renderer->prepareDecoderContext(m_VideoDecoderCtx)) {
|
if (!m_BackendRenderer->prepareDecoderContext(m_VideoDecoderCtx)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +244,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Unable to open decoder for format: %x",
|
"Unable to open decoder for format: %x",
|
||||||
videoFormat);
|
params->videoFormat);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +254,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||||||
// now to see if things will actually work when the video stream
|
// now to see if things will actually work when the video stream
|
||||||
// comes in.
|
// comes in.
|
||||||
if (testFrame) {
|
if (testFrame) {
|
||||||
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
|
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||||
m_Pkt.data = (uint8_t*)k_H264TestFrame;
|
m_Pkt.data = (uint8_t*)k_H264TestFrame;
|
||||||
m_Pkt.size = sizeof(k_H264TestFrame);
|
m_Pkt.size = sizeof(k_H264TestFrame);
|
||||||
}
|
}
|
||||||
@@ -235,8 +273,8 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((videoFormat & VIDEO_FORMAT_MASK_H264) &&
|
if ((params->videoFormat & VIDEO_FORMAT_MASK_H264) &&
|
||||||
!(m_Renderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) {
|
!(m_BackendRenderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Using H.264 SPS fixup");
|
"Using H.264 SPS fixup");
|
||||||
m_NeedsSpsFixup = true;
|
m_NeedsSpsFixup = true;
|
||||||
@@ -245,8 +283,8 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||||||
m_NeedsSpsFixup = false;
|
m_NeedsSpsFixup = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell overlay manager to use this renderer
|
// Tell overlay manager to use this frontend renderer
|
||||||
Session::get()->getOverlayManager().setOverlayRenderer(m_Renderer);
|
Session::get()->getOverlayManager().setOverlayRenderer(m_FrontendRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -331,7 +369,7 @@ void FFmpegVideoDecoder::logVideoStats(VIDEO_STATS& stats, const char* title)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IFFmpegRenderer* FFmpegVideoDecoder::createAcceleratedRenderer(const AVCodecHWConfig* hwDecodeCfg)
|
IFFmpegRenderer* FFmpegVideoDecoder::createHwAccelRenderer(const AVCodecHWConfig* hwDecodeCfg)
|
||||||
{
|
{
|
||||||
if (!(hwDecodeCfg->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) {
|
if (!(hwDecodeCfg->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -360,25 +398,61 @@ IFFmpegRenderer* FFmpegVideoDecoder::createAcceleratedRenderer(const AVCodecHWCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FFmpegVideoDecoder::initialize(
|
bool FFmpegVideoDecoder::tryInitializeRenderer(AVCodec* decoder,
|
||||||
StreamingPreferences::VideoDecoderSelection vds,
|
PDECODER_PARAMETERS params,
|
||||||
SDL_Window* window,
|
const AVCodecHWConfig* hwConfig,
|
||||||
int videoFormat,
|
std::function<IFFmpegRenderer*()> createRendererFunc)
|
||||||
int width,
|
{
|
||||||
int height,
|
m_BackendRenderer = createRendererFunc();
|
||||||
int maxFps,
|
m_HwDecodeCfg = hwConfig;
|
||||||
bool enableVsync,
|
|
||||||
bool enableFramePacing)
|
if (m_BackendRenderer != nullptr &&
|
||||||
|
m_BackendRenderer->initialize(params) &&
|
||||||
|
completeInitialization(decoder, params, m_TestOnly || m_BackendRenderer->needsTestFrame())) {
|
||||||
|
if (m_TestOnly) {
|
||||||
|
// This decoder is only for testing capabilities, so don't bother
|
||||||
|
// creating a usable renderer
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_BackendRenderer->needsTestFrame()) {
|
||||||
|
// The test worked, so now let's initialize it for real
|
||||||
|
reset();
|
||||||
|
if ((m_BackendRenderer = createRendererFunc()) != nullptr &&
|
||||||
|
m_BackendRenderer->initialize(params) &&
|
||||||
|
completeInitialization(decoder, params, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Decoder failed to initialize after successful test");
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// No test required. Good to go now.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Failed to initialize or test frame failed, so keep looking
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FFmpegVideoDecoder::initialize(PDECODER_PARAMETERS params)
|
||||||
{
|
{
|
||||||
AVCodec* decoder;
|
AVCodec* decoder;
|
||||||
|
|
||||||
// Increase log level until the first frame is decoded
|
// Increase log level until the first frame is decoded
|
||||||
av_log_set_level(AV_LOG_DEBUG);
|
av_log_set_level(AV_LOG_DEBUG);
|
||||||
|
|
||||||
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
|
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||||
decoder = avcodec_find_decoder(AV_CODEC_ID_H264);
|
decoder = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||||
}
|
}
|
||||||
else if (videoFormat & VIDEO_FORMAT_MASK_H265) {
|
else if (params->videoFormat & VIDEO_FORMAT_MASK_H265) {
|
||||||
decoder = avcodec_find_decoder(AV_CODEC_ID_HEVC);
|
decoder = avcodec_find_decoder(AV_CODEC_ID_HEVC);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -389,67 +463,71 @@ bool FFmpegVideoDecoder::initialize(
|
|||||||
if (!decoder) {
|
if (!decoder) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Unable to find decoder for format: %x",
|
"Unable to find decoder for format: %x",
|
||||||
videoFormat);
|
params->videoFormat);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0;; i++) {
|
// Look for a hardware decoder first unless software-only
|
||||||
const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i);
|
if (params->vds != StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
||||||
if (!config || vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
// Look for the first matching hwaccel hardware decoder
|
||||||
// No matching hardware acceleration support.
|
for (int i = 0;; i++) {
|
||||||
// This is not an error.
|
const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i);
|
||||||
m_HwDecodeCfg = nullptr;
|
if (!config) {
|
||||||
m_Renderer = new SdlRenderer();
|
// No remaing hwaccel options
|
||||||
if (vds != StreamingPreferences::VDS_FORCE_HARDWARE &&
|
break;
|
||||||
m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
|
|
||||||
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, m_TestOnly)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
reset();
|
// Initialize the hardware codec and submit a test frame if the renderer needs it
|
||||||
return false;
|
if (tryInitializeRenderer(decoder, params, config,
|
||||||
|
[config]() -> IFFmpegRenderer* { return createHwAccelRenderer(config); })) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Renderer = createAcceleratedRenderer(config);
|
// Continue with special non-hwaccel hardware decoders
|
||||||
if (!m_Renderer) {
|
|
||||||
continue;
|
#ifdef HAVE_MMAL
|
||||||
|
// MMAL is the decoder for the Raspberry Pi
|
||||||
|
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||||
|
AVCodec* mmalDecoder = avcodec_find_decoder_by_name("h264_mmal");
|
||||||
|
if (mmalDecoder != nullptr &&
|
||||||
|
tryInitializeRenderer(mmalDecoder, params, nullptr,
|
||||||
|
[]() -> IFFmpegRenderer* { return new MmalRenderer(); })) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
m_HwDecodeCfg = config;
|
#ifdef HAVE_DRM
|
||||||
// Initialize the hardware codec and submit a test frame if the renderer needs it
|
// RKMPP is a hardware accelerated decoder that outputs DRI PRIME buffers
|
||||||
if (m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
|
AVCodec* rkmppDecoder;
|
||||||
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, m_TestOnly || m_Renderer->needsTestFrame())) {
|
|
||||||
if (m_TestOnly) {
|
|
||||||
// This decoder is only for testing capabilities, so don't bother
|
|
||||||
// creating a usable renderer
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Renderer->needsTestFrame()) {
|
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||||
// The test worked, so now let's initialize it for real
|
rkmppDecoder = avcodec_find_decoder_by_name("h264_rkmpp");
|
||||||
reset();
|
|
||||||
if ((m_Renderer = createAcceleratedRenderer(config)) != nullptr &&
|
|
||||||
m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
|
|
||||||
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, false)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Decoder failed to initialize after successful test");
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// No test required. Good to go now.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Failed to initialize or test frame failed, so keep looking
|
rkmppDecoder = avcodec_find_decoder_by_name("hevc_rkmpp");
|
||||||
reset();
|
}
|
||||||
|
|
||||||
|
if (rkmppDecoder != nullptr &&
|
||||||
|
tryInitializeRenderer(rkmppDecoder, params, nullptr,
|
||||||
|
[]() -> IFFmpegRenderer* { return new DrmRenderer(); })) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to software if no matching hardware decoder was found
|
||||||
|
// and if software fallback is allowed
|
||||||
|
if (params->vds != StreamingPreferences::VDS_FORCE_HARDWARE) {
|
||||||
|
if (tryInitializeRenderer(decoder, params, nullptr,
|
||||||
|
[]() -> IFFmpegRenderer* { return new SdlRenderer(); })) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No decoder worked
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpegVideoDecoder::writeBuffer(PLENTRY entry, int& offset)
|
void FFmpegVideoDecoder::writeBuffer(PLENTRY entry, int& offset)
|
||||||
@@ -630,14 +708,8 @@ int FFmpegVideoDecoder::submitDecodeUnit(PDECODE_UNIT du)
|
|||||||
return DR_OK;
|
return DR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called on main thread
|
void FFmpegVideoDecoder::renderFrameOnMainThread()
|
||||||
void FFmpegVideoDecoder::renderFrame(SDL_UserEvent*)
|
|
||||||
{
|
{
|
||||||
SDL_assert(false);
|
m_Pacer->renderOnMainThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called on main thread
|
|
||||||
void FFmpegVideoDecoder::dropFrame(SDL_UserEvent*)
|
|
||||||
{
|
|
||||||
SDL_assert(false);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "decoder.h"
|
#include "decoder.h"
|
||||||
#include "ffmpeg-renderers/renderer.h"
|
#include "ffmpeg-renderers/renderer.h"
|
||||||
#include "ffmpeg-renderers/pacer/pacer.h"
|
#include "ffmpeg-renderers/pacer/pacer.h"
|
||||||
@@ -12,26 +14,16 @@ class FFmpegVideoDecoder : public IVideoDecoder {
|
|||||||
public:
|
public:
|
||||||
FFmpegVideoDecoder(bool testOnly);
|
FFmpegVideoDecoder(bool testOnly);
|
||||||
virtual ~FFmpegVideoDecoder() override;
|
virtual ~FFmpegVideoDecoder() override;
|
||||||
virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds,
|
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||||
SDL_Window* window,
|
|
||||||
int videoFormat,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
int maxFps,
|
|
||||||
bool enableVsync,
|
|
||||||
bool enableFramePacing) override;
|
|
||||||
virtual bool isHardwareAccelerated() override;
|
virtual bool isHardwareAccelerated() override;
|
||||||
virtual int getDecoderCapabilities() override;
|
virtual int getDecoderCapabilities() override;
|
||||||
virtual int submitDecodeUnit(PDECODE_UNIT du) override;
|
virtual int submitDecodeUnit(PDECODE_UNIT du) override;
|
||||||
virtual void renderFrame(SDL_UserEvent* event) override;
|
virtual void renderFrameOnMainThread() override;
|
||||||
virtual void dropFrame(SDL_UserEvent* event) override;
|
|
||||||
|
|
||||||
virtual IFFmpegRenderer* getRenderer();
|
virtual IFFmpegRenderer* getBackendRenderer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool completeInitialization(AVCodec* decoder, SDL_Window* window,
|
bool completeInitialization(AVCodec* decoder, PDECODER_PARAMETERS params, bool testFrame);
|
||||||
int videoFormat, int width, int height,
|
|
||||||
int maxFps, bool enableFramePacing, bool testFrame);
|
|
||||||
|
|
||||||
void stringifyVideoStats(VIDEO_STATS& stats, char* output);
|
void stringifyVideoStats(VIDEO_STATS& stats, char* output);
|
||||||
|
|
||||||
@@ -39,7 +31,14 @@ private:
|
|||||||
|
|
||||||
void addVideoStats(VIDEO_STATS& src, VIDEO_STATS& dst);
|
void addVideoStats(VIDEO_STATS& src, VIDEO_STATS& dst);
|
||||||
|
|
||||||
IFFmpegRenderer* createAcceleratedRenderer(const AVCodecHWConfig* hwDecodeCfg);
|
bool createFrontendRenderer(PDECODER_PARAMETERS params);
|
||||||
|
|
||||||
|
bool tryInitializeRenderer(AVCodec* decoder,
|
||||||
|
PDECODER_PARAMETERS params,
|
||||||
|
const AVCodecHWConfig* hwConfig,
|
||||||
|
std::function<IFFmpegRenderer*()> createRendererFunc);
|
||||||
|
|
||||||
|
static IFFmpegRenderer* createHwAccelRenderer(const AVCodecHWConfig* hwDecodeCfg);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
@@ -53,7 +52,8 @@ private:
|
|||||||
AVCodecContext* m_VideoDecoderCtx;
|
AVCodecContext* m_VideoDecoderCtx;
|
||||||
QByteArray m_DecodeBuffer;
|
QByteArray m_DecodeBuffer;
|
||||||
const AVCodecHWConfig* m_HwDecodeCfg;
|
const AVCodecHWConfig* m_HwDecodeCfg;
|
||||||
IFFmpegRenderer* m_Renderer;
|
IFFmpegRenderer* m_BackendRenderer;
|
||||||
|
IFFmpegRenderer* m_FrontendRenderer;
|
||||||
int m_ConsecutiveFailedDecodes;
|
int m_ConsecutiveFailedDecodes;
|
||||||
Pacer* m_Pacer;
|
Pacer* m_Pacer;
|
||||||
VIDEO_STATS m_ActiveWndVideoStats;
|
VIDEO_STATS m_ActiveWndVideoStats;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ SLVideoDecoder::SLVideoDecoder(bool)
|
|||||||
: m_VideoContext(nullptr),
|
: m_VideoContext(nullptr),
|
||||||
m_VideoStream(nullptr)
|
m_VideoStream(nullptr)
|
||||||
{
|
{
|
||||||
|
SLVideo_SetLogFunction(SLVideoDecoder::slLogCallback, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
SLVideoDecoder::~SLVideoDecoder()
|
SLVideoDecoder::~SLVideoDecoder()
|
||||||
@@ -32,17 +32,15 @@ SLVideoDecoder::getDecoderCapabilities()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds,
|
SLVideoDecoder::initialize(PDECODER_PARAMETERS params)
|
||||||
SDL_Window*,
|
|
||||||
int videoFormat, int, int, int frameRate, bool, bool)
|
|
||||||
{
|
{
|
||||||
// SLVideo only supports hardware decoding
|
// SLVideo only supports hardware decoding
|
||||||
if (vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
if (params->vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SLVideo only supports H.264
|
// SLVideo only supports H.264
|
||||||
if (videoFormat != VIDEO_FORMAT_H264) {
|
if (params->videoFormat != VIDEO_FORMAT_H264) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +59,7 @@ SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SLVideo_SetStreamTargetFramerate(m_VideoStream, frameRate, 1);
|
SLVideo_SetStreamTargetFramerate(m_VideoStream, params->frameRate, 1);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -110,3 +108,30 @@ SLVideoDecoder::submitDecodeUnit(PDECODE_UNIT du)
|
|||||||
|
|
||||||
return DR_OK;
|
return DR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SLVideoDecoder::slLogCallback(void *context, ESLVideoLog logLevel, const char *message)
|
||||||
|
{
|
||||||
|
SDL_LogPriority priority;
|
||||||
|
|
||||||
|
switch (logLevel)
|
||||||
|
{
|
||||||
|
case k_ESLVideoLogError:
|
||||||
|
priority = SDL_LOG_PRIORITY_ERROR;
|
||||||
|
break;
|
||||||
|
case k_ESLVideoLogWarning:
|
||||||
|
priority = SDL_LOG_PRIORITY_WARN;
|
||||||
|
break;
|
||||||
|
case k_ESLVideoLogInfo:
|
||||||
|
priority = SDL_LOG_PRIORITY_INFO;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case k_ESLVideoLogDebug:
|
||||||
|
priority = SDL_LOG_PRIORITY_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
priority,
|
||||||
|
"SLVideo: %s",
|
||||||
|
message);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,23 +9,17 @@ class SLVideoDecoder : public IVideoDecoder
|
|||||||
public:
|
public:
|
||||||
SLVideoDecoder(bool testOnly);
|
SLVideoDecoder(bool testOnly);
|
||||||
virtual ~SLVideoDecoder();
|
virtual ~SLVideoDecoder();
|
||||||
virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds,
|
virtual bool initialize(PDECODER_PARAMETERS params);
|
||||||
SDL_Window* window,
|
|
||||||
int videoFormat,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
int frameRate,
|
|
||||||
bool enableVsync,
|
|
||||||
bool enableFramePacing);
|
|
||||||
virtual bool isHardwareAccelerated();
|
virtual bool isHardwareAccelerated();
|
||||||
virtual int getDecoderCapabilities();
|
virtual int getDecoderCapabilities();
|
||||||
virtual int submitDecodeUnit(PDECODE_UNIT du);
|
virtual int submitDecodeUnit(PDECODE_UNIT du);
|
||||||
|
|
||||||
// Unused since rendering is done directly from the decode thread
|
// Unused since rendering is done directly from the decode thread
|
||||||
virtual void renderFrame(SDL_UserEvent*) {}
|
virtual void renderFrameOnMainThread() {}
|
||||||
virtual void dropFrame(SDL_UserEvent*) {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void slLogCallback(void* context, ESLVideoLog logLevel, const char* message);
|
||||||
|
|
||||||
CSLVideoContext* m_VideoContext;
|
CSLVideoContext* m_VideoContext;
|
||||||
CSLVideoStream* m_VideoStream;
|
CSLVideoStream* m_VideoStream;
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
0.10.0
|
0.10.1
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Support debug and release builds from command line for CI
|
||||||
|
CONFIG += debug_and_release
|
||||||
|
|
||||||
|
# Ensure symbols are always generated
|
||||||
|
CONFIG += force_debug_info
|
||||||
|
|
||||||
|
# Disable asserts on release builds
|
||||||
|
CONFIG(release, debug|release) {
|
||||||
|
DEFINES += NDEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enable ASan if desired
|
||||||
|
#CONFIG += sanitizer sanitize_address
|
||||||
@@ -10,18 +10,15 @@ QT -= core gui
|
|||||||
TARGET = h264bitstream
|
TARGET = h264bitstream
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
|
||||||
# Support debug and release builds from command line for CI
|
|
||||||
CONFIG += debug_and_release
|
|
||||||
|
|
||||||
# Ensure symbols are always generated
|
|
||||||
CONFIG += force_debug_info
|
|
||||||
|
|
||||||
# Build a static library
|
# Build a static library
|
||||||
CONFIG += staticlib
|
CONFIG += staticlib
|
||||||
|
|
||||||
# Disable warnings
|
# Disable warnings
|
||||||
CONFIG += warn_off
|
CONFIG += warn_off
|
||||||
|
|
||||||
|
# Include global qmake defs
|
||||||
|
include(../globaldefs.pri)
|
||||||
|
|
||||||
# Older GCC versions defaulted to GNU89
|
# Older GCC versions defaulted to GNU89
|
||||||
*-g++ {
|
*-g++ {
|
||||||
QMAKE_CFLAGS += -std=gnu99
|
QMAKE_CFLAGS += -std=gnu99
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
#include "SDL_power.h"
|
#include "SDL_power.h"
|
||||||
#include "SDL_render.h"
|
#include "SDL_render.h"
|
||||||
#include "SDL_rwops.h"
|
#include "SDL_rwops.h"
|
||||||
|
#include "SDL_sensor.h"
|
||||||
#include "SDL_shape.h"
|
#include "SDL_shape.h"
|
||||||
#include "SDL_system.h"
|
#include "SDL_system.h"
|
||||||
#include "SDL_thread.h"
|
#include "SDL_thread.h"
|
||||||
@@ -80,10 +81,11 @@ extern "C" {
|
|||||||
#define SDL_INIT_HAPTIC 0x00001000u
|
#define SDL_INIT_HAPTIC 0x00001000u
|
||||||
#define SDL_INIT_GAMECONTROLLER 0x00002000u /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
|
#define SDL_INIT_GAMECONTROLLER 0x00002000u /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
|
||||||
#define SDL_INIT_EVENTS 0x00004000u
|
#define SDL_INIT_EVENTS 0x00004000u
|
||||||
|
#define SDL_INIT_SENSOR 0x00008000u
|
||||||
#define SDL_INIT_NOPARACHUTE 0x00100000u /**< compatibility; this flag is ignored. */
|
#define SDL_INIT_NOPARACHUTE 0x00100000u /**< compatibility; this flag is ignored. */
|
||||||
#define SDL_INIT_EVERYTHING ( \
|
#define SDL_INIT_EVERYTHING ( \
|
||||||
SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
|
SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
|
||||||
SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER \
|
SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_SENSOR \
|
||||||
)
|
)
|
||||||
/* @} */
|
/* @} */
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,8 @@ typedef Uint16 SDL_AudioFormat;
|
|||||||
#define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001
|
#define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001
|
||||||
#define SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002
|
#define SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002
|
||||||
#define SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004
|
#define SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004
|
||||||
#define SDL_AUDIO_ALLOW_ANY_CHANGE (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE)
|
#define SDL_AUDIO_ALLOW_SAMPLES_CHANGE 0x00000008
|
||||||
|
#define SDL_AUDIO_ALLOW_ANY_CHANGE (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE)
|
||||||
/* @} */
|
/* @} */
|
||||||
|
|
||||||
/* @} *//* Audio flags */
|
/* @} *//* Audio flags */
|
||||||
|
|||||||
@@ -41,8 +41,10 @@
|
|||||||
#include "SDL_config_android.h"
|
#include "SDL_config_android.h"
|
||||||
#elif defined(__PSP__)
|
#elif defined(__PSP__)
|
||||||
#include "SDL_config_psp.h"
|
#include "SDL_config_psp.h"
|
||||||
|
#elif defined(__OS2__)
|
||||||
|
#include "SDL_config_os2.h"
|
||||||
#else
|
#else
|
||||||
/* This is a minimal configuration just to get SDL running on new platforms */
|
/* This is a minimal configuration just to get SDL running on new platforms. */
|
||||||
#include "SDL_config_minimal.h"
|
#include "SDL_config_minimal.h"
|
||||||
#endif /* platform config */
|
#endif /* platform config */
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,8 @@
|
|||||||
#define HAVE_COPYSIGNF 1
|
#define HAVE_COPYSIGNF 1
|
||||||
#define HAVE_COS 1
|
#define HAVE_COS 1
|
||||||
#define HAVE_COSF 1
|
#define HAVE_COSF 1
|
||||||
|
#define HAVE_EXP 1
|
||||||
|
#define HAVE_EXPF 1
|
||||||
#define HAVE_FABS 1
|
#define HAVE_FABS 1
|
||||||
#define HAVE_FABSF 1
|
#define HAVE_FABSF 1
|
||||||
#define HAVE_FLOOR 1
|
#define HAVE_FLOOR 1
|
||||||
@@ -135,8 +137,12 @@
|
|||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
#define SDL_JOYSTICK_IOKIT 1
|
#define SDL_JOYSTICK_IOKIT 1
|
||||||
|
#define SDL_JOYSTICK_HIDAPI 1
|
||||||
#define SDL_HAPTIC_IOKIT 1
|
#define SDL_HAPTIC_IOKIT 1
|
||||||
|
|
||||||
|
/* Enable the dummy sensor driver */
|
||||||
|
#define SDL_SENSOR_DUMMY 1
|
||||||
|
|
||||||
/* Enable various shared object loading systems */
|
/* Enable various shared object loading systems */
|
||||||
#define SDL_LOADSO_DLOPEN 1
|
#define SDL_LOADSO_DLOPEN 1
|
||||||
|
|
||||||
|
|||||||
@@ -51,16 +51,19 @@
|
|||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
#else
|
#else
|
||||||
#ifdef __ALTIVEC__
|
#ifdef __ALTIVEC__
|
||||||
#if HAVE_ALTIVEC_H && !defined(__APPLE_ALTIVEC__) && !defined(SDL_DISABLE_ALTIVEC_H)
|
#if defined(HAVE_ALTIVEC_H) && !defined(__APPLE_ALTIVEC__) && !defined(SDL_DISABLE_ALTIVEC_H)
|
||||||
#include <altivec.h>
|
#include <altivec.h>
|
||||||
#undef pixel
|
#undef pixel
|
||||||
#undef bool
|
#undef bool
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(__ARM_NEON__) && !defined(SDL_DISABLE_ARM_NEON_H)
|
||||||
|
#include <arm_neon.h>
|
||||||
|
#endif
|
||||||
#if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
|
#if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
|
||||||
#include <mm3dnow.h>
|
#include <mm3dnow.h>
|
||||||
#endif
|
#endif
|
||||||
#if HAVE_IMMINTRIN_H && !defined(SDL_DISABLE_IMMINTRIN_H)
|
#if defined(HAVE_IMMINTRIN_H) && !defined(SDL_DISABLE_IMMINTRIN_H)
|
||||||
#include <immintrin.h>
|
#include <immintrin.h>
|
||||||
#else
|
#else
|
||||||
#if defined(__MMX__) && !defined(SDL_DISABLE_MMINTRIN_H)
|
#if defined(__MMX__) && !defined(SDL_DISABLE_MMINTRIN_H)
|
||||||
@@ -159,6 +162,11 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX(void);
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
|
extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if the CPU has AVX-512F (foundation) features.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX512F(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function returns true if the CPU has NEON (ARM SIMD) features.
|
* This function returns true if the CPU has NEON (ARM SIMD) features.
|
||||||
*/
|
*/
|
||||||
@@ -169,7 +177,6 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
|
extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
|
||||||
|
|
||||||
|
|
||||||
/* Ends C function definitions when using C++ */
|
/* Ends C function definitions when using C++ */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ typedef enum
|
|||||||
Called on Android in onResume()
|
Called on Android in onResume()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Display events */
|
||||||
|
SDL_DISPLAYEVENT = 0x150, /**< Display state change */
|
||||||
|
|
||||||
/* Window events */
|
/* Window events */
|
||||||
SDL_WINDOWEVENT = 0x200, /**< Window state change */
|
SDL_WINDOWEVENT = 0x200, /**< Window state change */
|
||||||
SDL_SYSWMEVENT, /**< System specific event */
|
SDL_SYSWMEVENT, /**< System specific event */
|
||||||
@@ -144,6 +147,9 @@ typedef enum
|
|||||||
SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */
|
SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */
|
||||||
SDL_AUDIODEVICEREMOVED, /**< An audio device has been removed. */
|
SDL_AUDIODEVICEREMOVED, /**< An audio device has been removed. */
|
||||||
|
|
||||||
|
/* Sensor events */
|
||||||
|
SDL_SENSORUPDATE = 0x1200, /**< A sensor was updated */
|
||||||
|
|
||||||
/* Render events */
|
/* Render events */
|
||||||
SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
|
SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
|
||||||
SDL_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */
|
SDL_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */
|
||||||
@@ -168,6 +174,21 @@ typedef struct SDL_CommonEvent
|
|||||||
Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */
|
Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */
|
||||||
} SDL_CommonEvent;
|
} SDL_CommonEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Display state change event data (event.display.*)
|
||||||
|
*/
|
||||||
|
typedef struct SDL_DisplayEvent
|
||||||
|
{
|
||||||
|
Uint32 type; /**< ::SDL_DISPLAYEVENT */
|
||||||
|
Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */
|
||||||
|
Uint32 display; /**< The associated display index */
|
||||||
|
Uint8 event; /**< ::SDL_DisplayEventID */
|
||||||
|
Uint8 padding1;
|
||||||
|
Uint8 padding2;
|
||||||
|
Uint8 padding3;
|
||||||
|
Sint32 data1; /**< event dependent data */
|
||||||
|
} SDL_DisplayEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Window state change event data (event.window.*)
|
* \brief Window state change event data (event.window.*)
|
||||||
*/
|
*/
|
||||||
@@ -471,6 +492,17 @@ typedef struct SDL_DropEvent
|
|||||||
} SDL_DropEvent;
|
} SDL_DropEvent;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sensor event structure (event.sensor.*)
|
||||||
|
*/
|
||||||
|
typedef struct SDL_SensorEvent
|
||||||
|
{
|
||||||
|
Uint32 type; /**< ::SDL_SENSORUPDATE */
|
||||||
|
Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */
|
||||||
|
Sint32 which; /**< The instance ID of the sensor */
|
||||||
|
float data[6]; /**< Up to 6 values from the sensor - additional values can be queried using SDL_SensorGetData() */
|
||||||
|
} SDL_SensorEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief The "quit requested" event
|
* \brief The "quit requested" event
|
||||||
*/
|
*/
|
||||||
@@ -526,6 +558,7 @@ typedef union SDL_Event
|
|||||||
{
|
{
|
||||||
Uint32 type; /**< Event type, shared with all events */
|
Uint32 type; /**< Event type, shared with all events */
|
||||||
SDL_CommonEvent common; /**< Common event data */
|
SDL_CommonEvent common; /**< Common event data */
|
||||||
|
SDL_DisplayEvent display; /**< Window event data */
|
||||||
SDL_WindowEvent window; /**< Window event data */
|
SDL_WindowEvent window; /**< Window event data */
|
||||||
SDL_KeyboardEvent key; /**< Keyboard event data */
|
SDL_KeyboardEvent key; /**< Keyboard event data */
|
||||||
SDL_TextEditingEvent edit; /**< Text editing event data */
|
SDL_TextEditingEvent edit; /**< Text editing event data */
|
||||||
@@ -542,6 +575,7 @@ typedef union SDL_Event
|
|||||||
SDL_ControllerButtonEvent cbutton; /**< Game Controller button event data */
|
SDL_ControllerButtonEvent cbutton; /**< Game Controller button event data */
|
||||||
SDL_ControllerDeviceEvent cdevice; /**< Game Controller device event data */
|
SDL_ControllerDeviceEvent cdevice; /**< Game Controller device event data */
|
||||||
SDL_AudioDeviceEvent adevice; /**< Audio device event data */
|
SDL_AudioDeviceEvent adevice; /**< Audio device event data */
|
||||||
|
SDL_SensorEvent sensor; /**< Sensor event data */
|
||||||
SDL_QuitEvent quit; /**< Quit request event data */
|
SDL_QuitEvent quit; /**< Quit request event data */
|
||||||
SDL_UserEvent user; /**< Custom event data */
|
SDL_UserEvent user; /**< Custom event data */
|
||||||
SDL_SysWMEvent syswm; /**< System dependent window event data */
|
SDL_SysWMEvent syswm; /**< System dependent window event data */
|
||||||
|
|||||||
@@ -175,6 +175,14 @@ extern DECLSPEC SDL_bool SDLCALL SDL_IsGameController(int joystick_index);
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
|
extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mapping of a game controller.
|
||||||
|
* This can be called before any controllers are opened.
|
||||||
|
*
|
||||||
|
* \return the mapping string. Must be freed with SDL_free(). Returns NULL if no mapping is available
|
||||||
|
*/
|
||||||
|
extern DECLSPEC char *SDLCALL SDL_GameControllerMappingForDeviceIndex(int joystick_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a game controller for use.
|
* Open a game controller for use.
|
||||||
* The index passed as an argument refers to the N'th game controller on the system.
|
* The index passed as an argument refers to the N'th game controller on the system.
|
||||||
@@ -196,6 +204,13 @@ extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerFromInstanceID(SDL
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
|
extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the player index of an opened game controller, or -1 if it's not available
|
||||||
|
*
|
||||||
|
* For XInput controllers this returns the XInput user index.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the USB vendor ID of an opened controller, if available.
|
* Get the USB vendor ID of an opened controller, if available.
|
||||||
* If the vendor ID isn't available this function returns 0.
|
* If the vendor ID isn't available this function returns 0.
|
||||||
@@ -345,6 +360,19 @@ SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller,
|
|||||||
extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *gamecontroller,
|
extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *gamecontroller,
|
||||||
SDL_GameControllerButton button);
|
SDL_GameControllerButton button);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger a rumble effect
|
||||||
|
* Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
|
||||||
|
*
|
||||||
|
* \param gamecontroller The controller to vibrate
|
||||||
|
* \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
|
||||||
|
* \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
|
||||||
|
* \param duration_ms The duration of the rumble effect, in milliseconds
|
||||||
|
*
|
||||||
|
* \return 0, or -1 if rumble isn't supported on this joystick
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close a controller previously opened with SDL_GameControllerOpen().
|
* Close a controller previously opened with SDL_GameControllerOpen().
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -117,6 +117,17 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/* FIXME: For SDL 2.1, adjust all the magnitude variables to be Uint16 (0xFFFF).
|
||||||
|
*
|
||||||
|
* At the moment the magnitude variables are mixed between signed/unsigned, and
|
||||||
|
* it is also not made clear that ALL of those variables expect a max of 0x7FFF.
|
||||||
|
*
|
||||||
|
* Some platforms may have higher precision than that (Linux FF, Windows XInput)
|
||||||
|
* so we should fix the inconsistency in favor of higher possible precision,
|
||||||
|
* adjusting for platforms that use different scales.
|
||||||
|
* -flibit
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \typedef SDL_Haptic
|
* \typedef SDL_Haptic
|
||||||
*
|
*
|
||||||
@@ -656,8 +667,8 @@ typedef struct SDL_HapticRamp
|
|||||||
* This struct is exclusively for the ::SDL_HAPTIC_LEFTRIGHT effect.
|
* This struct is exclusively for the ::SDL_HAPTIC_LEFTRIGHT effect.
|
||||||
*
|
*
|
||||||
* The Left/Right effect is used to explicitly control the large and small
|
* The Left/Right effect is used to explicitly control the large and small
|
||||||
* motors, commonly found in modern game controllers. One motor is high
|
* motors, commonly found in modern game controllers. The small (right) motor
|
||||||
* frequency, the other is low frequency.
|
* is high frequency, and the large (left) motor is low frequency.
|
||||||
*
|
*
|
||||||
* \sa SDL_HAPTIC_LEFTRIGHT
|
* \sa SDL_HAPTIC_LEFTRIGHT
|
||||||
* \sa SDL_HapticEffect
|
* \sa SDL_HapticEffect
|
||||||
@@ -668,7 +679,7 @@ typedef struct SDL_HapticLeftRight
|
|||||||
Uint16 type; /**< ::SDL_HAPTIC_LEFTRIGHT */
|
Uint16 type; /**< ::SDL_HAPTIC_LEFTRIGHT */
|
||||||
|
|
||||||
/* Replay */
|
/* Replay */
|
||||||
Uint32 length; /**< Duration of the effect. */
|
Uint32 length; /**< Duration of the effect in milliseconds. */
|
||||||
|
|
||||||
/* Rumble */
|
/* Rumble */
|
||||||
Uint16 large_magnitude; /**< Control of the large controller motor. */
|
Uint16 large_magnitude; /**< Control of the large controller motor. */
|
||||||
|
|||||||
@@ -262,6 +262,16 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define SDL_HINT_GRAB_KEYBOARD "SDL_GRAB_KEYBOARD"
|
#define SDL_HINT_GRAB_KEYBOARD "SDL_GRAB_KEYBOARD"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable setting the double click time, in milliseconds.
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_MOUSE_DOUBLE_CLICK_TIME "SDL_MOUSE_DOUBLE_CLICK_TIME"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable setting the double click radius, in pixels.
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS "SDL_MOUSE_DOUBLE_CLICK_RADIUS"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief A variable setting the speed scale for mouse motion, in floating point, when the mouse is not in relative mode
|
* \brief A variable setting the speed scale for mouse motion, in floating point, when the mouse is not in relative mode
|
||||||
*/
|
*/
|
||||||
@@ -329,7 +339,7 @@ extern "C" {
|
|||||||
#define SDL_HINT_IDLE_TIMER_DISABLED "SDL_IOS_IDLE_TIMER_DISABLED"
|
#define SDL_HINT_IDLE_TIMER_DISABLED "SDL_IOS_IDLE_TIMER_DISABLED"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief A variable controlling which orientations are allowed on iOS.
|
* \brief A variable controlling which orientations are allowed on iOS/Android.
|
||||||
*
|
*
|
||||||
* In some circumstances it is necessary to be able to explicitly control
|
* In some circumstances it is necessary to be able to explicitly control
|
||||||
* which UI orientations are allowed.
|
* which UI orientations are allowed.
|
||||||
@@ -465,6 +475,88 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
|
#define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable controlling whether the HIDAPI joystick drivers should be used.
|
||||||
|
*
|
||||||
|
* This variable can be set to the following values:
|
||||||
|
* "0" - HIDAPI drivers are not used
|
||||||
|
* "1" - HIDAPI drivers are used (the default)
|
||||||
|
*
|
||||||
|
* This variable is the default for all drivers, but can be overridden by the hints for specific drivers below.
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_JOYSTICK_HIDAPI "SDL_JOYSTICK_HIDAPI"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
|
||||||
|
*
|
||||||
|
* This variable can be set to the following values:
|
||||||
|
* "0" - HIDAPI driver is not used
|
||||||
|
* "1" - HIDAPI driver is used
|
||||||
|
*
|
||||||
|
* The default is the value of SDL_HINT_JOYSTICK_HIDAPI
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_JOYSTICK_HIDAPI_PS4 "SDL_JOYSTICK_HIDAPI_PS4"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable controlling whether extended input reports should be used for PS4 controllers when using the HIDAPI driver.
|
||||||
|
*
|
||||||
|
* This variable can be set to the following values:
|
||||||
|
* "0" - extended reports are not enabled (the default)
|
||||||
|
* "1" - extended reports
|
||||||
|
*
|
||||||
|
* Extended input reports allow rumble on Bluetooth PS4 controllers, but
|
||||||
|
* break DirectInput handling for applications that don't use SDL.
|
||||||
|
*
|
||||||
|
* Once extended reports are enabled, they can not be disabled without
|
||||||
|
* power cycling the controller.
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE "SDL_JOYSTICK_HIDAPI_PS4_RUMBLE"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable controlling whether the HIDAPI driver for Steam Controllers should be used.
|
||||||
|
*
|
||||||
|
* This variable can be set to the following values:
|
||||||
|
* "0" - HIDAPI driver is not used
|
||||||
|
* "1" - HIDAPI driver is used
|
||||||
|
*
|
||||||
|
* The default is the value of SDL_HINT_JOYSTICK_HIDAPI
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_JOYSTICK_HIDAPI_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable controlling whether the HIDAPI driver for Nintendo Switch controllers should be used.
|
||||||
|
*
|
||||||
|
* This variable can be set to the following values:
|
||||||
|
* "0" - HIDAPI driver is not used
|
||||||
|
* "1" - HIDAPI driver is used
|
||||||
|
*
|
||||||
|
* The default is the value of SDL_HINT_JOYSTICK_HIDAPI
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_JOYSTICK_HIDAPI_SWITCH "SDL_JOYSTICK_HIDAPI_SWITCH"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable controlling whether the HIDAPI driver for XBox controllers should be used.
|
||||||
|
*
|
||||||
|
* This variable can be set to the following values:
|
||||||
|
* "0" - HIDAPI driver is not used
|
||||||
|
* "1" - HIDAPI driver is used
|
||||||
|
*
|
||||||
|
* The default is the value of SDL_HINT_JOYSTICK_HIDAPI
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX "SDL_JOYSTICK_HIDAPI_XBOX"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
|
||||||
|
*
|
||||||
|
* The variable can be set to the following values:
|
||||||
|
* "0" - Do not scan for Steam Controllers
|
||||||
|
* "1" - Scan for Steam Controllers (the default)
|
||||||
|
*
|
||||||
|
* The default value is "1". This hint must be set before initializing the joystick subsystem.
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_ENABLE_STEAM_CONTROLLERS "SDL_ENABLE_STEAM_CONTROLLERS"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief If set to "0" then never set the top most bit on a SDL Window, even if the video mode expects it.
|
* \brief If set to "0" then never set the top most bit on a SDL Window, even if the video mode expects it.
|
||||||
* This is a debugging aid for developers and not expected to be used by end users. The default is "1"
|
* This is a debugging aid for developers and not expected to be used by end users. The default is "1"
|
||||||
@@ -527,6 +619,10 @@ extern "C" {
|
|||||||
* This is specially useful if you build SDL against a non glibc libc library (such as musl) which
|
* This is specially useful if you build SDL against a non glibc libc library (such as musl) which
|
||||||
* provides a relatively small default thread stack size (a few kilobytes versus the default 8MB glibc uses).
|
* provides a relatively small default thread stack size (a few kilobytes versus the default 8MB glibc uses).
|
||||||
* Support for this hint is currently available only in the pthread, Windows, and PSP backend.
|
* Support for this hint is currently available only in the pthread, Windows, and PSP backend.
|
||||||
|
*
|
||||||
|
* Instead of this hint, in 2.0.9 and later, you can use
|
||||||
|
* SDL_CreateThreadWithStackSize(). This hint only works with the classic
|
||||||
|
* SDL_CreateThread().
|
||||||
*/
|
*/
|
||||||
#define SDL_HINT_THREAD_STACK_SIZE "SDL_THREAD_STACK_SIZE"
|
#define SDL_HINT_THREAD_STACK_SIZE "SDL_THREAD_STACK_SIZE"
|
||||||
|
|
||||||
@@ -752,6 +848,23 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"
|
#define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A variable to control whether we trap the Android back button to handle it manually.
|
||||||
|
* This is necessary for the right mouse button to work on some Android devices, or
|
||||||
|
* to be able to trap the back button for use in your code reliably. If set to true,
|
||||||
|
* the back button will show up as an SDL_KEYDOWN / SDL_KEYUP pair with a keycode of
|
||||||
|
* SDL_SCANCODE_AC_BACK.
|
||||||
|
*
|
||||||
|
* The variable can be set to the following values:
|
||||||
|
* "0" - Back button will be handled as usual for system. (default)
|
||||||
|
* "1" - Back button will be trapped, allowing you to handle the key press
|
||||||
|
* manually. (This will also let right mouse click work on systems
|
||||||
|
* where the right mouse button functions as back.)
|
||||||
|
*
|
||||||
|
* The value of this hint is used at runtime, so it can be changed at any time.
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_ANDROID_TRAP_BACK_BUTTON "SDL_ANDROID_TRAP_BACK_BUTTON"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief A variable to control whether the return key on the soft keyboard
|
* \brief A variable to control whether the return key on the soft keyboard
|
||||||
* should hide the soft keyboard on Android and iOS.
|
* should hide the soft keyboard on Android and iOS.
|
||||||
|
|||||||
@@ -97,10 +97,10 @@ typedef enum
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
SDL_JOYSTICK_POWER_UNKNOWN = -1,
|
SDL_JOYSTICK_POWER_UNKNOWN = -1,
|
||||||
SDL_JOYSTICK_POWER_EMPTY,
|
SDL_JOYSTICK_POWER_EMPTY, /* <= 5% */
|
||||||
SDL_JOYSTICK_POWER_LOW,
|
SDL_JOYSTICK_POWER_LOW, /* <= 20% */
|
||||||
SDL_JOYSTICK_POWER_MEDIUM,
|
SDL_JOYSTICK_POWER_MEDIUM, /* <= 70% */
|
||||||
SDL_JOYSTICK_POWER_FULL,
|
SDL_JOYSTICK_POWER_FULL, /* <= 100% */
|
||||||
SDL_JOYSTICK_POWER_WIRED,
|
SDL_JOYSTICK_POWER_WIRED,
|
||||||
SDL_JOYSTICK_POWER_MAX
|
SDL_JOYSTICK_POWER_MAX
|
||||||
} SDL_JoystickPowerLevel;
|
} SDL_JoystickPowerLevel;
|
||||||
@@ -132,6 +132,12 @@ extern DECLSPEC int SDLCALL SDL_NumJoysticks(void);
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index);
|
extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the player index of a joystick, or -1 if it's not available
|
||||||
|
* This can be called before any joysticks are opened.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_JoystickGetDevicePlayerIndex(int device_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the GUID for the joystick at this index
|
* Return the GUID for the joystick at this index
|
||||||
* This can be called before any joysticks are opened.
|
* This can be called before any joysticks are opened.
|
||||||
@@ -194,6 +200,13 @@ extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromInstanceID(SDL_JoystickID
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick * joystick);
|
extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick * joystick);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the player index of an opened joystick, or -1 if it's not available
|
||||||
|
*
|
||||||
|
* For XInput controllers this returns the XInput user index.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the GUID for this opened joystick
|
* Return the GUID for this opened joystick
|
||||||
*/
|
*/
|
||||||
@@ -361,6 +374,19 @@ extern DECLSPEC int SDLCALL SDL_JoystickGetBall(SDL_Joystick * joystick,
|
|||||||
extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
|
extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
|
||||||
int button);
|
int button);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger a rumble effect
|
||||||
|
* Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
|
||||||
|
*
|
||||||
|
* \param joystick The joystick to vibrate
|
||||||
|
* \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
|
||||||
|
* \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
|
||||||
|
* \param duration_ms The duration of the rumble effect, in milliseconds
|
||||||
|
*
|
||||||
|
* \return 0, or -1 if rumble isn't supported on this joystick
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close a joystick previously opened with SDL_JoystickOpen().
|
* Close a joystick previously opened with SDL_JoystickOpen().
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#define SDL_REVISION "hg-11914:f1084c419f33"
|
#define SDL_REVISION "hg-0:aaaaaaaaaaah"
|
||||||
#define SDL_REVISION_NUMBER 11914
|
#define SDL_REVISION_NUMBER 0
|
||||||
|
|||||||
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file SDL_sensor.h
|
||||||
|
*
|
||||||
|
* Include file for SDL sensor event handling
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SDL_sensor_h
|
||||||
|
#define _SDL_sensor_h
|
||||||
|
|
||||||
|
#include "SDL_stdinc.h"
|
||||||
|
#include "SDL_error.h"
|
||||||
|
|
||||||
|
#include "begin_code.h"
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
extern "C" {
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief SDL_sensor.h
|
||||||
|
*
|
||||||
|
* In order to use these functions, SDL_Init() must have been called
|
||||||
|
* with the ::SDL_INIT_SENSOR flag. This causes SDL to scan the system
|
||||||
|
* for sensors, and load appropriate drivers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct _SDL_Sensor;
|
||||||
|
typedef struct _SDL_Sensor SDL_Sensor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a unique ID for a sensor for the time it is connected to the system,
|
||||||
|
* and is never reused for the lifetime of the application.
|
||||||
|
*
|
||||||
|
* The ID value starts at 0 and increments from there. The value -1 is an invalid ID.
|
||||||
|
*/
|
||||||
|
typedef Sint32 SDL_SensorID;
|
||||||
|
|
||||||
|
/* The different sensors defined by SDL
|
||||||
|
*
|
||||||
|
* Additional sensors may be available, using platform dependent semantics.
|
||||||
|
*
|
||||||
|
* Hare are the additional Android sensors:
|
||||||
|
* https://developer.android.com/reference/android/hardware/SensorEvent.html#values
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SDL_SENSOR_INVALID = -1, /**< Returned for an invalid sensor */
|
||||||
|
SDL_SENSOR_UNKNOWN, /**< Unknown sensor type */
|
||||||
|
SDL_SENSOR_ACCEL, /**< Accelerometer */
|
||||||
|
SDL_SENSOR_GYRO /**< Gyroscope */
|
||||||
|
} SDL_SensorType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accelerometer sensor
|
||||||
|
*
|
||||||
|
* The accelerometer returns the current acceleration in SI meters per
|
||||||
|
* second squared. This includes gravity, so a device at rest will have
|
||||||
|
* an acceleration of SDL_STANDARD_GRAVITY straight down.
|
||||||
|
*
|
||||||
|
* values[0]: Acceleration on the x axis
|
||||||
|
* values[1]: Acceleration on the y axis
|
||||||
|
* values[2]: Acceleration on the z axis
|
||||||
|
*
|
||||||
|
* For phones held in portrait mode, the axes are defined as follows:
|
||||||
|
* -X ... +X : left ... right
|
||||||
|
* -Y ... +Y : bottom ... top
|
||||||
|
* -Z ... +Z : farther ... closer
|
||||||
|
*
|
||||||
|
* The axis data is not changed when the phone is rotated.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetDisplayOrientation()
|
||||||
|
*/
|
||||||
|
#define SDL_STANDARD_GRAVITY 9.80665f
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gyroscope sensor
|
||||||
|
*
|
||||||
|
* The gyroscope returns the current rate of rotation in radians per second.
|
||||||
|
* The rotation is positive in the counter-clockwise direction. That is,
|
||||||
|
* an observer looking from a positive location on one of the axes would
|
||||||
|
* see positive rotation on that axis when it appeared to be rotating
|
||||||
|
* counter-clockwise.
|
||||||
|
*
|
||||||
|
* values[0]: Angular speed around the x axis
|
||||||
|
* values[1]: Angular speed around the y axis
|
||||||
|
* values[2]: Angular speed around the z axis
|
||||||
|
*
|
||||||
|
* For phones held in portrait mode, the axes are defined as follows:
|
||||||
|
* -X ... +X : left ... right
|
||||||
|
* -Y ... +Y : bottom ... top
|
||||||
|
* -Z ... +Z : farther ... closer
|
||||||
|
*
|
||||||
|
* The axis data is not changed when the phone is rotated.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetDisplayOrientation()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Function prototypes */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Count the number of sensors attached to the system right now
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_NumSensors(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the implementation dependent name of a sensor.
|
||||||
|
*
|
||||||
|
* This can be called before any sensors are opened.
|
||||||
|
*
|
||||||
|
* \return The sensor name, or NULL if device_index is out of range.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC const char *SDLCALL SDL_SensorGetDeviceName(int device_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the type of a sensor.
|
||||||
|
*
|
||||||
|
* This can be called before any sensors are opened.
|
||||||
|
*
|
||||||
|
* \return The sensor type, or SDL_SENSOR_INVALID if device_index is out of range.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_SensorType SDLCALL SDL_SensorGetDeviceType(int device_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the platform dependent type of a sensor.
|
||||||
|
*
|
||||||
|
* This can be called before any sensors are opened.
|
||||||
|
*
|
||||||
|
* \return The sensor platform dependent type, or -1 if device_index is out of range.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_SensorGetDeviceNonPortableType(int device_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the instance ID of a sensor.
|
||||||
|
*
|
||||||
|
* This can be called before any sensors are opened.
|
||||||
|
*
|
||||||
|
* \return The sensor instance ID, or -1 if device_index is out of range.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_SensorID SDLCALL SDL_SensorGetDeviceInstanceID(int device_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Open a sensor for use.
|
||||||
|
*
|
||||||
|
* The index passed as an argument refers to the N'th sensor on the system.
|
||||||
|
*
|
||||||
|
* \return A sensor identifier, or NULL if an error occurred.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_Sensor *SDLCALL SDL_SensorOpen(int device_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the SDL_Sensor associated with an instance id.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_Sensor *SDLCALL SDL_SensorFromInstanceID(SDL_SensorID instance_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the implementation dependent name of a sensor.
|
||||||
|
*
|
||||||
|
* \return The sensor name, or NULL if the sensor is NULL.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC const char *SDLCALL SDL_SensorGetName(SDL_Sensor *sensor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the type of a sensor.
|
||||||
|
*
|
||||||
|
* This can be called before any sensors are opened.
|
||||||
|
*
|
||||||
|
* \return The sensor type, or SDL_SENSOR_INVALID if the sensor is NULL.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_SensorType SDLCALL SDL_SensorGetType(SDL_Sensor *sensor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the platform dependent type of a sensor.
|
||||||
|
*
|
||||||
|
* This can be called before any sensors are opened.
|
||||||
|
*
|
||||||
|
* \return The sensor platform dependent type, or -1 if the sensor is NULL.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_SensorGetNonPortableType(SDL_Sensor *sensor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the instance ID of a sensor.
|
||||||
|
*
|
||||||
|
* This can be called before any sensors are opened.
|
||||||
|
*
|
||||||
|
* \return The sensor instance ID, or -1 if the sensor is NULL.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_SensorID SDLCALL SDL_SensorGetInstanceID(SDL_Sensor *sensor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current state of an opened sensor.
|
||||||
|
*
|
||||||
|
* The number of values and interpretation of the data is sensor dependent.
|
||||||
|
*
|
||||||
|
* \param sensor The sensor to query
|
||||||
|
* \param data A pointer filled with the current sensor state
|
||||||
|
* \param num_values The number of values to write to data
|
||||||
|
*
|
||||||
|
* \return 0 or -1 if an error occurred.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_SensorGetData(SDL_Sensor * sensor, float *data, int num_values);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a sensor previously opened with SDL_SensorOpen()
|
||||||
|
*/
|
||||||
|
extern DECLSPEC void SDLCALL SDL_SensorClose(SDL_Sensor * sensor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the current state of the open sensors.
|
||||||
|
*
|
||||||
|
* This is called automatically by the event loop if sensor events are enabled.
|
||||||
|
*
|
||||||
|
* This needs to be called from the thread that initialized the sensor subsystem.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC void SDLCALL SDL_SensorUpdate(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
}
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
#endif
|
||||||
|
#include "close_code.h"
|
||||||
|
|
||||||
|
#endif /* _SDL_sensor_h */
|
||||||
|
|
||||||
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
@@ -86,6 +86,28 @@
|
|||||||
#ifdef HAVE_FLOAT_H
|
#ifdef HAVE_FLOAT_H
|
||||||
# include <float.h>
|
# include <float.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_ALLOCA) && !defined(alloca)
|
||||||
|
# if defined(HAVE_ALLOCA_H)
|
||||||
|
# include <alloca.h>
|
||||||
|
# elif defined(__GNUC__)
|
||||||
|
# define alloca __builtin_alloca
|
||||||
|
# elif defined(_MSC_VER)
|
||||||
|
# include <malloc.h>
|
||||||
|
# define alloca _alloca
|
||||||
|
# elif defined(__WATCOMC__)
|
||||||
|
# include <malloc.h>
|
||||||
|
# elif defined(__BORLANDC__)
|
||||||
|
# include <malloc.h>
|
||||||
|
# elif defined(__DMC__)
|
||||||
|
# include <stdlib.h>
|
||||||
|
# elif defined(__AIX__)
|
||||||
|
#pragma alloca
|
||||||
|
# elif defined(__MRC__)
|
||||||
|
void *alloca(unsigned);
|
||||||
|
# else
|
||||||
|
char *alloca();
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of elements in an array.
|
* The number of elements in an array.
|
||||||
@@ -328,28 +350,6 @@ SDL_COMPILE_TIME_ASSERT(enum, sizeof(SDL_DUMMY_ENUM) == sizeof(int));
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_ALLOCA) && !defined(alloca)
|
|
||||||
# if defined(HAVE_ALLOCA_H)
|
|
||||||
# include <alloca.h>
|
|
||||||
# elif defined(__GNUC__)
|
|
||||||
# define alloca __builtin_alloca
|
|
||||||
# elif defined(_MSC_VER)
|
|
||||||
# include <malloc.h>
|
|
||||||
# define alloca _alloca
|
|
||||||
# elif defined(__WATCOMC__)
|
|
||||||
# include <malloc.h>
|
|
||||||
# elif defined(__BORLANDC__)
|
|
||||||
# include <malloc.h>
|
|
||||||
# elif defined(__DMC__)
|
|
||||||
# include <stdlib.h>
|
|
||||||
# elif defined(__AIX__)
|
|
||||||
#pragma alloca
|
|
||||||
# elif defined(__MRC__)
|
|
||||||
void *alloca(unsigned);
|
|
||||||
# else
|
|
||||||
char *alloca();
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_ALLOCA
|
#ifdef HAVE_ALLOCA
|
||||||
#define SDL_stack_alloc(type, count) (type*)alloca(sizeof(type)*(count))
|
#define SDL_stack_alloc(type, count) (type*)alloca(sizeof(type)*(count))
|
||||||
#define SDL_stack_free(data)
|
#define SDL_stack_free(data)
|
||||||
@@ -445,12 +445,12 @@ SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern DECLSPEC void *SDLCALL SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
|
extern DECLSPEC void *SDLCALL SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
|
||||||
|
|
||||||
extern DECLSPEC void *SDLCALL SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
|
extern DECLSPEC void *SDLCALL SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
|
||||||
extern DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len);
|
extern DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len);
|
||||||
|
|
||||||
|
extern DECLSPEC wchar_t *SDLCALL SDL_wcsdup(const wchar_t *wstr);
|
||||||
extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t *wstr);
|
extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t *wstr);
|
||||||
extern DECLSPEC size_t SDLCALL SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
|
extern DECLSPEC size_t SDLCALL SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
|
||||||
extern DECLSPEC size_t SDLCALL SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
|
extern DECLSPEC size_t SDLCALL SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
|
||||||
@@ -514,6 +514,8 @@ extern DECLSPEC double SDLCALL SDL_copysign(double x, double y);
|
|||||||
extern DECLSPEC float SDLCALL SDL_copysignf(float x, float y);
|
extern DECLSPEC float SDLCALL SDL_copysignf(float x, float y);
|
||||||
extern DECLSPEC double SDLCALL SDL_cos(double x);
|
extern DECLSPEC double SDLCALL SDL_cos(double x);
|
||||||
extern DECLSPEC float SDLCALL SDL_cosf(float x);
|
extern DECLSPEC float SDLCALL SDL_cosf(float x);
|
||||||
|
extern DECLSPEC double SDLCALL SDL_exp(double x);
|
||||||
|
extern DECLSPEC float SDLCALL SDL_expf(float x);
|
||||||
extern DECLSPEC double SDLCALL SDL_fabs(double x);
|
extern DECLSPEC double SDLCALL SDL_fabs(double x);
|
||||||
extern DECLSPEC float SDLCALL SDL_fabsf(float x);
|
extern DECLSPEC float SDLCALL SDL_fabsf(float x);
|
||||||
extern DECLSPEC double SDLCALL SDL_floor(double x);
|
extern DECLSPEC double SDLCALL SDL_floor(double x);
|
||||||
|
|||||||
@@ -248,6 +248,13 @@ extern DECLSPEC int SDLCALL SDL_SetSurfaceRLE(SDL_Surface * surface,
|
|||||||
extern DECLSPEC int SDLCALL SDL_SetColorKey(SDL_Surface * surface,
|
extern DECLSPEC int SDLCALL SDL_SetColorKey(SDL_Surface * surface,
|
||||||
int flag, Uint32 key);
|
int flag, Uint32 key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns whether the surface has a color key
|
||||||
|
*
|
||||||
|
* \return SDL_TRUE if the surface has a color key, or SDL_FALSE if the surface is NULL or has no color key
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_bool SDLCALL SDL_HasColorKey(SDL_Surface * surface);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Gets the color key (transparent pixel) in a blittable surface.
|
* \brief Gets the color key (transparent pixel) in a blittable surface.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -76,6 +76,18 @@ extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *a
|
|||||||
#endif /* __WIN32__ */
|
#endif /* __WIN32__ */
|
||||||
|
|
||||||
|
|
||||||
|
/* Platform specific functions for Linux */
|
||||||
|
#ifdef __LINUX__
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Sets the UNIX nice value for a thread, using setpriority() if possible, and RealtimeKit if available.
|
||||||
|
|
||||||
|
\return 0 on success, or -1 on error.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_LinuxSetThreadPriority(Sint64 threadID, int priority);
|
||||||
|
|
||||||
|
#endif /* __LINUX__ */
|
||||||
|
|
||||||
/* Platform specific functions for iOS */
|
/* Platform specific functions for iOS */
|
||||||
#if defined(__IPHONEOS__) && __IPHONEOS__
|
#if defined(__IPHONEOS__) && __IPHONEOS__
|
||||||
|
|
||||||
@@ -113,6 +125,21 @@ extern DECLSPEC void * SDLCALL SDL_AndroidGetActivity(void);
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_bool SDLCALL SDL_IsAndroidTV(void);
|
extern DECLSPEC SDL_bool SDLCALL SDL_IsAndroidTV(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Return true if the application is running on a Chromebook
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_bool SDLCALL SDL_IsChromebook(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Return true is the application is running on a Samsung DeX docking station
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_bool SDLCALL SDL_IsDeXMode(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Trigger the Android system back button behavior.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC void SDLCALL SDL_AndroidBackButton(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
See the official Android developer guide for more information:
|
See the official Android developer guide for more information:
|
||||||
http://developer.android.com/guide/topics/data/data-storage.html
|
http://developer.android.com/guide/topics/data/data-storage.html
|
||||||
@@ -236,6 +263,11 @@ extern DECLSPEC SDL_WinRT_DeviceFamily SDLCALL SDL_WinRTGetDeviceFamily();
|
|||||||
|
|
||||||
#endif /* __WINRT__ */
|
#endif /* __WINRT__ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Return true if the current device is a tablet.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_bool SDLCALL SDL_IsTablet(void);
|
||||||
|
|
||||||
/* Ends C function definitions when using C++ */
|
/* Ends C function definitions when using C++ */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,12 +33,6 @@
|
|||||||
#include "SDL_video.h"
|
#include "SDL_video.h"
|
||||||
#include "SDL_version.h"
|
#include "SDL_version.h"
|
||||||
|
|
||||||
#include "begin_code.h"
|
|
||||||
/* Set up for C function definitions, even when using C++ */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \file SDL_syswm.h
|
* \file SDL_syswm.h
|
||||||
*
|
*
|
||||||
@@ -110,6 +104,12 @@ typedef void *EGLSurface;
|
|||||||
#include "SDL_egl.h"
|
#include "SDL_egl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "begin_code.h"
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These are the various supported windowing subsystems
|
* These are the various supported windowing subsystems
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -54,12 +54,13 @@ typedef unsigned int SDL_TLSID;
|
|||||||
/**
|
/**
|
||||||
* The SDL thread priority.
|
* The SDL thread priority.
|
||||||
*
|
*
|
||||||
* \note On many systems you require special privileges to set high priority.
|
* \note On many systems you require special privileges to set high or time critical priority.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SDL_THREAD_PRIORITY_LOW,
|
SDL_THREAD_PRIORITY_LOW,
|
||||||
SDL_THREAD_PRIORITY_NORMAL,
|
SDL_THREAD_PRIORITY_NORMAL,
|
||||||
SDL_THREAD_PRIORITY_HIGH
|
SDL_THREAD_PRIORITY_HIGH,
|
||||||
|
SDL_THREAD_PRIORITY_TIME_CRITICAL
|
||||||
} SDL_ThreadPriority;
|
} SDL_ThreadPriority;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,14 +106,24 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
|
|||||||
pfnSDL_CurrentBeginThread pfnBeginThread,
|
pfnSDL_CurrentBeginThread pfnBeginThread,
|
||||||
pfnSDL_CurrentEndThread pfnEndThread);
|
pfnSDL_CurrentEndThread pfnEndThread);
|
||||||
|
|
||||||
|
extern DECLSPEC SDL_Thread *SDLCALL
|
||||||
|
SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
|
||||||
|
const char *name, const size_t stacksize, void *data,
|
||||||
|
pfnSDL_CurrentBeginThread pfnBeginThread,
|
||||||
|
pfnSDL_CurrentEndThread pfnEndThread);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a thread.
|
* Create a thread.
|
||||||
*/
|
*/
|
||||||
#if defined(SDL_CreateThread) && SDL_DYNAMIC_API
|
#if defined(SDL_CreateThread) && SDL_DYNAMIC_API
|
||||||
#undef SDL_CreateThread
|
#undef SDL_CreateThread
|
||||||
#define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
|
#define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
|
||||||
|
#undef SDL_CreateThreadWithStackSize
|
||||||
|
#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
|
||||||
#else
|
#else
|
||||||
#define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
|
#define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
|
||||||
|
#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(__OS2__)
|
#elif defined(__OS2__)
|
||||||
@@ -132,15 +143,31 @@ extern DECLSPEC SDL_Thread *SDLCALL
|
|||||||
SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
|
SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
|
||||||
pfnSDL_CurrentBeginThread pfnBeginThread,
|
pfnSDL_CurrentBeginThread pfnBeginThread,
|
||||||
pfnSDL_CurrentEndThread pfnEndThread);
|
pfnSDL_CurrentEndThread pfnEndThread);
|
||||||
|
extern DECLSPEC SDL_Thread *SDLCALL
|
||||||
|
SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data,
|
||||||
|
pfnSDL_CurrentBeginThread pfnBeginThread,
|
||||||
|
pfnSDL_CurrentEndThread pfnEndThread);
|
||||||
#if defined(SDL_CreateThread) && SDL_DYNAMIC_API
|
#if defined(SDL_CreateThread) && SDL_DYNAMIC_API
|
||||||
#undef SDL_CreateThread
|
#undef SDL_CreateThread
|
||||||
#define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
|
#define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
|
||||||
|
#undef SDL_CreateThreadWithStackSize
|
||||||
|
#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
|
||||||
#else
|
#else
|
||||||
#define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
|
#define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
|
||||||
|
#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a thread with a default stack size.
|
||||||
|
*
|
||||||
|
* This is equivalent to calling:
|
||||||
|
* SDL_CreateThreadWithStackSize(fn, name, 0, data);
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_Thread *SDLCALL
|
||||||
|
SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a thread.
|
* Create a thread.
|
||||||
*
|
*
|
||||||
@@ -158,9 +185,17 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
|
|||||||
* If a system imposes requirements, SDL will try to munge the string for
|
* If a system imposes requirements, SDL will try to munge the string for
|
||||||
* it (truncate, etc), but the original string contents will be available
|
* it (truncate, etc), but the original string contents will be available
|
||||||
* from SDL_GetThreadName().
|
* from SDL_GetThreadName().
|
||||||
|
*
|
||||||
|
* The size (in bytes) of the new stack can be specified. Zero means "use
|
||||||
|
* the system default" which might be wildly different between platforms
|
||||||
|
* (x86 Linux generally defaults to eight megabytes, an embedded device
|
||||||
|
* might be a few kilobytes instead).
|
||||||
|
*
|
||||||
|
* In SDL 2.1, stacksize will be folded into the original SDL_CreateThread
|
||||||
|
* function.
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_Thread *SDLCALL
|
extern DECLSPEC SDL_Thread *SDLCALL
|
||||||
SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
|
SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ typedef struct SDL_version
|
|||||||
*/
|
*/
|
||||||
#define SDL_MAJOR_VERSION 2
|
#define SDL_MAJOR_VERSION 2
|
||||||
#define SDL_MINOR_VERSION 0
|
#define SDL_MINOR_VERSION 0
|
||||||
#define SDL_PATCHLEVEL 8
|
#define SDL_PATCHLEVEL 9
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Macro to determine SDL version program was compiled against.
|
* \brief Macro to determine SDL version program was compiled against.
|
||||||
|
|||||||
@@ -169,6 +169,24 @@ typedef enum
|
|||||||
SDL_WINDOWEVENT_HIT_TEST /**< Window had a hit test that wasn't SDL_HITTEST_NORMAL. */
|
SDL_WINDOWEVENT_HIT_TEST /**< Window had a hit test that wasn't SDL_HITTEST_NORMAL. */
|
||||||
} SDL_WindowEventID;
|
} SDL_WindowEventID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Event subtype for display events
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SDL_DISPLAYEVENT_NONE, /**< Never used */
|
||||||
|
SDL_DISPLAYEVENT_ORIENTATION /**< Display orientation has changed to data1 */
|
||||||
|
} SDL_DisplayEventID;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SDL_ORIENTATION_UNKNOWN, /**< The display orientation can't be determined */
|
||||||
|
SDL_ORIENTATION_LANDSCAPE, /**< The display is in landscape mode, with the right side up, relative to portrait mode */
|
||||||
|
SDL_ORIENTATION_LANDSCAPE_FLIPPED, /**< The display is in landscape mode, with the left side up, relative to portrait mode */
|
||||||
|
SDL_ORIENTATION_PORTRAIT, /**< The display is in portrait mode */
|
||||||
|
SDL_ORIENTATION_PORTRAIT_FLIPPED /**< The display is in portrait mode, upside down */
|
||||||
|
} SDL_DisplayOrientation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief An opaque handle to an OpenGL context.
|
* \brief An opaque handle to an OpenGL context.
|
||||||
*/
|
*/
|
||||||
@@ -316,18 +334,6 @@ extern DECLSPEC const char * SDLCALL SDL_GetDisplayName(int displayIndex);
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
|
extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the dots/pixels-per-inch for a display
|
|
||||||
*
|
|
||||||
* \note Diagonal, horizontal and vertical DPI can all be optionally
|
|
||||||
* returned if the parameter is non-NULL.
|
|
||||||
*
|
|
||||||
* \return 0 on success, or -1 if no DPI information is available or the index is out of range.
|
|
||||||
*
|
|
||||||
* \sa SDL_GetNumVideoDisplays()
|
|
||||||
*/
|
|
||||||
extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get the usable desktop area represented by a display, with the
|
* \brief Get the usable desktop area represented by a display, with the
|
||||||
* primary display located at 0,0
|
* primary display located at 0,0
|
||||||
@@ -347,6 +353,27 @@ extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, fl
|
|||||||
*/
|
*/
|
||||||
extern DECLSPEC int SDLCALL SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect);
|
extern DECLSPEC int SDLCALL SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the dots/pixels-per-inch for a display
|
||||||
|
*
|
||||||
|
* \note Diagonal, horizontal and vertical DPI can all be optionally
|
||||||
|
* returned if the parameter is non-NULL.
|
||||||
|
*
|
||||||
|
* \return 0 on success, or -1 if no DPI information is available or the index is out of range.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetNumVideoDisplays()
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the orientation of a display
|
||||||
|
*
|
||||||
|
* \return The orientation of the display, or SDL_ORIENTATION_UNKNOWN if it isn't available.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetNumVideoDisplays()
|
||||||
|
*/
|
||||||
|
extern DECLSPEC SDL_DisplayOrientation SDLCALL SDL_GetDisplayOrientation(int displayIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Returns the number of available display modes.
|
* \brief Returns the number of available display modes.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -135,11 +135,11 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
|
|||||||
* \brief Get the names of the Vulkan instance extensions needed to create
|
* \brief Get the names of the Vulkan instance extensions needed to create
|
||||||
* a surface with \c SDL_Vulkan_CreateSurface().
|
* a surface with \c SDL_Vulkan_CreateSurface().
|
||||||
*
|
*
|
||||||
* \param [in] window Window for which the required Vulkan instance
|
* \param [in] \c NULL or window Window for which the required Vulkan instance
|
||||||
* extensions should be retrieved
|
* extensions should be retrieved
|
||||||
* \param [in,out] count pointer to an \c unsigned related to the number of
|
* \param [in,out] pCount pointer to an \c unsigned related to the number of
|
||||||
* required Vulkan instance extensions
|
* required Vulkan instance extensions
|
||||||
* \param [out] names \c NULL or a pointer to an array to be filled with the
|
* \param [out] pNames \c NULL or a pointer to an array to be filled with the
|
||||||
* required Vulkan instance extensions
|
* required Vulkan instance extensions
|
||||||
*
|
*
|
||||||
* \return \c SDL_TRUE on success, \c SDL_FALSE on error.
|
* \return \c SDL_TRUE on success, \c SDL_FALSE on error.
|
||||||
@@ -153,6 +153,10 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
|
|||||||
* is smaller than the number of required extensions, \c SDL_FALSE will be
|
* is smaller than the number of required extensions, \c SDL_FALSE will be
|
||||||
* returned instead of \c SDL_TRUE, to indicate that not all the required
|
* returned instead of \c SDL_TRUE, to indicate that not all the required
|
||||||
* extensions were returned.
|
* extensions were returned.
|
||||||
|
*
|
||||||
|
* \note If \c window is not NULL, it will be checked against its creation
|
||||||
|
* flags to ensure that the Vulkan flag is present. This parameter
|
||||||
|
* will be removed in a future major release.
|
||||||
*
|
*
|
||||||
* \note The returned list of extensions will contain \c VK_KHR_surface
|
* \note The returned list of extensions will contain \c VK_KHR_surface
|
||||||
* and zero or more platform specific extensions
|
* and zero or more platform specific extensions
|
||||||
@@ -160,12 +164,13 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
|
|||||||
* \note The extension names queried here must be enabled when calling
|
* \note The extension names queried here must be enabled when calling
|
||||||
* VkCreateInstance, otherwise surface creation will fail.
|
* VkCreateInstance, otherwise surface creation will fail.
|
||||||
*
|
*
|
||||||
* \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag.
|
* \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag
|
||||||
|
* or be \c NULL
|
||||||
*
|
*
|
||||||
* \code
|
* \code
|
||||||
* unsigned int count;
|
* unsigned int count;
|
||||||
* // get count of required extensions
|
* // get count of required extensions
|
||||||
* if(!SDL_Vulkan_GetInstanceExtensions(window, &count, NULL))
|
* if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, NULL))
|
||||||
* handle_error();
|
* handle_error();
|
||||||
*
|
*
|
||||||
* static const char *const additionalExtensions[] =
|
* static const char *const additionalExtensions[] =
|
||||||
@@ -179,7 +184,7 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
|
|||||||
* handle_error();
|
* handle_error();
|
||||||
*
|
*
|
||||||
* // get names of required extensions
|
* // get names of required extensions
|
||||||
* if(!SDL_Vulkan_GetInstanceExtensions(window, &count, names))
|
* if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, names))
|
||||||
* handle_error();
|
* handle_error();
|
||||||
*
|
*
|
||||||
* // copy additional extensions after required extensions
|
* // copy additional extensions after required extensions
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>BuildMachineOSBuild</key>
|
<key>BuildMachineOSBuild</key>
|
||||||
<string>17C88</string>
|
<string>18E226</string>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2.0.8</string>
|
<string>2.0.9</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>SDLX</string>
|
<string>SDLX</string>
|
||||||
<key>CFBundleSupportedPlatforms</key>
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
@@ -27,20 +27,20 @@
|
|||||||
<string>MacOSX</string>
|
<string>MacOSX</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2.0.8</string>
|
<string>2.0.9</string>
|
||||||
<key>DTCompiler</key>
|
<key>DTCompiler</key>
|
||||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
<key>DTPlatformBuild</key>
|
<key>DTPlatformBuild</key>
|
||||||
<string>9C40b</string>
|
<string>10E1001</string>
|
||||||
<key>DTPlatformVersion</key>
|
<key>DTPlatformVersion</key>
|
||||||
<string>GM</string>
|
<string>GM</string>
|
||||||
<key>DTSDKBuild</key>
|
<key>DTSDKBuild</key>
|
||||||
<string>17C76</string>
|
<string>18E219</string>
|
||||||
<key>DTSDKName</key>
|
<key>DTSDKName</key>
|
||||||
<string>macosx10.13</string>
|
<string>macosx10.14</string>
|
||||||
<key>DTXcode</key>
|
<key>DTXcode</key>
|
||||||
<string>0920</string>
|
<string>1020</string>
|
||||||
<key>DTXcodeBuild</key>
|
<key>DTXcodeBuild</key>
|
||||||
<string>9C40b</string>
|
<string>10E1001</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
Binary file not shown.
@@ -6,7 +6,7 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>Resources/Info.plist</key>
|
<key>Resources/Info.plist</key>
|
||||||
<data>
|
<data>
|
||||||
dts8ape5zBg3+8u8BQ5kWqp9cC8=
|
R+u/+U4v4MZreoaFKEgSTferTn0=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>files2</key>
|
<key>files2</key>
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
wiqwnVgtbgjGPAOFejxz8yw7geU=
|
49nvc7QToCAQLOuQYg5d779VW3g=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
LLwzMAHn2OsCr2SVR7M71KeQf+TiJpHk/KKojzQdRlI=
|
NLgB0IPWGKfeYCtUqAAuK70AxrNGD5IUCdRh2wM0+VU=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_assert.h</key>
|
<key>Headers/SDL_assert.h</key>
|
||||||
@@ -48,11 +48,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
9uJv81fH9Op/f3sF7/GVuNYQNOc=
|
bCT1aBK06cMR6XwF8XLvtevSVAY=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
KDokTSV3kZuHCQFFrRum3VoTP1QSW2xAghjceoIArXY=
|
38oQKCI+MpwiSgdqg/YUBSB6cfzpXXnqv4oPEScXDDM=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_bits.h</key>
|
<key>Headers/SDL_bits.h</key>
|
||||||
@@ -92,22 +92,22 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
nJnfliCMDJUfOG8t4QYt5U9tFBY=
|
d/fShSScdM47JT6zVSrfULAMtpk=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
qkVvxnI+XRMTIdbzQ9tV+ERRc75r/EzWu0qRTgt5K5c=
|
hqFomi7gM/LXRjuRae5d3D/SKLBKmrPAp6TgW+OdkVg=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_config_macosx.h</key>
|
<key>Headers/SDL_config_macosx.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
D0LXp0FibaaLSE6877hbyqf2Jb8=
|
H0+NaeWz7cJLtW/LjkuWlCT2/oE=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
pCQLXwJ6HaGZiG5vr9njJtgNcIV9p0mxcSJtYoj147A=
|
skiBjJo1Yq2nen+FcO3Pxy4PjWbcUdDKF8p72tPBrpw=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_copying.h</key>
|
<key>Headers/SDL_copying.h</key>
|
||||||
@@ -125,11 +125,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
2wleDfJFmCBrEssrE9rcuaiqOLQ=
|
Nw8KCHXkAAuqJAvJOv+SWhZGEhU=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
MEpF0mFQFLhuTV+5uSB++q8tT2z5heESxyP1HuzuKxc=
|
0eRfEAH+V/dL+6GHKmkbzcmeR9nISfmjBGcoOn8J9J8=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_endian.h</key>
|
<key>Headers/SDL_endian.h</key>
|
||||||
@@ -158,11 +158,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
ptgRA0IBsCg5za/lwhTOPGNmekY=
|
szOypQL+tBWkumW9xkwm5kpiGCE=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
lwISPqzee6nV4HCHaMzZCVJJAtFZmoi8cYlJkY41wKA=
|
Iz2fuclzBbpDLa+Dq/Eq8MupiacS6vcB2AWrbvzWinM=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_filesystem.h</key>
|
<key>Headers/SDL_filesystem.h</key>
|
||||||
@@ -180,11 +180,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
sUaSBwOprX7A696W6u2oOtIne+Y=
|
Y46TpYRoYCHK4qV9HMp76Vj6jB8=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
VZDstHk/V+tZik3q3xnDCAG3AfA+BoHk9lB406mKtxU=
|
5cmyPcoPpG+9ZJCq4n1GsKirMlwU1NNi0dLGL7qH6qI=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_gesture.h</key>
|
<key>Headers/SDL_gesture.h</key>
|
||||||
@@ -202,33 +202,33 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
95rNclZzbsuV6pyeG8cbIETgS84=
|
aNb86XMA8j7OVT9j3ReBkzfOvzI=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
O4RUmC9HMqsjAf22Ru6z5j9HaYTsc7SxOnzOXPR3kz0=
|
8QEdekDVr5cLtobUqsj19TtgOspGlP/2vlVCx1L+xcs=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_hints.h</key>
|
<key>Headers/SDL_hints.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
UjEgXfZiLUmQTh9G+Bkx8Y1Ov6k=
|
wO6x0FskYQ3YXeNo8nC4fUuwVF0=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
DqFPmBXNg9BovdIAlipnBKZo5mcQJCrLmhyIM/O+tvU=
|
6V1lCUmwIWOAqq2OQ23J1/VhfbzwDnlQZPWTlhojfa4=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_joystick.h</key>
|
<key>Headers/SDL_joystick.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
97SJSCx+xjRHUQ6ilndhP8TZ110=
|
iMGs3U89FHkp1B8fAL14WyLC4Is=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
xYWL+BS5f9NGr7eeP+vL0kD5K6O99PXgOWLT2Bx2dRQ=
|
bUyUDarySk37tfBr5tn+rYVIboNQ8aSXAujz55F6HZo=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_keyboard.h</key>
|
<key>Headers/SDL_keyboard.h</key>
|
||||||
@@ -488,11 +488,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
XBn2NI8Qm53MeZGaXVB3fQrs0uc=
|
ixjPDg2DQUEDn7ID2l4wMHDUvDk=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
FHG6Lqi1wMmjow+JjxKYy/LAoqP+iDH8QYuJS1zr6T4=
|
LUUZKxelLmuZXjHwFWFSYH8HA96Px1JVmtuv79n+gYY=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_rwops.h</key>
|
<key>Headers/SDL_rwops.h</key>
|
||||||
@@ -517,6 +517,17 @@
|
|||||||
5VaZC9IfMuNgz3h6OJn9Q/IGB/+cpymxIrjkluCWzOo=
|
5VaZC9IfMuNgz3h6OJn9Q/IGB/+cpymxIrjkluCWzOo=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>Headers/SDL_sensor.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash</key>
|
||||||
|
<data>
|
||||||
|
Be7Gy5/r1i7xekMvnpx2rligsYU=
|
||||||
|
</data>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
E/d0hIQ2nn69Cryv+nT2Hr+JmWa2ETnsBgE/JpJ36uc=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
<key>Headers/SDL_shape.h</key>
|
<key>Headers/SDL_shape.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
@@ -532,55 +543,55 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
qBTB0Yqh+34vD3n3dN9ry9GwqJM=
|
Z0uzAbGiXidgebOz6idDVTr7qtc=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
TDMriI0PPYF73lvh6suExzpMldCmX1SkLgg+wkBqt7A=
|
JMXREkpaKMdzh4IgZzSHyp5vbIaa3IjvgFjfUzDN6Y4=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_surface.h</key>
|
<key>Headers/SDL_surface.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
bssTKTIF4Yw/3a6fyF7GhaVrdU0=
|
xCVDDdRmW3XjJfDaMiKm/c9oQlM=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
zRF/b8bCqjClZnbPorqjhlWw9aujM9RwnVemHyiC2yM=
|
IzrFWzZUTMjqUmCN5fCPOQuJuhE5P0NMUWtqfHJGWz4=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_system.h</key>
|
<key>Headers/SDL_system.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
n2WodCV+WpbfpFSKUUKpB/i5ZPw=
|
gfiAZLnsMKtcBY30ygv+FLGYBeE=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
3W0Z/Fdwbc7dTyR+v4g6eVE58XcEYLTzDGO+RMwcmJc=
|
8mRRFbV80FDAFMhJcJBBLuMOEzRZlaK9BaFNLvaZdFQ=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_syswm.h</key>
|
<key>Headers/SDL_syswm.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
QoebSqgb1XslKPBwMiUOM6daVKo=
|
lBCQTJ7UvTA5qYKTiEpsqFTGXHo=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
rCqmdvdibhT5MBOnvKCT0gK7Howb5uLewC321yLYr5U=
|
NVDqg+40pJZm/xBJTcr2sQFRQrov9a14KBJ07lfbwgs=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_thread.h</key>
|
<key>Headers/SDL_thread.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
fXCWQD4MIniqvdB6pWVwlxNS9jk=
|
6gQ6df2RG9ffNYRQj6PwIE732BE=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
18iJ1yFzOTeiM30JwK3GMlbgUqzNDIQiw3ZLLr3M+XQ=
|
b7aDhH9W57nyn9u+xXrlA2kJVj91wFAAafUP07nphY0=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_timer.h</key>
|
<key>Headers/SDL_timer.h</key>
|
||||||
@@ -620,33 +631,33 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
nKLee2vSNZZK9p94Up9o87OoiDE=
|
n/L/bdSBJArMDPWwOU5CABfDXtE=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
F3dpo9XlvebIS2NLJ1ovH+W7fG3bzb01F8OKUeqd+U0=
|
of5yxPHtdFdC8JwFB7ULi195Ws4KbiM1l/WjB8Y2Os8=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_video.h</key>
|
<key>Headers/SDL_video.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
UFZPU1U3CDog3RBKdd5wu9LFQZk=
|
DwvB/tKrFg/8GMK9DWe7RYPVCDo=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
6/OCq92BIQnGHBLmlGX4nUNnfLM7LzPoMp+lPlYY4ew=
|
yBnTX5Y53PXTHttQX3YGhklBGQc/uUzL2ntHnjxM4DE=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/SDL_vulkan.h</key>
|
<key>Headers/SDL_vulkan.h</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
eLdIezOR2pV1ai5rLBrtiR3NAok=
|
i1vRVTlmtbM2IJt9r8QO8MOL8eI=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
iCB8avj2P0+ZkjVGfTchu5BAd7BJ+LeC1fJ9BU+80IE=
|
EKCF9MU8qtxJHzJRCp0Zk2krWF631/jBU58TFGyfxcw=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Headers/begin_code.h</key>
|
<key>Headers/begin_code.h</key>
|
||||||
@@ -675,11 +686,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<data>
|
<data>
|
||||||
dts8ape5zBg3+8u8BQ5kWqp9cC8=
|
R+u/+U4v4MZreoaFKEgSTferTn0=
|
||||||
</data>
|
</data>
|
||||||
<key>hash2</key>
|
<key>hash2</key>
|
||||||
<data>
|
<data>
|
||||||
ZCgx1szeVwObsPiq6VoZh8Q9ym7l+7WXzv0HTSoFT0U=
|
IRZvZMEiRywMETq3zPZTAHg/qtglFprMndUohrhHyFI=
|
||||||
</data>
|
</data>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
Submodule moonlight-common-c/moonlight-common-c updated: d6971983aa...4a82762118
@@ -9,11 +9,14 @@ QT -= core gui
|
|||||||
TARGET = moonlight-common-c
|
TARGET = moonlight-common-c
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
|
||||||
# Support debug and release builds from command line for CI
|
# Build a static library
|
||||||
CONFIG += debug_and_release
|
CONFIG += staticlib
|
||||||
|
|
||||||
# Ensure symbols are always generated
|
# Disable warnings
|
||||||
CONFIG += force_debug_info
|
CONFIG += warn_off
|
||||||
|
|
||||||
|
# Include global qmake defs
|
||||||
|
include(../globaldefs.pri)
|
||||||
|
|
||||||
win32 {
|
win32 {
|
||||||
INCLUDEPATH += $$PWD/../libs/windows/include
|
INCLUDEPATH += $$PWD/../libs/windows/include
|
||||||
@@ -65,7 +68,6 @@ INCLUDEPATH += \
|
|||||||
$$RS_DIR \
|
$$RS_DIR \
|
||||||
$$ENET_DIR/include \
|
$$ENET_DIR/include \
|
||||||
$$COMMON_C_DIR/src
|
$$COMMON_C_DIR/src
|
||||||
CONFIG += warn_off staticlib
|
|
||||||
DEFINES += HAS_SOCKLEN_T
|
DEFINES += HAS_SOCKLEN_T
|
||||||
|
|
||||||
CONFIG(debug, debug|release) {
|
CONFIG(debug, debug|release) {
|
||||||
|
|||||||
+1
-1
Submodule qmdnsengine/qmdnsengine updated: 7d81424763...40646208d0
@@ -4,11 +4,17 @@ QT += network
|
|||||||
TARGET = qmdnsengine
|
TARGET = qmdnsengine
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
|
||||||
# Support debug and release builds from command line for CI
|
# Build a static library
|
||||||
CONFIG += debug_and_release
|
CONFIG += staticlib
|
||||||
|
|
||||||
# Ensure symbols are always generated
|
# Disable warnings
|
||||||
CONFIG += force_debug_info
|
CONFIG += warn_off
|
||||||
|
|
||||||
|
# C++11 is required to build
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
# Include global qmake defs
|
||||||
|
include(../globaldefs.pri)
|
||||||
|
|
||||||
QMDNSE_DIR = $$PWD/qmdnsengine/src
|
QMDNSE_DIR = $$PWD/qmdnsengine/src
|
||||||
DEFINES += \
|
DEFINES += \
|
||||||
@@ -66,5 +72,3 @@ SOURCES += \
|
|||||||
INCLUDEPATH += \
|
INCLUDEPATH += \
|
||||||
$$QMDNSE_DIR/include \
|
$$QMDNSE_DIR/include \
|
||||||
$$PWD/qmdnsengine
|
$$PWD/qmdnsengine
|
||||||
|
|
||||||
CONFIG += warn_off staticlib c++11
|
|
||||||
|
|||||||
+22
-2
@@ -49,10 +49,30 @@ cp $SOURCE_ROOT/libs/mac/lib/*.dylib $BUILD_FOLDER/app/Moonlight.app/Contents/li
|
|||||||
echo Creating app bundle
|
echo Creating app bundle
|
||||||
EXTRA_ARGS=
|
EXTRA_ARGS=
|
||||||
if [ "$BUILD_CONFIG" == "Debug" ]; then EXTRA_ARGS="$EXTRA_ARGS -use-debug-libs"; fi
|
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
|
echo Extra deployment arguments: $EXTRA_ARGS
|
||||||
macdeployqt $BUILD_FOLDER/app/Moonlight.app $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!"
|
||||||
|
|
||||||
|
if [ "$SIGNING_KEY" != "" ]; then
|
||||||
|
echo Signing app bundle
|
||||||
|
codesign --force --deep --options runtime --timestamp --sign $SIGNING_KEY $BUILD_FOLDER/app/Moonlight.app || fail "Signing failed!"
|
||||||
|
fi
|
||||||
|
|
||||||
echo Creating DMG
|
echo Creating DMG
|
||||||
create-dmg $BUILD_FOLDER/app/Moonlight.app $INSTALLER_FOLDER || fail "create-dmg failed!"
|
create-dmg $BUILD_FOLDER/app/Moonlight.app $INSTALLER_FOLDER || fail "create-dmg failed!"
|
||||||
mv $INSTALLER_FOLDER/Moonlight\ $VERSION.dmg $INSTALLER_FOLDER/Moonlight-$VERSION.dmg
|
|
||||||
|
if [ "$NOTARY_USERNAME" != "" ] && [ "$NOTARY_PASSWORD" != "" ]; then
|
||||||
|
echo Uploading to App Notary service
|
||||||
|
xcrun altool -t osx -f $INSTALLER_FOLDER/Moonlight\ $VERSION.dmg --primary-bundle-id com.moonlight-stream.Moonlight --notarize-app --username "$NOTARY_USERNAME" --password "$NOTARY_PASSWORD" --asc-provider $SIGNING_KEY || fail "Notary submission failed"
|
||||||
|
|
||||||
|
echo Waiting 5 minutes for notarization to complete
|
||||||
|
sleep 300
|
||||||
|
|
||||||
|
echo Getting notarization status
|
||||||
|
xcrun altool -t osx --notarization-history 0 --username "$NOTARY_USERNAME" --password "$NOTARY_PASSWORD" --asc-provider $SIGNING_KEY || fail "Unable to fetch notarization history!"
|
||||||
|
|
||||||
|
echo Stapling notary ticket to DMG
|
||||||
|
xcrun stapler staple -v $INSTALLER_FOLDER/Moonlight\ $VERSION.dmg || fail "Notary ticket stapling failed!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv $INSTALLER_FOLDER/Moonlight\ $VERSION.dmg $INSTALLER_FOLDER/Moonlight-$VERSION.dmg
|
||||||
|
echo Build successful
|
||||||
@@ -124,7 +124,15 @@ copy %SOURCE_ROOT%\app\SDL_GameControllerDB\gamecontrollerdb.txt %DEPLOY_FOLDER%
|
|||||||
if !ERRORLEVEL! NEQ 0 goto Error
|
if !ERRORLEVEL! NEQ 0 goto Error
|
||||||
|
|
||||||
echo Deploying Qt dependencies
|
echo Deploying Qt dependencies
|
||||||
windeployqt.exe --dir %DEPLOY_FOLDER% --%BUILD_CONFIG% --qmldir %SOURCE_ROOT%\app\gui --no-opengl-sw --no-compiler-runtime %BUILD_FOLDER%\app\%BUILD_CONFIG%\Moonlight.exe
|
windeployqt.exe --dir %DEPLOY_FOLDER% --%BUILD_CONFIG% --qmldir %SOURCE_ROOT%\app\gui --no-opengl-sw --no-compiler-runtime --no-qmltooling %BUILD_FOLDER%\app\%BUILD_CONFIG%\Moonlight.exe
|
||||||
|
if !ERRORLEVEL! NEQ 0 goto Error
|
||||||
|
|
||||||
|
echo Generating QML cache
|
||||||
|
forfiles /p %DEPLOY_FOLDER% /m *.qml /s /c "cmd /c qmlcachegen.exe @path"
|
||||||
|
if !ERRORLEVEL! NEQ 0 goto Error
|
||||||
|
|
||||||
|
echo Deleting original QML files
|
||||||
|
forfiles /p %DEPLOY_FOLDER% /m *.qml /s /c "cmd /c del @path"
|
||||||
if !ERRORLEVEL! NEQ 0 goto Error
|
if !ERRORLEVEL! NEQ 0 goto Error
|
||||||
|
|
||||||
echo Harvesting files for WiX
|
echo Harvesting files for WiX
|
||||||
|
|||||||
+6
-14
@@ -9,15 +9,15 @@ QT -= core gui
|
|||||||
TARGET = soundio
|
TARGET = soundio
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
|
||||||
# Support debug and release builds from command line for CI
|
|
||||||
CONFIG += debug_and_release
|
|
||||||
|
|
||||||
# Ensure symbols are always generated
|
|
||||||
CONFIG += force_debug_info
|
|
||||||
|
|
||||||
# Build a static library
|
# Build a static library
|
||||||
CONFIG += staticlib
|
CONFIG += staticlib
|
||||||
|
|
||||||
|
# Disable warnings
|
||||||
|
CONFIG += warn_off
|
||||||
|
|
||||||
|
# Include global qmake defs
|
||||||
|
include(../globaldefs.pri)
|
||||||
|
|
||||||
# Force MSVC to compile C as C++ for atomic support
|
# Force MSVC to compile C as C++ for atomic support
|
||||||
*-msvc {
|
*-msvc {
|
||||||
QMAKE_CFLAGS += /TP
|
QMAKE_CFLAGS += /TP
|
||||||
@@ -28,9 +28,6 @@ CONFIG += staticlib
|
|||||||
QMAKE_CFLAGS += -std=gnu99
|
QMAKE_CFLAGS += -std=gnu99
|
||||||
}
|
}
|
||||||
|
|
||||||
# Disable warnings
|
|
||||||
CONFIG += warn_off
|
|
||||||
|
|
||||||
unix:!macx {
|
unix:!macx {
|
||||||
CONFIG += link_pkgconfig
|
CONFIG += link_pkgconfig
|
||||||
|
|
||||||
@@ -44,11 +41,6 @@ unix:!macx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG(release, debug|release) {
|
|
||||||
# Disable asserts on release builds
|
|
||||||
DEFINES += NDEBUG
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINES += \
|
DEFINES += \
|
||||||
SOUNDIO_STATIC_LIBRARY \
|
SOUNDIO_STATIC_LIBRARY \
|
||||||
SOUNDIO_VERSION_MAJOR=1 \
|
SOUNDIO_VERSION_MAJOR=1 \
|
||||||
|
|||||||
Reference in New Issue
Block a user