From c23ea4d63c95a215aa03f1b9103e0c734010a877 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 7 Aug 2026 03:16:26 +0000 Subject: [PATCH 14/38] codec (Apple): dlopen VideoToolbox instead of linking it directly VideoToolbox doesn't exist pre-10.7; resolve VTCopyVideoEncoderList and VTIsHardwareDecodeSupported via dlopen/dlsym with RTLD_NOLOAD so the binary degrades to reporting no codecs instead of failing to link. Ported from https://github.com/macos-powerpc/powerpc-ports/blob/main/sysutils/fastfetch/files/0012-Misc-fixes-for-legacy-systems.patch --- src/detection/codec/codec_apple.c | 54 ++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/src/detection/codec/codec_apple.c b/src/detection/codec/codec_apple.c index 2cf2a48b2..dd51f981b 100644 --- a/src/detection/codec/codec_apple.c +++ b/src/detection/codec/codec_apple.c @@ -1,12 +1,46 @@ #include "codec.h" - -#include #include "common/apple/cf_helpers.h" +#include +#include +#include + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + #include +#else + /* CoreMedia is not available; define the type and constants manually. + * CMVideoCodecType is FourCharCode which is uint32_t. */ + typedef uint32_t CMVideoCodecType; +#endif + +/* Use plain uint32_t in the typedefs so they compile even without CoreMedia. */ +typedef int (*VTCopyVideoEncoderList_fn)(void*, CFArrayRef*); +typedef int (*VTIsHardwareDecodeSupported_fn)(uint32_t); + +static VTCopyVideoEncoderList_fn pVTCopyVideoEncoderList = nullptr; +static VTIsHardwareDecodeSupported_fn pVTIsHardwareDecodeSupported = nullptr; + #ifdef MAC_OS_VERSION_11_0 [[clang::weak_import]] VT_EXPORT void VTRegisterSupplementalVideoDecoderIfAvailable(CMVideoCodecType codecType); #endif +static void ffCodecLoadSymbols(void) { + static bool loaded = false; + if (loaded) return; + loaded = true; + /* RTLD_LAZY | RTLD_NOLOAD: only succeed if the framework is already present */ + void* vt = dlopen( + "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox", + RTLD_LAZY | RTLD_NOLOAD); + if (!vt) { + return; + } + pVTCopyVideoEncoderList = (VTCopyVideoEncoderList_fn) + dlsym(vt, "VTCopyVideoEncoderList"); + pVTIsHardwareDecodeSupported = (VTIsHardwareDecodeSupported_fn) + dlsym(vt, "VTIsHardwareDecodeSupported"); +} + static const struct { CMVideoCodecType codec; FFCodecType type; @@ -45,8 +79,11 @@ } static FFCodecType ffCodecDetectEncoders(void) { + if (!pVTCopyVideoEncoderList) + return FF_CODEC_TYPE_NONE; + FF_CFTYPE_AUTO_RELEASE CFArrayRef encoderList = nullptr; - if (VTCopyVideoEncoderList(nullptr, &encoderList) != noErr || !encoderList) { + if (pVTCopyVideoEncoderList(nullptr, &encoderList) != 0 || !encoderList) { return FF_CODEC_TYPE_NONE; } @@ -66,7 +103,10 @@ return types; } -static FFCodecType ffCodecDetectDecoders() { +static FFCodecType ffCodecDetectDecoders(void) { + if (!pVTIsHardwareDecodeSupported) + return FF_CODEC_TYPE_NONE; + FFCodecType types = FF_CODEC_TYPE_NONE; for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_CODECS); ++i) { auto codec = FF_CODEC_CODECS[i]; @@ -79,7 +119,7 @@ VTRegisterSupplementalVideoDecoderIfAvailable(codec.codec); } #endif - bool supported = VTIsHardwareDecodeSupported(codec.codec); + bool supported = pVTIsHardwareDecodeSupported((uint32_t) codec.codec); if (!supported) { continue; } @@ -91,6 +131,8 @@ } const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) { + ffCodecLoadSymbols(); + FFCodecType decoders = options->showType & FF_CODEC_SHOW_TYPE_DECODER ? ffCodecDetectDecoders() : FF_CODEC_TYPE_NONE; FFCodecType encoders = options->showType & FF_CODEC_SHOW_TYPE_ENCODER ? ffCodecDetectEncoders() : FF_CODEC_TYPE_NONE;