Skip to content
Merged
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
2 changes: 1 addition & 1 deletion app/backend/nvpairingmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ NvPairingManager::saltPin(const QByteArray& salt, QString pin)
NvPairingManager::PairState
NvPairingManager::pair(QString appVersion, QString pin, QSslCertificate& serverCert)
{
int serverMajorVersion = NvHTTP::parseQuad(appVersion).at(0);
int serverMajorVersion = NvHTTP::parseQuad(appVersion).value(0);
qInfo() << "Pairing with server generation:" << serverMajorVersion;

QCryptographicHash::Algorithm hashAlgo;
Expand Down
11 changes: 10 additions & 1 deletion app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,16 @@ int main(int argc, char *argv[])
#endif
{
s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch())));
if (s_LoggerFile->open(QIODevice::WriteOnly | QIODevice::Text)) {

// The log directory may be shared with other users (/tmp on macOS), so
// we must never open a file or symlink that someone else planted there.
// NewOnly fails if anything already exists at this path.
QIODevice::OpenMode logOpenMode = QIODevice::WriteOnly | QIODevice::Text | QIODevice::NewOnly;
#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
if (s_LoggerFile->open(logOpenMode, QFileDevice::ReadOwner | QFileDevice::WriteOwner)) {
#else
if (s_LoggerFile->open(logOpenMode)) {
#endif
QTextStream(stderr) << "Redirecting log output to " << s_LoggerFile->fileName() << Qt::endl;
s_LoggerStream.setDevice(s_LoggerFile);
}
Expand Down
2 changes: 1 addition & 1 deletion app/streaming/input/gamepad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ void SdlInputHandler::setAdaptiveTriggers(uint16_t controllerNumber, DualSenseOu

#if SDL_VERSION_ATLEAST(2, 0, 16)
// Make sure the controller number is within our supported count
if (controllerNumber <= MAX_GAMEPADS &&
if (controllerNumber < MAX_GAMEPADS &&
// and we have a valid controller
m_GamepadState[controllerNumber].controller != nullptr &&
// and it's a PS5 controller
Expand Down
5 changes: 2 additions & 3 deletions app/streaming/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -868,9 +868,8 @@ bool Session::initialize(QQuickWindow* qtWindow)
// to allow decoding via VideoToolbox on macOS. Since we don't
// have fixup code for HEVC, just avoid it if GFE is too old.
QVector<int> gfeVersion = NvHTTP::parseQuad(m_Computer->gfeVersion);
if (gfeVersion.isEmpty() || // Very old versions don't have GfeVersion at all
gfeVersion[0] < 3 ||
(gfeVersion[0] == 3 && gfeVersion[1] < 11)) {
if (gfeVersion.value(0) < 3 ||
(gfeVersion.value(0) == 3 && gfeVersion.value(1) < 11)) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Disabling HEVC on macOS due to old GFE version");
m_SupportedVideoFormats.removeByMask(VIDEO_FORMAT_MASK_H265);
Expand Down
6 changes: 3 additions & 3 deletions app/streaming/video/ffmpeg-renderers/d3d11va.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ D3D11VARenderer::D3D11VARenderer(int decoderSelectionPass)
m_DecoderSelectionPass(decoderSelectionPass),
m_DevicesWithFL11Support(0),
m_DevicesWithCodecSupport(0),
m_LastColorTrc(AVCOL_TRC_UNSPECIFIED),
m_SwapChainColorTrc(AVCOL_TRC_UNSPECIFIED),
m_AllowTearing(false),
m_OverlayLock(0),
m_HwDeviceContext(nullptr)
Expand Down Expand Up @@ -800,7 +800,7 @@ void D3D11VARenderer::renderFrame(AVFrame* frame)

HRESULT hr;

if (frame->color_trc != m_LastColorTrc) {
if (frame->color_trc != m_SwapChainColorTrc) {
if (frame->color_trc == AVCOL_TRC_SMPTE2084) {
// Switch to Rec 2020 PQ (SMPTE ST 2084) colorspace for HDR10 rendering
hr = m_SwapChain->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
Expand All @@ -820,7 +820,7 @@ void D3D11VARenderer::renderFrame(AVFrame* frame)
}
}

m_LastColorTrc = frame->color_trc;
m_SwapChainColorTrc = frame->color_trc;
}

// Present according to the decoder parameters
Expand Down
2 changes: 1 addition & 1 deletion app/streaming/video/ffmpeg-renderers/d3d11va.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class D3D11VARenderer : public IFFmpegRenderer
DXGI_FORMAT m_TextureFormat;
int m_DisplayWidth;
int m_DisplayHeight;
AVColorTransferCharacteristic m_LastColorTrc;
AVColorTransferCharacteristic m_SwapChainColorTrc;

bool m_AllowTearing;

Expand Down
2 changes: 1 addition & 1 deletion app/streaming/video/ffmpeg-renderers/drm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1307,7 +1307,7 @@ bool DrmRenderer::mapDumbBuffer(uint32_t handle, size_t size, void** mapping)
#else
*mapping = mmap(nullptr, size, PROT_WRITE, MAP_SHARED, m_DrmFd, mapBuf.offset);
#endif
if (mapping == MAP_FAILED) {
if (*mapping == MAP_FAILED) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"mmap() failed for dumb buffer: %d",
errno);
Expand Down
9 changes: 8 additions & 1 deletion app/streaming/video/ffmpeg-renderers/dxva2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,13 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)

D3DDISPLAYMODEEX currentMode;
currentMode.Size = sizeof(currentMode);
d3d9ex->GetAdapterDisplayModeEx(adapterIndex, &currentMode, nullptr);
hr = d3d9ex->GetAdapterDisplayModeEx(adapterIndex, &currentMode, nullptr);
if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"GetAdapterDisplayModeEx() failed: %x",
hr);
return false;
}

D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.hDeviceWindow = info.info.win.window;
Expand Down Expand Up @@ -987,6 +993,7 @@ void DXVA2Renderer::renderFrame(AVFrame *frame)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"StretchRect() failed: %x",
hr);
m_Device->EndScene();
SDL_Event event;
event.type = SDL_RENDER_DEVICE_RESET;
SDL_PushEvent(&event);
Expand Down
10 changes: 5 additions & 5 deletions app/streaming/video/ffmpeg-renderers/eglimagefactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ ssize_t EglImageFactory::exportDRMImages(AVFrame* frame, EGLDisplay dpy, EGLImag
else {
// Cast the EGLAttrib array elements to EGLint for the KHR extension
EGLint intAttribs[MAX_ATTRIB_COUNT];
for (int i = 0; i < MAX_ATTRIB_COUNT; i++) {
for (int i = 0; i < attribIndex; i++) {
intAttribs[i] = (EGLint)attribs[i];
}

Expand Down Expand Up @@ -328,7 +328,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
attribs[attribIndex++] = layer.offset[0];
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
attribs[attribIndex++] = layer.pitch[0];
if (m_EGLExtDmaBuf) {
if (m_EGLExtDmaBuf && object.drm_format_modifier != DRM_FORMAT_MOD_INVALID) {
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
Expand All @@ -343,7 +343,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
attribs[attribIndex++] = layer.offset[1];
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
attribs[attribIndex++] = layer.pitch[1];
if (m_EGLExtDmaBuf) {
if (m_EGLExtDmaBuf && object.drm_format_modifier != DRM_FORMAT_MOD_INVALID) {
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
Expand All @@ -358,7 +358,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
attribs[attribIndex++] = layer.offset[2];
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
attribs[attribIndex++] = layer.pitch[2];
if (m_EGLExtDmaBuf) {
if (m_EGLExtDmaBuf && object.drm_format_modifier != DRM_FORMAT_MOD_INVALID) {
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
Expand All @@ -373,7 +373,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
attribs[attribIndex++] = layer.offset[3];
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
attribs[attribIndex++] = layer.pitch[3];
if (m_EGLExtDmaBuf) {
if (m_EGLExtDmaBuf && object.drm_format_modifier != DRM_FORMAT_MOD_INVALID) {
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
Expand Down
20 changes: 11 additions & 9 deletions app/streaming/video/ffmpeg-renderers/eglvid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ EGLRenderer::EGLRenderer(IFFmpegRenderer *backendRenderer)
m_Window(nullptr),
m_Backend(backendRenderer),
m_VideoVAO(0),
m_VideoVBO(0),
m_BlockingSwapBuffers(false),
m_LastRenderSync(EGL_NO_SYNC),
m_glEGLImageTargetTexture2DOES(nullptr),
Expand Down Expand Up @@ -100,6 +101,7 @@ EGLRenderer::~EGLRenderer()
SDL_assert(m_glDeleteVertexArraysOES != nullptr);
m_glDeleteVertexArraysOES(1, &m_VideoVAO);
}
glDeleteBuffers(1, &m_VideoVBO);
glDeleteTextures(EGL_MAX_PLANES, m_Textures);

glDeleteTextures(Overlay::OverlayMax, m_OverlayTextures);
Expand Down Expand Up @@ -266,10 +268,9 @@ void EGLRenderer::renderOverlay(Overlay::OverlayType type, int viewportWidth, in
glDisable(GL_BLEND);
}

int EGLRenderer::loadAndBuildShader(int shaderType,
const char *file) {
GLuint EGLRenderer::loadAndBuildShader(int shaderType, const char *file) {
GLuint shader = glCreateShader(shaderType);
if (!shader || shader == GL_INVALID_ENUM) {
if (!shader) {
EGL_LOG(Error, "Can't create shader: %d", glGetError());
return 0;
}
Expand All @@ -286,6 +287,7 @@ int EGLRenderer::loadAndBuildShader(int shaderType,
char shaderLog[512];
glGetShaderInfoLog(shader, sizeof (shaderLog), nullptr, shaderLog);
EGL_LOG(Error, "Cannot load shader \"%s\": %s", file, shaderLog);
glDeleteShader(shader);
return 0;
}

Expand All @@ -297,7 +299,7 @@ unsigned EGLRenderer::compileShader(const char* vertexShaderSrc, const char* fra

GLuint vertexShader = loadAndBuildShader(GL_VERTEX_SHADER, vertexShaderSrc);
if (!vertexShader)
return false;
return 0;

GLuint fragmentShader = loadAndBuildShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);
if (!fragmentShader)
Expand Down Expand Up @@ -645,13 +647,12 @@ bool EGLRenderer::setupVideoRenderingState() {
};

// Setup the VAO and VBO
unsigned int VBO;
m_glGenVertexArraysOES(1, &m_VideoVAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &m_VideoVBO);

m_glBindVertexArrayOES(m_VideoVAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ARRAY_BUFFER, m_VideoVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// compileShader() ensures that aPosition and aTexCoord are indexes 0 and 1 respectively
Expand All @@ -663,7 +664,8 @@ bool EGLRenderer::setupVideoRenderingState() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_glBindVertexArrayOES(0);

glDeleteBuffers(1, &VBO);
// The VBO is kept alive as a member since the VAO still references it.
// It is deleted in ~EGLRenderer() alongside the other GL resources.

GLenum err = glGetError();
if (err != GL_NO_ERROR) {
Expand Down Expand Up @@ -787,7 +789,7 @@ void EGLRenderer::renderFrame(AVFrame* frame)
}

ssize_t plane_count = m_Backend->exportEGLImages(frame, m_EGLDisplay, imgs);
if (plane_count < 0)
if (plane_count <= 0)
return;
for (ssize_t i = 0; i < plane_count; ++i) {
glActiveTexture(GL_TEXTURE0 + i);
Expand Down
3 changes: 2 additions & 1 deletion app/streaming/video/ffmpeg-renderers/eglvid.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class EGLRenderer : public IFFmpegRenderer {
bool compileShaders();
bool setupVideoRenderingState();
bool setupOverlayRenderingState();
static int loadAndBuildShader(int shaderType, const char *filename);
static GLuint loadAndBuildShader(int shaderType, const char *filename);

AVPixelFormat m_EGLImagePixelFormat;
void *m_EGLDisplay;
Expand All @@ -44,6 +44,7 @@ class EGLRenderer : public IFFmpegRenderer {
SDL_Window *m_Window;
IFFmpegRenderer *m_Backend;
unsigned int m_VideoVAO;
unsigned int m_VideoVBO;
bool m_BlockingSwapBuffers;
EGLSync m_LastRenderSync;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_glEGLImageTargetTexture2DOES;
Expand Down
11 changes: 11 additions & 0 deletions app/streaming/video/ffmpeg-renderers/plvk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,7 @@ bool PlVkRenderer::populateQueues(int videoFormat)
vkDeviceContext->nb_comp_queues = m_Vulkan->queue_compute.count;

// Select a video decode queue that is capable of decoding our chosen format
vkDeviceContext->queue_family_decode_index = -1;
for (uint32_t i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFamilyProperties.queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
Expand Down Expand Up @@ -897,6 +898,16 @@ void PlVkRenderer::waitToRender()
return;
}

// If a swapchain (re)creation failed, m_Swapchain is NULL. We can't render
// or resize it, and a device reset has already been requested, so skip this
// frame and let the main thread recreate the renderer.
if (m_Swapchain == nullptr) {
SDL_Event event;
event.type = SDL_RENDER_DEVICE_RESET;
SDL_PushEvent(&event);
return;
}

#ifndef Q_OS_WIN32
// With libplacebo's Vulkan backend, all swap_buffers does is wait for queued
// presents to finish. This happens to be exactly what we want to do here, since
Expand Down
2 changes: 1 addition & 1 deletion app/streaming/video/ffmpeg-renderers/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ class IFFmpegRenderer : public Overlay::IOverlayRenderer {
#endif

protected:
InitFailureReason m_InitFailureReason;
InitFailureReason m_InitFailureReason = InitFailureReason::Unknown;

private:
RendererType m_Type;
Expand Down
5 changes: 5 additions & 0 deletions app/streaming/video/ffmpeg-renderers/vaapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
VAAPIRenderer::VAAPIRenderer(int decoderSelectionPass)
: IFFmpegRenderer(RendererType::VAAPI),
m_DecoderSelectionPass(decoderSelectionPass),
m_WindowSystem(SDL_SYSWM_UNKNOWN),
m_HwContext(nullptr),
m_BlacklistedForDirectRendering(false),
m_HasRfiLatencyBug(false),
m_RequiresExplicitPixelFormat(false),
m_OverlayMutex(nullptr)
#ifdef HAVE_EGL
Expand Down Expand Up @@ -159,6 +161,9 @@ VAAPIRenderer::openDisplay(SDL_Window* window)
errno);
return nullptr;
}
// This FD is owned by us (not shared with SDL), so it must be
// closed when we're done with it or adopted into m_DrmFd.
mustCloseFd = true;
}

// If the KMSDRM FD is not a render node FD, open the render node for libva to use.
Expand Down
10 changes: 6 additions & 4 deletions app/streaming/video/ffmpeg-renderers/vdpau.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,11 +541,12 @@ void VDPAURenderer::renderFrame(AVFrame* frame)
// We need to create the mixer on the fly, because we don't know the dimensions
// of our video surfaces in advance of decoding. We also need to recreate it when
// the frame format or size changes.
if (hasFrameFormatChanged(frame)) {
if (m_VideoMixer != 0) {
m_VdpVideoMixerDestroy(m_VideoMixer);
}
if (hasFrameFormatChanged(frame) && m_VideoMixer != 0) {
m_VdpVideoMixerDestroy(m_VideoMixer);
m_VideoMixer = 0;
}

if (m_VideoMixer == 0) {
VdpChromaType videoSurfaceChroma;
uint32_t videoSurfaceWidth, videoSurfaceHeight;
status = m_VdpVideoSurfaceGetParameters(videoSurface, &videoSurfaceChroma,
Expand Down Expand Up @@ -580,6 +581,7 @@ void VDPAURenderer::renderFrame(AVFrame* frame)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"VdpVideoMixerCreate() failed: %s",
m_VdpGetErrorString(status));
m_VideoMixer = 0;
return;
}
}
Expand Down
35 changes: 28 additions & 7 deletions app/streaming/video/ffmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1765,11 +1765,21 @@ void FFmpegVideoDecoder::writeBuffer(PLENTRY entry, int& offset)
int nalStart, nalEnd;
bool needsFixup;

// Read the old NALU
find_nal_unit((uint8_t*)entry->data, entry->length, &nalStart, &nalEnd);
read_nal_unit(stream,
(unsigned char *)&entry->data[nalStart],
nalEnd - nalStart);
// Find the old SPS NALU
if (find_nal_unit((uint8_t*)entry->data, entry->length, &nalStart, &nalEnd) <= 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Failed to find SPS");
h264_free(stream);
goto WriteUnmodifiedBuffer;
}

// Read the SPS. Pass it through unmodified if we fail to parse it.
if (read_nal_unit(stream, (uint8_t*)&entry->data[nalStart], nalEnd - nalStart) < 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Failed to read SPS");
h264_free(stream);
goto WriteUnmodifiedBuffer;
}

SDL_assert(nalStart == 3 || nalStart == 4); // 3 or 4 byte Annex B start sequence
SDL_assert(nalEnd == entry->length);
Expand Down Expand Up @@ -1802,8 +1812,18 @@ void FFmpegVideoDecoder::writeBuffer(PLENTRY entry, int& offset)

// Copy the modified NALU data. This clobbers byte 0 and starts NALU data at byte 1.
// Since it prepended one extra byte, subtract one from the returned length.
offset += write_nal_unit(stream, (uint8_t*)&m_DecodeBuffer.data()[initialOffset + nalStart - 1],
MAX_SPS_EXTRA_SIZE + entry->length - nalStart) - 1;
//
// Pass the SPS through unmodified if the write fails.
int writeLength = write_nal_unit(stream, (uint8_t*)&m_DecodeBuffer.data()[initialOffset + nalStart - 1],
MAX_SPS_EXTRA_SIZE + entry->length - nalStart);
if (writeLength < 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Failed to write modified SPS");
h264_free(stream);
goto WriteUnmodifiedBuffer;
}

offset += writeLength - 1;

// Copy the NALU prefix over from the original SPS
memcpy(&m_DecodeBuffer.data()[initialOffset], entry->data, nalStart);
Expand Down Expand Up @@ -1834,6 +1854,7 @@ void FFmpegVideoDecoder::writeBuffer(PLENTRY entry, int& offset)
h264_free(stream);
}
else {
WriteUnmodifiedBuffer:
// Write the buffer as-is
memcpy(&m_DecodeBuffer.data()[offset],
entry->data,
Expand Down
Loading
Loading