Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/cli/commandlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
parser.addFlagOption("1440", "2560x1440 resolution");
parser.addFlagOption("4K", "3840x2160 resolution");
parser.addValueOption("resolution", "custom <width>x<height> resolution");
parser.addToggleOption("ignore-aspect-ratio", "ignore aspect ratio");
parser.addToggleOption("vsync", "V-Sync");
parser.addValueOption("fps", "FPS");
parser.addValueOption("bitrate", "bitrate in Kbps");
Expand Down Expand Up @@ -442,6 +443,9 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
preferences->windowMode = mapValue(m_WindowModeMap, parser.getChoiceOptionValue("display-mode"));
}

// Resolve --ignore-aspect-ratio
preferences->ignoreAspectRatio = parser.getToggleOptionValue("ignore-aspect-ratio", preferences->ignoreAspectRatio);

// Resolve --vsync and --no-vsync options
preferences->enableVsync = parser.getToggleOptionValue("vsync", preferences->enableVsync);

Expand Down
17 changes: 17 additions & 0 deletions app/gui/SettingsView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,23 @@ Flickable {
ToolTip.text: qsTr("Fullscreen generally provides the best performance, but borderless windowed may work better with features like macOS Spaces, Alt+Tab, screenshot tools, on-screen overlays, etc.")
}

CheckBox {
id: ignoreAspectRatioCheck
width: parent.width
hoverEnabled: true
text: qsTr("Stretch presentation")
font.pointSize: 12
checked: StreamingPreferences.ignoreAspectRatio
onCheckedChanged: {
StreamingPreferences.ignoreAspectRatio = checked
}

ToolTip.delay: 1000
ToolTip.timeout: 12000
ToolTip.visible: hovered
ToolTip.text: qsTr("Ignores both client and host PC aspect ratios, which is required for displaying Half-SBS (Side-By-Side) 3D signals to AR/XR devices that only support Full-SBS (usually 1920x1080 per eye, meaning a total resolution of 3840x1080)")
}

CheckBox {
id: vsyncCheck
width: parent.width
Expand Down
3 changes: 3 additions & 0 deletions app/settings/streamingpreferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define SER_BITRATE "bitrate"
#define SER_UNLOCK_BITRATE "unlockbitrate"
#define SER_FULLSCREEN "fullscreen"
#define SER_IGNORE_ASPECT_RATIO "ignoreaspectratio"
#define SER_VSYNC "vsync"
#define SER_GAMEOPTS "gameopts"
#define SER_HOSTAUDIO "hostaudio"
Expand Down Expand Up @@ -122,6 +123,7 @@ void StreamingPreferences::reload()
enableYUV444 = settings.value(SER_YUV444, false).toBool();
bitrateKbps = settings.value(SER_BITRATE, getDefaultBitrate(width, height, fps, enableYUV444)).toInt();
unlockBitrate = settings.value(SER_UNLOCK_BITRATE, false).toBool();
ignoreAspectRatio = settings.value(SER_IGNORE_ASPECT_RATIO, true).toBool();
enableVsync = settings.value(SER_VSYNC, true).toBool();
gameOptimizations = settings.value(SER_GAMEOPTS, true).toBool();
playAudioOnHost = settings.value(SER_HOSTAUDIO, false).toBool();
Expand Down Expand Up @@ -312,6 +314,7 @@ void StreamingPreferences::save()
settings.setValue(SER_FPS, fps);
settings.setValue(SER_BITRATE, bitrateKbps);
settings.setValue(SER_UNLOCK_BITRATE, unlockBitrate);
settings.setValue(SER_IGNORE_ASPECT_RATIO, ignoreAspectRatio);
settings.setValue(SER_VSYNC, enableVsync);
settings.setValue(SER_GAMEOPTS, gameOptimizations);
settings.setValue(SER_HOSTAUDIO, playAudioOnHost);
Expand Down
3 changes: 3 additions & 0 deletions app/settings/streamingpreferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class StreamingPreferences : public QObject
Q_PROPERTY(int fps MEMBER fps NOTIFY displayModeChanged)
Q_PROPERTY(int bitrateKbps MEMBER bitrateKbps NOTIFY bitrateChanged)
Q_PROPERTY(bool unlockBitrate MEMBER unlockBitrate NOTIFY unlockBitrateChanged)
Q_PROPERTY(bool ignoreAspectRatio MEMBER ignoreAspectRatio NOTIFY ignoreAspectRatioChanged)
Q_PROPERTY(bool enableVsync MEMBER enableVsync NOTIFY enableVsyncChanged)
Q_PROPERTY(bool gameOptimizations MEMBER gameOptimizations NOTIFY gameOptimizationsChanged)
Q_PROPERTY(bool playAudioOnHost MEMBER playAudioOnHost NOTIFY playAudioOnHostChanged)
Expand Down Expand Up @@ -149,6 +150,7 @@ class StreamingPreferences : public QObject
int fps;
int bitrateKbps;
bool unlockBitrate;
bool ignoreAspectRatio;
bool enableVsync;
bool gameOptimizations;
bool playAudioOnHost;
Expand Down Expand Up @@ -185,6 +187,7 @@ class StreamingPreferences : public QObject
void displayModeChanged();
void bitrateChanged();
void unlockBitrateChanged();
void ignoreAspectRatioChanged();
void enableVsyncChanged();
void gameOptimizationsChanged();
void playAudioOnHostChanged();
Expand Down
23 changes: 13 additions & 10 deletions app/streaming/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ void Session::clSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g

bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
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 ignoreAspectRatio, bool testOnly, IVideoDecoder*& chosenDecoder)
{
DECODER_PARAMETERS params;

Expand All @@ -277,6 +278,7 @@ bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
params.window = window;
params.enableVsync = enableVsync;
params.enableFramePacing = enableFramePacing;
params.ignoreAspectRatio = ignoreAspectRatio;
params.testOnly = testOnly;
params.vds = vds;

Expand Down Expand Up @@ -381,7 +383,7 @@ void Session::getDecoderInfo(SDL_Window* window,
// Try an HEVC Main10 decoder first to see if we have HDR support
if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE,
window, VIDEO_FORMAT_H265_MAIN10, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, false, true, decoder)) {
isHardwareAccelerated = decoder->isHardwareAccelerated();
isFullScreenOnly = decoder->isAlwaysFullScreen();
isHdrSupported = decoder->isHdrSupported();
Expand All @@ -394,7 +396,7 @@ void Session::getDecoderInfo(SDL_Window* window,
// Try an AV1 Main10 decoder next to see if we have HDR support
if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE,
window, VIDEO_FORMAT_AV1_MAIN10, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, false, true, decoder)) {
// If we've got a working AV1 Main 10-bit decoder, we'll enable the HDR checkbox
// but we will still continue probing to get other attributes for HEVC or H.264
// decoders. See the AV1 comment at the top of the function for more info.
Expand All @@ -406,10 +408,10 @@ void Session::getDecoderInfo(SDL_Window* window,
// that supports HDR rendering with software decoded frames.
if (chooseDecoder(StreamingPreferences::VDS_FORCE_SOFTWARE,
window, VIDEO_FORMAT_H265_MAIN10, 1920, 1080, 60,
false, false, true, decoder) ||
false, false, false, true, decoder) ||
chooseDecoder(StreamingPreferences::VDS_FORCE_SOFTWARE,
window, VIDEO_FORMAT_AV1_MAIN10, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, false, true, decoder)) {
isHdrSupported = decoder->isHdrSupported();
delete decoder;
}
Expand All @@ -423,7 +425,7 @@ void Session::getDecoderInfo(SDL_Window* window,
// Try a regular hardware accelerated HEVC decoder now
if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE,
window, VIDEO_FORMAT_H265, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, false, true, decoder)) {
isHardwareAccelerated = decoder->isHardwareAccelerated();
isFullScreenOnly = decoder->isAlwaysFullScreen();
maxResolution = decoder->getDecoderMaxResolution();
Expand All @@ -436,7 +438,7 @@ void Session::getDecoderInfo(SDL_Window* window,
#if 0 // See AV1 comment at the top of this function
if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE,
window, VIDEO_FORMAT_AV1_MAIN8, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, false, true, decoder)) {
isHardwareAccelerated = decoder->isHardwareAccelerated();
isFullScreenOnly = decoder->isAlwaysFullScreen();
maxResolution = decoder->getDecoderMaxResolution();
Expand All @@ -450,7 +452,7 @@ void Session::getDecoderInfo(SDL_Window* window,
// This will fall back to software decoding, so it should always work.
if (chooseDecoder(StreamingPreferences::VDS_AUTO,
window, VIDEO_FORMAT_H264, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, false, true, decoder)) {
isHardwareAccelerated = decoder->isHardwareAccelerated();
isFullScreenOnly = decoder->isAlwaysFullScreen();
maxResolution = decoder->getDecoderMaxResolution();
Expand All @@ -470,7 +472,7 @@ Session::getDecoderAvailability(SDL_Window* window,
{
IVideoDecoder* decoder;

if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, false, false, true, decoder)) {
if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, false, false, false, true, decoder)) {
return DecoderAvailability::None;
}

Expand All @@ -491,7 +493,7 @@ bool Session::populateDecoderProperties(SDL_Window* window)
m_StreamConfig.width,
m_StreamConfig.height,
m_StreamConfig.fps,
false, false, true, decoder)) {
false, false, false, true, decoder)) {
return false;
}

Expand Down Expand Up @@ -2219,6 +2221,7 @@ void Session::execInternal()
m_ActiveVideoHeight, m_ActiveVideoFrameRate,
enableVsync,
enableVsync && m_Preferences->framePacing,
m_Preferences->ignoreAspectRatio,
false,
s_ActiveSession->m_VideoDecoder)) {
SDL_AtomicUnlock(&m_DecoderLock);
Expand Down
2 changes: 1 addition & 1 deletion app/streaming/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ class Session : public QObject
bool chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window* window, int videoFormat, int width, int height,
int frameRate, bool enableVsync, bool enableFramePacing,
bool testOnly,
bool ignoreAspectRatio, bool testOnly,
IVideoDecoder*& chosenDecoder);

static
Expand Down
1 change: 1 addition & 0 deletions app/streaming/video/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ typedef struct _DECODER_PARAMETERS {
int frameRate;
bool enableVsync;
bool enableFramePacing;
bool ignoreAspectRatio;
bool testOnly;
} DECODER_PARAMETERS, *PDECODER_PARAMETERS;

Expand Down
5 changes: 4 additions & 1 deletion app/streaming/video/ffmpeg-renderers/d3d11va.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,10 @@ bool D3D11VARenderer::setupRenderingResources()
dst.x = dst.y = 0;
dst.w = m_DisplayWidth;
dst.h = m_DisplayHeight;
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);

if (!m_DecoderParams.ignoreAspectRatio) {
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
}

// Convert screen space to normalized device coordinates
SDL_FRect renderRect;
Expand Down
7 changes: 6 additions & 1 deletion app/streaming/video/ffmpeg-renderers/plvk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,9 @@ bool PlVkRenderer::initialize(PDECODER_PARAMETERS params)
return false;
}

// Ignores aspect ratio to fill the entire screen
m_IgnoreAspectRatio = params->ignoreAspectRatio;

VkPresentModeKHR presentMode;
if (params->enableVsync) {
// FIFO mode improves frame pacing compared with Mailbox, especially for
Expand Down Expand Up @@ -841,7 +844,9 @@ void PlVkRenderer::renderFrame(AVFrame *frame)
dst.h = targetFrame.crop.y1 - targetFrame.crop.y0;

// Scale the video to the surface size while preserving the aspect ratio
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
if (!m_IgnoreAspectRatio) {
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
}

targetFrame.crop.x0 = dst.x;
targetFrame.crop.y0 = dst.y;
Expand Down
2 changes: 2 additions & 0 deletions app/streaming/video/ffmpeg-renderers/plvk.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class PlVkRenderer : public IFFmpegRenderer {
// Pending swapchain state shared between waitToRender(), renderFrame(), and cleanupRenderContext()
pl_swapchain_frame m_SwapchainFrame = {};
bool m_HasPendingSwapchainFrame = false;

bool m_IgnoreAspectRatio = false;

// Overlay state
SDL_SpinLock m_OverlayLock = 0;
Expand Down
12 changes: 10 additions & 2 deletions app/streaming/video/ffmpeg-renderers/vt_metal.mm
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@
m_LastDrawableHeight(-1),
m_PresentationMutex(SDL_CreateMutex()),
m_PresentationCond(SDL_CreateCond()),
m_PendingPresentationCount(0)
m_PendingPresentationCount(0),
m_IgnoreAspectRatio(false)
{
}

Expand Down Expand Up @@ -260,7 +261,10 @@ bool updateVideoRegionSizeForFrame(AVFrame* frame)
dst.x = dst.y = 0;
dst.w = drawableWidth;
dst.h = drawableHeight;
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);

if (!m_IgnoreAspectRatio) {
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
}

// Convert screen space to normalized device coordinates
SDL_FRect renderRect;
Expand Down Expand Up @@ -750,6 +754,9 @@ virtual bool initialize(PDECODER_PARAMETERS params) override
// Allow tearing if V-Sync is off (also requires direct display path)
m_MetalLayer.displaySyncEnabled = params->enableVsync;

// Ignores aspect ratio to fill the entire screen
m_IgnoreAspectRatio = params->ignoreAspectRatio;

// Create the Metal texture cache for our CVPixelBuffers
CFStringRef keys[1] = { kCVMetalTextureUsage };
NSUInteger values[1] = { MTLTextureUsageShaderRead };
Expand Down Expand Up @@ -939,6 +946,7 @@ bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info) override
SDL_mutex* m_PresentationMutex;
SDL_cond* m_PresentationCond;
int m_PendingPresentationCount;
bool m_IgnoreAspectRatio;
};

IFFmpegRenderer* VTMetalRendererFactory::createRenderer(bool hwAccel) {
Expand Down