diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71d78f634..46451748c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,7 @@ concurrency: cancel-in-progress: true env: + FREEBSD_CLANG_VERSION: 19 LINUX_GCC_VERSION: 12 MACOSX_DEPLOYMENT_TARGET: 13.0 @@ -78,16 +79,30 @@ jobs: shell: msys2 {0} msystem: clangarm64 toolchain: clang-aarch64 + - name: FreeBSD-amd64 + os: ubuntu-latest + arch: x86_64 + bsd_release: '14.3' + generator: "Unix Makefiles" + shell: freebsd {0} + - name: FreeBSD-aarch64 + os: ubuntu-latest # ubuntu-24.04-arm is slower with the FreeBSD VM + arch: aarch64 + bsd_release: '14.3' + generator: "Unix Makefiles" + shell: freebsd {0} defaults: run: shell: ${{ matrix.shell }} steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive - name: Prepare Dependencies Linux id: cross_compile - if: runner.os == 'Linux' + if: runner.os == 'Linux' && !startsWith(matrix.shell, 'freebsd') run: | echo "::group::distro detection" # detect dist name like bionic, focal, etc @@ -254,7 +269,7 @@ jobs: echo "::endgroup::" - name: Setup Dependencies Linux - if: runner.os == 'Linux' + if: runner.os == 'Linux' && !startsWith(matrix.shell, 'freebsd') run: | echo "::group::apt update" sudo apt-get update @@ -363,22 +378,59 @@ jobs: echo "MSYS2_ROOT=${{ runner.temp }}/msys64" >> $GITHUB_ENV cat "${{ runner.temp }}/setup-msys2/msys2.CMD" - - name: Initialize Submodules - # libx265 has issues when using the recursive method of the first checkout action - # this is after `msys2/setup-msys2@v2` because `msys2` (default) shell is not available until then. - run: | - git submodule update --init --recursive + - name: Setup FreeBSD + if: startsWith(matrix.shell, 'freebsd') + uses: vmactions/freebsd-vm@v1.2.1 + with: + arch: ${{ matrix.arch }} + prepare: | + pkg install -y \ + devel/autoconf \ + devel/automake \ + devel/cmake \ + devel/git \ + devel/gmake \ + devel/llvm${{ env.FREEBSD_CLANG_VERSION }} \ + devel/nasm \ + devel/ninja \ + devel/pkgconf \ + multimedia/libass \ + multimedia/libv4l \ + multimedia/libva \ + multimedia/v4l_compat \ + print/freetype2 \ + security/gnutls \ + shells/bash \ + x11/libx11 \ + x11/libxcb \ + x11/libXfixes + + # create symlink for shebang bash compatibility + ln -s /usr/local/bin/bash /bin/bash + release: ${{ matrix.bsd_release }} + sync: nfs - name: Setup ENV id: root run: | + set -e + cd $GITHUB_WORKSPACE echo "ROOT_PATH=$PWD" >> $GITHUB_ENV + MAKE_CMD="make" + if [ "${{ startsWith(matrix.shell, 'freebsd') }}" = true ]; then + # use gmake on FreeBSD instead of make + MAKE_CMD="gmake" + fi + echo "MAKE_CMD=${MAKE_CMD}" >> $GITHUB_ENV + - name: Setup cross compilation id: cross if: matrix.target != '' run: | - TOOLCHAIN=${ROOT_PATH}/cmake/toolchains/${{ matrix.target }}.cmake + set -e + cd $GITHUB_WORKSPACE + TOOLCHAIN=${{ env.ROOT_PATH }}/cmake/toolchains/${{ matrix.target }}.cmake # fail if file does not exist if [ ! -f $TOOLCHAIN ]; then @@ -394,33 +446,76 @@ jobs: - name: Get Processor Count id: processor_count run: | - if [[ ${{ runner.os }} == 'macOS' ]]; then - echo "PROCESSOR_COUNT=$(sysctl -n hw.ncpu)" >> $GITHUB_OUTPUT + set -e + cd $GITHUB_WORKSPACE + if [ "${{ runner.os }}" = 'macOS' ]; then + PROCESSOR_COUNT=$(sysctl -n hw.ncpu) else - echo "PROCESSOR_COUNT=$(nproc)" >> $GITHUB_OUTPUT + PROCESSOR_COUNT=$(nproc) fi + echo "PROCESSOR_COUNT=${PROCESSOR_COUNT}" >> $GITHUB_OUTPUT + echo "PROCESSOR_COUNT: $PROCESSOR_COUNT" + + - name: Get x265 git history + run: | + set -e + + # x265.pc will not be installed if their cmake cannot detect the latest tag + # SVT-AV1 cannot determine version if the git history is not available + + for repo in "x265_git" "SVT-AV1"; do + cd $GITHUB_WORKSPACE/third-party/FFmpeg/$repo + git config --global --add safe.directory $(pwd) + git fetch --tags --force origin + done - name: Configure run: | + set -e + cd $GITHUB_WORKSPACE + + if [ "${{ startsWith(matrix.shell, 'freebsd') }}" = true ]; then + export CC=$(which clang${{ env.FREEBSD_CLANG_VERSION }}) + export CXX=$(which clang++${{ env.FREEBSD_CLANG_VERSION }}) + + # make sure they exist + if [ ! -f "$CC" ]; then + echo "Compiler not found: $CC" + exit 1 + fi + if [ ! -f "$CXX" ]; then + echo "Compiler not found: $CXX" + exit 1 + fi + fi + mkdir -p ./build/dist cmake \ -B build \ -S . \ -G "${{ matrix.generator }}" \ - -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} \ - -DCMAKE_INSTALL_PREFIX="${ROOT_PATH}/build/dist" + -DCMAKE_TOOLCHAIN_FILE=${{ env.CMAKE_TOOLCHAIN_FILE }} \ + -DCMAKE_INSTALL_PREFIX="${{ env.ROOT_PATH }}/build/dist" \ + -DPARALLEL_BUILDS=${{ steps.processor_count.outputs.PROCESSOR_COUNT || 1 }} - name: Build run: | - make -C build -j${{ steps.processor_count.outputs.PROCESSOR_COUNT }} + set -e + cd $GITHUB_WORKSPACE + ${{ env.MAKE_CMD }} -C build --jobs=${{ steps.processor_count.outputs.PROCESSOR_COUNT || 1 }} - name: Install run: | - make -C build install + set -e + cd $GITHUB_WORKSPACE + ${{ env.MAKE_CMD }} -C build install - name: Debug logs if: always() run: | + set -e + cd $GITHUB_WORKSPACE + echo "::group::x264 config.log" cat ./third-party/FFmpeg/x264/config.log || true echo "::endgroup::" @@ -432,20 +527,27 @@ jobs: - name: Debug build directory if: always() run: | + set -e + cd $GITHUB_WORKSPACE ls -R ./build - name: Debug build/dist directory if: always() run: | + set -e + cd $GITHUB_WORKSPACE ls -R ./build/dist - name: Cleanup run: | + set -e + cd $GITHUB_WORKSPACE rm -f -r ./build/dist/share - name: Upload Artifacts uses: actions/upload-artifact@v4 with: + if-no-files-found: error name: ${{ matrix.name }} path: ./build/dist diff --git a/CMakeLists.txt b/CMakeLists.txt index b10cb61e9..2cedd8fd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,10 @@ option(BUILD_FFMPEG_X265_PATCHES "Apply FFmpeg x265 patches" ON) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/apply_git_patch.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/unix_path.cmake) +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + set(FREEBSD ON) +endif() + if(UNIX AND NOT APPLE) include(GNUInstallDirs) endif() @@ -44,12 +48,13 @@ if(NOT DEFINED PARALLEL_BUILDS) else() set(N_PROC ${PARALLEL_BUILDS}) endif() -if(N EQUAL 0) +if(N_PROC EQUAL 0) set(N_PROC 1) -elseif(NOT N MATCHES "^[0-9]+$") +elseif(NOT N_PROC MATCHES "^[0-9]+$") # if not a number, set it to 1 set(N_PROC 1) endif() +message(STATUS "parallel builds: ${N_PROC}") set(MSYS2_ROOT "C:/msys64") if(WIN32 AND DEFINED ENV{MSYS2_ROOT}) @@ -60,14 +65,22 @@ endif() if(NOT DEFINED BASH_EXECUTABLE) find_program(BASH_EXECUTABLE NAMES zsh bash - REQUIRED - HINTS "${MSYS2_ROOT}/usr/bin" /bin /usr/bin /usr/local/bin) + HINTS "${MSYS2_ROOT}/usr/bin" /bin /usr/bin /usr/local/bin + DOC "Bash shell executable" + REQUIRED) message(STATUS "Found bash: ${BASH_EXECUTABLE}") endif() +if(FREEBSD) + set(MAKE_FIND_NAMES "gmake") # We get invalid line types in nv-codec-headers Makefile if we use BSD make +else() + set(MAKE_FIND_NAMES "mingw32-make;make;gmake") +endif() + find_program(MAKE_EXECUTABLE - NAMES mingw32-make make gmake + NAMES ${MAKE_FIND_NAMES} NAMES_PER_DIR + HINTS "${MSYS2_ROOT}/usr/bin" /bin /usr/bin /usr/local/bin DOC "GNU Make" REQUIRED) message(STATUS "Found make: ${MAKE_EXECUTABLE}") @@ -169,6 +182,10 @@ add_custom_target(${CMAKE_PROJECT_NAME} # set architecture string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} arch) +message(STATUS "Detected system name: ${CMAKE_SYSTEM_NAME}") +message(STATUS "Detected architecture: ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS "CI Matrix name should be: '${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}'") + # set generated source path set(CMAKE_GENERATED_SRC_PATH ${CMAKE_CURRENT_BINARY_DIR}/generated-src) diff --git a/README.md b/README.md index 4cc40186c..8f65c3adb 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,30 @@ git checkout HEAD -- . ### Dependencies +#### FreeBSD + +```bash +pkg install -y \ + devel/autoconf \ + devel/automake \ + devel/cmake \ + devel/git \ + devel/gmake \ + devel/nasm \ + devel/ninja \ + devel/pkgconf \ + multimedia/libass \ + multimedia/libv4l \ + multimedia/libva \ + multimedia/v4l_compat \ + print/freetype2 \ + security/gnutls \ + shells/bash \ + x11/libx11 \ + x11/libxcb \ + x11/libXfixes +``` + #### Linux ```bash @@ -205,6 +229,8 @@ Valid options are, 1, 2, and 3. The default is 1. ### Build +ℹ️ On FreeBSD, use `gmake` instead of `make`. + ```bash make -C build ``` diff --git a/cmake/ffmpeg/_main.cmake b/cmake/ffmpeg/_main.cmake index 9c42f6044..cfce8ba0c 100644 --- a/cmake/ffmpeg/_main.cmake +++ b/cmake/ffmpeg/_main.cmake @@ -5,13 +5,25 @@ set(AVCODEC_GENERATED_SRC_PATH ${CMAKE_GENERATED_SRC_PATH}/FFmpeg/libavcodec) if(WIN32) set(BUILD_FFMPEG_VAAPI OFF) + + # We must disable CUDA and NVENC on ARM64 until following issues is resolved + # https://github.com/FFmpeg/FFmpeg/blob/4e5523c98597a417eb43555933b1075d18ec5f8b/configure#L7443 + if (${arch} STREQUAL "arm64") + set(BUILD_FFMPEG_NV_CODEC_HEADERS OFF) + endif() elseif(APPLE) set(BUILD_FFMPEG_AMF OFF) set(BUILD_FFMPEG_MF OFF) set(BUILD_FFMPEG_NV_CODEC_HEADERS OFF) set(BUILD_FFMPEG_VAAPI OFF) +elseif(FREEBSD) + set(BUILD_FFMPEG_AMF OFF) + set(BUILD_FFMPEG_MF OFF) + if(${arch} STREQUAL "aarch64") + set(BUILD_FFMPEG_NV_CODEC_HEADERS OFF) + endif() elseif(UNIX) - # nothing to disable for Linux + set(BUILD_FFMPEG_MF OFF) endif() if(BUILD_FFMPEG_AMF) diff --git a/cmake/ffmpeg/ffmpeg.cmake b/cmake/ffmpeg/ffmpeg.cmake index f621394d6..efc303047 100644 --- a/cmake/ffmpeg/ffmpeg.cmake +++ b/cmake/ffmpeg/ffmpeg.cmake @@ -41,54 +41,83 @@ list(APPEND FFMPEG_EXTRA_CONFIGURE --enable-avcodec --enable-avutil --enable-bsfs # ensure config.h will have CONFIG_CBS_ flags - --enable-encoder=libsvtav1 - --enable-encoder=libx264,libx265 - --enable-libsvtav1 - --enable-libx264 - --enable-libx265 --enable-swscale ) -if(WIN32) +if(BUILD_FFMPEG_AMF) list(APPEND FFMPEG_EXTRA_CONFIGURE --enable-amf - --enable-d3d11va --enable-encoder=h264_amf,hevc_amf,av1_amf + ) +endif() +if(BUILD_FFMPEG_MF) + list(APPEND FFMPEG_EXTRA_CONFIGURE --enable-encoder=h264_mf,hevc_mf - --enable-encoder=h264_qsv,hevc_qsv,av1_qsv - --enable-libvpl --enable-mediafoundation ) - - # We must disable CUDA and NVENC until following issues is resolved - # - # https://github.com/FFmpeg/FFmpeg/blob/4e5523c98597a417eb43555933b1075d18ec5f8b/configure#L7443 - if (${arch} STREQUAL "amd64" OR ${arch} STREQUAL "x86_64") +endif() +if(BUILD_FFMPEG_NV_CODEC_HEADERS) + list(APPEND FFMPEG_EXTRA_CONFIGURE + --enable-cuda + --enable-encoder=h264_nvenc,hevc_nvenc,av1_nvenc + --enable-ffnvcodec + --enable-nvenc + ) + if(UNIX AND NOT APPLE AND NOT FREEBSD) list(APPEND FFMPEG_EXTRA_CONFIGURE - --enable-cuda - --enable-encoder=h264_nvenc,hevc_nvenc,av1_nvenc - --enable-ffnvcodec - --enable-nvenc + --enable-cuda_llvm ) endif() +endif() +if(BUILD_FFMPEG_SVT_AV1) + list(APPEND FFMPEG_EXTRA_CONFIGURE + --enable-libsvtav1 + --enable-encoder=libsvtav1 + ) +endif() +if(BUILD_FFMPEG_VAAPI) + list(APPEND FFMPEG_EXTRA_CONFIGURE + --enable-vaapi + --enable-encoder=h264_vaapi,hevc_vaapi,av1_vaapi + ) +endif() +if(BUILD_FFMPEG_X264) + list(APPEND FFMPEG_EXTRA_CONFIGURE + --enable-libx264 + --enable-encoder=libx264 + ) +endif() +if(BUILD_FFMPEG_X265) + list(APPEND FFMPEG_EXTRA_CONFIGURE + --enable-libx265 + --enable-encoder=libx265 + ) +endif() + +# OS specific options not defined by the above BUILD_FFMPEG_* options +if(WIN32) + list(APPEND FFMPEG_EXTRA_CONFIGURE + --enable-d3d11va + --enable-encoder=h264_qsv,hevc_qsv,av1_qsv + --enable-libvpl + ) elseif(APPLE) list(APPEND FFMPEG_EXTRA_CONFIGURE --enable-encoder=h264_videotoolbox,hevc_videotoolbox --enable-videotoolbox ) +elseif(FREEBSD) + # FFmpeg does not build with this encoder on aarch64 FreeBSD + if(${arch} STREQUAL "amd64") + list(APPEND FFMPEG_EXTRA_CONFIGURE + --enable-encoder=h264_v4l2m2m + --enable-v4l2_m2m + ) + endif() elseif(UNIX) list(APPEND FFMPEG_EXTRA_CONFIGURE - --enable-amf - --enable-cuda - --enable-cuda_llvm - --enable-encoder=h264_amf,hevc_amf,av1_amf - --enable-encoder=h264_nvenc,hevc_nvenc,av1_nvenc - --enable-encoder=h264_vaapi,hevc_vaapi,av1_vaapi --enable-encoder=h264_v4l2m2m - --enable-ffnvcodec - --enable-nvenc --enable-v4l2_m2m - --enable-vaapi ) endif() @@ -116,7 +145,7 @@ add_custom_target(ffmpeg ALL COMMAND ${SHELL_CMD} "PKG_CONFIG_PATH='${PKG_CONFIG_PATH}' \ ./configure \ ${FFMPEG_EXTRA_CONFIGURE}" - COMMAND ${SHELL_CMD} "${MAKE_EXECUTABLE} -j${N_PROC}" + COMMAND ${SHELL_CMD} "${MAKE_EXECUTABLE} --jobs=${N_PROC}" COMMAND ${SHELL_CMD} "${MAKE_EXECUTABLE} install" WORKING_DIRECTORY ${WORKING_DIR} COMMENT "Target: FFmpeg" diff --git a/cmake/ffmpeg/nv_codec_headers.cmake b/cmake/ffmpeg/nv_codec_headers.cmake index 2e4920b99..c64b3f390 100644 --- a/cmake/ffmpeg/nv_codec_headers.cmake +++ b/cmake/ffmpeg/nv_codec_headers.cmake @@ -10,7 +10,7 @@ set(WORKING_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third-party/FFmpeg/nv-codec-headers UNIX_PATH(WORKING_DIR_UNIX ${WORKING_DIR}) UNIX_PATH(DEST_DIR_UNIX ${CMAKE_CURRENT_BINARY_DIR}) add_custom_target(nv-codec-headers ALL - COMMAND ${SHELL_CMD} "${MAKE_EXECUTABLE} -j${N_PROC}" + COMMAND ${SHELL_CMD} "${MAKE_EXECUTABLE} --jobs=${N_PROC}" # this will install the headers to the CMAKE_CURRENT_BINARY_DIR/usr/local COMMAND ${SHELL_CMD} "DESTDIR=${DEST_DIR_UNIX} ${MAKE_EXECUTABLE} install" WORKING_DIRECTORY ${WORKING_DIR} diff --git a/cmake/ffmpeg/x264.cmake b/cmake/ffmpeg/x264.cmake index 57f2ee770..4311a8df4 100644 --- a/cmake/ffmpeg/x264.cmake +++ b/cmake/ffmpeg/x264.cmake @@ -41,17 +41,26 @@ endif() # configure command will only take the first argument if not converted to string string(REPLACE ";" " " FFMPEG_X264_EXTRA_CONFIGURE "${FFMPEG_X264_EXTRA_CONFIGURE}") +# Set compiler for x264 configure script +set(X264_COMPILER_FLAGS "") +if(CMAKE_C_COMPILER) + set(X264_COMPILER_FLAGS "CC=${CMAKE_C_COMPILER}") +endif() +if(CMAKE_CXX_COMPILER) + set(X264_COMPILER_FLAGS "${X264_COMPILER_FLAGS} CXX=${CMAKE_CXX_COMPILER}") +endif() + # On Windows, the x264 submodule needs to have line endings converted to LF, see the README.md set(WORKING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third-party/FFmpeg/x264) UNIX_PATH(WORKING_DIR_UNIX ${WORKING_DIR}) add_custom_target(x264 ALL - COMMAND ${SHELL_CMD} "./configure \ + COMMAND ${SHELL_CMD} "${X264_COMPILER_FLAGS} ./configure \ --prefix=${CMAKE_CURRENT_BINARY_DIR_UNIX}/x264 \ --disable-cli \ --enable-static \ ${FFMPEG_X264_EXTRA_CONFIGURE}" - COMMAND ${SHELL_CMD} "${MAKE_EXECUTABLE} -j${N_PROC}" + COMMAND ${SHELL_CMD} "${MAKE_EXECUTABLE} --jobs=${N_PROC}" COMMAND ${SHELL_CMD} "${MAKE_EXECUTABLE} install" WORKING_DIRECTORY ${WORKING_DIR} COMMENT "Target: x264" diff --git a/cmake/ffmpeg/x265.cmake b/cmake/ffmpeg/x265.cmake index 8d676baa2..cf39578f5 100644 --- a/cmake/ffmpeg/x265.cmake +++ b/cmake/ffmpeg/x265.cmake @@ -34,4 +34,4 @@ if(ENABLE_HDR10_PLUS) add_dependencies(x265 hdr10plus-static) endif() -# PKG_CONFIG_PATH alraedy set since this is installed directly to the prefix +# PKG_CONFIG_PATH already set since this is installed directly to the prefix