From 5349a3747d45ee5d5342090228b25a9a2005193b Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 08:46:49 +0900 Subject: [PATCH 1/8] fix: render a qualified template dependency and decode a generated sample --- .github/workflows/templates.yml | 40 +++++++++++++++ .xlings.json | 6 +-- README.md | 20 ++++++++ mcpp.toml | 2 +- templates/decode/mcpp.toml.in | 7 +-- templates/decode/src/main.cpp.in | 88 ++++++++++++++++++++------------ templates/decode/template.toml | 4 +- tools/test_template.py | 83 ++++++++++++++++++++++++++++++ 8 files changed, 206 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/templates.yml create mode 100644 tools/test_template.py diff --git a/.github/workflows/templates.yml b/.github/workflows/templates.yml new file mode 100644 index 0000000..0ff08be --- /dev/null +++ b/.github/workflows/templates.yml @@ -0,0 +1,40 @@ +name: Actual project templates +on: + pull_request: + workflow_dispatch: +permissions: + contents: read +concurrency: + group: templates-${{ github.ref }} + cancel-in-progress: true +env: + MCPP_VERSION: "2026.10.24.1" +jobs: + templates: + runs-on: ubuntu-latest + timeout-minutes: 120 + steps: + - uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ~/.mcpp/registry + key: template-registry-${{ github.repository }}-${{ env.MCPP_VERSION }}-${{ hashFiles('mcpp.toml') }} + restore-keys: | + template-registry-${{ github.repository }}-${{ env.MCPP_VERSION }}- + - name: Install current 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" + root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64" + mkdir -p "$HOME/.mcpp/registry" + cp -a "$root/registry/." "$HOME/.mcpp/registry/" + echo "$root/bin" >> "$GITHUB_PATH" + - name: Install toolchains + run: | + mcpp toolchain install gcc 16.1.0 + mcpp toolchain install llvm 23.1.3 + - name: Actual scaffold, strict build and runtime behavior + run: | + python3 tools/test_template.py --template decode --toolchain llvm@23.1.3 diff --git a/.xlings.json b/.xlings.json index da059b5..4dcdd6b 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1,5 +1,5 @@ { - "workspace": { - "xim:mcpp": "2026.8.5.4" - } + "workspace": { + "xim:mcpp": "2026.10.24.1" + } } diff --git a/README.md b/README.md index c9c9df5..f215cbc 100644 --- a/README.md +++ b/README.md @@ -84,3 +84,23 @@ cd examples/decode_frames && mcpp run -- video.mp4 ## License 封装代码 MIT;上游 FFmpeg 经 `compat.ffmpeg` 提供,**LGPL-2.1-or-later**(无 `--enable-gpl`/`nonfree` 组件),源码分发天然满足 LGPL 重链接要求。 + + +## Current-client quickstart candidate + +The wrapper revision is `8.1.2.1`; the upstream C/C++ API and published module +identity stay unchanged. Development tooling uses mcpp `2026.10.24.1`. Templates +now write one qualified dependency from `self.name`, without repeating a namespace. + +```sh +mcpp new quickstart --template ffmpeg.ffmpeg@8.1.2.1:decode +cd quickstart +mcpp run +``` + +This revision is a PR candidate until its source archive and index entry are +validated. `tools/test_template.py` exercises actual `mcpp new`, checks the +rendered dependency, strictly builds the candidate and runs it. + +Without arguments the decoder generates a tiny Y4M input and verifies three +decoded frames. Pass `mcpp run -- ` to decode your own input. diff --git a/mcpp.toml b/mcpp.toml index 7dd1b99..10f8641 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -8,7 +8,7 @@ [package] namespace = "ffmpeg" name = "ffmpeg" -version = "8.1.2" +version = "8.1.2.1" description = "FFmpeg 8.1.2 C++ modules for mcpp (import ffmpeg.av;) on top of the compat.ffmpeg source build" license = "MIT" repo = "https://github.com/mcpplibs/ffmpeg-m" diff --git a/templates/decode/mcpp.toml.in b/templates/decode/mcpp.toml.in index 578ba68..b20fbcb 100644 --- a/templates/decode/mcpp.toml.in +++ b/templates/decode/mcpp.toml.in @@ -2,8 +2,5 @@ name = "{{project.name}}" version = "0.1.0" -# `ffmpeg` is spelled out: templates substitute only project.name, -# self.name and self.version — there is no namespace placeholder yet. -# See mcpp-index#163. -[dependencies.ffmpeg] -{{self.name}} = "{{self.version}}" +[dependencies] +"{{self.name}}" = "{{self.version}}" diff --git a/templates/decode/src/main.cpp.in b/templates/decode/src/main.cpp.in index 327f2f8..1813289 100644 --- a/templates/decode/src/main.cpp.in +++ b/templates/decode/src/main.cpp.in @@ -1,42 +1,64 @@ -// Decode every video frame of the given file — plain FFmpeg C API, no headers. +// Decode a supplied video, or a generated three-frame sample when run without arguments. import std; import ffmpeg.av; int main(int argc, char** argv) { + struct Sample { + std::filesystem::path path; + ~Sample() { if (!path.empty()) { std::error_code error; std::filesystem::remove(path, error); } } + } sample; if (argc < 2) { - std::println("usage: {} ", argv[0]); - return 64; + sample.path = std::filesystem::temp_directory_path() / ("mcpp-video-" + + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + ".y4m"); + std::ofstream output(sample.path, std::ios::binary); + output << "YUV4MPEG2 W16 H16 F24:1 Ip A1:1 C420jpeg\n"; + for (int frame = 0; frame < 3; ++frame) { + output << "FRAME\n"; + output << std::string(16 * 16, static_cast(32 + frame * 16)); + output << std::string(2 * 8 * 8, static_cast(128)); + } + if (!output) return 1; } - - AVFormatContext* fmt { nullptr }; - if (avformat_open_input(&fmt, argv[1], nullptr, nullptr) < 0) { - std::println("cannot open {}", argv[1]); - return 1; + const std::string filename = argc > 1 ? argv[1] : sample.path.string(); + struct Decoder { + AVFormatContext* format = nullptr; + AVCodecContext* codec = nullptr; + AVPacket* packet = nullptr; + AVFrame* frame = nullptr; + ~Decoder() { + av_frame_free(&frame); + av_packet_free(&packet); + avcodec_free_context(&codec); + avformat_close_input(&format); + } + } decoder; + if (avformat_open_input(&decoder.format, filename.c_str(), nullptr, nullptr) < 0 || + avformat_find_stream_info(decoder.format, nullptr) < 0) { + std::println("Cannot open video: {}", filename); + return 2; } - avformat_find_stream_info(fmt, nullptr); - - int video { av_find_best_stream(fmt, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0) }; - const AVCodec* codec { avcodec_find_decoder(fmt->streams[video]->codecpar->codec_id) }; - AVCodecContext* dec { avcodec_alloc_context3(codec) }; - avcodec_parameters_to_context(dec, fmt->streams[video]->codecpar); - avcodec_open2(dec, codec, nullptr); - - AVPacket* packet { av_packet_alloc() }; - AVFrame* frame { av_frame_alloc() }; - long frames { 0 }; - while (av_read_frame(fmt, packet) >= 0) { - if (packet->stream_index == video && avcodec_send_packet(dec, packet) >= 0) - while (avcodec_receive_frame(dec, frame) >= 0) ++frames; - av_packet_unref(packet); + const int stream = av_find_best_stream(decoder.format, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); + if (stream < 0) { std::println("No video stream in {}", filename); return 3; } + const AVCodec* codec = avcodec_find_decoder(decoder.format->streams[stream]->codecpar->codec_id); + if (!codec) return 4; + decoder.codec = avcodec_alloc_context3(codec); + if (!decoder.codec || avcodec_parameters_to_context(decoder.codec, + decoder.format->streams[stream]->codecpar) < 0 || avcodec_open2(decoder.codec, codec, nullptr) < 0) + return 5; + decoder.packet = av_packet_alloc(); + decoder.frame = av_frame_alloc(); + if (!decoder.packet || !decoder.frame) return 6; + long frames = 0; + while (av_read_frame(decoder.format, decoder.packet) >= 0) { + if (decoder.packet->stream_index == stream) { + if (avcodec_send_packet(decoder.codec, decoder.packet) < 0) return 7; + while (avcodec_receive_frame(decoder.codec, decoder.frame) >= 0) ++frames; + } + av_packet_unref(decoder.packet); } - avcodec_send_packet(dec, nullptr); - while (avcodec_receive_frame(dec, frame) >= 0) ++frames; - - std::println("{}: {} ({}x{}), {} frames decoded", - argv[1], codec->name, dec->width, dec->height, frames); - - av_frame_free(&frame); - av_packet_free(&packet); - avcodec_free_context(&dec); - avformat_close_input(&fmt); + if (avcodec_send_packet(decoder.codec, nullptr) < 0) return 8; + while (avcodec_receive_frame(decoder.codec, decoder.frame) >= 0) ++frames; + std::println("{}: {} ({}x{}), {} frames decoded", filename, codec->name, + decoder.codec->width, decoder.codec->height, frames); + return frames > 0 && (argc > 1 || frames == 3) ? 0 : 9; } diff --git a/templates/decode/template.toml b/templates/decode/template.toml index 6de44e0..2e0211b 100644 --- a/templates/decode/template.toml +++ b/templates/decode/template.toml @@ -1,4 +1,4 @@ [template] -description = "Decode a video file's frames with import ffmpeg.av" +description = "Decode a generated sample or a supplied video with import ffmpeg.av" default = true -post_message = "cd into the project and run `mcpp run -- `." +post_message = "Run `mcpp run` for a generated sample, or `mcpp run -- ` for your own file." diff --git a/tools/test_template.py b/tools/test_template.py new file mode 100644 index 0000000..81ea805 --- /dev/null +++ b/tools/test_template.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +"""Render an installed candidate's default mcpp template, then build and run it.""" +import argparse +import json +import os +from pathlib import Path +import shutil +import subprocess +import tempfile +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--mcpp", default="mcpp") + parser.add_argument("--namespace", help="index namespace for legacy manifests without package.namespace") + parser.add_argument("--toolchain", default="llvm@23.1.3") + parser.add_argument("--template", help="named template; omit for the package default") + parser.add_argument("--run-arg", action="append", default=[]) + parser.add_argument("--index", type=Path, help="candidate SDK/wrapper index for unpublished feature dependencies") + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + metadata = tomllib.loads((root / "mcpp.toml").read_text())["package"] + namespace = metadata.get("namespace", args.namespace) + assert namespace, "Supply the published index namespace for this legacy manifest" + name, version = metadata["name"], metadata["version"] + identity = namespace + "." + name + with tempfile.TemporaryDirectory(prefix=name + "-template-") as directory: + temporary = Path(directory) + home = temporary / "home" + package = home / "registry/data/xpkgs" / (namespace + "-x-" + name) / version / (name + "-" + version) + shutil.copytree(root, package, ignore=shutil.ignore_patterns( + ".git", "target", ".mcpp", ".xlings", ".candidate-index", "__pycache__", "mcpp.lock", "compile_commands.json", "mcpp-2026.*")) + index = home / "indices/mcpplibs/pkgs/mwrap" + index.mkdir(parents=True) + entry = '{url="https://example.invalid/candidate.tar.gz",sha256="fixture"}' + descriptor = ('package={spec="1",namespace=' + json.dumps(namespace) + ',name=' + json.dumps(name) + + ',description="Installed template fixture",type="package",mcpp="mcpp.toml",xpm={') + descriptor += ",".join(platform + "={[" + json.dumps(version) + "]=" + entry + "}" + for platform in ("linux", "macosx", "windows")) + "}}\n" + (index / (identity + ".lua")).write_text(descriptor) + env = dict(os.environ, MCPP_HOME=str(home)) + selector = identity + "@" + version + for command in ([args.mcpp, "new", "--list-templates", selector], + [args.mcpp, "new", "quickstart", "--template", selector + (":" + args.template if args.template else "")]): + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=temporary, env=env, check=True) + project = temporary / "quickstart" + manifest = project / "mcpp.toml" + text = manifest.read_text() + dependency = tomllib.loads(text)["dependencies"][identity] + options = {"version": dependency} if isinstance(dependency, str) else dependency + assert options["version"] == version, options + replacement = '{ path = ' + json.dumps(package.as_posix()) + if options.get("features"): + replacement += ', features = ' + json.dumps(options["features"]) + replacement += ' }' + lines = text.splitlines() + matches = [i for i, line in enumerate(lines) if line.startswith(json.dumps(identity) + " =")] + assert len(matches) == 1, "Expected exactly one qualified dependency from self.name" + lines[matches[0]] = json.dumps(identity) + " = " + replacement + manifest.write_text("\n".join(lines) + "\n") + if args.index: + candidate_index = args.index.resolve() + subprocess.run([os.sys.executable, str(candidate_index / "tests/prepare_mwrap_indices.py")], + cwd=candidate_index, check=True) + with manifest.open("a") as out: + out.write("\n[indices]\n") + for namespace in ("compat", "mcpplibs.mwrap"): + view = candidate_index / "tests/mwrap/.indices" / namespace + out.write(json.dumps(namespace) + ' = { path = ' + json.dumps(view.as_posix()) + ' }\n') + command = [args.mcpp, "build", "--toolchain", args.toolchain, "--strict"] + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=project, check=True) + command = [args.mcpp, "run", "--toolchain", args.toolchain] + if args.run_arg: + command += ["--", *args.run_arg] + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=project, check=True) + + +if __name__ == "__main__": + main() From fa850f4e2322d754772eee0c07e31252f3918e01 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 10:09:06 +0900 Subject: [PATCH 2/8] docs: unify the concise package README and move details into docs --- README.md | 109 +++++++++++--------------------------------------- docs/usage.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 85 deletions(-) create mode 100644 docs/usage.md diff --git a/README.md b/README.md index f215cbc..17b2480 100644 --- a/README.md +++ b/README.md @@ -1,106 +1,45 @@ -# ffmpeg +# ffmpeg-m -> FFmpeg 的 C++ 模块化封装 — `import ffmpeg.av;` 即用 · 三平台 · 全从源码构建,API 不变 - -[![Release](https://img.shields.io/github/v/release/mcpplibs/ffmpeg-m)](https://github.com/mcpplibs/ffmpeg-m/releases) -[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) -[![Module](https://img.shields.io/badge/module-ok-green.svg)](https://en.cppreference.com/w/cpp/language/modules) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) - -| [mcpp 构建工具](https://github.com/mcpp-community/mcpp) · [包索引 mcpp-index](https://github.com/mcpp-community/mcpp-index) · [FFmpeg 上游](https://github.com/FFmpeg/FFmpeg) · [Issues](https://github.com/mcpplibs/ffmpeg-m/issues) · [Releases](https://github.com/mcpplibs/ffmpeg-m/releases) | -|:---:| -| [![CI](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml) | - -## 核心特性 - -- **纯模块导入** — `import ffmpeg.av;`,消费者代码零 `#include`,用的仍是你熟悉的 C API 与全局名(`avcodec_open2`、`AVFrame`、`AV_CODEC_ID_H264` …) -- **从源码构建,消费端不跑 configure** — [`compat.ffmpeg`](https://github.com/mcpp-community/mcpp-index) 携带冻结 configure 快照 + 精确源码清单,mcpp 直接编译整套 FFmpeg 8.1.2(2124 `.c` + 157 NASM `.asm`,x86 SIMD 含)—— 32 核冷构建 ≈ 21 s;本仓库只是薄薄的模块层 -- **全功能 profile** — 600+ decoders / 350+ demuxers / encoders / muxers / filters / swscale / swresample 全开,hermetic(不探测宿主库),LGPL-2.1+ 干净(无 `--enable-gpl`/`nonfree`) -- **三平台** — Linux / macOS / Windows 三平台 CI +FFmpeg **8.1.2** 的 C++23 模块封装,保留 `AVFrame`、`avcodec_open2` 等上游 C API。 ## 快速开始 -```bash -mcpp new myplayer --template ffmpeg && cd myplayer && mcpp run -- video.mp4 # 解码骨架 +使用 mcpp **2026.10.24.1**。以下为候选版本,索引发布后可直接创建项目。 + +```sh +mcpp new video --template ffmpeg.ffmpeg@8.1.2.1 +cd video +mcpp run ``` -或在已有项目中手动接入: +默认模板生成一个三帧样例并解码;处理自己的视频可使用 `mcpp run -- video.mp4`。 + +## 已有项目 ```toml -[dependencies.ffmpeg] -ffmpeg = "8.1.2" +[dependencies] +"ffmpeg.ffmpeg" = "8.1.2.1" ``` ```cpp import std; -import ffmpeg.av; // 整套 FFmpeg 表面,Python `import av` 风格 - +import ffmpeg.av; int main() { - AVFormatContext* fmt { nullptr }; - avformat_open_input(&fmt, "video.mp4", nullptr, nullptr); - // … 还是你熟悉的 C API,只是不用 #include - avformat_close_input(&fmt); - return 0; + std::println("FFmpeg {}", av_version_info()); } ``` -## 模块一览 - -| import | 内容 | -|---|---| -| `ffmpeg.av` | 下面全部(推荐默认) | -| `ffmpeg.avutil` / `ffmpeg.avcodec` / `ffmpeg.avformat` / `ffmpeg.avfilter` / `ffmpeg.avdevice` / `ffmpeg.swscale` / `ffmpeg.swresample` | 每库一个;依赖自动 re-export(`import ffmpeg.avformat;` 带上 avcodec + avutil) | -| `ffmpeg` | `ffmpeg.av` 的 lib-root 别名 | - -命名模块不能导出宏或 `static inline` 帮助函数。有链接的都从 import 来;宏拼写(`AVERROR`、`AV_NOPTS_VALUE`、`AVIO_FLAG_WRITE`、`MKTAG` …)与 inline 工具(`av_q2d`、`av_clip` …)在 import 前加可选侧头: - -```cpp -#include -import ffmpeg.av; -``` +## 能力边界 -C 的复合字面量宏有 C++ 替换从模块导出:`av_err2str` → `av_err2string(err).c_str()`、`av_ts2str` → `av_ts2string`、`av_ts2timestr` → `av_ts2timestring`、`av_fourcc2str` → `av_fourcc2string`。 +实现由 `compat.ffmpeg` 从源码构建,模块层保留原 API。目标平台为 Linux、macOS、Windows。 +`ffmpeg.av` 聚合各库,也可独立 import `ffmpeg.avcodec`、`ffmpeg.avformat` 等子模块。 -## 示例 +宏与内部链接帮助函数通过 import 前包含 `` 使用。 +外部 codec、GPU SDK 及其他构建 profile 的范围见详细文档。 -| 示例 | 内容 | -|---|---| -| [`examples/probe`](examples/probe) | 版本 / 组件信息(无需输入) | -| [`examples/decode_frames`](examples/decode_frames) | 解码一个视频文件的帧 | - -```bash -cd examples/decode_frames && mcpp run -- video.mp4 -``` - -`mcpp build && mcpp test` 验证包(自包含 encode→decode 往返 + API 表面测试)。 - -## 工具链与运行时 - -包不固定工具链(mcpp 解析环境默认)。上游 FFmpeg 源码**不 vendored**,经 `compat.ffmpeg` 索引包(官方 ffmpeg.org tarball,GLOBAL + CN 镜像,sha256 锁定)到达消费端;描述符(configure 快照 inline 为 `generated_files` + `make -n` 源码清单)在 mcpp-index(`tools/compat-ffmpeg/`)维护。需要外部 SDK 的硬件加速头(`libavutil/hwcontext_cuda.h`、VAAPI …)不在模块导出面内,SDK 存在时在 import 旁 textual include。外部编解码器 / GPL 组件 / slim profile 等变体计划以 mcpp features(按 profile 的配置快照)提供。 - -> [!NOTE] -> 早期版本,接口可能调整。问题与想法欢迎提 [issue](https://github.com/mcpplibs/ffmpeg-m/issues)。 - -## License - -封装代码 MIT;上游 FFmpeg 经 `compat.ffmpeg` 提供,**LGPL-2.1-or-later**(无 `--enable-gpl`/`nonfree` 组件),源码分发天然满足 LGPL 重链接要求。 - - -## Current-client quickstart candidate - -The wrapper revision is `8.1.2.1`; the upstream C/C++ API and published module -identity stay unchanged. Development tooling uses mcpp `2026.10.24.1`. Templates -now write one qualified dependency from `self.name`, without repeating a namespace. - -```sh -mcpp new quickstart --template ffmpeg.ffmpeg@8.1.2.1:decode -cd quickstart -mcpp run -``` +## 文档 -This revision is a PR candidate until its source archive and index entry are -validated. `tools/test_template.py` exercises actual `mcpp new`, checks the -rendered dependency, strictly builds the candidate and runs it. +[用法与模块](docs/usage.md) · [版本探针](examples/probe) · +[视频解码](examples/decode_frames) · [MIT 封装许可](LICENSE) -Without arguments the decoder generates a tiny Y4M input and verifies three -decoded frames. Pass `mcpp run -- ` to decode your own input. +上游 FFmpeg 的许可由对应 `compat.ffmpeg` 构建配置决定,本候选使用 LGPL 配置。 diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..d8fbcc7 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,108 @@ +Detailed usage and background. See the [README](../README.md) for the current candidate quickstart and support boundary. + +# ffmpeg + +> FFmpeg 的 C++ 模块化封装 — `import ffmpeg.av;` 即用 · 三平台 · 全从源码构建,API 不变 + +[![Release](https://img.shields.io/github/v/release/mcpplibs/ffmpeg-m)](https://github.com/mcpplibs/ffmpeg-m/releases) +[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) +[![Module](https://img.shields.io/badge/module-ok-green.svg)](https://en.cppreference.com/w/cpp/language/modules) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](../LICENSE) + +| [mcpp 构建工具](https://github.com/mcpp-community/mcpp) · [包索引 mcpp-index](https://github.com/mcpp-community/mcpp-index) · [FFmpeg 上游](https://github.com/FFmpeg/FFmpeg) · [Issues](https://github.com/mcpplibs/ffmpeg-m/issues) · [Releases](https://github.com/mcpplibs/ffmpeg-m/releases) | +|:---:| +| [![CI](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml) | + +## 核心特性 + +- **纯模块导入** — `import ffmpeg.av;`,消费者代码零 `#include`,用的仍是你熟悉的 C API 与全局名(`avcodec_open2`、`AVFrame`、`AV_CODEC_ID_H264` …) +- **从源码构建,消费端不跑 configure** — [`compat.ffmpeg`](https://github.com/mcpp-community/mcpp-index) 携带冻结 configure 快照 + 精确源码清单,mcpp 直接编译整套 FFmpeg 8.1.2(2124 `.c` + 157 NASM `.asm`,x86 SIMD 含)—— 32 核冷构建 ≈ 21 s;本仓库只是薄薄的模块层 +- **全功能 profile** — 600+ decoders / 350+ demuxers / encoders / muxers / filters / swscale / swresample 全开,hermetic(不探测宿主库),LGPL-2.1+ 干净(无 `--enable-gpl`/`nonfree`) +- **三平台** — Linux / macOS / Windows 三平台 CI + +## 快速开始 + +```bash +mcpp new myplayer --template ffmpeg && cd myplayer && mcpp run -- video.mp4 # 解码骨架 +``` + +或在已有项目中手动接入: + +```toml +[dependencies.ffmpeg] +ffmpeg = "8.1.2" +``` + +```cpp +import std; +import ffmpeg.av; // 整套 FFmpeg 表面,Python `import av` 风格 + +int main() { + AVFormatContext* fmt { nullptr }; + avformat_open_input(&fmt, "video.mp4", nullptr, nullptr); + // … 还是你熟悉的 C API,只是不用 #include + avformat_close_input(&fmt); + return 0; +} +``` + +## 模块一览 + +| import | 内容 | +|---|---| +| `ffmpeg.av` | 下面全部(推荐默认) | +| `ffmpeg.avutil` / `ffmpeg.avcodec` / `ffmpeg.avformat` / `ffmpeg.avfilter` / `ffmpeg.avdevice` / `ffmpeg.swscale` / `ffmpeg.swresample` | 每库一个;依赖自动 re-export(`import ffmpeg.avformat;` 带上 avcodec + avutil) | +| `ffmpeg` | `ffmpeg.av` 的 lib-root 别名 | + +命名模块不能导出宏或 `static inline` 帮助函数。有链接的都从 import 来;宏拼写(`AVERROR`、`AV_NOPTS_VALUE`、`AVIO_FLAG_WRITE`、`MKTAG` …)与 inline 工具(`av_q2d`、`av_clip` …)在 import 前加可选侧头: + +```cpp +#include +import ffmpeg.av; +``` + +C 的复合字面量宏有 C++ 替换从模块导出:`av_err2str` → `av_err2string(err).c_str()`、`av_ts2str` → `av_ts2string`、`av_ts2timestr` → `av_ts2timestring`、`av_fourcc2str` → `av_fourcc2string`。 + +## 示例 + +| 示例 | 内容 | +|---|---| +| [`examples/probe`](../examples/probe) | 版本 / 组件信息(无需输入) | +| [`examples/decode_frames`](../examples/decode_frames) | 解码一个视频文件的帧 | + +```bash +cd examples/decode_frames && mcpp run -- video.mp4 +``` + +`mcpp build && mcpp test` 验证包(自包含 encode→decode 往返 + API 表面测试)。 + +## 工具链与运行时 + +包不固定工具链(mcpp 解析环境默认)。上游 FFmpeg 源码**不 vendored**,经 `compat.ffmpeg` 索引包(官方 ffmpeg.org tarball,GLOBAL + CN 镜像,sha256 锁定)到达消费端;描述符(configure 快照 inline 为 `generated_files` + `make -n` 源码清单)在 mcpp-index(`tools/compat-ffmpeg/`)维护。需要外部 SDK 的硬件加速头(`libavutil/hwcontext_cuda.h`、VAAPI …)不在模块导出面内,SDK 存在时在 import 旁 textual include。外部编解码器 / GPL 组件 / slim profile 等变体计划以 mcpp features(按 profile 的配置快照)提供。 + +> [!NOTE] +> 早期版本,接口可能调整。问题与想法欢迎提 [issue](https://github.com/mcpplibs/ffmpeg-m/issues)。 + +## License + +封装代码 MIT;上游 FFmpeg 经 `compat.ffmpeg` 提供,**LGPL-2.1-or-later**(无 `--enable-gpl`/`nonfree` 组件),源码分发天然满足 LGPL 重链接要求。 + + +## Current-client quickstart candidate + +The wrapper revision is `8.1.2.1`; the upstream C/C++ API and published module +identity stay unchanged. Development tooling uses mcpp `2026.10.24.1`. Templates +now write one qualified dependency from `self.name`, without repeating a namespace. + +```sh +mcpp new quickstart --template ffmpeg.ffmpeg@8.1.2.1:decode +cd quickstart +mcpp run +``` + +This revision is a PR candidate until its source archive and index entry are +validated. `tools/test_template.py` exercises actual `mcpp new`, checks the +rendered dependency, strictly builds the candidate and runs it. + +Without arguments the decoder generates a tiny Y4M input and verifies three +decoded frames. Pass `mcpp run -- ` to decode your own input. From 1e8bce6ee12c50e43058245df42515ffbabfc78f Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 10:30:13 +0900 Subject: [PATCH 3/8] fix: declare managed NASM for strict x86 FFmpeg consumers --- mcpp.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mcpp.toml b/mcpp.toml index 10f8641..2a91960 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -29,6 +29,11 @@ cxxflags = ["-D__STDC_CONSTANT_MACROS"] # the compat.ffmpeg index package (2281 TUs incl. NASM asm, built by mcpp). compat.ffmpeg = "8.1.2" +[target.'cfg(all(arch = "x86_64", any(os = "linux", os = "windows")))'.xlings.workspace] +# Frozen x86 FFmpeg profiles use NASM. Provision the managed assembler even +# when an unrelated NASM is present on PATH, so strict consumers are portable. +"xim:nasm" = "3.02" + [dev-dependencies] compat.gtest = "1.15.2" From 60d7e08db1aee7b208042dbaf159f5fd87debcf1 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:09:49 +0900 Subject: [PATCH 4/8] feat: unify mwrap identity and upstream-aligned first release --- .../2026-10-25-unified-mwrap-checkpoint.md | 8 ++ .github/workflows/ci.yml | 3 + .github/workflows/release.yml | 83 +++++++++---------- .github/workflows/templates.yml | 2 + README.md | 59 +++++++------ README.zh.md | 54 ++++++++++++ docs/usage.md | 16 ++-- examples/decode_frames/mcpp.toml | 4 +- examples/decode_frames/src/main.cpp | 2 +- examples/probe/mcpp.toml | 4 +- examples/probe/src/main.cpp | 2 +- include/ffmpeg-m/macros.h | 4 +- include/mwrap/ffmpeg/macros.hpp | 2 + mcpp.toml | 19 ++--- src/av.cppm | 16 ++-- src/avcodec.cppm | 4 +- src/avdevice.cppm | 4 +- src/avfilter.cppm | 4 +- src/avformat.cppm | 4 +- src/avutil.cppm | 2 +- src/ffmpeg.cppm | 6 +- src/macros.cppm | 42 ++++++++++ src/swresample.cppm | 4 +- src/swscale.cppm | 4 +- templates/decode/src/main.cpp.in | 2 +- templates/decode/template.toml | 2 +- tests/api_surface_test.cpp | 2 +- tests/macros.cpp | 8 ++ tests/roundtrip_test.cpp | 2 +- tools/check_mwrap_release.py | 33 ++++++++ 30 files changed, 276 insertions(+), 125 deletions(-) create mode 100644 .agents/docs/2026-10-25-unified-mwrap-checkpoint.md create mode 100644 README.zh.md create mode 100644 include/mwrap/ffmpeg/macros.hpp create mode 100644 src/macros.cppm create mode 100644 tests/macros.cpp create mode 100644 tools/check_mwrap_release.py diff --git a/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md b/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md new file mode 100644 index 0000000..226c1ee --- /dev/null +++ b/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md @@ -0,0 +1,8 @@ +# Unified mwrap first release + +Package/module: `mcpplibs.mwrap.ffmpeg`; upstream version: `8.1.2`. + +This checkpoint migrates wrapper identity while retaining upstream API names and SDK sources. +Default README is English with a mandatory Chinese counterpart; original section order is preserved. +Validation and release evidence are recorded in the PR and the index ecosystem ledger. +No old release tag or source resource is rewritten. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 527c5a5..235cde1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,9 @@ jobs: # No host nasm needed: mcpp >= 0.0.97 provisions nasm through the same # synchronous gate as the toolchain (index refresh + install + payload # check BEFORE the build plans, mcpp#232). + - name: Mwrap identity and bilingual README contract + run: python3 tools/check_mwrap_release.py + - name: Install Xlings env: XLINGS_NON_INTERACTIVE: 1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7693727..f0c6447 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,58 +1,49 @@ name: Release - on: push: - tags: ["v*"] - + tags: ["mwrap-*"] permissions: - contents: write - + contents: read jobs: - verify-and-release: - name: verify (linux) + GitHub Release + publish: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 + permissions: + contents: write + actions: read steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install nasm - run: sudo apt-get update && sudo apt-get install -y nasm - - - name: Install Xlings + - 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: - XLINGS_NON_INTERACTIVE: 1 - 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 - run: | - xlings update - xlings install - - - name: Set default toolchain - run: | - mcpp toolchain install gcc 16.1.0 - mcpp toolchain default gcc@16.1.0 - mcpp --version - - - name: Build + test at the tagged revision - run: | - mcpp build - mcpp test - - - name: Verify tag matches package version + GH_TOKEN: ${{ github.token }} + shell: bash run: | - pkg_ver="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" - tag="${GITHUB_REF_NAME#v}" - test "$pkg_ver" = "$tag" || { echo "tag $GITHUB_REF_NAME != package version $pkg_ver"; exit 1; } - - - name: Create GitHub Release + 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: | - gh release create "$GITHUB_REF_NAME" \ - --title "ffmpeg-m $GITHUB_REF_NAME" \ - --generate-notes \ - --verify-tag + 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[@]}" diff --git a/.github/workflows/templates.yml b/.github/workflows/templates.yml index 0ff08be..a88169e 100644 --- a/.github/workflows/templates.yml +++ b/.github/workflows/templates.yml @@ -1,5 +1,7 @@ name: Actual project templates on: + push: + branches: [main] pull_request: workflow_dispatch: permissions: diff --git a/README.md b/README.md index 17b2480..46c7a0a 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,54 @@ -# ffmpeg-m +# ffmpeg -FFmpeg **8.1.2** 的 C++23 模块封装,保留 `AVFrame`、`avcodec_open2` 等上游 C API。 +> FFmpeg 8.1.2 as C++23 modules, preserving the C API. -## 快速开始 +**English** · [简体中文](README.zh.md) -使用 mcpp **2026.10.24.1**。以下为候选版本,索引发布后可直接创建项目。 +[Releases](https://github.com/mcpplibs/ffmpeg-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-MIT-blue.svg)](LICENSE) +[![CI](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml) + +Use mcpp **2026.10.24.1**. The new mwrap identity becomes installable after index publication. + +## Characteristics + +Thin module interfaces over `compat.ffmpeg`; sources, frozen configuration and NASM support belong to that provider. + +## Getting started ```sh -mcpp new video --template ffmpeg.ffmpeg@8.1.2.1 -cd video +mcpp new media --template mcpplibs.mwrap.ffmpeg@8.1.2 +cd media mcpp run ``` -默认模板生成一个三帧样例并解码;处理自己的视频可使用 `mcpp run -- video.mp4`。 - -## 已有项目 - ```toml [dependencies] -"ffmpeg.ffmpeg" = "8.1.2.1" +mcpplibs.mwrap.ffmpeg = "8.1.2" ``` ```cpp -import std; -import ffmpeg.av; -int main() { - std::println("FFmpeg {}", av_version_info()); -} +import mcpplibs.mwrap.ffmpeg.av; +int main() { return avcodec_version() == 0; } ``` -## 能力边界 +## Modules + +Root and `.av` aggregate `.avutil`, `.avcodec`, `.avformat`, `.avfilter`, `.avdevice`, `.swscale`, `.swresample`. +`.macros` maps common constants. For preprocessing and inline helpers include `` before imports. + +## Examples -实现由 `compat.ffmpeg` 从源码构建,模块层保留原 API。目标平台为 Linux、macOS、Windows。 -`ffmpeg.av` 聚合各库,也可独立 import `ffmpeg.avcodec`、`ffmpeg.avformat` 等子模块。 +The default template encodes and decodes a generated frame without external files. +[Probe](examples/probe) · [Decode frames](examples/decode_frames) · [Details](docs/usage.md) -宏与内部链接帮助函数通过 import 前包含 `` 使用。 -外部 codec、GPU SDK 及其他构建 profile 的范围见详细文档。 +## Build and runtime -## 文档 +Linux, macOS and Windows; use `mcpp build` and `mcpp test`. External hardware SDK APIs require separate headers/SDKs. +The source profile does not enable GPL/nonfree components. -[用法与模块](docs/usage.md) · [版本探针](examples/probe) · -[视频解码](examples/decode_frames) · [MIT 封装许可](LICENSE) +## License -上游 FFmpeg 的许可由对应 `compat.ffmpeg` 构建配置决定,本候选使用 LGPL 配置。 +Wrapper: [MIT](LICENSE). FFmpeg provider: LGPL-2.1-or-later; preserve selected source and license notices. diff --git a/README.zh.md b/README.zh.md new file mode 100644 index 0000000..55c8f85 --- /dev/null +++ b/README.zh.md @@ -0,0 +1,54 @@ +# ffmpeg + +> FFmpeg 8.1.2 的 C++23 模块封装,保留 C API。 + +[English](README.md) · **简体中文** + +[Releases](https://github.com/mcpplibs/ffmpeg-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-MIT-blue.svg)](LICENSE) +[![CI](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml) + +使用 mcpp **2026.10.24.1**。新 mwrap 身份在索引发布后可直接安装。 + +## 核心特性 + +基于 `compat.ffmpeg` 的薄模块层;源码、冻结配置与 NASM 支持由供应者提供。 + +## 快速开始 + +```sh +mcpp new media --template mcpplibs.mwrap.ffmpeg@8.1.2 +cd media +mcpp run +``` + +```toml +[dependencies] +mcpplibs.mwrap.ffmpeg = "8.1.2" +``` + +```cpp +import mcpplibs.mwrap.ffmpeg.av; +int main() { return avcodec_version() == 0; } +``` + +## 模块一览 + +根模块与 `.av` 聚合 `.avutil`、`.avcodec`、`.avformat`、`.avfilter`、`.avdevice`、`.swscale`、`.swresample`。 +`.macros` 映射常用常量;预处理宏与 inline 工具在 import 前包含 ``。 + +## 示例 + +默认模板编码并解码生成的图像帧,无需外部文件。 +[组件信息](examples/probe) · [视频解码](examples/decode_frames) · [详细说明](docs/usage.md) + +## 工具链与运行时 + +支持 Linux、macOS、Windows;使用 `mcpp build`、`mcpp test`。外部硬件 API 仍需要对应头文件与 SDK。 +当前源码 profile 未启用 GPL/nonfree 组件。 + +## 许可证 + +封装:[MIT](LICENSE)。FFmpeg 供应者:LGPL-2.1-or-later;保留选中源码与许可证通知。 diff --git a/docs/usage.md b/docs/usage.md index d8fbcc7..97d44ff 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -2,7 +2,7 @@ Detailed usage and background. See the [README](../README.md) for the current ca # ffmpeg -> FFmpeg 的 C++ 模块化封装 — `import ffmpeg.av;` 即用 · 三平台 · 全从源码构建,API 不变 +> FFmpeg 的 C++ 模块化封装 — `import mcpplibs.mwrap.ffmpeg.av;` 即用 · 三平台 · 全从源码构建,API 不变 [![Release](https://img.shields.io/github/v/release/mcpplibs/ffmpeg-m)](https://github.com/mcpplibs/ffmpeg-m/releases) [![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) @@ -15,7 +15,7 @@ Detailed usage and background. See the [README](../README.md) for the current ca ## 核心特性 -- **纯模块导入** — `import ffmpeg.av;`,消费者代码零 `#include`,用的仍是你熟悉的 C API 与全局名(`avcodec_open2`、`AVFrame`、`AV_CODEC_ID_H264` …) +- **纯模块导入** — `import mcpplibs.mwrap.ffmpeg.av;`,消费者代码零 `#include`,用的仍是你熟悉的 C API 与全局名(`avcodec_open2`、`AVFrame`、`AV_CODEC_ID_H264` …) - **从源码构建,消费端不跑 configure** — [`compat.ffmpeg`](https://github.com/mcpp-community/mcpp-index) 携带冻结 configure 快照 + 精确源码清单,mcpp 直接编译整套 FFmpeg 8.1.2(2124 `.c` + 157 NASM `.asm`,x86 SIMD 含)—— 32 核冷构建 ≈ 21 s;本仓库只是薄薄的模块层 - **全功能 profile** — 600+ decoders / 350+ demuxers / encoders / muxers / filters / swscale / swresample 全开,hermetic(不探测宿主库),LGPL-2.1+ 干净(无 `--enable-gpl`/`nonfree`) - **三平台** — Linux / macOS / Windows 三平台 CI @@ -29,13 +29,13 @@ mcpp new myplayer --template ffmpeg && cd myplayer && mcpp run -- video.mp4 # 或在已有项目中手动接入: ```toml -[dependencies.ffmpeg] +[dependencies.mcpplibs.mwrap] ffmpeg = "8.1.2" ``` ```cpp import std; -import ffmpeg.av; // 整套 FFmpeg 表面,Python `import av` 风格 +import mcpplibs.mwrap.ffmpeg.av; // 整套 FFmpeg 表面,Python `import av` 风格 int main() { AVFormatContext* fmt { nullptr }; @@ -51,14 +51,14 @@ int main() { | import | 内容 | |---|---| | `ffmpeg.av` | 下面全部(推荐默认) | -| `ffmpeg.avutil` / `ffmpeg.avcodec` / `ffmpeg.avformat` / `ffmpeg.avfilter` / `ffmpeg.avdevice` / `ffmpeg.swscale` / `ffmpeg.swresample` | 每库一个;依赖自动 re-export(`import ffmpeg.avformat;` 带上 avcodec + avutil) | +| `ffmpeg.avutil` / `ffmpeg.avcodec` / `ffmpeg.avformat` / `ffmpeg.avfilter` / `ffmpeg.avdevice` / `ffmpeg.swscale` / `ffmpeg.swresample` | 每库一个;依赖自动 re-export(`import mcpplibs.mwrap.ffmpeg.avformat;` 带上 avcodec + avutil) | | `ffmpeg` | `ffmpeg.av` 的 lib-root 别名 | 命名模块不能导出宏或 `static inline` 帮助函数。有链接的都从 import 来;宏拼写(`AVERROR`、`AV_NOPTS_VALUE`、`AVIO_FLAG_WRITE`、`MKTAG` …)与 inline 工具(`av_q2d`、`av_clip` …)在 import 前加可选侧头: ```cpp #include -import ffmpeg.av; +import mcpplibs.mwrap.ffmpeg.av; ``` C 的复合字面量宏有 C++ 替换从模块导出:`av_err2str` → `av_err2string(err).c_str()`、`av_ts2str` → `av_ts2string`、`av_ts2timestr` → `av_ts2timestring`、`av_fourcc2str` → `av_fourcc2string`。 @@ -90,12 +90,12 @@ cd examples/decode_frames && mcpp run -- video.mp4 ## Current-client quickstart candidate -The wrapper revision is `8.1.2.1`; the upstream C/C++ API and published module +The wrapper revision is `8.1.2`; the upstream C/C++ API and published module identity stay unchanged. Development tooling uses mcpp `2026.10.24.1`. Templates now write one qualified dependency from `self.name`, without repeating a namespace. ```sh -mcpp new quickstart --template ffmpeg.ffmpeg@8.1.2.1:decode +mcpp new quickstart --template mcpplibs.mwrap.ffmpeg@8.1.2:decode cd quickstart mcpp run ``` diff --git a/examples/decode_frames/mcpp.toml b/examples/decode_frames/mcpp.toml index 7313ab1..052f3ff 100644 --- a/examples/decode_frames/mcpp.toml +++ b/examples/decode_frames/mcpp.toml @@ -1,8 +1,8 @@ [package] name = "decode-frames" version = "0.1.0" -description = "Decode every frame of a video file via import ffmpeg.av" +description = "Decode every frame of a video file via import mcpplibs.mwrap.ffmpeg.av" license = "LGPL-2.1-or-later" [dependencies] -ffmpeg = { path = "../.." } +"mcpplibs.mwrap.ffmpeg" = { path = "../.." } diff --git a/examples/decode_frames/src/main.cpp b/examples/decode_frames/src/main.cpp index 327f2f8..791b01c 100644 --- a/examples/decode_frames/src/main.cpp +++ b/examples/decode_frames/src/main.cpp @@ -1,6 +1,6 @@ // Decode every video frame of the given file — plain FFmpeg C API, no headers. import std; -import ffmpeg.av; +import mcpplibs.mwrap.ffmpeg.av; int main(int argc, char** argv) { if (argc < 2) { diff --git a/examples/probe/mcpp.toml b/examples/probe/mcpp.toml index dc77bc0..ddb75af 100644 --- a/examples/probe/mcpp.toml +++ b/examples/probe/mcpp.toml @@ -1,8 +1,8 @@ [package] name = "ffmpeg-probe" version = "0.1.0" -description = "List the FFmpeg build surface through import ffmpeg.av" +description = "List the FFmpeg build surface through import mcpplibs.mwrap.ffmpeg.av" license = "LGPL-2.1-or-later" [dependencies] -ffmpeg = { path = "../.." } +"mcpplibs.mwrap.ffmpeg" = { path = "../.." } diff --git a/examples/probe/src/main.cpp b/examples/probe/src/main.cpp index a64da6f..3a8d839 100644 --- a/examples/probe/src/main.cpp +++ b/examples/probe/src/main.cpp @@ -1,6 +1,6 @@ // Show what the vendored FFmpeg exposes — versions and a few codecs/formats. import std; -import ffmpeg.av; +import mcpplibs.mwrap.ffmpeg.av; int main() { std::println("libavutil {}.{}", avutil_version() >> 16, (avutil_version() >> 8) & 0xff); diff --git a/include/ffmpeg-m/macros.h b/include/ffmpeg-m/macros.h index 587d50d..4476bc5 100644 --- a/include/ffmpeg-m/macros.h +++ b/include/ffmpeg-m/macros.h @@ -1,13 +1,13 @@ // ffmpeg-m/macros.h — optional side header for FFmpeg's preprocessor surface. // // C++ named modules cannot export macros or static-inline helpers. Everything -// with linkage comes from `import ffmpeg.av;`; consumers who also want the +// with linkage comes from `import mcpplibs.mwrap.ffmpeg.av;`; consumers who also want the // macro spellings (AVERROR, MKTAG, AV_NOPTS_VALUE, AV_TIME_BASE_Q, AV_RL32, // LIBAV*_VERSION_*) or the header-only inline utilities (av_q2d, av_make_q, // av_clip family, av_rescale_q) textually include THIS header next to the // import: // -// import ffmpeg.av; +// import mcpplibs.mwrap.ffmpeg.av; // #include // optional, macro habits only // // The declarations herein denote the same global-module entities the modules diff --git a/include/mwrap/ffmpeg/macros.hpp b/include/mwrap/ffmpeg/macros.hpp new file mode 100644 index 0000000..bc59aed --- /dev/null +++ b/include/mwrap/ffmpeg/macros.hpp @@ -0,0 +1,2 @@ +#pragma once +#include diff --git a/mcpp.toml b/mcpp.toml index 2a91960..91f9918 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,15 +1,9 @@ -# The namespace names whose library this is, not who packaged it; the version -# says which upstream you are getting. `mcpplibs` is mcpp's DEFAULT namespace -# (kDefaultNamespace), not an answer to "whose library"; and `0.0.3` told a -# consumer nothing about which FFmpeg was inside — it is 8.1.2, which is what -# the compat.ffmpeg dependency below has said all along. -# -# Rule and full migration table: mcpp-index#163. +# Module wrapper; upstream API preserved. Policy: mcpp-index/docs/mwrap.md. [package] -namespace = "ffmpeg" -name = "ffmpeg" -version = "8.1.2.1" -description = "FFmpeg 8.1.2 C++ modules for mcpp (import ffmpeg.av;) on top of the compat.ffmpeg source build" +namespace = "mcpplibs.mwrap" +name = "ffmpeg" +version = "8.1.2" +description = "FFmpeg 8.1.2 C++ modules for mcpp (import mcpplibs.mwrap.ffmpeg.av;) on top of the compat.ffmpeg source build" license = "MIT" repo = "https://github.com/mcpplibs/ffmpeg-m" platforms = ["linux", "macos", "windows"] @@ -37,3 +31,6 @@ compat.ffmpeg = "8.1.2" [dev-dependencies] compat.gtest = "1.15.2" + +[package.metadata.mwrap] +upstream-version = "8.1.2" diff --git a/src/av.cppm b/src/av.cppm index b464287..93d8016 100644 --- a/src/av.cppm +++ b/src/av.cppm @@ -1,10 +1,10 @@ // ffmpeg.av — the whole FFmpeg surface in one import (Python `import av` analog). -export module ffmpeg.av; +export module mcpplibs.mwrap.ffmpeg.av; -export import ffmpeg.avutil; -export import ffmpeg.avcodec; -export import ffmpeg.avformat; -export import ffmpeg.avfilter; -export import ffmpeg.avdevice; -export import ffmpeg.swscale; -export import ffmpeg.swresample; +export import mcpplibs.mwrap.ffmpeg.avutil; +export import mcpplibs.mwrap.ffmpeg.avcodec; +export import mcpplibs.mwrap.ffmpeg.avformat; +export import mcpplibs.mwrap.ffmpeg.avfilter; +export import mcpplibs.mwrap.ffmpeg.avdevice; +export import mcpplibs.mwrap.ffmpeg.swscale; +export import mcpplibs.mwrap.ffmpeg.swresample; diff --git a/src/avcodec.cppm b/src/avcodec.cppm index d5baed4..074cbe8 100644 --- a/src/avcodec.cppm +++ b/src/avcodec.cppm @@ -5,8 +5,8 @@ extern "C" { #include "gen_exports/avcodec.includes.inc" } -export module ffmpeg.avcodec; +export module mcpplibs.mwrap.ffmpeg.avcodec; -export import ffmpeg.avutil; +export import mcpplibs.mwrap.ffmpeg.avutil; #include "gen_exports/avcodec.inc" diff --git a/src/avdevice.cppm b/src/avdevice.cppm index 33317fb..99bd4e1 100644 --- a/src/avdevice.cppm +++ b/src/avdevice.cppm @@ -5,8 +5,8 @@ extern "C" { #include "gen_exports/avdevice.includes.inc" } -export module ffmpeg.avdevice; +export module mcpplibs.mwrap.ffmpeg.avdevice; -export import ffmpeg.avformat; +export import mcpplibs.mwrap.ffmpeg.avformat; #include "gen_exports/avdevice.inc" diff --git a/src/avfilter.cppm b/src/avfilter.cppm index b39fdf5..670ddb4 100644 --- a/src/avfilter.cppm +++ b/src/avfilter.cppm @@ -5,8 +5,8 @@ extern "C" { #include "gen_exports/avfilter.includes.inc" } -export module ffmpeg.avfilter; +export module mcpplibs.mwrap.ffmpeg.avfilter; -export import ffmpeg.avutil; +export import mcpplibs.mwrap.ffmpeg.avutil; #include "gen_exports/avfilter.inc" diff --git a/src/avformat.cppm b/src/avformat.cppm index 8ffc6fe..02583bc 100644 --- a/src/avformat.cppm +++ b/src/avformat.cppm @@ -5,8 +5,8 @@ extern "C" { #include "gen_exports/avformat.includes.inc" } -export module ffmpeg.avformat; +export module mcpplibs.mwrap.ffmpeg.avformat; -export import ffmpeg.avcodec; +export import mcpplibs.mwrap.ffmpeg.avcodec; #include "gen_exports/avformat.inc" diff --git a/src/avutil.cppm b/src/avutil.cppm index edbd675..9de404c 100644 --- a/src/avutil.cppm +++ b/src/avutil.cppm @@ -6,7 +6,7 @@ extern "C" { #include "gen_exports/avutil.includes.inc" } -export module ffmpeg.avutil; +export module mcpplibs.mwrap.ffmpeg.avutil; #include "gen_exports/avutil.inc" diff --git a/src/ffmpeg.cppm b/src/ffmpeg.cppm index a2edb6d..3935bd2 100644 --- a/src/ffmpeg.cppm +++ b/src/ffmpeg.cppm @@ -1,4 +1,6 @@ // ffmpeg — package lib-root module; forwards to the ffmpeg.av umbrella. -export module ffmpeg; +export module mcpplibs.mwrap.ffmpeg; -export import ffmpeg.av; +export import mcpplibs.mwrap.ffmpeg.av; + +export import mcpplibs.mwrap.ffmpeg.macros; diff --git a/src/macros.cppm b/src/macros.cppm new file mode 100644 index 0000000..2f7c745 --- /dev/null +++ b/src/macros.cppm @@ -0,0 +1,42 @@ +module; +extern "C" { +#include +#include +#include +#include +} +namespace mwrap_ffmpeg_capture { +inline constexpr auto value_AV_TIME_BASE = AV_TIME_BASE; +inline constexpr auto value_AV_NOPTS_VALUE = AV_NOPTS_VALUE; +inline constexpr auto value_AVERROR_EOF = AVERROR_EOF; +inline constexpr auto value_AVERROR_INVALIDDATA = AVERROR_INVALIDDATA; +inline constexpr auto value_AV_INPUT_BUFFER_PADDING_SIZE = AV_INPUT_BUFFER_PADDING_SIZE; +inline constexpr auto value_AV_PKT_FLAG_KEY = AV_PKT_FLAG_KEY; +inline constexpr auto value_AVIO_FLAG_READ = AVIO_FLAG_READ; +inline constexpr auto value_AVIO_FLAG_WRITE = AVIO_FLAG_WRITE; +inline constexpr auto value_AVSEEK_SIZE = AVSEEK_SIZE; +} +#undef AV_TIME_BASE +#undef AV_NOPTS_VALUE +#undef AVERROR_EOF +#undef AVERROR_INVALIDDATA +#undef AV_INPUT_BUFFER_PADDING_SIZE +#undef AV_PKT_FLAG_KEY +#undef AVIO_FLAG_READ +#undef AVIO_FLAG_WRITE +#undef AVSEEK_SIZE + +export module mcpplibs.mwrap.ffmpeg.macros; + +export namespace mcpplibs::mwrap::ffmpeg::macros { +inline constexpr auto AV_TIME_BASE = mwrap_ffmpeg_capture::value_AV_TIME_BASE; +inline constexpr auto AV_NOPTS_VALUE = mwrap_ffmpeg_capture::value_AV_NOPTS_VALUE; +inline constexpr auto AVERROR_EOF = mwrap_ffmpeg_capture::value_AVERROR_EOF; +inline constexpr auto AVERROR_INVALIDDATA = mwrap_ffmpeg_capture::value_AVERROR_INVALIDDATA; +inline constexpr auto AV_INPUT_BUFFER_PADDING_SIZE = mwrap_ffmpeg_capture::value_AV_INPUT_BUFFER_PADDING_SIZE; +inline constexpr auto AV_PKT_FLAG_KEY = mwrap_ffmpeg_capture::value_AV_PKT_FLAG_KEY; +inline constexpr auto AVIO_FLAG_READ = mwrap_ffmpeg_capture::value_AVIO_FLAG_READ; +inline constexpr auto AVIO_FLAG_WRITE = mwrap_ffmpeg_capture::value_AVIO_FLAG_WRITE; +inline constexpr auto AVSEEK_SIZE = mwrap_ffmpeg_capture::value_AVSEEK_SIZE; + +} diff --git a/src/swresample.cppm b/src/swresample.cppm index d71f7d9..b64d9c0 100644 --- a/src/swresample.cppm +++ b/src/swresample.cppm @@ -5,8 +5,8 @@ extern "C" { #include "gen_exports/swresample.includes.inc" } -export module ffmpeg.swresample; +export module mcpplibs.mwrap.ffmpeg.swresample; -export import ffmpeg.avutil; +export import mcpplibs.mwrap.ffmpeg.avutil; #include "gen_exports/swresample.inc" diff --git a/src/swscale.cppm b/src/swscale.cppm index f342278..6ae60f1 100644 --- a/src/swscale.cppm +++ b/src/swscale.cppm @@ -5,8 +5,8 @@ extern "C" { #include "gen_exports/swscale.includes.inc" } -export module ffmpeg.swscale; +export module mcpplibs.mwrap.ffmpeg.swscale; -export import ffmpeg.avutil; +export import mcpplibs.mwrap.ffmpeg.avutil; #include "gen_exports/swscale.inc" diff --git a/templates/decode/src/main.cpp.in b/templates/decode/src/main.cpp.in index 1813289..511dc12 100644 --- a/templates/decode/src/main.cpp.in +++ b/templates/decode/src/main.cpp.in @@ -1,6 +1,6 @@ // Decode a supplied video, or a generated three-frame sample when run without arguments. import std; -import ffmpeg.av; +import mcpplibs.mwrap.ffmpeg.av; int main(int argc, char** argv) { struct Sample { diff --git a/templates/decode/template.toml b/templates/decode/template.toml index 2e0211b..43cae58 100644 --- a/templates/decode/template.toml +++ b/templates/decode/template.toml @@ -1,4 +1,4 @@ [template] -description = "Decode a generated sample or a supplied video with import ffmpeg.av" +description = "Decode a generated sample or a supplied video with import mcpplibs.mwrap.ffmpeg.av" default = true post_message = "Run `mcpp run` for a generated sample, or `mcpp run -- ` for your own file." diff --git a/tests/api_surface_test.cpp b/tests/api_surface_test.cpp index bef6497..f309ab2 100644 --- a/tests/api_surface_test.cpp +++ b/tests/api_surface_test.cpp @@ -10,7 +10,7 @@ // compiler-hostile territory across the ecosystem). #include -import ffmpeg.av; +import mcpplibs.mwrap.ffmpeg.av; TEST(ApiSurface, VersionsMatchVendoredRelease) { EXPECT_EQ(avutil_version() >> 16, 60u); // n8.1.x: libavutil major 60 diff --git a/tests/macros.cpp b/tests/macros.cpp new file mode 100644 index 0000000..192cd68 --- /dev/null +++ b/tests/macros.cpp @@ -0,0 +1,8 @@ +import mcpplibs.mwrap.ffmpeg; +namespace macros = mcpplibs::mwrap::ffmpeg::macros; +int main() { + static_assert(macros::AV_TIME_BASE == 1000000); + static_assert(macros::AVERROR_EOF < 0); + static_assert(macros::AVIO_FLAG_READ == 1); + return avcodec_version() == 0; +} diff --git a/tests/roundtrip_test.cpp b/tests/roundtrip_test.cpp index 7c03743..a9423ef 100644 --- a/tests/roundtrip_test.cpp +++ b/tests/roundtrip_test.cpp @@ -13,7 +13,7 @@ #include -import ffmpeg.av; +import mcpplibs.mwrap.ffmpeg.av; namespace { diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py new file mode 100644 index 0000000..4dde1a9 --- /dev/null +++ b/tools/check_mwrap_release.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +"""Check the immutable mwrap release coordinate and bilingual entry pages.""" +import argparse +from pathlib import Path +import re +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--tag', help='release tag; omitted during PR checks') + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + package = tomllib.loads((root / 'mcpp.toml').read_text())['package'] + assert package['namespace'] == 'mcpplibs.mwrap', package + assert re.fullmatch(r'[A-Za-z_][A-Za-z_0-9]*', package['name']), package['name'] + upstream = package['metadata']['mwrap']['upstream-version'] + version = package['version'] + assert version == upstream or re.fullmatch(re.escape(upstream) + r'\.[1-9][0-9]*', version), (version, upstream) + if args.tag: + assert args.tag == 'mwrap-' + version, (args.tag, version) + identity = package['namespace'] + '.' + package['name'] + for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: + text = (root / name).read_text() + assert len(text.splitlines()) <= 100, name + assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name + assert identity in text and version in text, name + assert text.count('```') % 2 == 0, name + print(identity + '@' + version) + + +if __name__ == '__main__': + main() From 776160a829d062a8889271062409d7961a1703f1 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:13:24 +0900 Subject: [PATCH 5/8] fix(ci): read bilingual metadata explicitly as UTF-8 --- tools/check_mwrap_release.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py index 4dde1a9..9222469 100644 --- a/tools/check_mwrap_release.py +++ b/tools/check_mwrap_release.py @@ -11,7 +11,7 @@ def main(): parser.add_argument('--tag', help='release tag; omitted during PR checks') args = parser.parse_args() root = Path(__file__).resolve().parents[1] - package = tomllib.loads((root / 'mcpp.toml').read_text())['package'] + package = tomllib.loads((root / 'mcpp.toml').read_text(encoding="utf-8"))['package'] assert package['namespace'] == 'mcpplibs.mwrap', package assert re.fullmatch(r'[A-Za-z_][A-Za-z_0-9]*', package['name']), package['name'] upstream = package['metadata']['mwrap']['upstream-version'] @@ -21,7 +21,7 @@ def main(): assert args.tag == 'mwrap-' + version, (args.tag, version) identity = package['namespace'] + '.' + package['name'] for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: - text = (root / name).read_text() + text = (root / name).read_text(encoding="utf-8") assert len(text.splitlines()) <= 100, name assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name assert identity in text and version in text, name From 0ef31b22484fadb2372c8f0bcdf124429b8af8bc Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:31:42 +0900 Subject: [PATCH 6/8] docs: apply concise bilingual mwrap README layout --- README.md | 9 +++------ README.zh.md | 9 +++------ tools/check_mwrap_release.py | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 46c7a0a..6ecf91d 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,18 @@ # ffmpeg > FFmpeg 8.1.2 as C++23 modules, preserving the C API. +> Thin module interfaces over `compat.ffmpeg`; sources, frozen configuration and NASM support belong to that provider. **English** · [简体中文](README.zh.md) +Upstream: [FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg) + [Releases](https://github.com/mcpplibs/ffmpeg-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-MIT-blue.svg)](LICENSE) [![CI](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml) -Use mcpp **2026.10.24.1**. The new mwrap identity becomes installable after index publication. - -## Characteristics - -Thin module interfaces over `compat.ffmpeg`; sources, frozen configuration and NASM support belong to that provider. - ## Getting started ```sh diff --git a/README.zh.md b/README.zh.md index 55c8f85..b413c82 100644 --- a/README.zh.md +++ b/README.zh.md @@ -1,21 +1,18 @@ # ffmpeg > FFmpeg 8.1.2 的 C++23 模块封装,保留 C API。 +> 基于 `compat.ffmpeg` 的薄模块层;源码、冻结配置与 NASM 支持由供应者提供。 [English](README.md) · **简体中文** +上游仓库:[FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg) + [Releases](https://github.com/mcpplibs/ffmpeg-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-MIT-blue.svg)](LICENSE) [![CI](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml) -使用 mcpp **2026.10.24.1**。新 mwrap 身份在索引发布后可直接安装。 - -## 核心特性 - -基于 `compat.ffmpeg` 的薄模块层;源码、冻结配置与 NASM 支持由供应者提供。 - ## 快速开始 ```sh diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py index 9222469..227fd8d 100644 --- a/tools/check_mwrap_release.py +++ b/tools/check_mwrap_release.py @@ -22,7 +22,7 @@ def main(): identity = package['namespace'] + '.' + package['name'] for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: text = (root / name).read_text(encoding="utf-8") - assert len(text.splitlines()) <= 100, name + assert len(text.splitlines()) <= 150, name assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name assert identity in text and version in text, name assert text.count('```') % 2 == 0, name From 37efbe7841c920f7147021df57a118333ccb044d Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:36:22 +0900 Subject: [PATCH 7/8] docs: standardize navigation and introductory layout --- README.md | 9 +++------ README.zh.md | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6ecf91d..361e8e4 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,15 @@ # ffmpeg > FFmpeg 8.1.2 as C++23 modules, preserving the C API. -> Thin module interfaces over `compat.ffmpeg`; sources, frozen configuration and NASM support belong to that provider. -**English** · [简体中文](README.zh.md) - -Upstream: [FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg) - -[Releases](https://github.com/mcpplibs/ffmpeg-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) +**English** · [简体中文](README.zh.md) · Upstream: [FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg) · [Releases](https://github.com/mcpplibs/ffmpeg-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-MIT-blue.svg)](LICENSE) [![CI](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml) +Thin module interfaces over `compat.ffmpeg`; sources, frozen configuration and NASM support belong to that provider. + ## Getting started ```sh diff --git a/README.zh.md b/README.zh.md index b413c82..72d7c8a 100644 --- a/README.zh.md +++ b/README.zh.md @@ -1,18 +1,15 @@ # ffmpeg > FFmpeg 8.1.2 的 C++23 模块封装,保留 C API。 -> 基于 `compat.ffmpeg` 的薄模块层;源码、冻结配置与 NASM 支持由供应者提供。 -[English](README.md) · **简体中文** - -上游仓库:[FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg) - -[Releases](https://github.com/mcpplibs/ffmpeg-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) +[English](README.md) · **简体中文** · 上游:[FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg) · [Releases](https://github.com/mcpplibs/ffmpeg-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-MIT-blue.svg)](LICENSE) [![CI](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/ffmpeg-m/actions/workflows/ci.yml) +基于 `compat.ffmpeg` 的薄模块层;源码、冻结配置与 NASM 支持由供应者提供。 + ## 快速开始 ```sh From 572091c02606f66e47318176d25e7d821baaaae6 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:43:00 +0900 Subject: [PATCH 8/8] docs: lead quickstarts with core module imports and uniform upstream links --- README.md | 17 +++++++++++------ README.zh.md | 17 +++++++++++------ docs/usage.md | 6 +++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 361e8e4..e29e479 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > FFmpeg 8.1.2 as C++23 modules, preserving the C API. -**English** · [简体中文](README.zh.md) · Upstream: [FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg) · [Releases](https://github.com/mcpplibs/ffmpeg-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) +**English** · [简体中文](README.zh.md) · [Upstream](https://github.com/FFmpeg/FFmpeg) · [Releases](https://github.com/mcpplibs/ffmpeg-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-MIT-blue.svg)](LICENSE) @@ -10,6 +10,16 @@ Thin module interfaces over `compat.ffmpeg`; sources, frozen configuration and NASM support belong to that provider. +## Modules + +- `import mcpplibs.mwrap.ffmpeg;`: Complete FFmpeg module aggregate +- `import mcpplibs.mwrap.ffmpeg.avcodec;`: Audio/video codecs +- `import mcpplibs.mwrap.ffmpeg.avformat;`: Containers and stream I/O +- `import mcpplibs.mwrap.ffmpeg.avutil;`: Common media types and utilities +- `import mcpplibs.mwrap.ffmpeg.macros;`: Common macro constant mappings + +> More Modules API -> [Usage and API](docs/usage.md) + ## Getting started ```sh @@ -28,11 +38,6 @@ import mcpplibs.mwrap.ffmpeg.av; int main() { return avcodec_version() == 0; } ``` -## Modules - -Root and `.av` aggregate `.avutil`, `.avcodec`, `.avformat`, `.avfilter`, `.avdevice`, `.swscale`, `.swresample`. -`.macros` maps common constants. For preprocessing and inline helpers include `` before imports. - ## Examples The default template encodes and decodes a generated frame without external files. diff --git a/README.zh.md b/README.zh.md index 72d7c8a..56f1511 100644 --- a/README.zh.md +++ b/README.zh.md @@ -2,7 +2,7 @@ > FFmpeg 8.1.2 的 C++23 模块封装,保留 C API。 -[English](README.md) · **简体中文** · 上游:[FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg) · [Releases](https://github.com/mcpplibs/ffmpeg-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) +[English](README.md) · **简体中文** · [Upstream](https://github.com/FFmpeg/FFmpeg) · [Releases](https://github.com/mcpplibs/ffmpeg-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-MIT-blue.svg)](LICENSE) @@ -10,6 +10,16 @@ 基于 `compat.ffmpeg` 的薄模块层;源码、冻结配置与 NASM 支持由供应者提供。 +## 模块 + +- `import mcpplibs.mwrap.ffmpeg;`: FFmpeg 模块聚合 +- `import mcpplibs.mwrap.ffmpeg.avcodec;`: 音视频编解码 +- `import mcpplibs.mwrap.ffmpeg.avformat;`: 容器与流输入输出 +- `import mcpplibs.mwrap.ffmpeg.avutil;`: 媒体公共类型与工具 +- `import mcpplibs.mwrap.ffmpeg.macros;`: 常用宏常量映射 + +> More Modules API -> [模块与 API](docs/usage.md) + ## 快速开始 ```sh @@ -28,11 +38,6 @@ import mcpplibs.mwrap.ffmpeg.av; int main() { return avcodec_version() == 0; } ``` -## 模块一览 - -根模块与 `.av` 聚合 `.avutil`、`.avcodec`、`.avformat`、`.avfilter`、`.avdevice`、`.swscale`、`.swresample`。 -`.macros` 映射常用常量;预处理宏与 inline 工具在 import 前包含 ``。 - ## 示例 默认模板编码并解码生成的图像帧,无需外部文件。 diff --git a/docs/usage.md b/docs/usage.md index 97d44ff..f4139d9 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -50,9 +50,9 @@ int main() { | import | 内容 | |---|---| -| `ffmpeg.av` | 下面全部(推荐默认) | -| `ffmpeg.avutil` / `ffmpeg.avcodec` / `ffmpeg.avformat` / `ffmpeg.avfilter` / `ffmpeg.avdevice` / `ffmpeg.swscale` / `ffmpeg.swresample` | 每库一个;依赖自动 re-export(`import mcpplibs.mwrap.ffmpeg.avformat;` 带上 avcodec + avutil) | -| `ffmpeg` | `ffmpeg.av` 的 lib-root 别名 | +| `mcpplibs.mwrap.ffmpeg.av` | 下面全部(推荐默认) | +| `mcpplibs.mwrap.ffmpeg.avutil` / `mcpplibs.mwrap.ffmpeg.avcodec` / `mcpplibs.mwrap.ffmpeg.avformat` / `mcpplibs.mwrap.ffmpeg.avfilter` / `mcpplibs.mwrap.ffmpeg.avdevice` / `mcpplibs.mwrap.ffmpeg.swscale` / `mcpplibs.mwrap.ffmpeg.swresample` | 每库一个;依赖自动 re-export(`import mcpplibs.mwrap.ffmpeg.avformat;` 带上 avcodec + avutil) | +| `mcpplibs.mwrap.ffmpeg` | `mcpplibs.mwrap.ffmpeg.av` 的 lib-root 别名 | 命名模块不能导出宏或 `static inline` 帮助函数。有链接的都从 import 来;宏拼写(`AVERROR`、`AV_NOPTS_VALUE`、`AVIO_FLAG_WRITE`、`MKTAG` …)与 inline 工具(`av_q2d`、`av_clip` …)在 import 前加可选侧头: