Compare commits
No commits in common. "b938e3ac5f3833abe454f244996dc86e829ffc22" and "387ecc992aff09c2be38f82611ba3dc6fa697d22" have entirely different histories.
b938e3ac5f
...
387ecc992a
222
README.md
222
README.md
|
|
@ -1,222 +0,0 @@
|
||||||
# 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
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue