Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 70 additions & 90 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
- master
- ci
- 'release/**'
tags:
- 'v0.*'
paths-ignore:
- 'DOCS/**'
- 'TOOLS/lua/**'
Expand Down Expand Up @@ -129,6 +131,66 @@ jobs:
path: ${{ env.CCACHE_DIR }}
key: ${{ env.TARGET }}-${{ steps.get_time.outputs.timestamp }}

mingw64-full:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: [win64, winarm64]
variant: [gpl, lgpl]
container:
image: ghcr.io/btbn/ffmpeg-builds/${{ matrix.target }}-${{ matrix.variant }}:latest
env:
WINEPREFIX: /tmp/wine
steps:
- uses: actions/checkout@v7

- name: Build
id: build
run: |
./ci/build-mingw64-full.sh

- name: Print meson log
if: ${{ failure() && steps.build.outcome == 'failure' }}
run: |
cat ./build/meson-logs/meson-log.txt

- name: Functional test
if: ${{ matrix.target == 'win64' }}
run: |
cd artifact && wine ./mpv.com -v --no-config

- name: Run meson tests
if: ${{ matrix.target == 'win64' }}
id: tests
run: |
meson test -C build

- name: Print meson test log
if: ${{ failure() && steps.tests.outcome == 'failure' }}
run: |
cat ./build/meson-logs/testlog.txt

- name: Artifact name
id: artifact
run: |
VERSION_FILE=$(find . -path "*/common/version.h" -type f | head -n 1)
VER=$(grep VERSION "$VERSION_FILE" | cut -d'"' -f2)
PR=${{ github.event.pull_request.number && format('-pr{0}', github.event.pull_request.number) || '' }}
echo "mpv=mpv-$VER$PR-${{ github.run_id }}-$FFBUILD_TOOLCHAIN-full" >> "$GITHUB_OUTPUT"
echo "libmpv=libmpv-$VER$PR-${{ github.run_id }}-$FFBUILD_TOOLCHAIN-${{ matrix.variant }}" >> "$GITHUB_OUTPUT"

- uses: actions/upload-artifact@v7
if: ${{ matrix.variant == 'gpl' }}
with:
name: ${{ steps.artifact.outputs.mpv }}
path: artifact/*

- uses: actions/upload-artifact@v7
with:
name: ${{ steps.artifact.outputs.libmpv }}
path: artifact-libmpv/*

win32:
runs-on: ${{ matrix.os }}
strategy:
Expand Down Expand Up @@ -729,108 +791,26 @@ jobs:
cat ./build/meson-logs/testlog.txt

publish:
name: Publish git release
needs: [mingw, win32, macos]
if: github.event_name == 'push' && github.ref == 'refs/heads/master' &&
github.repository == 'mpv-player/mpv'
name: Publish release
needs: [mingw, mingw64-full, win32, macos]
if: github.event_name == 'push' && github.repository == 'mpv-player/mpv' &&
(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v0.'))
runs-on: ubuntu-slim
permissions:
contents: write
actions: read
concurrency:
group: publish-git
group: publish
cancel-in-progress: false
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true

- name: Publish to git release
- name: Publish
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -eu
tag=git-release
base_url="https://github.com/$GH_REPO/releases/download/$tag"

artifacts=$(gh api "repos/{owner}/{repo}/actions/runs/${{ github.run_id }}/artifacts")

# Attach every build artifact unchanged; the notes link to them with
# labels derived from the verbose names.
mkdir -p release
jq -r '.artifacts[] | "\(.id)\t\(.name)"' <<< "$artifacts" |
while IFS=$'\t' read -r id name; do
gh api "repos/{owner}/{repo}/actions/artifacts/$id/zip" > "release/$name.zip"
done

section() {
jq -r --arg url "$base_url" --arg re "$1" '
def pretty:
(if test("i686") then "i686"
elif test("aarch64") then "arm64"
elif test("-arm$") then "arm64"
elif test("intel") then "x86_64"
else "x86_64" end) as $arch
| [ (if test("mingw") then "GCC" elif test("msvc") then "Clang" else empty end),
(if test("macos") then "macOS " + capture("macos-(?<v>[0-9]+)").v else empty end),
(if test("-pdb") then "debug symbols" else empty end) ] as $q
| $arch + (if ($q | length) > 0 then " (" + ($q | join(", ")) + ")" else "" end);
# primary builds first (x86_64, arm64, i686; Clang before GCC), debug symbols last
def rank:
[ (if test("-pdb") then 1 else 0 end),
(if test("x86_64|intel") then 0 elif test("i686") then 2 else 1 end),
(if test("mingw") then 1 else 0 end),
(if test("macos") then (capture("macos-(?<v>[0-9]+)").v | tonumber) else 0 end) ];
[ .artifacts[] | select(.name | test($re)) ] | sort_by(.name | rank)
| map("* [\(.name | pretty)](\($url)/\(.name).zip)") | join("\n")
' <<< "$artifacts"
}

# Match the version string baked into the build (see common/meson.build).
version=$(git describe --abbrev=9 --tags --dirty --match "v0.*")
notes=$(cat <<EOF
Automated development build of the latest \`master\` branch.

- Version: \`$version\`
- Commit: ${{ github.sha }}
- Built: $(date -u '+%Y-%m-%d %H:%M:%S UTC')

### Windows

$(section 'w64|msvc')

### macOS

$(section 'macos')

> [!WARNING]
> These are untested development builds of the very latest \`master\`.
> They are **not** official releases. For stable builds see the
> [latest release](https://github.com/$GH_REPO/releases/latest).
EOF
)

# Create the release once (which also creates the tag), then only edit
# it in place so watchers aren't notified on every master push. Stale
# assets are dropped first since their names embed the run id.
if gh release view "$tag" >/dev/null 2>&1; then
gh release view "$tag" --json assets --jq '.assets[].name' |
while read -r asset; do
gh release delete-asset "$tag" "$asset" --yes
done
gh release edit "$tag" \
--prerelease \
--latest=false \
--title "mpv development build" \
--notes "$notes"
gh release upload "$tag" release/*
else
gh release create "$tag" \
--target "$GITHUB_SHA" \
--prerelease \
--latest=false \
--title "mpv development build" \
--notes "$notes" \
release/*
fi
./ci/publish-release.sh
10 changes: 10 additions & 0 deletions DOCS/compile-windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ cross-compiling environment. For a basic example, please refer to
Alternatively, consider using [mpv-winbuild-cmake](https://github.com/shinchiro/mpv-winbuild-cmake),
which bootstraps a MinGW-w64 toolchain and builds mpv along with its dependencies.

The full Windows builds on the [release page](https://github.com/mpv-player/mpv/releases)
are cross-compiled in the [FFmpeg-Builds](https://github.com/BtbN/FFmpeg-Builds)
container images, which provide a toolchain and all dependencies as static
libraries. [ci/build-mingw64-full.sh](https://github.com/mpv-player/mpv/blob/master/ci/build-mingw64-full.sh)
reproduces such a build from the mpv source tree:

``` bash
docker run --rm -v "$PWD:/mpv" -w /mpv ghcr.io/btbn/ffmpeg-builds/win64-gpl:latest ./ci/build-mingw64-full.sh
```

### Example with Meson

1. Create ``cross-file.txt`` with definitions for your toolchain and target platform.
Expand Down
10 changes: 5 additions & 5 deletions audio/out/ao_lavc.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ static int init(struct ao *ao)
{
struct priv *ac = ao->priv;

ac->enc = encoder_context_alloc(ao->encode_lavc_ctx, STREAM_AUDIO, ao->log);
ac->enc = mp_encoder_context_alloc(ao->encode_lavc_ctx, STREAM_AUDIO, ao->log);
if (!ac->enc)
return -1;
talloc_steal(ac, ac->enc);
Expand Down Expand Up @@ -137,10 +137,10 @@ static int init(struct ao *ao)
encoder->sample_fmt = af_to_avformat(ao->format);
encoder->bits_per_raw_sample = ac->sample_size * 8;

if (!encoder_init_codec_and_muxer(ac->enc))
if (!mp_encoder_init_codec_and_muxer(ac->enc))
goto fail;

ac->worst_time_base = encoder_get_mux_timebase_unlocked(ac->enc);
ac->worst_time_base = mp_encoder_get_mux_timebase_unlocked(ac->enc);
ac->pcmhack = 0;
if (encoder->frame_size <= 1)
ac->pcmhack = av_get_bits_per_sample(encoder->codec_id) / 8;
Expand Down Expand Up @@ -183,7 +183,7 @@ static void uninit(struct ao *ao)
if (!ac->shutdown) {
if (!write_frame(ao, MP_EOF_FRAME))
MP_WARN(ao, "could not flush last frame\n");
encoder_encode(ac->enc, NULL);
mp_encoder_encode(ac->enc, NULL);
}

talloc_free(ac->filter_root);
Expand Down Expand Up @@ -217,7 +217,7 @@ static void encode(struct ao *ao, struct mp_aframe *af)
ac->lastpts = frame_pts;

frame->quality = encoder->global_quality;
encoder_encode(ac->enc, frame);
mp_encoder_encode(ac->enc, frame);
av_frame_free(&frame);
}

Expand Down
128 changes: 128 additions & 0 deletions ci/build-mingw64-full.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env bash
#
# Static mpv and libmpv builds on top of the FFmpeg-Builds container images
# (ghcr.io/btbn/ffmpeg-builds/<target>-<variant>, see
# https://github.com/BtbN/FFmpeg-Builds). The image ships the cross toolchain,
# a matching /cross.meson and every FFmpeg dependency as static library in
# $FFBUILD_PREFIX, so only FFmpeg itself and the things FFmpeg does not need
# are built here. Run it from the mpv source tree inside the container:
#
# docker run --rm -v "$PWD:/mpv" -w /mpv \
# ghcr.io/btbn/ffmpeg-builds/win64-gpl:latest ./ci/build-mingw64-full.sh
#
# The mpv binaries end up in artifact/, the libmpv package in artifact-libmpv/.
set -euo pipefail

: "${FFBUILD_PREFIX:?not running in a FFmpeg-Builds image}"
: "${VARIANT:?not running in a FFmpeg-Builds image}"

. ./ci/build-common.sh

# The dependency headers are not ours to fix, keep --werror to mpv's own code.
CFLAGS="${CFLAGS/-I${FFBUILD_PREFIX}\/include/-isystem${FFBUILD_PREFIX}/include}"
CXXFLAGS="${CXXFLAGS/-I${FFBUILD_PREFIX}\/include/-isystem${FFBUILD_PREFIX}/include}"

gpl=false
[[ $VARIANT == gpl* ]] && gpl=true

gitclone="git clone --depth=1 --recursive --shallow-submodules"
group() { echo "::group::$1"; }
endgroup() { echo "::endgroup::"; }

group "Building FFmpeg"
$gitclone https://github.com/FFmpeg/FFmpeg.git ffmpeg
pushd ffmpeg
# rav1e and librsvg bring their own Rust runtime, which clashes with subrandr's.
./configure --prefix="$FFBUILD_PREFIX" --pkg-config-flags="--static" \
$FFBUILD_TARGET_FLAGS $FF_CONFIGURE \
--extra-cflags="$FF_CFLAGS" --extra-cxxflags="$FF_CXXFLAGS" \
--extra-libs="$FF_LIBS" --extra-ldflags="$FF_LDFLAGS" \
--extra-ldexeflags="$FF_LDEXEFLAGS" \
--cc="$CC" --cxx="$CXX" --ar="$AR" --ranlib="$RANLIB" --nm="$NM" \
--enable-static --disable-shared --disable-{doc,programs} \
--disable-{librav1e,librsvg,openal} || { cat ffbuild/config.log; exit 1; }
make -j"$(nproc)"
make install
popd
endgroup

group "Building LuaJIT"
$gitclone -b v2.1 https://github.com/LuaJIT/LuaJIT.git
pushd LuaJIT
# Strip -ldl, not needed for Windows.
sed -i "/^Libs\.private/d" etc/luajit.pc
# FILE_T and INSTALL_DEP are only needed to glue install target.
make TARGET_SYS=Windows PREFIX="$FFBUILD_PREFIX" HOST_CC="$HOST_CC" \
CFLAGS="$HOST_CFLAGS" CROSS="$FFBUILD_CROSS_PREFIX" TARGET_CFLAGS="$CFLAGS" \
BUILDMODE=static XCFLAGS=-DLUAJIT_ENABLE_LUA52COMPAT FILE_T=luajit.exe \
INSTALL_DEP=src/luajit.exe amalg install
popd
endgroup

group "Building subrandr"
build_subrandr "$FFBUILD_PREFIX" --target "$FFBUILD_RUST_TARGET" \
--static-library true --shared-library false
endgroup

group "Building cppwinrt"
# win32-smtc needs the C++/WinRT projection headers, generated from the
# Windows metadata that windows-rs carries.
cppwinrt_ver=2.0.250303.1
windows_rs_ver=73
wget -q "https://github.com/microsoft/cppwinrt/archive/${cppwinrt_ver}.tar.gz" -O - | tar -xz
git clone --depth=1 --filter=blob:none --sparse -b "$windows_rs_ver" \
https://github.com/microsoft/windows-rs.git
git -C windows-rs sparse-checkout set crates/libs/bindgen/default
mkdir -p "cppwinrt-$cppwinrt_ver/build"
pushd "cppwinrt-$cppwinrt_ver/build"
CFLAGS="$HOST_CFLAGS" CXXFLAGS="$HOST_CXXFLAGS" LDFLAGS= \
cmake -GNinja -DCMAKE_CXX_COMPILER="$HOST_CXX" -DCMAKE_BUILD_TYPE=Release \
-DCPPWINRT_BUILD_VERSION="$cppwinrt_ver" ..
ninja cppwinrt
./cppwinrt -input ../../windows-rs/crates/libs/bindgen/default \
-output "$FFBUILD_PREFIX/include"
popd
endgroup

group "Building mpv"
mkdir -p subprojects
meson wrap install mujs
meson subprojects download

mpv_args=(
--cross-file /cross.meson $common_args
--buildtype=release
--prefer-static
--default-library=shared
-Dc_link_args="$FF_LIBS"
-Dcpp_link_args="$FF_LIBS"
-Dgpl=$gpl
--force-fallback-for=mujs
-Dmujs:werror=false
-Dmujs:default_library=static
-Dlua=luajit
-D{amf,d3d11,javascript,lcms2,libbluray,libcurl,shaderc,spirv-cross}=enabled
-D{subrandr,vulkan,win32-smtc,zimg}=enabled
)
if $gpl; then
# Only the GPL image carries the dependencies of the GPL features.
mpv_args+=(-D{dvda,dvdnav,rubberband}=enabled)
fi
meson setup build "${mpv_args[@]}"
meson compile -C build
endgroup

group "Packaging"
license=LICENSE.LGPL
if $gpl; then
license=LICENSE.GPL
fi
mkdir -p artifact artifact-libmpv/include/mpv
cp -p build/mpv.{exe,com} etc/mpv-*.bat "$license" artifact/
cp -p build/libmpv*.dll build/libmpv*.dll.a "$license" artifact-libmpv/
cp -p include/mpv/*.h artifact-libmpv/include/mpv/
cp -p "$FFBUILD_PREFIX"/share/java/libbluray-*.jar artifact/
cp -p "$FFBUILD_PREFIX"/share/java/libbluray-*.jar artifact-libmpv/
"${FFBUILD_CROSS_PREFIX}strip" artifact/mpv.{exe,com} artifact-libmpv/libmpv*.dll
ls -l artifact artifact-libmpv
endgroup
Loading
Loading