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
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Preserve upstream document bytes and original whitespace on every platform.
upstream/** -text -whitespace
150 changes: 150 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
mcpp:
name: mcpp (${{ matrix.os }}, ${{ matrix.toolchain }})
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-24.04, toolchain: 'gcc@16.1.0' }
- { os: ubuntu-24.04, toolchain: 'llvm@23.1.3' }
- { os: ubuntu-24.04-arm, toolchain: 'gcc@16.1.0' }
- { os: macos-15, toolchain: 'llvm@23.1.3' }
- { os: windows-2025, toolchain: 'llvm@23.1.3' }
runs-on: ${{ matrix.os }}
timeout-minutes: 60
defaults:
run:
shell: bash
env:
XLINGS_NON_INTERACTIVE: 1
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Mwrap identity and bilingual README contract
run: python3 tools/check_mwrap_release.py

- name: Install Xlings (Linux/macOS)
if: runner.os != 'Windows'
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/refs/heads/main/tools/other/quick_install.sh | bash
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install Xlings (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
"$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: Install project tools (.xlings.json)
run: |
for attempt in 1 2 3; do
xlings update > /dev/null 2>&1 || true
if xlings install; then break; fi
[ "$attempt" = 3 ] && exit 1
sleep 30
done
mcpp --version

- name: Select the toolchain
run: |
name="${{ matrix.toolchain }}"
mcpp toolchain install "${name%@*}" "${name#*@}"
mcpp toolchain default "$name"

# Until mcpp-index publishes compat.libvpx and compat.libwebm
# (mcpplibs/mcpp-index#624), the compat namespace of this checkout's
# manifests resolves from that PR's branch, as an unchanged namespace
# view of its descriptors. Once the published index has the descriptors,
# this step does nothing.
- name: Candidate compat index (only while compat.libvpx is unpublished)
run: python3 tools/candidate_index.py --ci

- name: Build the modules
run: mcpp build

- name: Tests (VP9 in WebM through the modules, every macro mapping against the headers, every function linked)
run: mcpp test

- name: Tests, release profile
run: mcpp test --profile release

- name: Export audit (the generated sources are fresh; every declaration and macro of the public headers)
run: python3 tools/check_exports.py

# Upstream's vpxenc and vpxdec from the same tag, built by its own
# configure and makefiles with the system compilers: needs make (not on
# Windows).
- name: Conformance (examples/vpxwebm byte-identical to upstream vpxenc; WebM read by vpxdec and by mkvparser alike)
if: runner.os != 'Windows'
run: python3 tools/run_conformance.py

- name: The example builds (Windows)
if: runner.os == 'Windows'
working-directory: examples/vpxwebm
run: mcpp build

# The Web: wasm32-emscripten (emsdk from xlings, through mcpp), the tests
# under node.
web:
name: mcpp (web, wasm32-emscripten)
runs-on: ubuntu-24.04
timeout-minutes: 60
defaults:
run:
shell: bash
env:
XLINGS_NON_INTERACTIVE: 1
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Xlings
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/refs/heads/main/tools/other/quick_install.sh | bash
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install project tools (.xlings.json)
run: |
for attempt in 1 2 3; do
xlings update > /dev/null 2>&1 || true
if xlings install; then break; fi
[ "$attempt" = 3 ] && exit 1
sleep 30
done
mcpp --version

- name: Install emsdk
run: mcpp toolchain install emsdk 6.0.9

- name: Candidate compat index (only while compat.libvpx is unpublished)
run: python3 tools/candidate_index.py --ci

- name: Tests under node
run: mcpp test --toolchain emsdk@6.0.9 --target wasm32-emscripten

- name: Tests under node, release profile
run: mcpp test --toolchain emsdk@6.0.9 --target wasm32-emscripten --profile release
49 changes: 49 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Release
on:
push:
tags: ["mwrap-*"]
permissions:
contents: read
jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
actions: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Check tag, upstream version and bilingual entry pages
run: python3 tools/check_mwrap_release.py --tag "$GITHUB_REF_NAME"
- name: Require successful source CI at this exact commit
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
result=$(gh run list --repo "$GITHUB_REPOSITORY" --workflow ci.yml --commit "$GITHUB_SHA" --limit 1 --json status,conclusion --jq '.[0] | .status == "completed" and .conclusion == "success"')
test "$result" = true || { echo 'No successful source CI at the tag commit'; exit 1; }
- name: Build immutable source asset and publish
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
version="${GITHUB_REF_NAME#mwrap-}"
repo="${GITHUB_REPOSITORY#*/}"
asset="${repo}-${version}.tar.gz"
git archive --format=tar.gz --prefix="${repo}-${version}/" "$GITHUB_SHA" > "$RUNNER_TEMP/$asset"
(cd "$RUNNER_TEMP" && sha256sum "$asset" > "$asset.sha256")
if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo 'Release already exists; refusing to change immutable assets'; exit 1
fi
extra=()
if [[ "$version" == *-rc* ]]; then extra+=(--prerelease); fi
gh release create "$GITHUB_REF_NAME" "$RUNNER_TEMP/$asset" "$RUNNER_TEMP/$asset.sha256" \
--repo "$GITHUB_REPOSITORY" --verify-tag --title "$repo $version" \
--notes "Module wrapper for upstream $version. New mwrap package identities become installable after mcpp-index publication; see the bilingual README for the tested support scope." "${extra[@]}"
33 changes: 33 additions & 0 deletions .github/workflows/templates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Actual project templates
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: templates-${{ github.ref }}
cancel-in-progress: true
env:
MCPP_VERSION: "2026.10.27.1"
jobs:
templates:
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Install the pinned mcpp
shell: bash
run: |
archive="mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
curl -L -fsS -o "$archive" "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/$archive"
tar -xzf "$archive"
echo "$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/bin" >> "$GITHUB_PATH"
# The candidate index (tools/candidate_index.py) only while mcpp-index
# does not publish compat.libvpx and compat.libwebm.
- name: Actual scaffold, strict build and run of the default template (webm)
shell: bash
run: |
index=$(python3 tools/candidate_index.py --checkout-only)
python3 tools/test_template.py --toolchain gcc@16.1.0 ${index:+--index "$index"}
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
target
compile_commands.json
mcpp.lock
.mcpp/
.xlings/
doctor.log
__pycache__/
5 changes: 5 additions & 0 deletions .xlings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"workspace": {
"xim:mcpp": "2026.10.27.1"
}
}
20 changes: 20 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
libvpx-m: C++ module wrapper
Copyright (c) 2026 mcpp-community contributors

The wrapper contributions are licensed under the Apache License, Version 2.0.
Upstream code, copied interfaces and dependencies retain their original
licenses and copyright notices.

libvpx is distributed under the BSD 3-Clause license, with the WebM
project's additional patent grant:

Copyright (c) 2010, The WebM Project authors. All rights reserved.

libwebm is distributed under the BSD 3-Clause license, with the same grant:

Copyright (c) 2010, Google Inc. All rights reserved.

Their original READMEs, licenses, patent grants and authors are retained in
upstream/libvpx/ and upstream/libwebm/. The libraries themselves are built
by compat.libvpx and compat.libwebm from the same tags. Provenance and
checksums are recorded in upstream/documents.json.
116 changes: 114 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,115 @@
# libvpx-m
# libvpx

libvpx (VP9) and libwebm (WebM) as C++23 modules for mcpp. Work in progress.
> libvpx, the VP9 video codec, and libwebm, the WebM container, through C++23 modules.

**English** · [简体中文](README.zh.md) · [Upstream](https://chromium.googlesource.com/webm/libvpx) · [libwebm](https://github.com/webmproject/libwebm) · [Releases](https://github.com/mcpplibs/libvpx-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index)

[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
[![libvpx](https://img.shields.io/badge/libvpx-BSD--3--Clause-blue.svg)](upstream/libvpx/LICENSE)
[![libwebm](https://img.shields.io/badge/libwebm-BSD--3--Clause-blue.svg)](upstream/libwebm/LICENSE.TXT)
[![mcpp-community](https://img.shields.io/badge/mcpp--community-mwrap-blue)](https://github.com/mcpp-community)
[![CI](https://github.com/mcpplibs/libvpx-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/libvpx-m/actions/workflows/ci.yml)

`mcpplibs.mwrap.libvpx` 1.17.0 encodes and decodes VP9, the royalty-free
video of the Web, and writes and reads WebM, the container every browser
plays. The upstream APIs are unchanged: `vpx_codec_enc_config_default`,
`vpx_codec_encode`, `vpx_codec_get_cx_data`, `vpx_codec_decode`,
`vpx_codec_get_frame`, `vpx_img_alloc` … are libvpx's globals, and
`mkvmuxer::Segment`, `mkvparser::Segment`, `mkvmuxer::IMkvWriter`,
`mkvparser::IMkvReader` … are libwebm's classes in their own namespaces. The
libraries are `compat.libvpx` 1.17.0 and `compat.libwebm` 1.0.0.32. The
headers' typed controls (`vpx_codec_control_VP8E_SET_CPUUSED` …) are adapted
under the same names, and the macros are constants and functions. On every
CI run the files written are byte-identical to upstream's own `vpxenc`, and
`vpxdec` reads them to the same frames.

## Modules

- `import mcpplibs.mwrap.libvpx;`: the encoder and decoder (`vpx/vpx_encoder.h`, `vpx/vpx_decoder.h`, `vpx/vp8cx.h`, `vpx/vp8dx.h` …), re-exporting the two below
- `import mcpplibs.mwrap.libvpx.webm;`: libwebm's `mkvmuxer`, `mkvparser` and `libwebm` namespaces
- `import mcpplibs.mwrap.libvpx.macros;`: `VPX_DL_REALTIME`, `VPX_FRAME_IS_KEY`, `VPX_CODEC_CAP_ENCODER`, `vpx_codec_enc_init` … in `mcpplibs::mwrap::libvpx::macros`

> More Modules API -> [Usage and API](docs/usage.md)

## Getting started

```sh
mcpp new clip --template mcpplibs.mwrap.libvpx@1.17.0
cd clip
mcpp run -- clip.webm
```

The default template encodes two seconds of moving pictures, muxes them into
a WebM in memory, parses it back, decodes every frame and prints the file's
size and the worst PSNR; given a file name it also writes the WebM.

```toml
[dependencies]
"mcpplibs.mwrap.libvpx" = "1.17.0"
```

```cpp
import std;
import mcpplibs.mwrap.libvpx;

namespace m = mcpplibs::mwrap::libvpx::macros;

int main() {
vpx_codec_enc_cfg_t cfg;
vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &cfg, 0);
cfg.g_w = 320;
cfg.g_h = 180;
cfg.g_timebase = {1, 30};
vpx_codec_ctx_t encoder;
m::vpx_codec_enc_init(&encoder, vpx_codec_vp9_cx(), &cfg, 0);
mcpplibs::mwrap::libvpx::vpx_codec_control_VP8E_SET_CPUUSED(&encoder, VP8E_SET_CPUUSED, 6);
vpx_image_t img;
vpx_img_alloc(&img, VPX_IMG_FMT_I420, 320, 180, 16);
// … fill img.planes, then vpx_codec_encode(&encoder, &img, pts, 1, 0, m::VPX_DL_GOOD_QUALITY)
vpx_img_free(&img);
vpx_codec_destroy(&encoder);
std::println("{}", vpx_codec_version_str());
}
```

## The libraries

`compat.libvpx` builds the 101 C files upstream's own `configure
--target=generic-gnu --disable-vp8 --enable-vp9` compiles: libvpx's portable
C, without SIMD, assembler or run-time CPU detection, so one configuration
builds on x86-64 and aarch64, Linux, macOS, Windows and wasm32-emscripten. One
thread (the default) gives the same bytes on every target; more threads tile
the work (on Emscripten without pthreads, in turn on one). VP8 is not built.
`compat.libwebm` builds upstream's `webm` library (mkvmuxer, mkvparser and
the common helpers). mkvmuxer gives a track a random UID unless one is set
(`Track::set_uid`): set it for reproducible files. Details and limits:
[docs/usage.md](docs/usage.md).

## Examples

- [examples/vpxwebm](examples/vpxwebm): encodes Y4M to VP9 in WebM or IVF, decodes WebM or IVF to raw I420 and
describes a WebM, written against the module; [tools/run_conformance.py](tools/run_conformance.py) compares it with
upstream's `vpxenc` and `vpxdec`.

## Build and testing

Linux (x86_64 GCC and LLVM, arm64 GCC), macOS, Windows and wasm32-emscripten
(under node) CI build the modules and run the tests in the dev and release
profiles: VP9 at good quality, real time, four threads and lossless, muxed
into WebM, parsed and decoded back, each file's bytes pinned; every macro
mapping against the raw headers; every exported function linked. The native
rows also run the export audit ([tools/check_exports.py](tools/check_exports.py):
the generated modules are fresh, every declaration exported, every macro
mapped or accounted for) and, but on Windows, the conformance run against
upstream's tools. A separate job scaffolds the template as an installed
package and runs it.

## License

[Apache-2.0](LICENSE) for the wrapper, by mcpp-community; libvpx and libwebm
remain BSD-3-Clause with the WebM project's patent grant
([upstream/libvpx/LICENSE](upstream/libvpx/LICENSE),
[upstream/libvpx/PATENTS](upstream/libvpx/PATENTS),
[upstream/libwebm/LICENSE.TXT](upstream/libwebm/LICENSE.TXT),
[upstream/libwebm/PATENTS.TXT](upstream/libwebm/PATENTS.TXT)).
Loading
Loading