feat: 添加 goffmpeg 项目的 README 文档

新增完整的项目说明文档,包含以下内容:
- 项目简介和系统依赖说明
- 详细的项目结构介绍
- 构建方法和使用示例
- API 概览,包括 FormatContext、OutputFormatContext、Stream、
CodecParameters、Context、Packet、Frame 等核心组件的接口说明
- 使用注意事项和许可证信息
```
This commit is contained in:
kingecg 2026-03-20 21:53:09 +08:00
parent 03039dec91
commit b938e3ac5f
1 changed files with 222 additions and 0 deletions

222
README.md Normal file
View File

@ -0,0 +1,222 @@
# goffmpeg
Go bindings for FFmpeg using CGO.
## 项目简介
本项目提供 Go 语言对 FFmpeg 动态库的 CGO 绑定,以 lib 库形式开放接口供其他应用调用。
## 系统依赖
### FFmpeg 开发库
**Ubuntu/Debian:**
```bash
sudo apt install libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libswscale-dev libswresample-dev pkg-config
```
**验证安装:**
```bash
pkg-config --exists libavcodec libavformat libavutil
echo $? # 应输出 0
```
## 项目结构
```
goffmpeg/
├── pkg/ffmpeg/ # 核心库
│ ├── cgo.go # CGO 配置和头文件导入
│ ├── errors.go # 错误类型定义
│ ├── ffmpeg.go # FormatContext、Stream、CodecParameters
│ ├── codec.go # 编解码器封装
│ ├── frame.go # 帧数据封装
│ └── packet.go # 数据包封装
├── cmd/ffmpeg-cli/ # CLI 工具
├── examples/ # 示例代码
│ └── simple-transcode/ # 简单转码示例
└── README.md
```
## 构建
```bash
go build ./...
```
## 示例用法
### 简单转码 (流拷贝模式)
```go
package main
import (
"fmt"
"log"
"os"
"git.kingecg.top/kingecg/goffmpeg/pkg/ffmpeg"
)
func main() {
inputURL := "input.mp4"
outputURL := "output.mp4"
// 打开输入文件
ic := ffmpeg.AllocFormatContext()
defer ic.Free()
if err := ic.OpenInput(inputURL); err != nil {
log.Fatalf("Failed to open input: %v", err)
}
defer ic.Close()
// 查找流信息
if err := ic.FindStreamInfo(); err != nil {
log.Fatalf("Failed to find stream info: %v", err)
}
// 打印输入格式信息
fmt.Printf("Input: %s\n", inputURL)
ic.DumpFormat(0, inputURL, false)
// 猜测输出格式
of := ffmpeg.GuessFormat("", outputURL)
if of == nil {
log.Fatal("Failed to guess output format")
}
// 创建输出上下文
ofc, err := ffmpeg.AllocOutputContext(outputURL, of)
if err != nil {
log.Fatalf("Failed to allocate output context: %v", err)
}
defer ofc.Free()
// 获取输入流
inputStreams := ic.Streams()
// 处理流
for i, is := range inputStreams {
cp := is.CodecParameters()
if cp == nil {
continue
}
// 只处理视频和音频
if cp.CodecType() != ffmpeg.CodecTypeVideo &&
cp.CodecType() != ffmpeg.CodecTypeAudio {
continue
}
// 添加输出流 (流拷贝模式)
os, err := ofc.AddStream(nil)
if err != nil {
continue
}
// 复制编解码参数
os.SetCodecParameters(cp)
os.SetTimeBase(is.TimeBase())
fmt.Printf("Stream %d: type=%d\n", i, cp.CodecType())
}
// 打开输出文件
if err := ofc.OpenOutput(outputURL); err != nil {
log.Fatalf("Failed to open output: %v", err)
}
// 写入头部
if err := ofc.WriteHeader(); err != nil {
log.Fatalf("Failed to write header: %v", err)
}
// 转封装循环
pkt := ffmpeg.AllocPacket()
defer pkt.Free()
for {
err := ic.ReadPacket(pkt)
if err != nil {
break
}
ofc.WritePacket(pkt)
pkt.Unref()
}
// 写入尾部
ofc.WriteTrailer()
fmt.Printf("Remuxing complete! Output saved to: %s\n", outputURL)
}
```
## API 概览
### FormatContext
- `AllocFormatContext()` - 分配格式上下文
- `OpenInput(url)` - 打开输入
- `FindStreamInfo()` - 查找流信息
- `Streams()` - 获取所有流
- `VideoStreams()` - 获取视频流
- `AudioStreams()` - 获取音频流
- `ReadPacket()` / `WritePacket()` - 读写数据包
### OutputFormatContext
- `AllocOutputContext(url, format)` - 分配输出上下文
- `AddStream(codec)` - 添加流
- `OpenOutput(url)` - 打开输出文件
- `WriteHeader()` / `WriteTrailer()` - 写入头部/尾部
### Stream
- `CodecParameters()` - 获取编解码参数
- `SetCodecParameters(cp)` - 设置编解码参数
- `TimeBase()` / `SetTimeBase(r)` - 时间基
### CodecParameters
- `CodecType()` - 编解码器类型
- `CodecID()` - 编解码器 ID
- `Width()` / `Height()` - 尺寸
- `Format()` - 格式
- `SampleRate()` - 采样率
- `Channels()` - 声道数
### Context (编解码器上下文)
- `AllocContext()` - 分配上下文
- `SetCodec(codec)` - 设置编解码器
- `Open(codec)` - 打开编解码器
- `SendPacket()` / `ReceiveFrame()` - 解码
- `SendFrame()` / `ReceivePacket()` - 编码
### Packet
- `AllocPacket()` - 分配数据包
- `Data()` / `Size()` - 数据和大小
- `PTS()` / `DTS()` - 时间戳
- `StreamIndex()` - 流索引
### Frame
- `AllocFrame()` - 分配帧
- `Width()` / `Height()` - 尺寸
- `Format()` - 格式
- `NbSamples()` - 样本数
## 注意事项
1. **CGO 构建标签**: 项目使用 `//go:build cgo` 约束,需要 CGO 支持才能构建
2. **FFmpeg 版本**: 需要 FFmpeg 4.0+
3. **线程安全**: FFmpeg 的某些操作不是线程安全的,请参考 FFmpeg 文档
4. **内存管理**: 使用 `Free()` 方法释放资源,或使用 `defer`
## 许可证
MIT License