build-ffmpeg #55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: build-ffmpeg | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| profile: | |
| description: Path to build profile | |
| required: false | |
| default: profiles/default.yml | |
| type: string | |
| ffmpeg_version: | |
| description: Override FFmpeg version (optional) | |
| required: false | |
| default: "" | |
| type: string | |
| nonfree: | |
| description: Enable nonfree (requires nonfree libs configured) | |
| required: false | |
| default: false | |
| type: boolean | |
| macos_arm64: | |
| description: Build macOS arm64 | |
| required: false | |
| default: true | |
| type: boolean | |
| macos_x86_64: | |
| description: Build macOS x86_64 (Intel) | |
| required: false | |
| default: false | |
| type: boolean | |
| linux_x86_64: | |
| description: Build Linux x86_64 | |
| required: false | |
| default: false | |
| type: boolean | |
| windows_x86_64: | |
| description: Build Windows x86_64 | |
| required: false | |
| default: false | |
| type: boolean | |
| push: | |
| tags: | |
| - "v*" | |
| jobs: | |
| setup: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| ffmpeg_version: ${{ steps.set-matrix.outputs.ffmpeg_version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - id: set-matrix | |
| shell: bash | |
| run: | | |
| # On tag push, build the default release platforms (macOS arm64 + Windows x86_64). | |
| # On workflow_dispatch, use the selected inputs. | |
| IS_RELEASE=${{ github.event_name != 'workflow_dispatch' }} | |
| # Resolve FFmpeg version from input or profile | |
| FFMPEG_VERSION="${{ inputs.ffmpeg_version }}" | |
| if [[ -z "$FFMPEG_VERSION" ]]; then | |
| FFMPEG_VERSION=$(yq '.ffmpeg.version' profiles/default.yml) | |
| fi | |
| echo "ffmpeg_version=$FFMPEG_VERSION" >> $GITHUB_OUTPUT | |
| ENTRIES='[]' | |
| add() { ENTRIES=$(echo "$ENTRIES" | jq -c --argjson e "$1" '. + [$e]'); } | |
| if [[ "$IS_RELEASE" == "true" ]] || [[ "${{ inputs.macos_arm64 }}" == "true" ]]; then | |
| add '{"os":"macos-26","arch":"arm64","runner":"macos-26"}' | |
| fi | |
| if [[ "$IS_RELEASE" == "true" ]] || [[ "${{ inputs.macos_x86_64 }}" == "true" ]]; then | |
| add '{"os":"macos-26-intel","arch":"x86_64","runner":"macos-26-intel"}' | |
| fi | |
| if [[ "${{ inputs.linux_x86_64 }}" == "true" ]]; then | |
| add '{"os":"ubuntu-22.04","arch":"x86_64","runner":"ubuntu-22.04"}' | |
| fi | |
| if [[ "$IS_RELEASE" == "true" ]] || [[ "${{ inputs.windows_x86_64 }}" == "true" ]]; then | |
| add '{"os":"windows-2022","arch":"x86_64","runner":"windows-2022"}' | |
| fi | |
| echo "matrix={\"include\":$ENTRIES}" >> $GITHUB_OUTPUT | |
| build: | |
| needs: setup | |
| name: ${{ matrix.os }} • ${{ matrix.arch }} | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.setup.outputs.matrix) }} | |
| runs-on: ${{ matrix.runner }} | |
| env: | |
| # Use workflow_dispatch inputs when present, otherwise fall back to defaults | |
| PROFILE: >- | |
| ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.profile || 'profiles/default.yml' }} | |
| FFMPEG_VERSION: ${{ needs.setup.outputs.ffmpeg_version }} | |
| ENABLE_NONFREE: >- | |
| ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.nonfree || false }} | |
| CCACHE_DIR: ${{ github.workspace }}/.ccache | |
| BUILD_CACHE: ${{ github.workspace }}/.build-cache | |
| # Exposed for use in step `if` conditions — empty string when secret is not set | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Restore caches | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ${{ env.CCACHE_DIR }} | |
| ${{ env.BUILD_CACHE }} | |
| # Cache key based on OS/arch + all profiles | |
| key: ${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('profiles/**/*.yml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ matrix.arch }}- | |
| # Signing and notarization are optional — skipped automatically if secrets are not set. | |
| # Required to run on macOS without a Gatekeeper warning. See README for setup instructions. | |
| - name: Import Apple certificate (macOS) | |
| if: runner.os == 'macOS' && env.APPLE_CERTIFICATE != '' | |
| env: | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| run: | | |
| echo "$APPLE_CERTIFICATE" | base64 --decode > certificate.p12 | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security set-keychain-settings -t 3600 -u build.keychain | |
| security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain | |
| rm certificate.p12 | |
| CERT_INFO=$(security find-identity -v -p codesigning build.keychain | head -n 1) | |
| CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}') | |
| echo "APPLE_SIGNING_IDENTITY=$CERT_ID" >> $GITHUB_ENV | |
| - name: Bootstrap toolchain (Linux/macOS) | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ "${{ runner.os }}" == "Linux" ]]; then | |
| ./scripts/bootstrap-linux.sh | |
| else | |
| ./scripts/bootstrap-macos.sh | |
| fi | |
| - name: Bootstrap toolchain (Windows) | |
| if: runner.os == 'Windows' | |
| uses: msys2/setup-msys2@v2 | |
| with: | |
| msystem: MINGW64 | |
| update: true | |
| install: >- | |
| base-devel git nasm yasm zip autoconf automake libtool | |
| mingw-w64-x86_64-toolchain mingw-w64-x86_64-pkgconf | |
| mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-meson | |
| - name: Build FFmpeg (Linux/macOS) | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| run: ./scripts/build-ffmpeg.sh | |
| - name: Upload FFmpeg config.log on failure (macOS/Linux) | |
| if: runner.os != 'Windows' && failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ffmpeg-config-log-${{ matrix.os }}-${{ matrix.arch }} | |
| path: .build-cache/src/ffmpeg-*/ffbuild/config.log | |
| if-no-files-found: ignore | |
| - name: Build FFmpeg (Windows) | |
| if: runner.os == 'Windows' | |
| shell: msys2 {0} | |
| run: ./scripts/build-ffmpeg-windows.sh | |
| - name: Sign binaries (macOS) | |
| if: runner.os == 'macOS' && env.APPLE_CERTIFICATE != '' | |
| run: | | |
| set -euo pipefail | |
| for bin in out/*/bin/ffmpeg out/*/bin/ffprobe .build-cache/out/*/bin/ffmpeg .build-cache/out/*/bin/ffprobe; do | |
| [ -x "$bin" ] || continue | |
| codesign --force --options runtime --sign "$APPLE_SIGNING_IDENTITY" "$bin" | |
| echo "Signed: $bin" | |
| done | |
| - name: Package artifacts (POSIX) | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| run: ./scripts/package.sh | |
| - name: Package artifacts (Windows) | |
| if: runner.os == 'Windows' | |
| shell: msys2 {0} | |
| run: ./scripts/package-windows.sh | |
| - name: Notarize (macOS) | |
| if: runner.os == 'macOS' && env.APPLE_CERTIFICATE != '' | |
| env: | |
| APPLE_API_KEY_CONTENTS: ${{ secrets.APPLE_API_KEY_CONTENTS }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | |
| run: | | |
| set -euo pipefail | |
| echo "$APPLE_API_KEY_CONTENTS" | base64 --decode > AuthKey.p8 | |
| for zip in dist/*.zip; do | |
| echo "==> Notarizing $zip" | |
| xcrun notarytool submit "$zip" \ | |
| --key AuthKey.p8 \ | |
| --key-id "$APPLE_API_KEY" \ | |
| --issuer "$APPLE_API_ISSUER" \ | |
| --wait | |
| done | |
| rm AuthKey.p8 | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ffmpeg-${{ matrix.os }}-${{ matrix.arch }}${{ env.ENABLE_NONFREE == 'true' && '-nonfree' || '' }} | |
| path: dist/*.zip | |
| release: | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: build | |
| runs-on: ubuntu-22.04 | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: ./dist | |
| - uses: softprops/action-gh-release@v2 | |
| with: | |
| files: dist/**/**.zip | |
| generate_release_notes: true |