mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-06-15 21:22:40 +00:00
Add support for native resolution streaming
This commit is contained in:
@@ -43,7 +43,7 @@ ScrollView {
|
|||||||
Label {
|
Label {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
id: resFPSdesc
|
id: resFPSdesc
|
||||||
text: qsTr("Setting values too high for your PC may cause lag, stuttering, or errors")
|
text: qsTr("Setting values too high for your PC may cause lag, stuttering, or errors.")
|
||||||
font.pointSize: 9
|
font.pointSize: 9
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
color: "white"
|
color: "white"
|
||||||
@@ -55,6 +55,41 @@ ScrollView {
|
|||||||
ComboBox {
|
ComboBox {
|
||||||
// ignore setting the index at first, and actually set it when the component is loaded
|
// ignore setting the index at first, and actually set it when the component is loaded
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
// Add native resolutions for all attached displays
|
||||||
|
for (var displayIndex = 0;; displayIndex++) {
|
||||||
|
var screenRect = prefs.getDisplayResolution(displayIndex)
|
||||||
|
if (screenRect.width === 0) {
|
||||||
|
// Exceeded max count of displays
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var indexToAdd = 0
|
||||||
|
for (var j = 0; j < resolutionComboBox.count; j++) {
|
||||||
|
var existing_width = parseInt(resolutionListModel.get(j).video_width);
|
||||||
|
var existing_height = parseInt(resolutionListModel.get(j).video_height);
|
||||||
|
|
||||||
|
if (screenRect.width * screenRect.height === existing_width * existing_height) {
|
||||||
|
// Duplicate entry, skip
|
||||||
|
indexToAdd = -1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
else if (screenRect.width * screenRect.height > existing_width * existing_height) {
|
||||||
|
// Candidate entrypoint after this entry
|
||||||
|
indexToAdd = j + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert this display's resolution if it's not a duplicate
|
||||||
|
if (indexToAdd >= 0) {
|
||||||
|
resolutionListModel.insert(indexToAdd,
|
||||||
|
{
|
||||||
|
"text": "Native ("+screenRect.width+"x"+screenRect.height+")",
|
||||||
|
"video_width": ""+screenRect.width,
|
||||||
|
"video_height": ""+screenRect.height
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// load the saved width/height, and iterate through the ComboBox until a match is found
|
// load the saved width/height, and iterate through the ComboBox until a match is found
|
||||||
// and set it to that index.
|
// and set it to that index.
|
||||||
var saved_width = prefs.width
|
var saved_width = prefs.width
|
||||||
@@ -63,17 +98,21 @@ ScrollView {
|
|||||||
for (var i = 0; i < resolutionComboBox.count; i++) {
|
for (var i = 0; i < resolutionComboBox.count; i++) {
|
||||||
var el_width = parseInt(resolutionListModel.get(i).video_width);
|
var el_width = parseInt(resolutionListModel.get(i).video_width);
|
||||||
var el_height = parseInt(resolutionListModel.get(i).video_height);
|
var el_height = parseInt(resolutionListModel.get(i).video_height);
|
||||||
if (saved_width === el_width && saved_height === el_height) {
|
|
||||||
|
// Pick the highest value lesser or equal to the saved resolution
|
||||||
|
if (saved_width * saved_height >= el_width * el_height) {
|
||||||
currentIndex = i
|
currentIndex = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
id: resolutionComboBox
|
id: resolutionComboBox
|
||||||
font.pointSize: 9
|
width: 200
|
||||||
textRole: "text"
|
textRole: "text"
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
id: resolutionListModel
|
id: resolutionListModel
|
||||||
|
// Other elements may be added at runtime
|
||||||
|
// based on attached display resolution
|
||||||
ListElement {
|
ListElement {
|
||||||
text: "720p"
|
text: "720p"
|
||||||
video_width: "1280"
|
video_width: "1280"
|
||||||
@@ -121,14 +160,15 @@ ScrollView {
|
|||||||
currentIndex = 0
|
currentIndex = 0
|
||||||
for (var i = 0; i < fpsComboBox.count; i++) {
|
for (var i = 0; i < fpsComboBox.count; i++) {
|
||||||
var el_fps = parseInt(fpsListModel.get(i).video_fps);
|
var el_fps = parseInt(fpsListModel.get(i).video_fps);
|
||||||
if (el_fps === saved_fps) {
|
|
||||||
|
// Pick the highest value lesser or equal to the saved FPS
|
||||||
|
if (el_fps >= saved_fps) {
|
||||||
currentIndex = i
|
currentIndex = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
id: fpsComboBox
|
id: fpsComboBox
|
||||||
font.pointSize: 9
|
|
||||||
textRole: "text"
|
textRole: "text"
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
id: fpsListModel
|
id: fpsListModel
|
||||||
@@ -238,7 +278,6 @@ ScrollView {
|
|||||||
|
|
||||||
id: audioComboBox
|
id: audioComboBox
|
||||||
width: Math.min(bitrateDesc.implicitWidth, parent.width)
|
width: Math.min(bitrateDesc.implicitWidth, parent.width)
|
||||||
font.pointSize: 9
|
|
||||||
textRole: "text"
|
textRole: "text"
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
id: audioListModel
|
id: audioListModel
|
||||||
@@ -362,7 +401,6 @@ ScrollView {
|
|||||||
|
|
||||||
id: decoderComboBox
|
id: decoderComboBox
|
||||||
width: Math.min(bitrateDesc.implicitWidth, parent.width)
|
width: Math.min(bitrateDesc.implicitWidth, parent.width)
|
||||||
font.pointSize: 9
|
|
||||||
textRole: "text"
|
textRole: "text"
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
id: decoderListModel
|
id: decoderListModel
|
||||||
@@ -409,7 +447,6 @@ ScrollView {
|
|||||||
|
|
||||||
id: codecComboBox
|
id: codecComboBox
|
||||||
width: Math.min(bitrateDesc.implicitWidth, parent.width)
|
width: Math.min(bitrateDesc.implicitWidth, parent.width)
|
||||||
font.pointSize: 9
|
|
||||||
textRole: "text"
|
textRole: "text"
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
id: codecListModel
|
id: codecListModel
|
||||||
|
|||||||
@@ -93,15 +93,50 @@ int StreamingPreferences::getMaximumStreamingFrameRate()
|
|||||||
return maxFrameRate;
|
return maxFrameRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRect StreamingPreferences::getDisplayResolution(int displayIndex)
|
||||||
|
{
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
return QRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayIndex >= SDL_GetNumVideoDisplays()) {
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
return QRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_DisplayMode mode;
|
||||||
|
int err = SDL_GetCurrentDisplayMode(displayIndex, &mode);
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
if (err == 0) {
|
||||||
|
return QRect(0, 0, mode.w, mode.h);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_GetCurrentDisplayMode() failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
return QRect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int StreamingPreferences::getDefaultBitrate(int width, int height, int fps)
|
int StreamingPreferences::getDefaultBitrate(int width, int height, int fps)
|
||||||
{
|
{
|
||||||
if (width * height <= 1280 * 720) {
|
// This table prefers 16:10 resolutions because they are
|
||||||
|
// only slightly more pixels than the 16:9 equivalents, so
|
||||||
|
// we don't want to bump those 16:10 resolutions up to the
|
||||||
|
// next 16:9 slot.
|
||||||
|
|
||||||
|
// This covers 1280x720 and 1280x800 too
|
||||||
|
if (width * height <= 1366 * 768) {
|
||||||
return static_cast<int>(5000 * (fps / 30.0));
|
return static_cast<int>(5000 * (fps / 30.0));
|
||||||
}
|
}
|
||||||
else if (width * height <= 1920 * 1080) {
|
else if (width * height <= 1920 * 1200) {
|
||||||
return static_cast<int>(10000 * (fps / 30.0));
|
return static_cast<int>(10000 * (fps / 30.0));
|
||||||
}
|
}
|
||||||
else if (width * height <= 2560 * 1440) {
|
else if (width * height <= 2560 * 1600) {
|
||||||
return static_cast<int>(20000 * (fps / 30.0));
|
return static_cast<int>(20000 * (fps / 30.0));
|
||||||
}
|
}
|
||||||
else /* if (width * height <= 3840 * 2160) */ {
|
else /* if (width * height <= 3840 * 2160) */ {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QRect>
|
||||||
|
|
||||||
class StreamingPreferences : public QObject
|
class StreamingPreferences : public QObject
|
||||||
{
|
{
|
||||||
@@ -18,6 +19,8 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE static int getMaximumStreamingFrameRate();
|
Q_INVOKABLE static int getMaximumStreamingFrameRate();
|
||||||
|
|
||||||
|
Q_INVOKABLE QRect getDisplayResolution(int displayIndex);
|
||||||
|
|
||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
enum AudioConfig
|
enum AudioConfig
|
||||||
|
|||||||
@@ -450,6 +450,24 @@ void Session::getWindowDimensions(bool fullScreen,
|
|||||||
{
|
{
|
||||||
int displayIndex = 0;
|
int displayIndex = 0;
|
||||||
|
|
||||||
|
// If there's a display matching this exact resolution, pick that
|
||||||
|
// one (for native full-screen streaming). Otherwise, assume
|
||||||
|
// display 0 for now. TODO: Default to the screen that the Qt window is on
|
||||||
|
if (fullScreen) {
|
||||||
|
for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) {
|
||||||
|
SDL_DisplayMode mode;
|
||||||
|
if (SDL_GetCurrentDisplayMode(i, &mode) == 0 &&
|
||||||
|
m_ActiveVideoWidth == mode.w &&
|
||||||
|
m_ActiveVideoHeight == mode.h) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Found exact resolution match on display: %d",
|
||||||
|
i);
|
||||||
|
displayIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_Window != nullptr) {
|
if (m_Window != nullptr) {
|
||||||
displayIndex = SDL_GetWindowDisplayIndex(m_Window);
|
displayIndex = SDL_GetWindowDisplayIndex(m_Window);
|
||||||
if (displayIndex < 0) {
|
if (displayIndex < 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user