目标
- 理解 AV1 Codec Configuration Record 结构
- 搞懂位运算在协议解析中的应用
- 学会"防御式解析"的思维方式
故事开场
AV1 是新一代视频编码,但它的配置结构极其复杂。
一个字节里塞了 Marker、Version、Profile......
你该如何正确解析?
核心知识
- AV1 Codec Configuration Record 布局
bash
| Marker(1) | Version(7) | Profile(3) | Level(5) | ...
- 位运算拆解
go
Marker := b >> 7
Version := b & 0x7F
- 为什么校验这么严格?
- AV1 配置错误会导致"静默失败"
- 严格校验是对播放器的保护
源码精读
go
func (p *AV1Ctx) Unmarshal(data *gomem.MemoryReader) (err error) {
b, err = data.ReadByte()
Marker := b >> 7
if Marker != 1 {
return ErrInvalidMarker
}
// ...
}
难点突破
- 一个字节 = 多个字段 → 位运算拆解
- Reserved Bits → 必须为 0,否则数据异常
- Marker Bit → 必须是 1,用于格式识别
代码示例
go
package main
import (
"fmt"
"github.com/langhuihui/gomem"
"m7s.live/v5/pkg/codec/rtmp"
)
func main() {
// AV1CodecConfigurationRecord (合法示例)
data := []byte{
0x81, // Marker=1, Version=1
0x0A, // Profile=0, Level=10
0x00, // Tier=0, Bitdepth=8, Mono=0...
0x00, // Reserved + PresentDelay
0x12, 0x34, // 模拟 ConfigOBUs
}
reader := gomem.NewMemoryReader(data)
ctx := &rtmp.AV1Ctx{}
if err := ctx.Unmarshal(reader); err != nil {
fmt.Println("Parse error:", err)
return
}
fmt.Println("Parse success:")
fmt.Println("Version:", ctx.Version)
fmt.Println("Profile:", ctx.SeqProfile)
fmt.Println("Level:", ctx.SeqLevelIdx0)
fmt.Println("ConfigOBUs:", fmt.Sprintf("% 02X", ctx.ConfigOBUs))
}
运行结果
bash
Parse success:
Version: 1
Profile: 0
Level: 10
ConfigOBUs: 12 34
总结
- 位运算是协议解析的基本功
- 严格校验能避免"静默失败"
- AV1 配置解析是 RTMP 中的"硬骨头"