CMakeLists.txt 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. # SPDX-FileCopyrightText: 2021 yuzu Emulator Project
  2. # SPDX-License-Identifier: GPL-2.0-or-later
  3. if (NOT WIN32 AND NOT ANDROID)
  4. # Build FFmpeg from externals
  5. message(STATUS "Using FFmpeg from externals")
  6. if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)")
  7. # FFmpeg has source that requires one of nasm or yasm to assemble it.
  8. # REQUIRED throws an error if not found here during configuration rather than during compilation.
  9. find_program(ASSEMBLER NAMES nasm yasm)
  10. if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND")
  11. message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.")
  12. endif()
  13. endif()
  14. find_program(AUTOCONF autoconf)
  15. if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND")
  16. message(FATAL_ERROR "Required program `autoconf` not found.")
  17. endif()
  18. set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg/ffmpeg)
  19. set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg-build)
  20. set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile)
  21. make_directory(${FFmpeg_BUILD_DIR})
  22. # Read version string from external
  23. file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION)
  24. set(FFmpeg_FOUND NO)
  25. if (NOT FFmpeg_VERSION STREQUAL "")
  26. set(FFmpeg_FOUND YES)
  27. endif()
  28. unset(FFmpeg_LIBRARIES CACHE)
  29. foreach(COMPONENT ${FFmpeg_COMPONENTS})
  30. set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}")
  31. set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a")
  32. set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}")
  33. set(FFmpeg_LIBRARIES
  34. ${FFmpeg_LIBRARIES}
  35. ${FFmpeg_${COMPONENT}_LIBRARY}
  36. CACHE PATH "Paths to FFmpeg libraries" FORCE)
  37. endforeach()
  38. find_package(PkgConfig REQUIRED)
  39. if (NOT ANDROID)
  40. pkg_check_modules(LIBVA libva)
  41. pkg_check_modules(CUDA cuda)
  42. pkg_check_modules(FFNVCODEC ffnvcodec)
  43. pkg_check_modules(VDPAU vdpau)
  44. endif()
  45. set(FFmpeg_HWACCEL_LIBRARIES)
  46. set(FFmpeg_HWACCEL_FLAGS)
  47. set(FFmpeg_HWACCEL_INCLUDE_DIRS)
  48. set(FFmpeg_HWACCEL_LDFLAGS)
  49. if(LIBVA_FOUND)
  50. pkg_check_modules(LIBDRM libdrm REQUIRED)
  51. find_package(X11 REQUIRED)
  52. pkg_check_modules(LIBVA-DRM libva-drm REQUIRED)
  53. pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED)
  54. list(APPEND FFmpeg_HWACCEL_LIBRARIES
  55. ${LIBDRM_LIBRARIES}
  56. ${X11_LIBRARIES}
  57. ${LIBVA-DRM_LIBRARIES}
  58. ${LIBVA-X11_LIBRARIES}
  59. ${LIBVA_LIBRARIES})
  60. set(FFmpeg_HWACCEL_FLAGS
  61. --enable-hwaccel=h264_vaapi
  62. --enable-hwaccel=vp8_vaapi
  63. --enable-hwaccel=vp9_vaapi
  64. --enable-libdrm)
  65. list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
  66. ${LIBDRM_INCLUDE_DIRS}
  67. ${X11_INCLUDE_DIRS}
  68. ${LIBVA-DRM_INCLUDE_DIRS}
  69. ${LIBVA-X11_INCLUDE_DIRS}
  70. ${LIBVA_INCLUDE_DIRS}
  71. )
  72. message(STATUS "VA-API found")
  73. else()
  74. set(FFmpeg_HWACCEL_FLAGS --disable-vaapi)
  75. endif()
  76. if (FFNVCODEC_FOUND)
  77. list(APPEND FFmpeg_HWACCEL_FLAGS
  78. --enable-cuvid
  79. --enable-ffnvcodec
  80. --enable-nvdec
  81. --enable-hwaccel=h264_nvdec
  82. --enable-hwaccel=vp8_nvdec
  83. --enable-hwaccel=vp9_nvdec
  84. )
  85. list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES})
  86. list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS})
  87. list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS})
  88. message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found")
  89. # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress
  90. # here we handle the hard-linking senario where CUDA is linked during compilation
  91. if (CUDA_FOUND)
  92. # This line causes build error if CUDA_INCLUDE_DIRS is anything but a single non-empty value
  93. #list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS})
  94. list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES})
  95. list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS})
  96. list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS})
  97. message(STATUS "CUDA libraries found, hard-linking will be performed")
  98. endif(CUDA_FOUND)
  99. endif()
  100. if (VDPAU_FOUND)
  101. list(APPEND FFmpeg_HWACCEL_FLAGS
  102. --enable-vdpau
  103. --enable-hwaccel=h264_vdpau
  104. --enable-hwaccel=vp9_vdpau
  105. )
  106. list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES})
  107. list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS})
  108. list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS})
  109. message(STATUS "vdpau libraries version ${VDPAU_VERSION} found")
  110. else()
  111. list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau)
  112. endif()
  113. find_program(BASH_PROGRAM bash REQUIRED)
  114. set(FFmpeg_CROSS_COMPILE_FLAGS "")
  115. if (ANDROID)
  116. string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME)
  117. set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}")
  118. set(SYSROOT "${TOOLCHAIN}/sysroot")
  119. set(FFmpeg_CPU "armv8-a")
  120. list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
  121. --arch=arm64
  122. #--cpu=${FFmpeg_CPU}
  123. --enable-cross-compile
  124. --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
  125. --sysroot=${SYSROOT}
  126. --target-os=android
  127. --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
  128. --extra-ldflags="-nostdlib"
  129. )
  130. endif()
  131. # `configure` parameters builds only exactly what yuzu needs from FFmpeg
  132. # `--disable-vdpau` is needed to avoid linking issues
  133. set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
  134. set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER})
  135. add_custom_command(
  136. OUTPUT
  137. ${FFmpeg_MAKEFILE}
  138. COMMAND
  139. ${BASH_PROGRAM} ${FFmpeg_PREFIX}/configure
  140. --disable-avdevice
  141. --disable-avformat
  142. --disable-doc
  143. --disable-everything
  144. --disable-ffmpeg
  145. --disable-ffprobe
  146. --disable-network
  147. --disable-postproc
  148. --disable-swresample
  149. --enable-decoder=h264
  150. --enable-decoder=vp8
  151. --enable-decoder=vp9
  152. --enable-filter=yadif,scale
  153. --cc="${FFmpeg_CC}"
  154. --cxx="${FFmpeg_CXX}"
  155. ${FFmpeg_HWACCEL_FLAGS}
  156. ${FFmpeg_CROSS_COMPILE_FLAGS}
  157. WORKING_DIRECTORY
  158. ${FFmpeg_BUILD_DIR}
  159. )
  160. unset(FFmpeg_CC)
  161. unset(FFmpeg_CXX)
  162. unset(FFmpeg_HWACCEL_FLAGS)
  163. unset(FFmpeg_CROSS_COMPILE_FLAGS)
  164. # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
  165. # with context of the jobserver. Also helps ninja users.
  166. execute_process(
  167. COMMAND
  168. nproc
  169. OUTPUT_VARIABLE
  170. SYSTEM_THREADS)
  171. set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
  172. add_custom_command(
  173. OUTPUT
  174. ${FFmpeg_BUILD_LIBRARIES}
  175. COMMAND
  176. make -j${SYSTEM_THREADS}
  177. WORKING_DIRECTORY
  178. ${FFmpeg_BUILD_DIR}
  179. )
  180. set(FFmpeg_INCLUDE_DIR
  181. "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}"
  182. CACHE PATH "Path to FFmpeg headers" FORCE)
  183. set(FFmpeg_LDFLAGS
  184. "${FFmpeg_HWACCEL_LDFLAGS}"
  185. CACHE STRING "FFmpeg linker flags" FORCE)
  186. # ALL makes this custom target build every time
  187. # but it won't actually build if the DEPENDS parameter is up to date
  188. add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE})
  189. add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure)
  190. link_libraries(${FFmpeg_LIBVA_LIBRARIES})
  191. set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES}
  192. CACHE PATH "Paths to FFmpeg libraries" FORCE)
  193. unset(FFmpeg_BUILD_LIBRARIES)
  194. unset(FFmpeg_HWACCEL_FLAGS)
  195. unset(FFmpeg_HWACCEL_INCLUDE_DIRS)
  196. unset(FFmpeg_HWACCEL_LDFLAGS)
  197. unset(FFmpeg_HWACCEL_LIBRARIES)
  198. if (FFmpeg_FOUND)
  199. message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
  200. else()
  201. message(FATAL_ERROR "FFmpeg not found")
  202. endif()
  203. elseif(ANDROID)
  204. # Use yuzu FFmpeg binaries
  205. if (ARCHITECTURE_arm64)
  206. set(FFmpeg_EXT_NAME "ffmpeg-android-v5.1.LTS-aarch64")
  207. elseif (ARCHITECTURE_x86_64)
  208. set(FFmpeg_EXT_NAME "ffmpeg-android-v5.1.LTS-x86_64")
  209. else()
  210. message(FATAL_ERROR "Unsupported architecture for Android FFmpeg")
  211. endif()
  212. set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
  213. download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
  214. set(FFmpeg_FOUND YES)
  215. set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
  216. set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/lib" CACHE PATH "Path to FFmpeg library directory" FORCE)
  217. set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE)
  218. set(FFmpeg_LIBRARIES
  219. ${FFmpeg_LIBRARY_DIR}/libavcodec.so
  220. ${FFmpeg_LIBRARY_DIR}/libavdevice.so
  221. ${FFmpeg_LIBRARY_DIR}/libavfilter.so
  222. ${FFmpeg_LIBRARY_DIR}/libavformat.so
  223. ${FFmpeg_LIBRARY_DIR}/libavutil.so
  224. ${FFmpeg_LIBRARY_DIR}/libswresample.so
  225. ${FFmpeg_LIBRARY_DIR}/libswscale.so
  226. ${FFmpeg_LIBRARY_DIR}/libvpx.a
  227. ${FFmpeg_LIBRARY_DIR}/libx264.a
  228. CACHE PATH "Paths to FFmpeg libraries" FORCE)
  229. # exported variables
  230. set(FFmpeg_PATH "${FFmpeg_PATH}" PARENT_SCOPE)
  231. set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE)
  232. set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)
  233. set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
  234. elseif(WIN32)
  235. # Use yuzu FFmpeg binaries
  236. set(FFmpeg_EXT_NAME "ffmpeg-6.0")
  237. set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
  238. download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
  239. set(FFmpeg_FOUND YES)
  240. set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
  241. set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE)
  242. set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE)
  243. set(FFmpeg_LIBRARIES
  244. ${FFmpeg_LIBRARY_DIR}/swscale.lib
  245. ${FFmpeg_LIBRARY_DIR}/avcodec.lib
  246. ${FFmpeg_LIBRARY_DIR}/avfilter.lib
  247. ${FFmpeg_LIBRARY_DIR}/avutil.lib
  248. CACHE PATH "Paths to FFmpeg libraries" FORCE)
  249. # exported variables
  250. set(FFmpeg_PATH "${FFmpeg_PATH}" PARENT_SCOPE)
  251. set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE)
  252. set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)
  253. set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
  254. endif()
  255. unset(FFmpeg_COMPONENTS)