| # SPDX-FileCopyrightText: 2021 yuzu Emulator Project | |
| # SPDX-License-Identifier: GPL-2.0-or-later | |
| if (NOT WIN32 AND NOT ANDROID) | |
| # Build FFmpeg from externals | |
| message(STATUS "Using FFmpeg from externals") | |
| if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)") | |
| # FFmpeg has source that requires one of nasm or yasm to assemble it. | |
| # REQUIRED throws an error if not found here during configuration rather than during compilation. | |
| find_program(ASSEMBLER NAMES nasm yasm) | |
| if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND") | |
| message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.") | |
| endif() | |
| endif() | |
| find_program(AUTOCONF autoconf) | |
| if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND") | |
| message(FATAL_ERROR "Required program `autoconf` not found.") | |
| endif() | |
| set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg/ffmpeg) | |
| set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg-build) | |
| set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) | |
| make_directory(${FFmpeg_BUILD_DIR}) | |
| # Read version string from external | |
| file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION) | |
| set(FFmpeg_FOUND NO) | |
| if (NOT FFmpeg_VERSION STREQUAL "") | |
| set(FFmpeg_FOUND YES) | |
| endif() | |
| unset(FFmpeg_LIBRARIES CACHE) | |
| foreach(COMPONENT ${FFmpeg_COMPONENTS}) | |
| set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}") | |
| set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a") | |
| set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}") | |
| set(FFmpeg_LIBRARIES | |
| ${FFmpeg_LIBRARIES} | |
| ${FFmpeg_${COMPONENT}_LIBRARY} | |
| CACHE PATH "Paths to FFmpeg libraries" FORCE) | |
| endforeach() | |
| find_package(PkgConfig REQUIRED) | |
| if (NOT ANDROID) | |
| pkg_check_modules(LIBVA libva) | |
| pkg_check_modules(CUDA cuda) | |
| pkg_check_modules(FFNVCODEC ffnvcodec) | |
| pkg_check_modules(VDPAU vdpau) | |
| endif() | |
| set(FFmpeg_HWACCEL_LIBRARIES) | |
| set(FFmpeg_HWACCEL_FLAGS) | |
| set(FFmpeg_HWACCEL_INCLUDE_DIRS) | |
| set(FFmpeg_HWACCEL_LDFLAGS) | |
| if(LIBVA_FOUND) | |
| pkg_check_modules(LIBDRM libdrm REQUIRED) | |
| find_package(X11 REQUIRED) | |
| pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) | |
| pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) | |
| list(APPEND FFmpeg_HWACCEL_LIBRARIES | |
| ${LIBDRM_LIBRARIES} | |
| ${X11_LIBRARIES} | |
| ${LIBVA-DRM_LIBRARIES} | |
| ${LIBVA-X11_LIBRARIES} | |
| ${LIBVA_LIBRARIES}) | |
| set(FFmpeg_HWACCEL_FLAGS | |
| --enable-hwaccel=h264_vaapi | |
| --enable-hwaccel=vp8_vaapi | |
| --enable-hwaccel=vp9_vaapi | |
| --enable-libdrm) | |
| list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS | |
| ${LIBDRM_INCLUDE_DIRS} | |
| ${X11_INCLUDE_DIRS} | |
| ${LIBVA-DRM_INCLUDE_DIRS} | |
| ${LIBVA-X11_INCLUDE_DIRS} | |
| ${LIBVA_INCLUDE_DIRS} | |
| ) | |
| message(STATUS "VA-API found") | |
| else() | |
| set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) | |
| endif() | |
| if (FFNVCODEC_FOUND) | |
| list(APPEND FFmpeg_HWACCEL_FLAGS | |
| --enable-cuvid | |
| --enable-ffnvcodec | |
| --enable-nvdec | |
| --enable-hwaccel=h264_nvdec | |
| --enable-hwaccel=vp8_nvdec | |
| --enable-hwaccel=vp9_nvdec | |
| ) | |
| list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) | |
| list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) | |
| list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) | |
| message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") | |
| # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress | |
| # here we handle the hard-linking senario where CUDA is linked during compilation | |
| if (CUDA_FOUND) | |
| # This line causes build error if CUDA_INCLUDE_DIRS is anything but a single non-empty value | |
| #list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) | |
| list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) | |
| list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) | |
| list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) | |
| message(STATUS "CUDA libraries found, hard-linking will be performed") | |
| endif(CUDA_FOUND) | |
| endif() | |
| if (VDPAU_FOUND) | |
| list(APPEND FFmpeg_HWACCEL_FLAGS | |
| --enable-vdpau | |
| --enable-hwaccel=h264_vdpau | |
| --enable-hwaccel=vp9_vdpau | |
| ) | |
| list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) | |
| list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) | |
| list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) | |
| message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") | |
| else() | |
| list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) | |
| endif() | |
| find_program(BASH_PROGRAM bash REQUIRED) | |
| set(FFmpeg_CROSS_COMPILE_FLAGS "") | |
| if (ANDROID) | |
| string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME) | |
| set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") | |
| set(SYSROOT "${TOOLCHAIN}/sysroot") | |
| set(FFmpeg_CPU "armv8-a") | |
| list(APPEND FFmpeg_CROSS_COMPILE_FLAGS | |
| --arch=arm64 | |
| #--cpu=${FFmpeg_CPU} | |
| --enable-cross-compile | |
| --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android- | |
| --sysroot=${SYSROOT} | |
| --target-os=android | |
| --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" | |
| --extra-ldflags="-nostdlib" | |
| ) | |
| endif() | |
| # `configure` parameters builds only exactly what yuzu needs from FFmpeg | |
| # `--disable-vdpau` is needed to avoid linking issues | |
| set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}) | |
| set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER}) | |
| add_custom_command( | |
| OUTPUT | |
| ${FFmpeg_MAKEFILE} | |
| COMMAND | |
| ${BASH_PROGRAM} ${FFmpeg_PREFIX}/configure | |
| --disable-avdevice | |
| --disable-avformat | |
| --disable-doc | |
| --disable-everything | |
| --disable-ffmpeg | |
| --disable-ffprobe | |
| --disable-network | |
| --disable-postproc | |
| --disable-swresample | |
| --enable-decoder=h264 | |
| --enable-decoder=vp8 | |
| --enable-decoder=vp9 | |
| --enable-filter=yadif,scale | |
| --cc="${FFmpeg_CC}" | |
| --cxx="${FFmpeg_CXX}" | |
| ${FFmpeg_HWACCEL_FLAGS} | |
| ${FFmpeg_CROSS_COMPILE_FLAGS} | |
| WORKING_DIRECTORY | |
| ${FFmpeg_BUILD_DIR} | |
| ) | |
| unset(FFmpeg_CC) | |
| unset(FFmpeg_CXX) | |
| unset(FFmpeg_HWACCEL_FLAGS) | |
| unset(FFmpeg_CROSS_COMPILE_FLAGS) | |
| # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child | |
| # with context of the jobserver. Also helps ninja users. | |
| execute_process( | |
| COMMAND | |
| nproc | |
| OUTPUT_VARIABLE | |
| SYSTEM_THREADS) | |
| set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) | |
| add_custom_command( | |
| OUTPUT | |
| ${FFmpeg_BUILD_LIBRARIES} | |
| COMMAND | |
| make -j${SYSTEM_THREADS} | |
| WORKING_DIRECTORY | |
| ${FFmpeg_BUILD_DIR} | |
| ) | |
| set(FFmpeg_INCLUDE_DIR | |
| "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}" | |
| CACHE PATH "Path to FFmpeg headers" FORCE) | |
| set(FFmpeg_LDFLAGS | |
| "${FFmpeg_HWACCEL_LDFLAGS}" | |
| CACHE STRING "FFmpeg linker flags" FORCE) | |
| # ALL makes this custom target build every time | |
| # but it won't actually build if the DEPENDS parameter is up to date | |
| add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE}) | |
| add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure) | |
| link_libraries(${FFmpeg_LIBVA_LIBRARIES}) | |
| set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES} | |
| CACHE PATH "Paths to FFmpeg libraries" FORCE) | |
| unset(FFmpeg_BUILD_LIBRARIES) | |
| unset(FFmpeg_HWACCEL_FLAGS) | |
| unset(FFmpeg_HWACCEL_INCLUDE_DIRS) | |
| unset(FFmpeg_HWACCEL_LDFLAGS) | |
| unset(FFmpeg_HWACCEL_LIBRARIES) | |
| if (FFmpeg_FOUND) | |
| message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}") | |
| else() | |
| message(FATAL_ERROR "FFmpeg not found") | |
| endif() | |
| elseif(ANDROID) | |
| # Use yuzu FFmpeg binaries | |
| if (ARCHITECTURE_arm64) | |
| set(FFmpeg_EXT_NAME "ffmpeg-android-v5.1.LTS-aarch64") | |
| elseif (ARCHITECTURE_x86_64) | |
| set(FFmpeg_EXT_NAME "ffmpeg-android-v5.1.LTS-x86_64") | |
| else() | |
| message(FATAL_ERROR "Unsupported architecture for Android FFmpeg") | |
| endif() | |
| set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") | |
| download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") | |
| set(FFmpeg_FOUND YES) | |
| set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) | |
| set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/lib" CACHE PATH "Path to FFmpeg library directory" FORCE) | |
| set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE) | |
| set(FFmpeg_LIBRARIES | |
| ${FFmpeg_LIBRARY_DIR}/libavcodec.so | |
| ${FFmpeg_LIBRARY_DIR}/libavdevice.so | |
| ${FFmpeg_LIBRARY_DIR}/libavfilter.so | |
| ${FFmpeg_LIBRARY_DIR}/libavformat.so | |
| ${FFmpeg_LIBRARY_DIR}/libavutil.so | |
| ${FFmpeg_LIBRARY_DIR}/libswresample.so | |
| ${FFmpeg_LIBRARY_DIR}/libswscale.so | |
| ${FFmpeg_LIBRARY_DIR}/libvpx.a | |
| ${FFmpeg_LIBRARY_DIR}/libx264.a | |
| CACHE PATH "Paths to FFmpeg libraries" FORCE) | |
| # exported variables | |
| set(FFmpeg_PATH "${FFmpeg_PATH}" PARENT_SCOPE) | |
| set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE) | |
| set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE) | |
| set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE) | |
| elseif(WIN32) | |
| # Use yuzu FFmpeg binaries | |
| set(FFmpeg_EXT_NAME "ffmpeg-6.0") | |
| set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") | |
| download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") | |
| set(FFmpeg_FOUND YES) | |
| set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) | |
| set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE) | |
| set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE) | |
| set(FFmpeg_LIBRARIES | |
| ${FFmpeg_LIBRARY_DIR}/swscale.lib | |
| ${FFmpeg_LIBRARY_DIR}/avcodec.lib | |
| ${FFmpeg_LIBRARY_DIR}/avfilter.lib | |
| ${FFmpeg_LIBRARY_DIR}/avutil.lib | |
| CACHE PATH "Paths to FFmpeg libraries" FORCE) | |
| # exported variables | |
| set(FFmpeg_PATH "${FFmpeg_PATH}" PARENT_SCOPE) | |
| set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE) | |
| set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE) | |
| set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE) | |
| endif() | |
| unset(FFmpeg_COMPONENTS) | |