From 473a08d85cf8f1d0dfd1e51a467d5302ea40a53d Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sun, 31 May 2026 13:16:24 +0800 Subject: [PATCH] Decoder: renames to `Codec` and adds encoders detection support --- CMakeLists.txt | 20 +- src/detection/codec/codec.h | 38 ++++ src/detection/codec/codec_apple.c | 95 ++++++++ .../decoder_linux.c => codec/codec_linux.c} | 102 ++++++--- .../codec_windows.cpp} | 55 ++--- src/detection/decoder/decoder.h | 37 --- src/detection/decoder/decoder_apple.m | 51 ----- src/modules/codec/codec.c | 214 ++++++++++++++++++ src/modules/codec/codec.h | 11 + src/modules/codec/option.h | 9 + src/modules/decoder/decoder.c | 194 ---------------- src/modules/decoder/decoder.h | 11 - src/modules/decoder/option.h | 9 - src/modules/modules.c | 6 +- src/modules/modules.h | 2 +- 15 files changed, 476 insertions(+), 378 deletions(-) create mode 100644 src/detection/codec/codec.h create mode 100644 src/detection/codec/codec_apple.c rename src/detection/{decoder/decoder_linux.c => codec/codec_linux.c} (72%) rename src/detection/{decoder/decoder_windows.cpp => codec/codec_windows.cpp} (81%) delete mode 100644 src/detection/decoder/decoder.h delete mode 100644 src/detection/decoder/decoder_apple.m create mode 100644 src/modules/codec/codec.c create mode 100644 src/modules/codec/codec.h create mode 100644 src/modules/codec/option.h delete mode 100644 src/modules/decoder/decoder.c delete mode 100644 src/modules/decoder/decoder.h delete mode 100644 src/modules/decoder/option.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ed6a9160..1c7239710 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -463,6 +463,7 @@ set(LIBFASTFETCH_SRC src/modules/btrfs/btrfs.c src/modules/camera/camera.c src/modules/chassis/chassis.c + src/modules/codec/codec.c src/modules/colors/colors.c src/modules/cpu/cpu.c src/modules/cpucache/cpucache.c @@ -471,7 +472,6 @@ set(LIBFASTFETCH_SRC src/modules/custom/custom.c src/modules/command/command.c src/modules/datetime/datetime.c - src/modules/decoder/decoder.c src/modules/de/de.c src/modules/disk/disk.c src/modules/diskio/diskio.c @@ -550,11 +550,11 @@ if(LINUX) src/detection/brightness/brightness_linux.c src/detection/btrfs/btrfs_linux.c src/detection/chassis/chassis_linux.c + src/detection/codec/codec_linux.c src/detection/cpu/cpu_linux.c src/detection/cpucache/cpucache_linux.c src/detection/cpuusage/cpuusage_linux.c src/detection/cursor/cursor_linux.c - src/detection/decoder/decoder_linux.c src/detection/bluetooth/bluetooth_linux.c src/detection/bluetoothradio/bluetoothradio_linux.c src/detection/disk/disk_linux.c @@ -712,11 +712,11 @@ elseif(FreeBSD) src/detection/brightness/brightness_bsd.c src/detection/btrfs/btrfs_nosupport.c src/detection/chassis/chassis_bsd.c + src/detection/codec/codec_linux.c src/detection/cpu/cpu_bsd.c src/detection/cpucache/cpucache_shared.c src/detection/cpuusage/cpuusage_bsd.c src/detection/cursor/cursor_linux.c - src/detection/decoder/decoder_linux.c src/detection/disk/disk_bsd.c src/detection/dns/dns_linux.c src/detection/physicaldisk/physicaldisk_bsd.c @@ -807,11 +807,11 @@ elseif(NetBSD) src/detection/brightness/brightness_nbsd.c src/detection/btrfs/btrfs_nosupport.c src/detection/chassis/chassis_nbsd.c + src/detection/codec/codec_linux.c src/detection/cpu/cpu_nbsd.c src/detection/cpucache/cpucache_shared.c src/detection/cpuusage/cpuusage_bsd.c src/detection/cursor/cursor_linux.c - src/detection/decoder/decoder_linux.c src/detection/disk/disk_bsd.c src/detection/dns/dns_linux.c src/detection/physicaldisk/physicaldisk_nbsd.c @@ -892,11 +892,11 @@ elseif(OpenBSD) src/detection/brightness/brightness_obsd.c src/detection/btrfs/btrfs_nosupport.c src/detection/chassis/chassis_windows.c + src/detection/codec/codec_linux.c src/detection/cpu/cpu_obsd.c src/detection/cpucache/cpucache_shared.c src/detection/cpuusage/cpuusage_bsd.c src/detection/cursor/cursor_linux.c - src/detection/decoder/decoder_linux.c src/detection/disk/disk_bsd.c src/detection/dns/dns_linux.c src/detection/physicaldisk/physicaldisk_obsd.c @@ -976,11 +976,11 @@ elseif(APPLE) src/detection/bootmgr/bootmgr_apple.c src/detection/brightness/brightness_apple.c src/detection/btrfs/btrfs_nosupport.c + src/detection/codec/codec_apple.c src/detection/cpu/cpu_apple.c src/detection/cpucache/cpucache_apple.c src/detection/cpuusage/cpuusage_apple.c src/detection/cursor/cursor_apple.m - src/detection/decoder/decoder_apple.m src/detection/disk/disk_bsd.c src/detection/dns/dns_apple.c src/detection/physicaldisk/physicaldisk_apple.c @@ -1067,11 +1067,11 @@ elseif(WIN32) src/detection/brightness/brightness_windows.c src/detection/btrfs/btrfs_nosupport.c src/detection/chassis/chassis_windows.c + src/detection/codec/codec_windows.cpp src/detection/cpu/cpu_windows.c src/detection/cpucache/cpucache_windows.c src/detection/cpuusage/cpuusage_windows.c src/detection/cursor/cursor_windows.c - src/detection/decoder/decoder_windows.cpp src/detection/disk/disk_windows.c src/detection/physicaldisk/physicaldisk_windows.c src/detection/diskio/diskio_windows.c @@ -1139,7 +1139,7 @@ elseif(SunOS) src/detection/cursor/cursor_linux.c src/detection/bluetooth/bluetooth_nosupport.c src/detection/bluetoothradio/bluetoothradio_nosupport.c - src/detection/decoder/decoder_linux.c + src/detection/codec/codec_linux.c src/detection/disk/disk_sunos.c src/detection/dns/dns_linux.c src/detection/physicaldisk/physicaldisk_sunos.c @@ -1223,7 +1223,7 @@ elseif(Haiku) src/detection/cursor/cursor_nosupport.c src/detection/bluetooth/bluetooth_haiku.cpp src/detection/bluetoothradio/bluetoothradio_nosupport.c - src/detection/decoder/decoder_linux.c + src/detection/codec/codec_linux.c src/detection/disk/disk_haiku.cpp src/detection/dns/dns_linux.c src/detection/physicaldisk/physicaldisk_haiku.c @@ -1293,8 +1293,8 @@ elseif(GNU) src/detection/cursor/cursor_linux.c src/detection/bluetooth/bluetooth_linux.c src/detection/bluetoothradio/bluetoothradio_linux.c + src/detection/codec/codec_linux.c src/detection/disk/disk_linux.c - src/detection/decoder/decoder_linux.c src/detection/dns/dns_linux.c src/detection/physicaldisk/physicaldisk_nosupport.c src/detection/physicalmemory/physicalmemory_nosupport.c diff --git a/src/detection/codec/codec.h b/src/detection/codec/codec.h new file mode 100644 index 000000000..1e7fa72d8 --- /dev/null +++ b/src/detection/codec/codec.h @@ -0,0 +1,38 @@ +#pragma once + +#include "fastfetch.h" +#include "modules/codec/option.h" + +typedef enum FF_A_PACKED FFCodecType { + FF_CODEC_TYPE_NONE = 0, + FF_CODEC_TYPE_UNKNOWN = UINT32_C(1) << 0, + FF_CODEC_TYPE_H261 = UINT32_C(1) << 1, + FF_CODEC_TYPE_H263 = UINT32_C(1) << 2, + FF_CODEC_TYPE_MJPEG = UINT32_C(1) << 3, + FF_CODEC_TYPE_MPEG1 = UINT32_C(1) << 4, + FF_CODEC_TYPE_MPEG2 = UINT32_C(1) << 5, + FF_CODEC_TYPE_DIVX_XVID = UINT32_C(1) << 6, + FF_CODEC_TYPE_H264 = UINT32_C(1) << 7, + FF_CODEC_TYPE_WMV8 = UINT32_C(1) << 8, + FF_CODEC_TYPE_WMV9 = UINT32_C(1) << 9, + FF_CODEC_TYPE_VC1 = UINT32_C(1) << 10, + FF_CODEC_TYPE_VP8 = UINT32_C(1) << 11, + FF_CODEC_TYPE_HEVC = UINT32_C(1) << 12, + FF_CODEC_TYPE_VP9 = UINT32_C(1) << 13, + FF_CODEC_TYPE_AV1 = UINT32_C(1) << 14, + FF_CODEC_TYPE_VVC = UINT32_C(1) << 15, + FF_CODEC_TYPE_DOLBY_VISION_HEVC = UINT32_C(1) << 16, + FF_CODEC_TYPE_PRORES = UINT32_C(1) << 17, + FF_CODEC_TYPE_PRORES_RAW = UINT32_C(1) << 18, + FF_CODEC_TYPE_JPEG_XL = UINT32_C(1) << 19, + FF_CODEC_TYPE_MAX = FF_CODEC_TYPE_JPEG_XL, + FF_CODEC_TYPE_FORCE_UNSIGNED = UINT32_MAX, +} FFCodecType; + +typedef struct FFCodecResult { + FFstrbuf gpu; + FFCodecType decoders; + FFCodecType encoders; +} FFCodecResult; + +const char* ffDetectCodec(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/); diff --git a/src/detection/codec/codec_apple.c b/src/detection/codec/codec_apple.c new file mode 100644 index 000000000..81588d0ee --- /dev/null +++ b/src/detection/codec/codec_apple.c @@ -0,0 +1,95 @@ +#include "codec.h" + +#include +#include "common/apple/cf_helpers.h" + +static const struct { + CMVideoCodecType codec; + FFCodecType type; +} FF_CODEC_CODECS[] = { + { kCMVideoCodecType_H263, FF_CODEC_TYPE_H263 }, + { kCMVideoCodecType_JPEG, FF_CODEC_TYPE_MJPEG }, + { kCMVideoCodecType_JPEG_XL, FF_CODEC_TYPE_JPEG_XL }, + { kCMVideoCodecType_MPEG1Video, FF_CODEC_TYPE_MPEG1 }, + { kCMVideoCodecType_MPEG2Video, FF_CODEC_TYPE_MPEG2 }, + { kCMVideoCodecType_MPEG4Video, FF_CODEC_TYPE_DIVX_XVID }, + { kCMVideoCodecType_H264, FF_CODEC_TYPE_H264 }, + { kCMVideoCodecType_HEVC, FF_CODEC_TYPE_HEVC }, + { kCMVideoCodecType_HEVCWithAlpha, FF_CODEC_TYPE_HEVC }, + { kCMVideoCodecType_DolbyVisionHEVC, FF_CODEC_TYPE_DOLBY_VISION_HEVC }, + { kCMVideoCodecType_DisparityHEVC, FF_CODEC_TYPE_HEVC }, + { kCMVideoCodecType_DepthHEVC, FF_CODEC_TYPE_HEVC }, + { kCMVideoCodecType_VP9, FF_CODEC_TYPE_VP9 }, + { kCMVideoCodecType_AV1, FF_CODEC_TYPE_AV1 }, + { kCMVideoCodecType_AppleProRes4444XQ, FF_CODEC_TYPE_PRORES }, + { kCMVideoCodecType_AppleProRes4444, FF_CODEC_TYPE_PRORES }, + { kCMVideoCodecType_AppleProRes422HQ, FF_CODEC_TYPE_PRORES }, + { kCMVideoCodecType_AppleProRes422, FF_CODEC_TYPE_PRORES }, + { kCMVideoCodecType_AppleProRes422LT, FF_CODEC_TYPE_PRORES }, + { kCMVideoCodecType_AppleProRes422Proxy, FF_CODEC_TYPE_PRORES }, + { kCMVideoCodecType_AppleProResRAW, FF_CODEC_TYPE_PRORES_RAW }, + { kCMVideoCodecType_AppleProResRAWHQ, FF_CODEC_TYPE_PRORES_RAW }, +}; + +static FFCodecType ffCodecCodecToType(CMVideoCodecType codec) { + for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_CODECS); ++i) { + if (FF_CODEC_CODECS[i].codec == codec) { + return FF_CODEC_CODECS[i].type; + } + } + return FF_CODEC_TYPE_NONE; +} + +static FFCodecType ffCodecDetectEncoders(void) { + CFArrayRef encoderList = NULL; + if (VTCopyVideoEncoderList(NULL, &encoderList) != noErr || !encoderList) { + return FF_CODEC_TYPE_NONE; + } + + FFCodecType types = FF_CODEC_TYPE_NONE; + for (uint32_t i = 0; i < CFArrayGetCount(encoderList); ++i) { + CFDictionaryRef encoder = CFArrayGetValueAtIndex(encoderList, i); + bool isHardwareAccelerated; + int codec; + if (ffCfDictGetBool(encoder, CFSTR("IsHardwareAccelerated"), &isHardwareAccelerated) != NULL || + !isHardwareAccelerated || + ffCfDictGetInt(encoder, CFSTR("CodecType"), &codec) != NULL) { + continue; + } + types |= ffCodecCodecToType((CMVideoCodecType) codec); + } + + return types; +} + +static FFCodecType ffCodecDetectDecoders() { + FFCodecType types = FF_CODEC_TYPE_NONE; + for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_CODECS); ++i) { + if (types & FF_CODEC_CODECS[i].type) { + continue; + } + + bool supported = VTIsHardwareDecodeSupported(FF_CODEC_CODECS[i].codec); + if (!supported) { + continue; + } + + types |= FF_CODEC_CODECS[i].type; + } + + return types; +} + +const char* ffDetectCodec(FF_A_UNUSED FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) { + FFCodecType decoders = ffCodecDetectDecoders(); + FFCodecType encoders = ffCodecDetectEncoders(); + + if (decoders != FF_CODEC_TYPE_NONE || encoders != FF_CODEC_TYPE_NONE) { + FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result); + ffStrbufInitStatic(&item->gpu, "Default"); + item->decoders = decoders; + item->encoders = encoders; + } + + return NULL; +} diff --git a/src/detection/decoder/decoder_linux.c b/src/detection/codec/codec_linux.c similarity index 72% rename from src/detection/decoder/decoder_linux.c rename to src/detection/codec/codec_linux.c index 401d7c867..0db288818 100644 --- a/src/detection/decoder/decoder_linux.c +++ b/src/detection/codec/codec_linux.c @@ -1,4 +1,4 @@ -#include "decoder.h" +#include "codec.h" #if FF_HAVE_DRM && FF_HAVE_VA @@ -13,22 +13,22 @@ #include #include -static FFDecoderType ffDecoderProfileToType(VAProfile profile) { +static FFCodecType ffCodecProfileToType(VAProfile profile) { switch (profile) { case 11: // VAProfileH263Baseline - return FF_DECODER_TYPE_H263; + return FF_CODEC_TYPE_H263; case 12: // VAProfileJPEGBaseline - return FF_DECODER_TYPE_MJPEG; + return FF_CODEC_TYPE_MJPEG; case 0: // VAProfileMPEG2Simple case 1: // VAProfileMPEG2Main - return FF_DECODER_TYPE_MPEG2; + return FF_CODEC_TYPE_MPEG2; case 2: // VAProfileMPEG4Simple case 3: // VAProfileMPEG4AdvancedSimple case 4: // VAProfileMPEG4Main - return FF_DECODER_TYPE_DIVX_XVID; + return FF_CODEC_TYPE_DIVX_XVID; case 5: // VAProfileH264Baseline case 6: // VAProfileH264Main @@ -38,15 +38,15 @@ static FFDecoderType ffDecoderProfileToType(VAProfile profile) { case 16: // VAProfileH264StereoHigh case 36: // VAProfileH264High10 case 40: // VAProfileH264High422 - return FF_DECODER_TYPE_H264; + return FF_CODEC_TYPE_H264; case 8: // VAProfileVC1Simple case 9: // VAProfileVC1Main case 10: // VAProfileVC1Advanced - return FF_DECODER_TYPE_VC1; + return FF_CODEC_TYPE_VC1; case 14: // VAProfileVP8Version0_3 - return FF_DECODER_TYPE_VP8; + return FF_CODEC_TYPE_VP8; case 17: // VAProfileHEVCMain case 18: // VAProfileHEVCMain10 @@ -60,29 +60,29 @@ static FFDecoderType ffDecoderProfileToType(VAProfile profile) { case 30: // VAProfileHEVCSccMain10 case 31: // VAProfileHEVCSccMain444 case 34: // VAProfileHEVCSccMain444_10 - return FF_DECODER_TYPE_HEVC; + return FF_CODEC_TYPE_HEVC; case 19: // VAProfileVP9Profile0 case 20: // VAProfileVP9Profile1 case 21: // VAProfileVP9Profile2 case 22: // VAProfileVP9Profile3 - return FF_DECODER_TYPE_VP9; + return FF_CODEC_TYPE_VP9; case 32: // VAProfileAV1Profile0 case 33: // VAProfileAV1Profile1 case 39: // VAProfileAV1Profile2 - return FF_DECODER_TYPE_AV1; + return FF_CODEC_TYPE_AV1; case 37: // VAProfileVVCMain10 case 38: // VAProfileVVCMultilayerMain10 - return FF_DECODER_TYPE_VVC; + return FF_CODEC_TYPE_VVC; default: - return FF_DECODER_TYPE_UNKNOWN; + return FF_CODEC_TYPE_UNKNOWN; } } -static bool ffDecoderEntrypointIsDecode(VAEntrypoint entrypoint) { +static bool ffCodecEntrypointIsDecode(VAEntrypoint entrypoint) { switch (entrypoint) { case VAEntrypointVLD: case VAEntrypointIDCT: @@ -93,13 +93,26 @@ static bool ffDecoderEntrypointIsDecode(VAEntrypoint entrypoint) { } } -static bool ffDecoderProfileHasOutput( +static bool ffCodecEntrypointIsEncode(VAEntrypoint entrypoint) { + switch (entrypoint) { + case VAEntrypointEncSlice: + case VAEntrypointEncPicture: + case VAEntrypointEncSliceLP: + case VAEntrypointEncFEI: + return true; + default: + return false; + } +} + +static bool ffCodecProfileHasOutput( VADisplay display, __typeof__(vaQueryConfigEntrypoints)* ffvaQueryConfigEntrypoints, __typeof__(vaGetConfigAttributes)* ffvaGetConfigAttributes, int maxEntrypoints, VAEntrypoint* entrypoints, - VAProfile profile + VAProfile profile, + bool encode ) { int numEntrypoints = maxEntrypoints; if (ffvaQueryConfigEntrypoints(display, profile, entrypoints, &numEntrypoints) != VA_STATUS_SUCCESS) { @@ -107,7 +120,7 @@ static bool ffDecoderProfileHasOutput( } for (int i = 0; i < numEntrypoints; ++i) { - if (!ffDecoderEntrypointIsDecode(entrypoints[i])) { + if (encode ? !ffCodecEntrypointIsEncode(entrypoints[i]) : !ffCodecEntrypointIsDecode(entrypoints[i])) { continue; } @@ -126,7 +139,7 @@ static bool ffDecoderProfileHasOutput( return false; } -static void ffDecoderFillGpuName(const drmDevice* dev, const char* path, FFstrbuf* name) { +static void ffCodecFillGpuName(const drmDevice* dev, const char* path, FFstrbuf* name) { ffStrbufInit(name); switch (dev->bustype) { @@ -167,7 +180,7 @@ static void ffDecoderFillGpuName(const drmDevice* dev, const char* path, FFstrbu } } -const char* ffDetectDecoder(FF_A_UNUSED FFDecoderOptions* options, FFlist* result /* list of FFDecoderResult */) { +const char* ffDetectCodec(FF_A_UNUSED FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) { FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm" FF_LIBRARY_EXTENSION, 2) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices) @@ -243,26 +256,45 @@ const char* ffDetectDecoder(FF_A_UNUSED FFDecoderOptions* options, FFlist* resul continue; } - FFDecoderType types = FF_DECODER_TYPE_NONE; + FFCodecType decoderTypes = FF_CODEC_TYPE_NONE; + FFCodecType encoderTypes = FF_CODEC_TYPE_NONE; for (int j = 0; j < numProfiles; ++j) { - if (!ffDecoderProfileHasOutput( - display, - ffvaQueryConfigEntrypoints, - ffvaGetConfigAttributes, - maxEntrypoints, - entrypoints, - profiles[j])) { + bool hasDecoder = ffCodecProfileHasOutput( + display, + ffvaQueryConfigEntrypoints, + ffvaGetConfigAttributes, + maxEntrypoints, + entrypoints, + profiles[j], + false); + + bool hasEncoder = ffCodecProfileHasOutput( + display, + ffvaQueryConfigEntrypoints, + ffvaGetConfigAttributes, + maxEntrypoints, + entrypoints, + profiles[j], + true); + + if (!hasDecoder && !hasEncoder) { continue; } - FFDecoderType type = ffDecoderProfileToType(profiles[j]); - types = (FFDecoderType) ((uint32_t) types | (uint32_t) type); + FFCodecType type = ffCodecProfileToType(profiles[j]); + if (hasDecoder) { + decoderTypes = (FFCodecType) ((uint32_t) decoderTypes | (uint32_t) type); + } + if (hasEncoder) { + encoderTypes = (FFCodecType) ((uint32_t) encoderTypes | (uint32_t) type); + } } - if (types != FF_DECODER_TYPE_NONE) { - FFDecoderResult* item = FF_LIST_ADD(FFDecoderResult, *result); - ffDecoderFillGpuName(dev, path, &item->gpu); - item->types = types; + if (decoderTypes != FF_CODEC_TYPE_NONE || encoderTypes != FF_CODEC_TYPE_NONE) { + FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result); + ffCodecFillGpuName(dev, path, &item->gpu); + item->decoders = decoderTypes; + item->encoders = encoderTypes; } ffvaTerminate(display); @@ -274,7 +306,7 @@ const char* ffDetectDecoder(FF_A_UNUSED FFDecoderOptions* options, FFlist* resul #else -const char* ffDetectDecoder(FFDecoderOptions* options, FFlist* result /* list of FFDecoderResult */) { +const char* ffDetectCodec(FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) { FF_UNUSED(options, result); return "Fastfetch was built without DRM / VA-API headers"; } diff --git a/src/detection/decoder/decoder_windows.cpp b/src/detection/codec/codec_windows.cpp similarity index 81% rename from src/detection/decoder/decoder_windows.cpp rename to src/detection/codec/codec_windows.cpp index 3bc140868..f9b256248 100644 --- a/src/detection/decoder/decoder_windows.cpp +++ b/src/detection/codec/codec_windows.cpp @@ -1,5 +1,5 @@ extern "C" { -#include "decoder.h" +#include "codec.h" #include "common/library.h" #include "common/windows/com.h" #include "common/windows/unicode.h" @@ -10,7 +10,7 @@ extern "C" { #include #include -static const DXGI_FORMAT FF_NATIVE_DECODER_FORMATS[] = { +static const DXGI_FORMAT FF_NATIVE_CODEC_FORMATS[] = { DXGI_FORMAT_420_OPAQUE, DXGI_FORMAT_NV12, DXGI_FORMAT_P010, @@ -23,11 +23,11 @@ static const DXGI_FORMAT FF_NATIVE_DECODER_FORMATS[] = { DXGI_FORMAT_Y416, }; -static FFDecoderType ffDecoderProfileToType(const GUID& profile) { +static FFCodecType ffCodecProfileToType(const GUID& profile) { // clang-format off if (IsEqualGUID(profile, DXVA_ModeH261_A) || IsEqualGUID(profile, DXVA_ModeH261_B)) { - return FF_DECODER_TYPE_H261; + return FF_CODEC_TYPE_H261; } if (IsEqualGUID(profile, DXVA_ModeH263_A) || @@ -36,7 +36,7 @@ static FFDecoderType ffDecoderProfileToType(const GUID& profile) { IsEqualGUID(profile, DXVA_ModeH263_D) || IsEqualGUID(profile, DXVA_ModeH263_E) || IsEqualGUID(profile, DXVA_ModeH263_F)) { - return FF_DECODER_TYPE_H263; + return FF_CODEC_TYPE_H263; } if (IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_420) || @@ -46,12 +46,12 @@ static FFDecoderType ffDecoderProfileToType(const GUID& profile) { IsEqualGUID(profile, DXVA_ModeJPEG_VLD_420) || IsEqualGUID(profile, DXVA_ModeJPEG_VLD_422) || IsEqualGUID(profile, DXVA_ModeJPEG_VLD_444)) { - return FF_DECODER_TYPE_MJPEG; + return FF_CODEC_TYPE_MJPEG; } if (IsEqualGUID(profile, DXVA_ModeMPEG1_A) || IsEqualGUID(profile, DXVA_ModeMPEG1_VLD)) { - return FF_DECODER_TYPE_MPEG1; + return FF_CODEC_TYPE_MPEG1; } if (IsEqualGUID(profile, DXVA_ModeMPEG2_A) || @@ -59,13 +59,13 @@ static FFDecoderType ffDecoderProfileToType(const GUID& profile) { IsEqualGUID(profile, DXVA_ModeMPEG2_C) || IsEqualGUID(profile, DXVA_ModeMPEG2_D) || IsEqualGUID(profile, DXVA_ModeMPEG2and1_VLD)) { - return FF_DECODER_TYPE_MPEG2; + return FF_CODEC_TYPE_MPEG2; } if (IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_Simple) || IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_AdvSimple_NoGMC) || IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_AdvSimple_GMC)) { - return FF_DECODER_TYPE_DIVX_XVID; + return FF_CODEC_TYPE_DIVX_XVID; } if (IsEqualGUID(profile, DXVA_ModeH264_E) || @@ -74,18 +74,18 @@ static FFDecoderType ffDecoderProfileToType(const GUID& profile) { IsEqualGUID(profile, DXVA_ModeH264_VLD_Stereo_Progressive_NoFGT) || IsEqualGUID(profile, DXVA_ModeH264_VLD_Stereo_NoFGT) || IsEqualGUID(profile, DXVA_ModeH264_VLD_Multiview_NoFGT)) { - return FF_DECODER_TYPE_H264; + return FF_CODEC_TYPE_H264; } if (IsEqualGUID(profile, DXVA_ModeWMV8_A) || IsEqualGUID(profile, DXVA_ModeWMV8_B)) { - return FF_DECODER_TYPE_WMV8; + return FF_CODEC_TYPE_WMV8; } if (IsEqualGUID(profile, DXVA_ModeWMV9_A) || IsEqualGUID(profile, DXVA_ModeWMV9_B) || IsEqualGUID(profile, DXVA_ModeWMV9_C)) { - return FF_DECODER_TYPE_WMV9; + return FF_CODEC_TYPE_WMV9; } if (IsEqualGUID(profile, DXVA_ModeVC1_A) || @@ -93,11 +93,11 @@ static FFDecoderType ffDecoderProfileToType(const GUID& profile) { IsEqualGUID(profile, DXVA_ModeVC1_C) || IsEqualGUID(profile, DXVA_ModeVC1_D) || IsEqualGUID(profile, DXVA_ModeVC1_D2010)) { - return FF_DECODER_TYPE_VC1; + return FF_CODEC_TYPE_VC1; } if (IsEqualGUID(profile, DXVA_ModeVP8_VLD)) { - return FF_DECODER_TYPE_VP8; + return FF_CODEC_TYPE_VP8; } if (IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main) || @@ -110,12 +110,12 @@ static FFDecoderType ffDecoderProfileToType(const GUID& profile) { IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10_444) || IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main12_444) || IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main16)) { - return FF_DECODER_TYPE_HEVC; + return FF_CODEC_TYPE_HEVC; } if (IsEqualGUID(profile, DXVA_ModeVP9_VLD_Profile0) || IsEqualGUID(profile, DXVA_ModeVP9_VLD_10bit_Profile2)) { - return FF_DECODER_TYPE_VP9; + return FF_CODEC_TYPE_VP9; } if (IsEqualGUID(profile, DXVA_ModeAV1_VLD_Profile0) || @@ -123,17 +123,17 @@ static FFDecoderType ffDecoderProfileToType(const GUID& profile) { IsEqualGUID(profile, DXVA_ModeAV1_VLD_Profile2) || IsEqualGUID(profile, DXVA_ModeAV1_VLD_12bit_Profile2) || IsEqualGUID(profile, DXVA_ModeAV1_VLD_12bit_Profile2_420)) { - return FF_DECODER_TYPE_AV1; + return FF_CODEC_TYPE_AV1; } // clang-format on - return FF_DECODER_TYPE_UNKNOWN; + return FF_CODEC_TYPE_UNKNOWN; } -static bool ffDecoderProfileHasNativeOutput(ID3D11VideoDevice* videoDevice, const GUID& profile) { - for (uint32_t i = 0; i < ARRAY_SIZE(FF_NATIVE_DECODER_FORMATS); ++i) { +static bool ffCodecProfileHasNativeOutput(ID3D11VideoDevice* videoDevice, const GUID& profile) { + for (uint32_t i = 0; i < ARRAY_SIZE(FF_NATIVE_CODEC_FORMATS); ++i) { BOOL supported = FALSE; - if (SUCCEEDED(videoDevice->CheckVideoDecoderFormat(&profile, FF_NATIVE_DECODER_FORMATS[i], &supported)) && supported) { + if (SUCCEEDED(videoDevice->CheckVideoDecoderFormat(&profile, FF_NATIVE_CODEC_FORMATS[i], &supported)) && supported) { return true; } } @@ -141,7 +141,7 @@ static bool ffDecoderProfileHasNativeOutput(ID3D11VideoDevice* videoDevice, cons return false; } -const char* ffDetectDecoder(FF_A_UNUSED FFDecoderOptions* options, FFlist* result /*list of FFDecoderResult*/) { +const char* ffDetectCodec(FF_A_UNUSED FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) { FF_LIBRARY_LOAD_MESSAGE(dxgi, "dxgi" FF_LIBRARY_EXTENSION, 1) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxgi, CreateDXGIFactory1) FF_LIBRARY_LOAD_MESSAGE(d3d11, "d3d11" FF_LIBRARY_EXTENSION, 1) @@ -197,7 +197,7 @@ const char* ffDetectDecoder(FF_A_UNUSED FFDecoderOptions* options, FFlist* resul continue; } - FFDecoderResult* gpuResult = nullptr; + FFCodecResult* gpuResult = nullptr; UINT profileCount = videoDevice->GetVideoDecoderProfileCount(); for (UINT profileIndex = 0; profileIndex < profileCount; ++profileIndex) { GUID profile; @@ -205,16 +205,17 @@ const char* ffDetectDecoder(FF_A_UNUSED FFDecoderOptions* options, FFlist* resul continue; } - if (!ffDecoderProfileHasNativeOutput(videoDevice, profile)) { + if (!ffCodecProfileHasNativeOutput(videoDevice, profile)) { continue; } if (!gpuResult) { - gpuResult = FF_LIST_ADD(FFDecoderResult, *result); + gpuResult = FF_LIST_ADD(FFCodecResult, *result); ffStrbufInitWS(&gpuResult->gpu, desc.Description); - gpuResult->types = FF_DECODER_TYPE_NONE; + gpuResult->decoders = FF_CODEC_TYPE_NONE; + gpuResult->encoders = FF_CODEC_TYPE_NONE; } - gpuResult->types = (FFDecoderType) (((uint32_t) gpuResult->types) | ((uint32_t) ffDecoderProfileToType(profile))); + gpuResult->decoders = (FFCodecType) (((uint32_t) gpuResult->decoders) | ((uint32_t) ffCodecProfileToType(profile))); } } diff --git a/src/detection/decoder/decoder.h b/src/detection/decoder/decoder.h deleted file mode 100644 index 76b946c53..000000000 --- a/src/detection/decoder/decoder.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "fastfetch.h" -#include "modules/decoder/option.h" - -typedef enum FF_A_PACKED FFDecoderType { - FF_DECODER_TYPE_NONE = 0, - FF_DECODER_TYPE_UNKNOWN = UINT32_C(1) << 0, - FF_DECODER_TYPE_H261 = UINT32_C(1) << 1, - FF_DECODER_TYPE_H263 = UINT32_C(1) << 2, - FF_DECODER_TYPE_MJPEG = UINT32_C(1) << 3, - FF_DECODER_TYPE_MPEG1 = UINT32_C(1) << 4, - FF_DECODER_TYPE_MPEG2 = UINT32_C(1) << 5, - FF_DECODER_TYPE_DIVX_XVID = UINT32_C(1) << 6, - FF_DECODER_TYPE_H264 = UINT32_C(1) << 7, - FF_DECODER_TYPE_WMV8 = UINT32_C(1) << 8, - FF_DECODER_TYPE_WMV9 = UINT32_C(1) << 9, - FF_DECODER_TYPE_VC1 = UINT32_C(1) << 10, - FF_DECODER_TYPE_VP8 = UINT32_C(1) << 11, - FF_DECODER_TYPE_HEVC = UINT32_C(1) << 12, - FF_DECODER_TYPE_VP9 = UINT32_C(1) << 13, - FF_DECODER_TYPE_AV1 = UINT32_C(1) << 14, - FF_DECODER_TYPE_VVC = UINT32_C(1) << 15, - FF_DECODER_TYPE_DOLBY_VISION_HEVC = UINT32_C(1) << 16, - FF_DECODER_TYPE_PRORES = UINT32_C(1) << 17, - FF_DECODER_TYPE_PRORES_RAW = UINT32_C(1) << 18, - FF_DECODER_TYPE_JPEG_XL = UINT32_C(1) << 19, - FF_DECODER_TYPE_MAX = FF_DECODER_TYPE_JPEG_XL, - FF_DECODER_TYPE_FORCE_UNSIGNED = UINT32_MAX, -} FFDecoderType; - -typedef struct FFDecoderResult { - FFstrbuf gpu; - FFDecoderType types; -} FFDecoderResult; - -const char* ffDetectDecoder(FFDecoderOptions* options, FFlist* result /*list of FFDecoderResult*/); diff --git a/src/detection/decoder/decoder_apple.m b/src/detection/decoder/decoder_apple.m deleted file mode 100644 index e8dab2895..000000000 --- a/src/detection/decoder/decoder_apple.m +++ /dev/null @@ -1,51 +0,0 @@ -#include "decoder.h" - -#import -#import - -const char* ffDetectDecoder(FF_A_UNUSED FFDecoderOptions* options, FFlist* result /* list of FFDecoderResult */) { - static const struct { - CMVideoCodecType codec; - FFDecoderType type; - } codecs[] = { - { kCMVideoCodecType_H263, FF_DECODER_TYPE_H263 }, - { kCMVideoCodecType_JPEG, FF_DECODER_TYPE_MJPEG }, - { kCMVideoCodecType_JPEG_XL, FF_DECODER_TYPE_JPEG_XL }, - { kCMVideoCodecType_MPEG1Video, FF_DECODER_TYPE_MPEG1 }, - { kCMVideoCodecType_MPEG2Video, FF_DECODER_TYPE_MPEG2 }, - { kCMVideoCodecType_MPEG4Video, FF_DECODER_TYPE_DIVX_XVID }, - { kCMVideoCodecType_H264, FF_DECODER_TYPE_H264 }, - { kCMVideoCodecType_HEVC, FF_DECODER_TYPE_HEVC }, - { kCMVideoCodecType_HEVCWithAlpha, FF_DECODER_TYPE_HEVC }, - { kCMVideoCodecType_DolbyVisionHEVC, FF_DECODER_TYPE_DOLBY_VISION_HEVC }, - { kCMVideoCodecType_DisparityHEVC, FF_DECODER_TYPE_HEVC }, - { kCMVideoCodecType_DepthHEVC, FF_DECODER_TYPE_HEVC }, - { kCMVideoCodecType_VP9, FF_DECODER_TYPE_VP9 }, - { kCMVideoCodecType_AV1, FF_DECODER_TYPE_AV1 }, - { kCMVideoCodecType_AppleProRes4444XQ, FF_DECODER_TYPE_PRORES }, - { kCMVideoCodecType_AppleProRes4444, FF_DECODER_TYPE_PRORES }, - { kCMVideoCodecType_AppleProRes422HQ, FF_DECODER_TYPE_PRORES }, - { kCMVideoCodecType_AppleProRes422, FF_DECODER_TYPE_PRORES }, - { kCMVideoCodecType_AppleProRes422LT, FF_DECODER_TYPE_PRORES }, - { kCMVideoCodecType_AppleProRes422Proxy, FF_DECODER_TYPE_PRORES }, - { kCMVideoCodecType_AppleProResRAW, FF_DECODER_TYPE_PRORES_RAW }, - { kCMVideoCodecType_AppleProResRAWHQ, FF_DECODER_TYPE_PRORES_RAW }, - }; - - FFDecoderType types = FF_DECODER_TYPE_NONE; - - for (uint32_t i = 0; i < ARRAY_SIZE(codecs); ++i) { - if (types & codecs[i].type || !VTIsHardwareDecodeSupported(codecs[i].codec)) { - continue; - } - types |= codecs[i].type; - } - - if (types != FF_DECODER_TYPE_NONE) { - FFDecoderResult* item = FF_LIST_ADD(FFDecoderResult, *result); - ffStrbufInitS(&item->gpu, MTLCreateSystemDefaultDevice().name.UTF8String ?: "VideoToolbox"); - item->types = types; - } - - return NULL; -} diff --git a/src/modules/codec/codec.c b/src/modules/codec/codec.c new file mode 100644 index 000000000..bdbb12c21 --- /dev/null +++ b/src/modules/codec/codec.c @@ -0,0 +1,214 @@ +#include "common/printing.h" +#include "common/jsonconfig.h" +#include "detection/codec/codec.h" +#include "modules/codec/codec.h" + +static const char* ffCodecTypeToString(FFCodecType type) { + switch (type) { + case FF_CODEC_TYPE_H261: + return "H.261"; + case FF_CODEC_TYPE_H263: + return "H.263"; + case FF_CODEC_TYPE_MJPEG: + return "MJPEG"; + case FF_CODEC_TYPE_MPEG1: + return "MPEG-1"; + case FF_CODEC_TYPE_MPEG2: + return "MPEG-2"; + case FF_CODEC_TYPE_DIVX_XVID: + return "DivX / Xvid"; + case FF_CODEC_TYPE_H264: + return "H.264"; + case FF_CODEC_TYPE_WMV8: + return "WMV-8"; + case FF_CODEC_TYPE_WMV9: + return "WMV-9"; + case FF_CODEC_TYPE_VC1: + return "VC-1"; + case FF_CODEC_TYPE_VP8: + return "VP8"; + case FF_CODEC_TYPE_HEVC: + return "HEVC / H.265"; + case FF_CODEC_TYPE_VP9: + return "VP9"; + case FF_CODEC_TYPE_AV1: + return "AV1"; + case FF_CODEC_TYPE_VVC: + return "VVC / H.266"; + case FF_CODEC_TYPE_DOLBY_VISION_HEVC: + return "Dolby Vision (HEVC)"; + case FF_CODEC_TYPE_PRORES: + return "Apple ProRes"; + case FF_CODEC_TYPE_PRORES_RAW: + return "Apple ProRes RAW"; + case FF_CODEC_TYPE_JPEG_XL: + return "JPEG XL"; + case FF_CODEC_TYPE_UNKNOWN: + default: + return "Unknown"; + } +} + +static void ffCodecAppendTypeList(FFlist* list, FFCodecType types) { + for (FFCodecType type = FF_CODEC_TYPE_UNKNOWN; type <= FF_CODEC_TYPE_MAX; type <<= 1) { + if ((types & type) == 0) { + continue; + } + ffStrbufInitStatic(FF_LIST_ADD(FFstrbuf, *list), ffCodecTypeToString(type)); + } +} + +static void ffCodecAppendTypeJoined(FFstrbuf* buffer, FFCodecType types) { + for (FFCodecType type = FF_CODEC_TYPE_UNKNOWN; type <= FF_CODEC_TYPE_MAX; type <<= 1) { + if ((types & type) == 0) { + continue; + } + if (buffer->length > 0) { + ffStrbufAppendS(buffer, ", "); + } + ffStrbufAppendS(buffer, ffCodecTypeToString(type)); + } +} + +static void ffDestroyCodecResults(FFlist* result) { + FF_LIST_FOR_EACH (FFCodecResult, item, *result) { + ffStrbufDestroy(&item->gpu); + } +} + +static void printCodec(const FFCodecOptions* options, const FFCodecResult* result, uint8_t index) { + FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate(); + + if (options->moduleArgs.key.length == 0) { + ffStrbufSetF(&key, "%s (%s)", FF_CODEC_MODULE_NAME, result->gpu.chars); + } else { + FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]){ + FF_ARG(result->gpu, "gpu"), + FF_ARG(options->moduleArgs.keyIcon, "icon"), + FF_ARG(index, "index"), + })); + } + + if (options->moduleArgs.outputFormat.length == 0) { + FF_STRBUF_AUTO_DESTROY decodersJoined = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY encodersJoined = ffStrbufCreate(); + ffCodecAppendTypeJoined(&decodersJoined, result->decoders); + ffCodecAppendTypeJoined(&encodersJoined, result->encoders); + + ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY); + printf("Decode: %s | Encode: %s", decodersJoined.length ? decodersJoined.chars : "None", encodersJoined.length ? encodersJoined.chars : "None"); + putchar('\n'); + } else { + FF_LIST_AUTO_DESTROY decoders = ffListCreate(); // Use list instead of pre-joined string for qjs and lua + FF_LIST_AUTO_DESTROY encoders = ffListCreate(); + ffCodecAppendTypeList(&decoders, result->decoders); + ffCodecAppendTypeList(&encoders, result->encoders); + + FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]){ + FF_ARG(result->gpu, "gpu"), + FF_ARG(decoders, "decoders"), + FF_ARG(encoders, "encoders"), + FF_ARG(decoders, "types"), + })); + // No need to destroy strings in lists, as they are static strings + } +} + +bool ffPrintCodec(FFCodecOptions* options) { + FF_LIST_AUTO_DESTROY result = ffListCreate(); + const char* error = ffDetectCodec(NULL, &result); + + if (error) { + ffPrintError(FF_CODEC_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error); + return false; + } + + if (result.length == 0) { + ffPrintError(FF_CODEC_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No hardware video acceleration found"); + return false; + } + + for (uint32_t i = 0; i < result.length; ++i) { + uint8_t index = (uint8_t) (result.length == 1 ? 0 : i + 1); + printCodec(options, FF_LIST_GET(FFCodecResult, result, i), index); + } + + ffDestroyCodecResults(&result); + return true; +} + +void ffParseCodecJsonObject(FFCodecOptions* options, yyjson_val* module) { + yyjson_val *key, *val; + size_t idx, max; + yyjson_obj_foreach (module, idx, max, key, val) { + if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) { + continue; + } + + ffPrintError(FF_CODEC_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key)); + } +} + +void ffGenerateCodecJsonConfig(FFCodecOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { + ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs); +} + +bool ffGenerateCodecJsonResult(FF_A_UNUSED FFCodecOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { + FF_LIST_AUTO_DESTROY result = ffListCreate(); + const char* error = ffDetectCodec(NULL, &result); + + if (error) { + yyjson_mut_obj_add_str(doc, module, "error", error); + return false; + } + + yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result"); + + FF_LIST_FOR_EACH (FFCodecResult, item, result) { + yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); + yyjson_mut_obj_add_strbuf(doc, obj, "gpu", &item->gpu); + + yyjson_mut_val* decoders = yyjson_mut_obj_add_arr(doc, obj, "decoders"); + yyjson_mut_val* encoders = yyjson_mut_obj_add_arr(doc, obj, "encoders"); + yyjson_mut_val* types = yyjson_mut_obj_add_arr(doc, obj, "types"); // compatibility alias for decoders + + for (FFCodecType type = FF_CODEC_TYPE_UNKNOWN; type <= FF_CODEC_TYPE_MAX; type <<= 1) { + if ((item->decoders & type) != 0) { + const char* name = ffCodecTypeToString(type); + yyjson_mut_arr_add_str(doc, decoders, name); + yyjson_mut_arr_add_str(doc, types, name); + } + if ((item->encoders & type) != 0) { + yyjson_mut_arr_add_str(doc, encoders, ffCodecTypeToString(type)); + } + } + } + + ffDestroyCodecResults(&result); + return true; +} + +void ffInitCodecOptions(FFCodecOptions* options) { + ffOptionInitModuleArg(&options->moduleArgs, "󰚔"); +} + +void ffDestroyCodecOptions(FFCodecOptions* options) { + ffOptionDestroyModuleArg(&options->moduleArgs); +} + +FFModuleBaseInfo ffCodecModuleInfo = { + .name = FF_CODEC_MODULE_NAME, + .description = "Print hardware video acceleration codec types (decode / encode)", + .initOptions = (void*) ffInitCodecOptions, + .destroyOptions = (void*) ffDestroyCodecOptions, + .parseJsonObject = (void*) ffParseCodecJsonObject, + .printModule = (void*) ffPrintCodec, + .generateJsonResult = (void*) ffGenerateCodecJsonResult, + .generateJsonConfig = (void*) ffGenerateCodecJsonConfig, + .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]){ + { "GPU name", "gpu" }, + { "Decoder codec type list", "decoders" }, + { "Encoder codec type list", "encoders" }, + { "Compatibility alias of decoders", "types" }, + })) +}; diff --git a/src/modules/codec/codec.h b/src/modules/codec/codec.h new file mode 100644 index 000000000..efd3d7c01 --- /dev/null +++ b/src/modules/codec/codec.h @@ -0,0 +1,11 @@ +#pragma once + +#include "option.h" + +#define FF_CODEC_MODULE_NAME "Codec" + +bool ffPrintCodec(FFCodecOptions* options); +void ffInitCodecOptions(FFCodecOptions* options); +void ffDestroyCodecOptions(FFCodecOptions* options); + +extern FFModuleBaseInfo ffCodecModuleInfo; diff --git a/src/modules/codec/option.h b/src/modules/codec/option.h new file mode 100644 index 000000000..aae176cf3 --- /dev/null +++ b/src/modules/codec/option.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common/option.h" + +typedef struct FFCodecOptions { + FFModuleArgs moduleArgs; +} FFCodecOptions; + +static_assert(sizeof(FFCodecOptions) <= FF_OPTION_MAX_SIZE, "FFCodecOptions size exceeds maximum allowed size"); diff --git a/src/modules/decoder/decoder.c b/src/modules/decoder/decoder.c deleted file mode 100644 index d8f0c5038..000000000 --- a/src/modules/decoder/decoder.c +++ /dev/null @@ -1,194 +0,0 @@ -#include "common/printing.h" -#include "common/jsonconfig.h" -#include "detection/decoder/decoder.h" -#include "modules/decoder/decoder.h" - -static const char* ffDecoderTypeToString(FFDecoderType type) { - switch (type) { - case FF_DECODER_TYPE_H261: - return "H.261"; - case FF_DECODER_TYPE_H263: - return "H.263"; - case FF_DECODER_TYPE_MJPEG: - return "MJPEG"; - case FF_DECODER_TYPE_MPEG1: - return "MPEG-1"; - case FF_DECODER_TYPE_MPEG2: - return "MPEG-2"; - case FF_DECODER_TYPE_DIVX_XVID: - return "DivX / Xvid"; - case FF_DECODER_TYPE_H264: - return "H.264"; - case FF_DECODER_TYPE_WMV8: - return "WMV-8"; - case FF_DECODER_TYPE_WMV9: - return "WMV-9"; - case FF_DECODER_TYPE_VC1: - return "VC-1"; - case FF_DECODER_TYPE_VP8: - return "VP8"; - case FF_DECODER_TYPE_HEVC: - return "HEVC / H.265"; - case FF_DECODER_TYPE_VP9: - return "VP9"; - case FF_DECODER_TYPE_AV1: - return "AV1"; - case FF_DECODER_TYPE_VVC: - return "VVC / H.266"; - case FF_DECODER_TYPE_DOLBY_VISION_HEVC: - return "Dolby Vision (HEVC)"; - case FF_DECODER_TYPE_PRORES: - return "Apple ProRes"; - case FF_DECODER_TYPE_PRORES_RAW: - return "Apple ProRes RAW"; - case FF_DECODER_TYPE_JPEG_XL: - return "JPEG XL"; - case FF_DECODER_TYPE_UNKNOWN: - default: - return "Unknown"; - } -} - -static void ffDestroyDecoderResults(FFlist* result) { - FF_LIST_FOR_EACH (FFDecoderResult, item, *result) { - ffStrbufDestroy(&item->gpu); - } -} - -static void printDecoder(const FFDecoderOptions* options, const FFDecoderResult* decoder, uint8_t index) { - FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate(); - - if (options->moduleArgs.key.length == 0) { - ffStrbufSetF(&key, "%s (%s)", FF_DECODER_MODULE_NAME, decoder->gpu.chars); - } else { - FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]){ - FF_ARG(decoder->gpu, "gpu"), - FF_ARG(options->moduleArgs.keyIcon, "icon"), - FF_ARG(index, "index"), - })); - } - - if (options->moduleArgs.outputFormat.length == 0) { - FF_STRBUF_AUTO_DESTROY typesJoined = ffStrbufCreate(); - for (FFDecoderType type = FF_DECODER_TYPE_UNKNOWN; type <= FF_DECODER_TYPE_MAX; type <<= 1) { - if ((decoder->types & type) == 0) { - continue; - } - if (typesJoined.length > 0) { - ffStrbufAppendS(&typesJoined, ", "); - } - ffStrbufAppendS(&typesJoined, ffDecoderTypeToString(type)); - } - - ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY); - - if (typesJoined.length > 0) { - ffStrbufWriteTo(&typesJoined, stdout); - } - putchar('\n'); - } else { - FF_LIST_AUTO_DESTROY types = ffListCreate(); // Use list instead of pre-joined string for qjs and lua - for (FFDecoderType type = FF_DECODER_TYPE_UNKNOWN; type <= FF_DECODER_TYPE_MAX; type <<= 1) { - if ((decoder->types & type) == 0) { - continue; - } - ffStrbufInitStatic(FF_LIST_ADD(FFstrbuf, types), ffDecoderTypeToString(type)); - } - - FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]){ - FF_ARG(decoder->gpu, "gpu"), - FF_ARG(types, "types"), - })); - // No need to destroy strings in types list, as they are static strings - } -} - -bool ffPrintDecoder(FFDecoderOptions* options) { - FF_LIST_AUTO_DESTROY result = ffListCreate(); - const char* error = ffDetectDecoder(NULL, &result); - - if (error) { - ffPrintError(FF_DECODER_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error); - return false; - } - - if (result.length == 0) { - ffPrintError(FF_DECODER_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No hardware decoder found"); - return false; - } - - for (uint32_t i = 0; i < result.length; ++i) { - uint8_t index = (uint8_t) (result.length == 1 ? 0 : i + 1); - printDecoder(options, FF_LIST_GET(FFDecoderResult, result, i), index); - } - - ffDestroyDecoderResults(&result); - return true; -} - -void ffParseDecoderJsonObject(FFDecoderOptions* options, yyjson_val* module) { - yyjson_val *key, *val; - size_t idx, max; - yyjson_obj_foreach (module, idx, max, key, val) { - if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) { - continue; - } - - ffPrintError(FF_DECODER_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key)); - } -} - -void ffGenerateDecoderJsonConfig(FFDecoderOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { - ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs); -} - -bool ffGenerateDecoderJsonResult(FF_A_UNUSED FFDecoderOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { - FF_LIST_AUTO_DESTROY result = ffListCreate(); - const char* error = ffDetectDecoder(NULL, &result); - - if (error) { - yyjson_mut_obj_add_str(doc, module, "error", error); - return false; - } - - yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result"); - - FF_LIST_FOR_EACH (FFDecoderResult, item, result) { - yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); - yyjson_mut_obj_add_strbuf(doc, obj, "gpu", &item->gpu); - - yyjson_mut_val* types = yyjson_mut_obj_add_arr(doc, obj, "types"); - for (FFDecoderType type = FF_DECODER_TYPE_UNKNOWN; type <= FF_DECODER_TYPE_MAX; type <<= 1) { - if ((item->types & type) == 0) { - continue; - } - yyjson_mut_arr_add_str(doc, types, ffDecoderTypeToString(type)); - } - } - - ffDestroyDecoderResults(&result); - return true; -} - -void ffInitDecoderOptions(FFDecoderOptions* options) { - ffOptionInitModuleArg(&options->moduleArgs, "󰚔"); -} - -void ffDestroyDecoderOptions(FFDecoderOptions* options) { - ffOptionDestroyModuleArg(&options->moduleArgs); -} - -FFModuleBaseInfo ffDecoderModuleInfo = { - .name = FF_DECODER_MODULE_NAME, - .description = "Print hardware decoder types grouped by GPU", - .initOptions = (void*) ffInitDecoderOptions, - .destroyOptions = (void*) ffDestroyDecoderOptions, - .parseJsonObject = (void*) ffParseDecoderJsonObject, - .printModule = (void*) ffPrintDecoder, - .generateJsonResult = (void*) ffGenerateDecoderJsonResult, - .generateJsonConfig = (void*) ffGenerateDecoderJsonConfig, - .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]){ - { "GPU name", "gpu" }, - { "Decoder types, comma-separated", "types" }, - })) -}; diff --git a/src/modules/decoder/decoder.h b/src/modules/decoder/decoder.h deleted file mode 100644 index b21177860..000000000 --- a/src/modules/decoder/decoder.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "option.h" - -#define FF_DECODER_MODULE_NAME "Decoder" - -bool ffPrintDecoder(FFDecoderOptions* options); -void ffInitDecoderOptions(FFDecoderOptions* options); -void ffDestroyDecoderOptions(FFDecoderOptions* options); - -extern FFModuleBaseInfo ffDecoderModuleInfo; diff --git a/src/modules/decoder/option.h b/src/modules/decoder/option.h deleted file mode 100644 index 137d86c61..000000000 --- a/src/modules/decoder/option.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "common/option.h" - -typedef struct FFDecoderOptions { - FFModuleArgs moduleArgs; -} FFDecoderOptions; - -static_assert(sizeof(FFDecoderOptions) <= FF_OPTION_MAX_SIZE, "FFDecoderOptions size exceeds maximum allowed size"); diff --git a/src/modules/modules.c b/src/modules/modules.c index 436d61df0..837871187 100644 --- a/src/modules/modules.c +++ b/src/modules/modules.c @@ -47,6 +47,9 @@ static FFModuleBaseInfo* C[] = { #if !FF_MODULE_DISABLE_CHASSIS &ffChassisModuleInfo, #endif +#if !FF_MODULE_DISABLE_CODEC + &ffCodecModuleInfo, +#endif #if !FF_MODULE_DISABLE_COMMAND &ffCommandModuleInfo, #endif @@ -78,9 +81,6 @@ static FFModuleBaseInfo* D[] = { #if !FF_MODULE_DISABLE_DE &ffDEModuleInfo, #endif -#if !FF_MODULE_DISABLE_DECODER - &ffDecoderModuleInfo, -#endif #if !FF_MODULE_DISABLE_DISPLAY &ffDisplayModuleInfo, #endif diff --git a/src/modules/modules.h b/src/modules/modules.h index 52c9f4a67..37ee242f0 100644 --- a/src/modules/modules.h +++ b/src/modules/modules.h @@ -15,11 +15,11 @@ #include "modules/cpucache/cpucache.h" #include "modules/cpuusage/cpuusage.h" #include "modules/command/command.h" +#include "modules/codec/codec.h" #include "modules/colors/colors.h" #include "modules/cursor/cursor.h" #include "modules/custom/custom.h" #include "modules/datetime/datetime.h" -#include "modules/decoder/decoder.h" #include "modules/disk/disk.h" #include "modules/diskio/diskio.h" #include "modules/display/display.h"