# FFmpegcj **Repository Path**: longkicode/ffmpegcj ## Basic Information - **Project Name**: FFmpegcj - **Description**: 基于仓颉 FFI(`foreign`)对 FFmpeg 共享库(libavcodec / libavformat / libavutil / libswscale / libswresample)的封装,分两层: - **友好 API 层**(`ffmpegcj`):媒体探测、解封装、解码、像素转换、重采样、编码、封装等高层能力,隐藏全部 C 指针细节,推荐日常使用。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-15 - **Last Updated**: 2026-09-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ffmpegcj — 仓颉 (Cangjie) 语言的 FFmpeg 封装库 作者:Longki 基于仓颉 FFI(`foreign`)对 FFmpeg 共享库(libavcodec / libavformat / libavutil / libswscale / libswresample)的封装,分两层: - **友好 API 层**(`ffmpegcj`):媒体探测、解封装、解码、像素转换、重采样、编码、封装等高层能力,隐藏全部 C 指针细节,推荐日常使用。 - **底层 FFI 层**(`ffmpegcj.c`):逐函数映射 FFmpeg C API(`avxxx_cjbindwrapper`),需要直接操作 `AVFormatContext` / `AVCodecContext` / `AVPacket` / `AVFrame` 等指针时使用。 - 语言:仓颉 Cangjie **1.0.4**(`cjc` / `cjpm`) - 平台:Windows x64 / Linux(x86_64,其他架构按需自编译) - FFmpeg:**6.0**(LGPL 动态链接,随库分发 DLL/SO,不修改 FFmpeg 源码) - 协议:本库 **MIT**;FFmpeg 为 **LGPL v2.1+**(见文末「许可与合规」) --- ## 一、功能特性(Windows / Linux 双平台,完整清单) 以下能力在两平台**完全一致**(同一份源码、同一份 `cjpm.toml`,仅链接的库文件后缀不同)。 ### 1. 底层 FFI 层(包 `ffmpegcj.c`)绑定的 FFmpeg 模块 | FFmpeg 库 | 版本查询 | 绑定范围(均为 `avxxx_cjbindwrapper` 形式) | |---|---|---| | **libavutil** | `avutil_version` | `av_strerror`(错误码转文本)、`AVRational` 结构体、`av_malloc`/`av_free`、`AVPacket` 生命周期(alloc/free/ref/unref/rescale_ts)、`AVFrame` 生命周期(alloc/free/unref)、`AVDictionary`(set/get/free)、`av_samples_alloc/free`、`av_get_bytes_per_sample`、`av_get_default_channel_layout`、`av_channel_layout_*`、`AVMediaType`/`AVPixelFormat`/`AVSampleFormat`/`AVCodecID`/`AVSEEK_FLAG_*` 等常量 | | **libavformat** | `avformat_version` | `avformat_network_init`、`avformat_open_input`、`avformat_find_stream_info`、`av_read_frame`、`av_seek_frame`、`avformat_close_input`、`avformat_free_context`、`av_dump_format`、`avformat_alloc_output_context2`、`avformat_new_stream`、`avformat_write_header`、`av_write_frame`、`av_interleaved_write_frame`、`av_write_trailer`、`av_guess_format`、`avio_open/close`、`av_stream_get_*` 常用访问器 | | **libavcodec** | `avcodec_version` | `avcodec_find_decoder`/`avcodec_find_encoder`、`avcodec_alloc_context3`、`avcodec_parameters_to_context`/`avcodec_parameters_from_context`、`avcodec_open2`、`avcodec_send_packet`/`avcodec_receive_frame`(解码)、`avcodec_send_frame`/`avcodec_receive_packet`(编码)、`avcodec_flush_buffers`、`avcodec_free_context`、`avcodec_get_name`、`avcodec_get_type`、`av_get_pix_fmt_name` | | **libswscale** | `swscale_version` | `sws_getContext`、`sws_scale`、`sws_freeContext`、`sws_scale_frame` | | **libswresample** | `swresample_version` | `swr_alloc_set_opts2`(新指针 API)、`swr_init`、`swr_convert`、`swr_free`、`swr_get_out_samples`、`swr_get_delay` | **不透明类型**:`AVFormatContext`、`AVStream`、`AVCodecContext`、`AVCodec`、`AVCodecParameters`、`AVPacket`、`AVFrame`、`AVDictionary`、`SwsContext`、`SwrContext`、`AVInputFormat`、`AVOutputFormat`、`AVIOContext`、`AVChannelLayout`。 **按值结构体**:`AVRational`(`num`/`den`,与 C 布局一致)。 ### 2. 友好 API 层(包 `ffmpegcj`)能力清单 | 能力 | 入口 | 说明 | |---|---|---| | 版本信息 | `version()` | 返回 avutil / avcodec / avformat 三个库的版本号(FFmpeg 6.0.x) | | **媒体探测** | `MediaInfo.probe(path)` | 打开→读取→自动关闭。容器格式名/长名、时长(秒)、总码率;**每条流**的 index、类型(video/audio/subtitle/data)、编码器名、codec_id、宽高、像素格式名、帧率、timebase、时长、采样率、声道数、channel_layout、码率 | | **解封装** | `Demuxer.open(path)` | 支持本地文件与网络 URL(http/https/rtmp/rtsp 取决于构建);`readPacket()` 逐包读取;`seek(sec)` 按秒向后定位(关键帧);`close()`;`context()` 暴露底层句柄 | | **数据包** | `Packet` | pts / dts / duration(按流 timebase 的原始整数,可转秒)、pos、streamIndex、size、`copyData()` 拷贝压缩数据 | | **视频解码** | `Decoder.open(demuxer, idx)` | 绑定某条流:自动 `avcodec_find_decoder` + `avcodec_parameters_to_context` + `avcodec_open2`;`decode(pkt)` 一包出 0..N 帧;`flush()` 冲刷解码器缓存帧;输出 `Frame`(pts/秒、宽高、像素格式、linesize、copyPlane/copyVideoBytes) | | **音频解码** | `Decoder` | 同一条路径(`decode`/`flush`),输出 PCM 帧(平面/交错)与采样格式、采样率、声道数 | | **像素转换+缩放** | `Scaler.create(...)` | 封装 libswscale:任意输入像素格式 → 任意目标格式/尺寸;`convert()` 一次输出连续字节(RGB24/BGR24=3、RGBA/BGRA/ARGB/ABGR=4、GRAY8=1、GRAY16LE=2 字节/像素),可直接写 BMP/PPM;`convertToFrame()` 转目标格式帧喂编码器 | | **音频重采样** | `Resampler.create(...)` | 封装 libswresample:任意采样率 / 声道数 / 采样格式互转(`swr_alloc_set_opts2` 新 API + `AVChannelLayout`);`convert()` 输出交错 PCM 字节数组 | | **视频编码** | `Encoder.createVideo(codecId, w, h, pixFmt, tbNum, tbDen, bitRate)` | 按 codec_id 查找**原生 LGPL 编码器**(mpeg4 / mjpeg / png / ffv1 / rawvideo 等);`sendFrame()` / `receivePacket()` / `flush()` | | **封装(写容器)** | `Muxer.create(path)` | 按扩展名自动猜格式;`addStream(demuxer, idx)` 流拷贝(自动清零 codec_tag,跨容器兼容);`writeHeader()` / `writePacket()`(自动按输出 timebase 重算 pts/dts + 交错写)/ `writeTrailer()` | | **转封装(remux)** | `Muxer` + `Demuxer` 组合 | 流拷贝:mp4 → mkv / avi / ts / flv 等,无需解码 | | 错误处理 | 全部抛 `Exception` | message 经 `av_strerror` 转为可读文本(如 `Invalid data found when processing input`) | ### 3. 双平台支持矩阵 | 项 | Windows | Linux | |---|---|---| | FFmpeg 版本 | 6.0(LGPL 共享构建) | 6.0(LGPL 共享构建) | | 链接库 | `libavcodec.dll.a` 等 MinGW 导入库 | `libavcodec.so` 等动态库(含未版本化符号链接) | | 运行时库 | `avcodec-60.dll` / `avformat-60.dll` / `avutil-58.dll` / `swscale-7.dll` / `swresample-4.dll` | `libavcodec.so.60` / `libavformat.so.60` / `libavutil.so.58` / `libswscale.so.7` / `libswresample.so.4` | | 获取方式 | 仓库 `lib/` 已发布(MSYS2/MinGW 自编译,见 `scripts/build_ffmpeg_windows.sh`) | 仓库 `lib/` 已发布(gcc 自编译,见 `scripts/build_ffmpeg_linux.sh`) | | 构建命令 | `cjpm build` | `cjpm build` | | 源码 / `cjpm.toml` | 同一份 | 同一份 | | 功能范围 | **与 Linux 完全一致** | **与 Windows 完全一致** | ### 4. 支持的编解码 / 容器 / 转换范围 取决于 FFmpeg 6.0 LGPL 构建内置能力(BtbN LGPL 构建或同配置自编译,含全部原生组件): - **视频解码**:h264、hevc、mpeg2video、mpeg4、vp8、vp9、av1、wmv3、rv40、msmpeg4、theora 等 FFmpeg 6.0 全部原生解码器 - **音频解码**:aac、mp3、ac3/eac3、flac、opus、vorbis、alac、pcm 全家族、dts、mlp 等全部原生解码器 - **容器解封装**:mp4/mov/m4a、mkv/webm、avi、flv、ts/m2ts、wav、mp3、ogg/oga、flac、rm 等 - **容器封装**:mp4/mov、mkv/webm、avi、flv、ts、wav、mp3、ogg 等原生 muxer - **编码器(LGPL 原生,不包含 GPL 组件)**:mpeg4、mjpeg、png、ffv1、rawvideo、aac(实验)、opus、flac 等 - **像素转换**:yuv420p / yuv422p / yuv444p / nv12 / nv21 / rgb24 / bgr24 / rgba / bgra / gray 等任意互转 + 任意尺寸缩放 - **音频重采样**:任意采样率 / 声道数 / 采样格式互转 - **协议**:file、http、https、tcp、udp、rtmp、rtsp(取决于构建是否启用) ### 5. 明确不在 v1 范围(Roadmap 与边界) | 能力 | 状态 / 规划 | |---|---| | **音频编码**(AAC / MP3 / PCM 写文件) | ❌ 未封装。库能解出 PCM 并重采样,但 `Encoder` 只有视频入口;音频编码器 API(`Encoder.createAudio`)计划 v1.1 | | 精确 seek(帧级 / 向前定位 / 指定流) | 部分。目前 `seek(sec)` 只支持按秒**向后**关键帧定位 | | libavfilter(滤镜链:裁剪/水印/转场/字幕烧录等) | v2 | | libavdevice(摄像头/麦克风采集、推流) | v2 | | 硬件加速解码/编码(dxva2 / cuda / vaapi / qsv) | v2(当前为纯软解) | | GPL 组件(x264 / x265 / libvpx-GPL 等编码器) | **刻意不内置**——GPL 会强制整个库开源,破坏 MIT 许可(见「许可与合规」)。如需使用,请自行替换 GPL 构建的 FFmpeg 动态库 | | 字幕流解析与渲染 | v2 / v3 | | 复杂音频滤波(混音、音量、延迟等) | v2 / v3 | | `ffmpeg.exe` 命令行能力 | 本库只提供编程接口,不做 CLI | --- ## 二、FFmpeg 版本选型与获取(推荐 6.0) ### 为什么是 6.0 1. **双平台共享构建齐全**:BtbN 同时提供 Windows 与 Linux 的 6.0 LGPL 共享构建,DLL/SO + MinGW 导入库 + 头文件一套齐; 2. **ABI 固定**:6.0 的库 soname 固定为 `avcodec-60 / avformat-60 / avutil-58 / swscale-7 / swresample-4`,绑定层按此 ABI 编写不会漂移; 3. **API 成熟**:新式 `send_packet/receive_frame`、`swr_alloc_set_opts2` 等均已稳定;7.x 移除了部分废弃 API,无必要冒险。 > 若你坚持用 7.x:绑定层需同步调整(soname 变为 avcodec-61 等),v1 不承诺。 ### 方式 A:直接用仓库自带的预编译共享库(最快,推荐) 本仓库 `lib/` 已直接发布 Windows(MSYS2/MinGW-w64 自编译)与 Linux(gcc 自编译)两套 FFmpeg 6.0.1 LGPL 共享库,克隆后**无需下载或编译 FFmpeg** 即可 `cjpm build` 与运行: - `lib/*.dll` + `lib/*.dll.a`(Windows 运行时 + MinGW 导入库) - `lib/lib*.so` + `lib/lib*.so.*`(Linux 动态库) > 早期建议的 BtbN 预编译链接(`ffmpeg-n6.0-latest-win64-lgpl.zip` / `ffmpeg-n6.0-latest-linux64-lgpl.tar.xz`)经实测已 404 失效,不再推荐;需要自行重新编译时见方式 B。 ### 方式 B:自行编译(Windows / Linux 同步出 dll 和 so) 源码:`https://ffmpeg.org/releases/ffmpeg-6.0.1.tar.xz`(或 `https://ffmpeg.org/download.html` 选 6.0.1) **通用配置要点(两平台一致,直接复制)**: ```bash ./configure \ --enable-shared --disable-static \ --disable-programs --disable-doc \ --disable-avdevice --disable-avfilter --disable-postproc \ --disable-debug --enable-optimizations --enable-pic \ # 保持 LGPL:绝不要加 --enable-gpl / --enable-nonfree ``` - 保留默认的 decoder/encoder/demuxer/muxer/parser(含全部原生编解码器,LGPL 安全); - 去掉 avdevice/avfilter 可显著缩短编译时间(v1 不需要); - `--disable-programs --disable-doc` 只出库、不出 ffmpeg.exe 和文档。 **Windows(用 MSYS2/MinGW-w64,不要用 MSVC)**: > 原因:cjc 的目标平台是 `x86_64-w64-mingw32`,cjpm 链接按 MinGW 约定找 `libavcodec.dll.a` 导入库;MSVC 的 `.lib` 不兼容。 ```bash pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-nasm cd ffmpeg-6.0.1 ./configure --prefix=/e/ffmpeg-6.0.1/out --target-os=mingw32 --arch=x86_64 \ --enable-shared --disable-static --disable-programs --disable-doc \ --disable-avdevice --disable-avfilter --disable-postproc \ --disable-debug --enable-optimizations --enable-pic make -j$(nproc) make install # 产物:out/bin/*.dll + out/lib/lib*.dll.a(导入库) ``` **Linux(x86_64)**: ```bash sudo apt install build-essential nasm pkg-config # 或 dnf install gcc nasm cd ffmpeg-6.0.1 ./configure --prefix=$PWD/out --enable-shared --disable-static \ --disable-programs --disable-doc \ --disable-avdevice --disable-avfilter --disable-postproc \ --disable-debug --enable-optimizations --enable-pic make -j$(nproc) make install # 产物:out/lib/lib*.so(含 .so.60 版本化文件与链接符号) ``` **编译完成后的放置规则**(两平台产物直接放入同一个 `lib/` 目录,文件名不冲突): ``` lib/ ├── avcodec-60.dll avformat-60.dll avutil-58.dll swscale-7.dll swresample-4.dll # Windows 运行时 ├── libavcodec.dll.a libavformat.dll.a libavutil.dll.a libswscale.dll.a libswresample.dll.a # Windows 导入库 ├── libavcodec.dll libavformat.dll ...(cjpm 存在性检查用的无版本副本) ├── libbz2-1.dll libiconv-2.dll liblzma-5.dll libwinpthread-1.dll zlib1.dll # Windows 外部依赖 ├── libavcodec.so libavcodec.so.60 libavcodec.so.60.3.100 (avformat/avutil/swscale/swresample 同理) # Linux └── ... ``` > 注意:自编译时若开启 `--enable-gpl`(x264/x265),FFmpeg 整体变 GPL,你的整个分发将被迫 GPL,MIT 协议不再适用——保持 LGPL 默认即可。 --- ## 三、目录结构 ``` FFmpegcj/ ├── cjpm.toml # 库包配置(output-type = static,[ffi.c] 声明 5 个原生库) ├── LICENSE # MIT(本库协议) ├── LICENSE.FFMPEG # FFmpeg LGPL v2.1 协议文本 ├── scripts/ │ ├── build_ffmpeg_windows.sh # Windows 自编译 FFmpeg(MSYS2/MinGW-w64,供需要重新编译时用) │ └── build_ffmpeg_linux.sh # Linux 自编译 FFmpeg(gcc,供需要重新编译时用) ├── src/ │ ├── main.cj # 占位文件(让 src 根目录被 cjpm 扫描) │ ├── util.cj # 友好 API:版本/错误码/内存工具 │ ├── media.cj # 友好 API:MediaInfo / Demuxer / Packet │ ├── decode.cj # 友好 API:Decoder / Frame │ ├── convert.cj # 友好 API:Scaler / Resampler │ ├── encode.cj # 友好 API:Encoder / Muxer │ └── c/ │ ├── avutil.cj # FFI:libavutil │ ├── avformat.cj # FFI:libavformat │ ├── avcodec.cj # FFI:libavcodec │ ├── swscale.cj # FFI:libswscale + libswresample │ └── structs.cj # FFI:不透明结构体字段偏移访问(offsetof 实测) ├── lib/ # FFmpeg 共享库,随仓库发布(Windows dll + Linux so 同目录,见 lib/README.md) └── examples/ # 独立示例项目(path 依赖引用本库) └── src/main.cj # version / probe / frames / remux 四个演示命令 ``` ## 四、开发实施步骤(每一步做什么) | # | 步骤 | 做什么 | 状态 | |---|---|---|---| | 1 | 项目骨架 | `cjpm.toml`、`.gitignore`、`LICENSE`、`LICENSE.FFMPEG`、目录结构 | ✅ | | 2 | 获取 FFmpeg 6.0 LGPL 共享库 | BtbN 预编译链接失效 → Windows 用 MSYS2/MinGW-w64 自编译、Linux 用 gcc 自编译(脚本 `scripts/build_ffmpeg_*.sh`),产物随仓库 `lib/` 发布 | ✅ | | 3 | FFI 声明层 | `src/c/avutil.cj`(常量/AVRational/Packet/Frame/Dictionary)→ `avformat.cj` → `avcodec.cj` → `swscale.cj`,每个函数配 `_cjbindwrapper`;inline 函数(`av_q2d`/`av_make_q`/`av_inv_q`)仓颉实现,改名函数(`av_channel_layout_uninit`)映射 | ✅ | | 4 | 结构体偏移表 | `.cache/ffmpeg_offsets.c` 用 gcc 对 6.0.1 头文件实测 offsetof,写入 `src/c/structs.cj`(AVFormatContext/AVStream/AVCodecParameters/AVFrame/AVPacket/AVCodec/AVChannelLayout/AVDictionaryEntry) | ✅ | | 5 | 友好 API 层 | `util.cj`(version/strerror)→ `media.cj`(MediaInfo/Demuxer/Packet)→ `decode.cj`(Decoder/Frame)→ `convert.cj`(Scaler/Resampler)→ `encode.cj`(Encoder/Muxer) | ✅ | | 6 | 示例项目 | `examples/`:①version 版本 ②probe 探测 ③frames 解码抽帧 PPM ④remux 转封装 | ✅ | | 7 | Windows 编译验证 | `cjpm build` + 用本机 ffmpeg.exe 生成测试视频,跑通 version/probe/frames/remux 全流程 | ✅ | | 8 | Linux 支持 | 龙蜥 Anolis 8 机器按同配置编译 so(已拷入 `lib/`);Linux 侧 examples 待跑通验证 | ⏳ | | 9 | 文档与发布 | README 收尾、API 参考补全、Gitee 发布 | ⏳ | ## 五、构建与运行步骤(用户视角) ### Windows ```bat :: 1) 环境(按你的 SDK 实际路径) set CANGJIE_HOME=E:\分布式服务\仓颉\cangjie-sdk-windows-x64-1.0.4\cangjie set PATH=%CANGJIE_HOME%\tools\bin;%CANGJIE_HOME%\bin;%CANGJIE_HOME%\runtime\lib\windows_x86_64_llvm;%PATH% cjc --version :: 应显示 1.0.4 :: 2) 编译 + 运行示例(lib\ 已随仓库发布,无需下载 FFmpeg) cd examples cjpm update cjpm build set PATH=..\lib;%CANGJIE_HOME%\runtime\lib\windows_x86_64_llvm;%PATH% target\release\bin\main.exe ``` ### Linux ```bash # 1) 环境 export CANGJIE_HOME=/opt/cangjie-sdk-linux-x86_64-1.0.4/cangjie export PATH="$CANGJIE_HOME/tools/bin:$CANGJIE_HOME/bin:$PATH" export LD_LIBRARY_PATH="$PWD/lib:$CANGJIE_HOME/runtime/lib/linux_x86_64_llvm:$LD_LIBRARY_PATH" # 2) 编译 + 运行示例(lib/ 已随仓库发布,无需下载 FFmpeg) cd examples cjpm update && cjpm build && cjpm run ``` ### 引用方式 ```toml [dependencies] # 本地开发 ffmpegcj = { path = ".." } # 发布后(Gitee) # ffmpegcj = { git = "https://gitee.com/longkicode/ffmpegcj.git", commitId = "" } ``` ## 六、API 参考(友好层 `ffmpegcj`) ### util.cj — 工具 | 方法 | 说明 | |---|---| | `version(): String` | avutil / avcodec / avformat 三个库版本号文本 | | `versionText(v: UInt32): String` | 单个版本号 → `58.2.100` 文本 | | `errmsg(errnum: Int32): String` | FFmpeg 错误码 → 可读文本(`av_strerror`) | | `isEof(errnum): Bool` / `isAgain(errnum): Bool` | 判断 `AVERROR_EOF` / `AVERROR_EAGAIN` | ### media.cj — 媒体探测 / 解封装 / 数据包 | 类型 / 方法 | 说明 | |---|---| | `MediaType` | `Unknown / Video / Audio / Data / Subtitle`;`typeName()` 转文本 | | `StreamInfo` | 单条流信息:index、类型、codecId、codecName、宽高、像素格式、采样率、声道数、sampleFormat、timebase(num/den)、帧率、时长(timebase 整数/秒)、nbFrames、bitRate;`isVideo()` / `isAudio()` / `toString()` | | `MediaInfo.probe(path): MediaInfo` | 静态探测:formatName/longName、durationSec、bitRate、`streams: ArrayList` | | `Packet` | `pts()/dts()/duration()/pos()`(按流 timebase 的原始整数)、`streamIndex()`、`size()`、`ptsSec(tb)/durationSec(tb)`(转秒)、`copyData(): Array`(拷贝数据);`finalize()` 释放 | | `Demuxer.open(path): Demuxer` | 打开输入(本地文件或 http/https/rtmp/rtsp URL),自动 `find_stream_info` | | `Demuxer.info(): MediaInfo` | 复用已打开上下文探测 | | `Demuxer.readPacket(): Option` | 读下一包;文件尾返回 `None`(EOF);调用方负责 `finalize()` | | `Demuxer.seek(seconds: Float64)` | 按秒**向后**定位(关键帧) | | `Demuxer.context(): CPointer` | 底层句柄(高级用法) | | `Demuxer.close()` / `finalize()` | 释放 | ### decode.cj — 解码 | 类型 / 方法 | 说明 | |---|---| | `Frame` | `width/height/format/nbSamples/sampleRate/channels/pts/linesize(plane)`;`pixelFormatName()`;`copyPlane(plane): Array`;`copyVideoBytes()`(按 linesize 连续拷贝,可直接写 BMP/PPM);`finalize()` | | `Decoder.open(demuxer, streamIndex): Decoder` | 按流参数自动找解码器并打开(视频/音频通用) | | `Decoder.decode(pkt: Option): Array` | 送包收帧(`send_packet` + 循环 `receive_frame`;音频一包可出多帧);返回 0..n 帧,调用方负责 `finalize()` | | `Decoder.flush(): Array` | 冲刷解码器尾部缓存帧(发空包 + 循环取帧 drain) | | `Decoder.width()/height()/pixFmt()/sampleRate()/channels()/sampleFmt()/timeBaseNum()/timeBaseDen()/codecName()` | 解码上下文信息 | | `Decoder.close()` / `finalize()` | 释放 | ### convert.cj — 像素转换 / 重采样 | 类型 / 方法 | 说明 | |---|---| | `Scaler.create(srcW, srcH, srcFmt, dstW, dstH, dstFmt, flags): Scaler` | 创建 libswscale 上下文;`flags` 用 `ffi.SWS_*`(如 `SWS_BILINEAR`) | | `Scaler.convert(frame: Frame): Array` | 转出目标像素格式连续字节(RGB24/BGR24=3、RGBA/BGRA/ARGB/ABGR=4、GRAY8=1、GRAY16LE=2 字节/像素),可直接写图像文件 | | `Scaler.convertToFrame(frame): Frame` | 输出为目标格式的 `Frame`(供继续处理/编码) | | `Resampler.create(inRate, inFmt, inCh, outRate, outFmt, outCh): Resampler` | 创建 libswresample 上下文(`swr_alloc_set_opts2` 新 API + AVChannelLayout) | | `Resampler.convert(frame: Frame): Array` | 输出交错 PCM 字节数组 | | 两者均提供 `close()` / `finalize()` | 释放 | ### encode.cj — 编码 / 封装 | 类型 / 方法 | 说明 | |---|---| | `Encoder.createVideo(codecId, width, height, pixFmt, timeBaseNum, timeBaseDen, bitRate): Encoder` | 按 codec_id 找原生 LGPL 编码器(mpeg4/mjpeg/png/ffv1/rawvideo 等)并打开 | | `Encoder.sendFrame(frame): Unit` / `receivePacket(): Option>` | 新式编码 API;`flush()` 冲刷尾部 | | `Muxer.create(path): Muxer` | 按扩展名猜输出格式并打开(`avio_open` + `avformat_alloc_output_context2`) | | `Muxer.addStream(demuxer, streamIndex): Int32` | 从输入流拷贝参数新建输出流(自动清零 codec_tag 兼容跨容器 remux),返回输出流序号 | | `Muxer.writeHeader()` / `writePacket(pkt, srcOutIndex)` / `writeTrailer()` | 写头/写包(自动按输出 timebase 重缩放 pts/dts,交错写入)/写尾 | | `Muxer.close()` / `finalize()` | 释放 | ### 底层 FFI 层(`ffmpegcj.c`) 全部绑定函数均为 `avxxx_cjbindwrapper` 形式(约 60 个),对应 FFmpeg C API 同名同参;不透明结构体字段通过 `src/c/structs.cj` 的偏移访问函数读写(如 `avFmtCtxNbStreams`、`avStreamCodecpar`、`avFrameWidth`、`avPacketPts`、`avCodecparSetCodecTag` 等)。升级 FFmpeg 大版本后用 `.cache/ffmpeg_offsets.c` 重新生成偏移表。 --- ## 七、许可与合规(重要) - **本库(仓颉封装代码)**:MIT License(见 `LICENSE`)。 - **FFmpeg**:LGPL v2.1 or later(见 `LICENSE.FFMPEG`)。本库**只动态链接** FFmpeg 共享库,**不包含、不修改** FFmpeg 源码,未开启任何 GPL/非自由组件。 > This library dynamically links FFmpeg, which is licensed under LGPL v2.1+. You may obtain the source code of FFmpeg at https://ffmpeg.org/. This library does not modify FFmpeg source code. **分发注意事项:** 1. 若随库分发 FFmpeg DLL/SO,需向用户提供对应版本 FFmpeg 源码获取方式(`https://ffmpeg.org/`),并允许用户替换该动态库(LGPL 义务); 2. **不要**把 FFmpeg 源码复制进本仓库; 3. **不要**静态链接 FFmpeg(合规成本极高); 4. 若你自行替换为 GPL 构建(如开启 x264/x265 的构建),FFmpeg 整体变 GPL——此时**仅限个人使用**,分发前请评估 GPL 传染性,本仓库的 MIT 声明不覆盖该场景。