diff --git a/.github/workflows/ci-bundle.yml b/.github/workflows/ci-bundle.yml index 60a57c60237..a6642de6454 100644 --- a/.github/workflows/ci-bundle.yml +++ b/.github/workflows/ci-bundle.yml @@ -23,6 +23,10 @@ jobs: - name: Install npm dependencies run: npm install --ignore-scripts + - name: Debug install + if: always() + run: cat "${HOME}/.npm/_logs/*-debug-0.log" || true + - name: Build env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index e869692a451..1c328b79783 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -29,6 +29,11 @@ jobs: arch: x86_64 msystem: ucrt64 toolchain: ucrt-x86_64 + - name: Windows-ARM64 + os: windows-11-arm + arch: aarch64 + msystem: clangarm64 + toolchain: clang-aarch64 steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -46,7 +51,9 @@ jobs: - name: Update Windows dependencies env: - MSYSTEM: ${{ matrix.msystem }} + # MSYSTEM is a built-in environment variable of MSYS2. + # Do not use this environment variable name. + MATRIX_MSYSTEM: ${{ matrix.msystem }} TOOLCHAIN: ${{ matrix.toolchain }} shell: msys2 {0} run: | @@ -62,17 +69,22 @@ jobs: "mingw-w64-${TOOLCHAIN}-curl-winssl" "mingw-w64-${TOOLCHAIN}-gcc" "mingw-w64-${TOOLCHAIN}-graphviz" - "mingw-w64-${TOOLCHAIN}-MinHook" "mingw-w64-${TOOLCHAIN}-miniupnpc" "mingw-w64-${TOOLCHAIN}-nlohmann-json" "mingw-w64-${TOOLCHAIN}-nodejs" - "mingw-w64-${TOOLCHAIN}-nsis" "mingw-w64-${TOOLCHAIN}-onevpl" "mingw-w64-${TOOLCHAIN}-openssl" "mingw-w64-${TOOLCHAIN}-opus" "mingw-w64-${TOOLCHAIN}-toolchain" ) + if [[ "${MATRIX_MSYSTEM}" == "ucrt64" ]]; then + dependencies+=( + "mingw-w64-${TOOLCHAIN}-MinHook" + "mingw-w64-${TOOLCHAIN}-nsis" + ) + fi + # do not modify below this line ignore_packages=() @@ -83,7 +95,7 @@ jobs: tarball="${pkg}-${version}-any.pkg.tar.zst" # download working version - wget "https://repo.msys2.org/mingw/${MSYSTEM}/${tarball}" + wget "https://repo.msys2.org/mingw/${MATRIX_MSYSTEM}/${tarball}" tarballs="${tarballs} ${tarball}" done @@ -169,17 +181,24 @@ jobs: echo "::remove-matcher owner=gcc::" - name: Package Windows + env: + # MSYSTEM is a built-in environment variable of MSYS2. + # Do not use this environment variable name. + # if MSYSTEM is used, it interferes with environment and cpack cannot be found. + MATRIX_MSYSTEM: ${{ matrix.msystem }} shell: msys2 {0} run: | mkdir -p artifacts cd build - # package - cpack -G NSIS - cpack -G ZIP + # nsis installer + if [[ "${MATRIX_MSYSTEM}" == "ucrt64" ]]; then + cpack -G NSIS + mv ./cpack_artifacts/Sunshine.exe ../artifacts/Sunshine-${{ matrix.name }}-installer.exe + fi - # move - mv ./cpack_artifacts/Sunshine.exe ../artifacts/Sunshine-${{ matrix.name }}-installer.exe + # portable version + cpack -G ZIP mv ./cpack_artifacts/Sunshine.zip ../artifacts/Sunshine-${{ matrix.name }}-portable.zip - name: Run tests diff --git a/cmake/compile_definitions/windows.cmake b/cmake/compile_definitions/windows.cmake index c1a2c95fc45..0e49e8e47f0 100644 --- a/cmake/compile_definitions/windows.cmake +++ b/cmake/compile_definitions/windows.cmake @@ -9,6 +9,13 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") # gcc complains about misleading indentation in some mingw includes list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-misleading-indentation) +# Disable warnings for Windows ARM64 +if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64") + list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-dll-attribute-on-redeclaration) # Boost + list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-unknown-warning-option) # ViGEmClient + list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-unused-variable) # Boost +endif() + # see gcc bug 98723 add_definitions(-DUSE_BOOST_REGEX) @@ -89,7 +96,6 @@ list(PREPEND PLATFORM_LIBRARIES libssp.a libstdc++.a libwinpthread.a - minhook::minhook ntdll setupapi shlwapi @@ -99,6 +105,12 @@ list(PREPEND PLATFORM_LIBRARIES wsock32 ) +if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64") + list(APPEND PLATFORM_LIBRARIES + minhook::minhook + ) +endif() + if(SUNSHINE_ENABLE_TRAY) list(APPEND PLATFORM_TARGET_FILES "${CMAKE_SOURCE_DIR}/third-party/tray/src/tray_windows.c") diff --git a/cmake/dependencies/windows.cmake b/cmake/dependencies/windows.cmake index 3faad7dfd41..3527418bd17 100644 --- a/cmake/dependencies/windows.cmake +++ b/cmake/dependencies/windows.cmake @@ -1,9 +1,11 @@ # windows specific dependencies -# Make sure MinHook is installed -find_library(MINHOOK_LIBRARY libMinHook.a REQUIRED) -find_path(MINHOOK_INCLUDE_DIR MinHook.h PATH_SUFFIXES include REQUIRED) +if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64") + # Make sure MinHook is installed + find_library(MINHOOK_LIBRARY libMinHook.a REQUIRED) + find_path(MINHOOK_INCLUDE_DIR MinHook.h PATH_SUFFIXES include REQUIRED) -add_library(minhook::minhook STATIC IMPORTED) -set_property(TARGET minhook::minhook PROPERTY IMPORTED_LOCATION ${MINHOOK_LIBRARY}) -target_include_directories(minhook::minhook INTERFACE ${MINHOOK_INCLUDE_DIR}) + add_library(minhook::minhook STATIC IMPORTED) + set_property(TARGET minhook::minhook PROPERTY IMPORTED_LOCATION ${MINHOOK_LIBRARY}) + target_include_directories(minhook::minhook INTERFACE ${MINHOOK_INCLUDE_DIR}) +endif() diff --git a/docs/building.md b/docs/building.md index 67b2066cd49..1323be7359d 100644 --- a/docs/building.md +++ b/docs/building.md @@ -126,33 +126,52 @@ sudo port install "${dependencies[@]}" ``` #### Windows -First you need to install [MSYS2](https://www.msys2.org), then startup "MSYS2 UCRT64" and execute the following -commands. + +@warning{Cross-compilation is not supported on Windows. You must build on the target architecture.} + +First, you need to install [MSYS2](https://www.msys2.org). + +For AMD64 startup "MSYS2 UCRT64" (or for ARM64 startup "MSYS2 CLANGARM64") then execute the following commands. ##### Update all packages ```bash pacman -Syu ``` +##### Set toolchain variable +For UCRT64: +```bash +export TOOLCHAIN="ucrt-x86_64" +``` + +For CLANGARM64: +```bash +export TOOLCHAIN="clang-aarch64" +``` + ##### Install dependencies ```bash dependencies=( "git" - "mingw-w64-ucrt-x86_64-boost" # Optional - "mingw-w64-ucrt-x86_64-cmake" - "mingw-w64-ucrt-x86_64-cppwinrt" - "mingw-w64-ucrt-x86_64-curl-winssl" - "mingw-w64-ucrt-x86_64-doxygen" # Optional, for docs... better to install official Doxygen - "mingw-w64-ucrt-x86_64-graphviz" # Optional, for docs - "mingw-w64-ucrt-x86_64-MinHook" - "mingw-w64-ucrt-x86_64-miniupnpc" - "mingw-w64-ucrt-x86_64-nodejs" - "mingw-w64-ucrt-x86_64-nsis" - "mingw-w64-ucrt-x86_64-onevpl" - "mingw-w64-ucrt-x86_64-openssl" - "mingw-w64-ucrt-x86_64-opus" - "mingw-w64-ucrt-x86_64-toolchain" + "mingw-w64-${TOOLCHAIN}-boost" # Optional + "mingw-w64-${TOOLCHAIN}-cmake" + "mingw-w64-${TOOLCHAIN}-cppwinrt" + "mingw-w64-${TOOLCHAIN}-curl-winssl" + "mingw-w64-${TOOLCHAIN}-doxygen" # Optional, for docs... better to install official Doxygen + "mingw-w64-${TOOLCHAIN}-graphviz" # Optional, for docs + "mingw-w64-${TOOLCHAIN}-miniupnpc" + "mingw-w64-${TOOLCHAIN}-nodejs" + "mingw-w64-${TOOLCHAIN}-onevpl" + "mingw-w64-${TOOLCHAIN}-openssl" + "mingw-w64-${TOOLCHAIN}-opus" + "mingw-w64-${TOOLCHAIN}-toolchain" ) +if [[ "${MSYSTEM}" == "UCRT64" ]]; then + dependencies+=( + "mingw-w64-${TOOLCHAIN}-MinHook" + "mingw-w64-${TOOLCHAIN}-nsis" + ) +fi pacman -S "${dependencies[@]}" ``` diff --git a/docs/getting_started.md b/docs/getting_started.md index d2afb2b9354..c88214009a5 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -329,10 +329,18 @@ brew uninstall sunshine ### Windows +@note{Sunshine supports ARM64 on Windows; however this should be considered experimental. This version does not properly +support GPU scheduling and any hardware acceleration.} + #### Installer (recommended) -1. Download and install - [Sunshine-Windows-AMD64-installer.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-installer.exe) +1. Download and install based on your architecture: + + | Architecture | Installer | + |-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------| + | AMD64/x64 (Intel/AMD) | [Sunshine-Windows-AMD64-installer.msi](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-installer.msi) | + | AMD64/x64 (Intel/AMD) | [Sunshine-Windows-AMD64-installer.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-installer.exe) | + | ARM64 | [Sunshine-Windows-ARM64-installer.msi](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-ARM64-installer.msi) | > [!CAUTION] > You should carefully select or unselect the options you want to install. Do not blindly install or @@ -347,8 +355,13 @@ overflow menu. Different versions of Windows may provide slightly different step > By using this package instead of the installer, performance will be reduced. This package is not > recommended for most users. No support will be provided! -1. Download and extract - [Sunshine-Windows-AMD64-portable.zip](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-portable.zip) +1. Download and extract based on your architecture: + + | Architecture | Installer | + |-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------| + | AMD64/x64 (Intel/AMD) | [Sunshine-Windows-AMD64-portable.zip](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-portable.zip) | + | ARM64 | [Sunshine-Windows-ARM64-portable.zip](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-ARM64-portable.zip) | + 2. Open command prompt as administrator 3. Firewall rules diff --git a/package.json b/package.json index 065fc6d3340..56df3046fff 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,10 @@ "@vitejs/plugin-vue": "6.0.1", "serve": "14.2.5", "vite": "6.3.6", - "vite-plugin-ejs": "1.7.0" + "vite-plugin-ejs": "1.7.0", + "@rollup/wasm-node": "4.57.1" + }, + "overrides": { + "rollup": "npm:@rollup/wasm-node@4.57.1" } } diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index 2b1d705ee7b..312c74fdec5 100755 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -695,7 +695,7 @@ elif grep -q "Debian GNU/Linux 12 (bookworm)" /etc/os-release; then cuda_version="12.9.1" cuda_build="575.57.08" gcc_version="13" - nvm_node=0 + nvm_node=1 elif grep -q "Debian GNU/Linux 13 (trixie)" /etc/os-release; then distro="debian" version="13" @@ -704,7 +704,7 @@ elif grep -q "Debian GNU/Linux 13 (trixie)" /etc/os-release; then cuda_version="12.9.1" cuda_build="575.57.08" gcc_version="14" - nvm_node=0 + nvm_node=1 elif grep -q "PLATFORM_ID=\"platform:f41\"" /etc/os-release; then distro="fedora" version="41" diff --git a/src/config.cpp b/src/config.cpp index e5d58f3eccc..c320ed6dccf 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -187,7 +187,7 @@ namespace config { }; template - std::optional quality_from_view(const std::string_view &quality_type, const std::optional(&original)) { + ::std::optional quality_from_view(const ::std::string_view &quality_type, const ::std::optional(&original)) { #define _CONVERT_(x) \ if (quality_type == #x##sv) \ return (int) T::x @@ -199,7 +199,7 @@ namespace config { } template - std::optional rc_from_view(const std::string_view &rc, const std::optional(&original)) { + ::std::optional rc_from_view(const ::std::string_view &rc, const ::std::optional(&original)) { #define _CONVERT_(x) \ if (rc == #x##sv) \ return (int) T::x @@ -212,7 +212,7 @@ namespace config { } template - std::optional usage_from_view(const std::string_view &usage, const std::optional(&original)) { + ::std::optional usage_from_view(const ::std::string_view &usage, const ::std::optional(&original)) { #define _CONVERT_(x) \ if (usage == #x##sv) \ return (int) T::x @@ -225,7 +225,7 @@ namespace config { return original; } - int coder_from_view(const std::string_view &coder) { + int coder_from_view(const ::std::string_view &coder) { if (coder == "auto"sv) { return _auto; } diff --git a/src/nvenc/nvenc_d3d11_on_cuda.h b/src/nvenc/nvenc_d3d11_on_cuda.h index 102e18097d1..80aeb9ed8f9 100644 --- a/src/nvenc/nvenc_d3d11_on_cuda.h +++ b/src/nvenc/nvenc_d3d11_on_cuda.h @@ -56,7 +56,6 @@ namespace nvenc { autopop_context push_context(); - HMODULE dll = nullptr; const ID3D11DevicePtr d3d_device; ID3D11Texture2DPtr d3d_input_texture; diff --git a/src/platform/windows/audio.cpp b/src/platform/windows/audio.cpp index d7d4680edfd..b26f91a811b 100644 --- a/src/platform/windows/audio.cpp +++ b/src/platform/windows/audio.cpp @@ -32,14 +32,14 @@ DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b #if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) #define STEAM_DRIVER_SUBDIR L"x64" -#else - #warning No known Steam audio driver for this architecture #endif namespace { constexpr auto SAMPLE_RATE = 48000; +#ifdef STEAM_DRIVER_SUBDIR constexpr auto STEAM_AUDIO_DRIVER_PATH = L"%CommonProgramFiles(x86)%\\Steam\\drivers\\Windows10\\" STEAM_DRIVER_SUBDIR L"\\SteamStreamingSpeakers.inf"; +#endif constexpr auto waveformat_mask_stereo = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; diff --git a/src/platform/windows/display_base.cpp b/src/platform/windows/display_base.cpp index e42bb8efa4b..a2e4fe6e462 100644 --- a/src/platform/windows/display_base.cpp +++ b/src/platform/windows/display_base.cpp @@ -12,7 +12,11 @@ // lib includes #include #include -#include + +// conditional includes +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) + #include +#endif // local includes #include "utf_utils.h" @@ -420,6 +424,7 @@ namespace platf::dxgi { return false; } +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) /** * @brief Hook for NtGdiDdDDIGetCachedHybridQueryValue() from win32u.dll. * @param gpuPreference A pointer to the location where the preference will be written. @@ -438,6 +443,7 @@ namespace platf::dxgi { return STATUS_INVALID_PARAMETER; } } +#endif int display_base_t::init(const ::video::config_t &config, const std::string &display_name) { std::once_flag windows_cpp_once_flag; @@ -457,12 +463,14 @@ namespace platf::dxgi { FreeLibrary(user32); } + #if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) { // We aren't calling MH_Uninitialize(), but that's okay because this hook lasts for the life of the process MH_Initialize(); MH_CreateHookApi(L"win32u.dll", "NtGdiDdDDIGetCachedHybridQueryValue", (void *) NtGdiDdDDIGetCachedHybridQueryValueHook, nullptr); MH_EnableHook(MH_ALL_HOOKS); } + #endif }); // Get rectangle of full desktop for absolute mouse coordinates diff --git a/src/platform/windows/display_vram.cpp b/src/platform/windows/display_vram.cpp index c6b694f0a35..52a87c7817d 100644 --- a/src/platform/windows/display_vram.cpp +++ b/src/platform/windows/display_vram.cpp @@ -1907,6 +1907,12 @@ namespace platf::dxgi { if (!boost::algorithm::ends_with(name, "_nvenc")) { return false; } + } else if (adapter_desc.VendorId == 0x4D4F4351 || // Qualcomm (QCOM as MOQC reversed) + adapter_desc.VendorId == 0x5143) { // Qualcomm alternate ID + // If it's not a MediaFoundation encoder, it's not compatible with a Qualcomm GPU + if (!boost::algorithm::ends_with(name, "_mf")) { + return false; + } } else { BOOST_LOG(warning) << "Unknown GPU vendor ID: " << util::hex(adapter_desc.VendorId).to_string_view(); } diff --git a/src/platform/windows/input.cpp b/src/platform/windows/input.cpp index 85273609ec5..533e3790013 100644 --- a/src/platform/windows/input.cpp +++ b/src/platform/windows/input.cpp @@ -10,6 +10,7 @@ // standard includes #include #include +#include // lib includes #include @@ -1134,9 +1135,9 @@ namespace platf { void unicode(input_t &input, char *utf8, int size) { // We can do no worse than one UTF-16 character per byte of UTF-8 - WCHAR wide[size]; + std::vector wide(size); - int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8, size, wide, size); + int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8, size, wide.data(), size); if (chars <= 0) { return; } diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 5a4ea26e709..4736a4c731c 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -9,6 +9,7 @@ #include #include #include +#include // lib includes #include @@ -1383,7 +1384,7 @@ namespace platf { auto const max_bufs_per_msg = send_info.payload_buffers.size() + (send_info.headers ? 1 : 0); - WSABUF bufs[(send_info.headers ? send_info.block_count : 1) * max_bufs_per_msg]; + std::vector bufs((send_info.headers ? send_info.block_count : 1) * max_bufs_per_msg); DWORD bufcount = 0; if (send_info.headers) { // Interleave buffers for headers and payloads @@ -1409,7 +1410,7 @@ namespace platf { } } - msg.lpBuffers = bufs; + msg.lpBuffers = bufs.data(); msg.dwBufferCount = bufcount; msg.dwFlags = 0; diff --git a/src/platform/windows/windows.rc b/src/platform/windows/windows.rc index 8f1c2bf767a..417fcf0d047 100644 --- a/src/platform/windows/windows.rc +++ b/src/platform/windows/windows.rc @@ -41,4 +41,4 @@ BEGIN END END -SuperDuperAmazing ICON DISCARDABLE PROJECT_ICON_PATH +SuperDuperAmazing ICON DISCARDABLE TOSTRING(PROJECT_ICON_PATH) diff --git a/src/video.cpp b/src/video.cpp index 0290fd95002..7487e1278e6 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -300,6 +300,7 @@ namespace video { ALWAYS_REPROBE = 1 << 9, ///< This is an encoder of last resort and we want to aggressively probe for a better one YUV444_SUPPORT = 1 << 10, ///< Encoder may support 4:4:4 chroma sampling depending on hardware ASYNC_TEARDOWN = 1 << 11, ///< Encoder supports async teardown on a different thread + FIXED_GOP_SIZE = 1 << 12, ///< Use fixed small GOP size (encoder doesn't support on-demand IDR frames) }; class avcodec_encode_session_t: public encode_session_t { @@ -825,6 +826,63 @@ namespace video { }, PARALLEL_ENCODING }; + + encoder_t mediafoundation { + "mediafoundation"sv, + std::make_unique( + AV_HWDEVICE_TYPE_D3D11VA, + AV_HWDEVICE_TYPE_NONE, + AV_PIX_FMT_D3D11, + AV_PIX_FMT_NV12, // SDR 4:2:0 8-bit (only format Qualcomm supports) + AV_PIX_FMT_NONE, // No HDR - Qualcomm MF only supports 8-bit + AV_PIX_FMT_NONE, // No YUV444 SDR + AV_PIX_FMT_NONE, // No YUV444 HDR + dxgi_init_avcodec_hardware_input_buffer + ), + { + // Common options for AV1 - Qualcomm MF encoder + { + {"hw_encoding"s, 1}, + {"rate_control"s, "cbr"s}, + {"scenario"s, "display_remoting"s}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "av1_mf"s, + }, + { + // Common options for HEVC - Qualcomm MF encoder + { + {"hw_encoding"s, 1}, + {"rate_control"s, "cbr"s}, + {"scenario"s, "display_remoting"s}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "hevc_mf"s, + }, + { + // Common options for H.264 - Qualcomm MF encoder + { + {"hw_encoding"s, 1}, + {"rate_control"s, "cbr"s}, + {"scenario"s, "display_remoting"s}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "h264_mf"s, + }, + PARALLEL_ENCODING | FIXED_GOP_SIZE // MF encoder doesn't support on-demand IDR frames + }; #endif encoder_t software { @@ -1031,6 +1089,7 @@ namespace video { #ifdef _WIN32 &quicksync, &amdvce, + &mediafoundation, #endif #if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__) &vaapi, @@ -1566,11 +1625,17 @@ namespace video { ctx->max_b_frames = 0; // Use an infinite GOP length since I-frames are generated on demand - ctx->gop_size = encoder.flags & LIMITED_GOP_SIZE ? - std::numeric_limits::max() : - std::numeric_limits::max(); - - ctx->keyint_min = std::numeric_limits::max(); + // Exception: encoders with FIXED_GOP_SIZE flag don't support on-demand IDR + if (encoder.flags & FIXED_GOP_SIZE) { + // Fixed GOP for encoders that don't support on-demand IDR (e.g. Media Foundation) + ctx->gop_size = 120; // ~2 seconds at 60 FPS - larger to reduce oversized IDR frame frequency + ctx->keyint_min = 120; + } else { + ctx->gop_size = encoder.flags & LIMITED_GOP_SIZE ? + std::numeric_limits::max() : + std::numeric_limits::max(); + ctx->keyint_min = std::numeric_limits::max(); + } // Some client decoders have limits on the number of reference frames if (config.numRefFrames) { diff --git a/src/video.h b/src/video.h index 8dbf76e27bd..eb8bb46f0dd 100644 --- a/src/video.h +++ b/src/video.h @@ -220,6 +220,7 @@ namespace video { #ifdef _WIN32 extern encoder_t amdvce; extern encoder_t quicksync; + extern encoder_t mediafoundation; #endif #if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__)