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: 1 addition & 1 deletion .github/lux-ci-config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"automation_ref": "v1.6",
"automation_ref": "903723cb3831e5721ce78e19b6ec53d061f0388f",
"review": {
"workflow_name": "luxie-tronic",
"branches": [
Expand Down
17 changes: 16 additions & 1 deletion .github/scripts/build-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,30 @@ if [ ! -z "$GITHUB_ENV" ]; then
echo "PATH=$PYBIN:$PATH" >> $GITHUB_ENV
fi

# Install Rust for the Linux backend.
if ! command -v cargo >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal --default-toolchain stable
fi
if [ -f "$HOME/.cargo/env" ]; then
source "$HOME/.cargo/env"
fi
rustc --version
cargo --version

# install compile-time dependencies
${PYBIN}/pip install numpy==${NUMPY_VERSION}
${PYBIN}/pip install setuptools
${PYBIN}/pip install setuptools 'setuptools-rust>=1.10.2,<1.11.0'

# List installed packages
${PYBIN}/pip freeze

# Build pyvirtualcam wheel
export LDFLAGS="-Wl,--strip-debug"
if [ "$PYTHON_VERSION" == "3.13" ]; then
# PyO3 0.21 officially supports up to Python 3.12; build cp313 via stable ABI.
export PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1
fi
${PYBIN}/python setup.py bdist_wheel --dist-dir dist-tmp

# Bundle external shared libraries into wheel and fix the wheel tags
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/build-macos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ set -x
popd

# Install dependencies
pip install numpy==$NUMPY_VERSION wheel delocate setuptools
pip install numpy=="$NUMPY_VERSION" wheel delocate setuptools

# List installed packages
pip freeze
Expand Down
18 changes: 3 additions & 15 deletions .github/scripts/test-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,6 @@ ${PYBIN}/pip install ./dist/pyvirtualcam*cp${PYVER}*manylinux*.whl

${PYBIN}/pip install -r dev-requirements.txt

mkdir tmp_for_test
pushd tmp_for_test
# NOTE: TESTING DISABLED!
# The v4l2loopback kernel module cannot be installed as it depends
# on v4l2 (videodev) kernel support.
# videodev can either be built into the kernel directly or supported
# as loadable module.
# Azure (which is what GitHub Actions uses) only offers videodev
# in linux-modules-extra-azure starting from Ubuntu 20.10.
# See https://packages.ubuntu.com/search?suite=groovy&arch=any&mode=exactfilename&searchon=contents&keywords=videodev.ko
# However, GitHub Actions only uses LTS releases of Ubuntu and they
# are currently at 20.04 LTS. The next LTS will be 22.04 LTS
# which will come out in 2022.
#${PYBIN}/pytest -v -s /io/test
popd
# Device-dependent tests (test_camera.py, test_capture.py) require v4l2loopback
# and are not run in CI. Mock/utility tests validate the Python API contract.
${PYBIN}/pytest -v /io/test/test_backend_contract.py /io/test/test_util.py
61 changes: 31 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,109 +34,110 @@ jobs:
# NOTE: When updating this list, also update the 'test' job!
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.8'
numpy-version: '1.24.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.9'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.10'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.11'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.12'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.13'
numpy-version: '2.2.*'

- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux2014_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.8'
numpy-version: '1.24.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.9'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.10'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.11'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.12'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.13'
numpy-version: '2.2.*'

- os-image: macos-13
# GitHub retired macos-13 on 2025-12-04; use macos-15-intel for x86_64.
- os-image: macos-15-intel
os-name: mac
python-arch: x86_64
macos-min-version: '10.9'
python-version: '3.8'
numpy-version: '1.24.*'
- os-image: macos-13
- os-image: macos-15-intel
os-name: mac
python-arch: x86_64
macos-min-version: '10.9'
python-version: '3.9'
numpy-version: '2.0.*'
- os-image: macos-13
- os-image: macos-15-intel
os-name: mac
python-arch: x86_64
macos-min-version: '10.9'
python-version: '3.10'
numpy-version: '2.0.*'
- os-image: macos-13
- os-image: macos-15-intel
os-name: mac
python-arch: x86_64
macos-min-version: '10.9'
python-version: '3.11'
numpy-version: '2.0.*'
- os-image: macos-13
- os-image: macos-15-intel
os-name: mac
python-arch: x86_64
macos-min-version: '10.9'
python-version: '3.12'
numpy-version: '2.0.*'
- os-image: macos-13
- os-image: macos-15-intel
os-name: mac
python-arch: x86_64
macos-min-version: '10.9'
Expand Down Expand Up @@ -232,74 +233,74 @@ jobs:
config:
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.8'
numpy-version: '1.24.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.9'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.10'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.11'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.12'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux2014_x86_64
docker-image: quay.io/pypa/manylinux2014_x86_64:2026.05.01-2
python-arch: 'x86_64'
python-version: '3.13'
numpy-version: '2.2.*'

- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux2014_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.8'
numpy-version: '1.24.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.9'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.10'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.11'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.12'
numpy-version: '2.0.*'
- os-image: ubuntu-latest
os-name: linux
docker-image: quay.io/pypa/manylinux_2_28_aarch64
docker-image: quay.io/pypa/manylinux_2_28_aarch64:2026.05.01-2
python-arch: 'aarch64'
python-version: '3.13'
numpy-version: '2.2.*'
Expand Down
12 changes: 9 additions & 3 deletions .github/workflows/luxie-tronic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ permissions:
issues: write
jobs:
review:
uses: LuxTronic/luxie-workflows/.github/workflows/reusable-luxie-tronic.yml@v1.6
uses: LuxTronic/luxie-workflows/.github/workflows/reusable-luxie-tronic.yml@903723cb3831e5721ce78e19b6ec53d061f0388f # v1.6
with:
automation_ref: v1.6
automation_ref: 903723cb3831e5721ce78e19b6ec53d061f0388f
policy_path: .codex/luxie-tronic-policy.json
pr_number: ${{ github.event.inputs.pr_number || '' }}
secrets: inherit
secrets:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
CODEX_BOT_PAT: ${{ secrets.CODEX_BOT_PAT }}
CODEX_BOT_GPG_PRIVATE_KEY: ${{ secrets.CODEX_BOT_GPG_PRIVATE_KEY }}
CODEX_BOT_GPG_PASSPHRASE: ${{ secrets.CODEX_BOT_GPG_PASSPHRASE }}
CODEX_BOT_GIT_NAME: ${{ secrets.CODEX_BOT_GIT_NAME }}
CODEX_BOT_GIT_EMAIL: ${{ secrets.CODEX_BOT_GIT_EMAIL }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ build
dist
dist-docs
*.pyd
*.so
*.pyc
*.zip
*.exe
.vscode
tmp
wheelhouse
target
external/miniconda*
*.png
*.json
Expand Down
28 changes: 28 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Agent Guidance

This repository provides `pyvirtualcam`, a Python package with native virtual
camera backends. Keep the public Python API stable unless a change is explicitly
intended to be breaking.

## Architecture

- `pyvirtualcam/` contains the Python compatibility API.
- `crates/pyvirtualcam-core/` contains the Rust core and the Linux
`v4l2loopback` backend.
- `crates/pyvirtualcam-py/` contains the PyO3 module exported as
`pyvirtualcam._native_linux_v4l2loopback`.
- macOS and Windows still use the existing native C++/ObjC++ backends.

## Development Notes

- Preserve `pyvirtualcam.Camera`, `PixelFormat`, `Backend`, and
`register_backend` behavior.
- Keep pixel conversions backed by vendored `external/libyuv` unless parity is
proven with capture tests.
- Treat the hand-written V4L2 ABI definitions as a small, private surface. If
the Linux backend needs more V4L2 APIs, prefer generated or crate-backed
bindings.
- Run Rust checks with `cargo fmt --check`, `cargo clippy --workspace --locked
--all-targets -- -D warnings`, and `cargo test --workspace --locked`.
- Run Python checks with `python -m pytest -q test/test_backend_contract.py
test/test_util.py`; full capture tests need real virtual camera devices.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Rust workspace (`pyvirtualcam-core`, `pyvirtualcam-py`) with a native Rust camera API and PyO3 bindings.
- Mock backend contract tests (`test/test_backend_contract.py`) for CI without a virtual camera device.
- `AGENTS.md` and crate-level architecture documentation.

### Changed
- Linux `v4l2loopback` backend is implemented in Rust; macOS and Windows backends remain C++/ObjC++.
- Linux CI installs Rust and runs mock Python tests on built wheels.

## [0.14.0] - 2025-09-10
### Added
- macOS 14 / OBS 30+ support (#134).
Expand Down
Loading
Loading