添加Track实现

This commit is contained in:
kingecg 2025-09-26 20:58:05 +08:00
parent db7e579916
commit 2b3c9ee03a
2 changed files with 281 additions and 0 deletions

64
doc/track.md Normal file
View File

@ -0,0 +1,64 @@
# Track 模块设计文档
## 概述
Track 模块用于描述媒体通道支持视频和音频轨道的处理包括帧的输入输出、SDP生成、比特率设置等功能。该模块是流媒体处理的核心组件确保不同协议间的媒体数据正确传输和转换。
## 接口设计
### Track 接口
```go
type Track interface {
Ready() bool
Clone() Track
GetSdp(payloadType uint8) *Sdp
GetBitRate() int
SetBitRate(bitRate int)
GetCodecId() CodecId
GetExtraData() []byte
SetExtraData(data []byte)
}
```
### VideoTrack 接口
```go
type VideoTrack interface {
Track
GetVideoWidth() int
GetVideoHeight() int
GetVideoFps() float32
GetConfigFrames() []Frame
}
```
### AudioTrack 接口
```go
type AudioTrack interface {
Track
GetAudioSampleRate() int
GetAudioSampleBit() int
GetAudioChannel() int
}
```
## 实现说明
- **并发安全**:所有结构体内部状态通过 `sync.Mutex` 保护,确保多线程环境下的数据一致性。
- **代码复用**:通过嵌入 `BaseTrack` 结构体实现公共方法(如比特率管理),避免重复代码。
- **接口隔离**:视频和音频轨道通过独立接口定义,明确职责边界。
- **内存管理**:依赖 Go 的 GC 机制,避免手动内存管理,但注意减少不必要的数据拷贝。
## 示例代码
```go
// 创建视频轨道
videoTrack := extension.NewVideoTrackImp(extension.CodecH264, 1920, 1080, 30)
sdp := videoTrack.GetSdp(96)
// 创建音频轨道
audioTrack := extension.NewAudioTrackImp(extension.CodecAAC, 44100, 2, 16)
```
## 与 C++ 实现的差异
| C++ 特性 | Go 实现方案 |
|-------------------|-------------------------------|
| 虚函数 | 接口定义 |
| 继承 | 结构体嵌入 |
| 共享指针 | Go 原生指针 + GC |
| 私有字段 | 首字母小写字段 + 公开访问方法 |

217
extension/track.go Normal file
View File

@ -0,0 +1,217 @@
package extension
import (
"sync"
)
// CodecId 媒体编解码类型
type CodecId int
const (
CodecH264 CodecId = iota + 96
CodecH265
CodecAAC
CodecG711A
CodecG711U
CodecOpus
)
// Track 媒体通道描述接口
type Track interface {
Ready() bool
Clone() Track
GetSdp(payloadType uint8) *Sdp
GetBitRate() int
SetBitRate(bitRate int)
GetCodecId() CodecId
GetExtraData() []byte
SetExtraData(data []byte)
}
// BaseTrack 实现Track的公共方法
type BaseTrack struct {
mutex sync.Mutex
bitRate int
codecId CodecId
extraData []byte
}
func (b *BaseTrack) GetBitRate() int {
b.mutex.Lock()
defer b.mutex.Unlock()
return b.bitRate
}
func (b *BaseTrack) SetBitRate(bitRate int) {
b.mutex.Lock()
defer b.mutex.Unlock()
b.bitRate = bitRate
}
func (b *BaseTrack) GetCodecId() CodecId {
return b.codecId
}
func (b *BaseTrack) GetExtraData() []byte {
b.mutex.Lock()
defer b.mutex.Unlock()
return b.extraData
}
func (b *BaseTrack) SetExtraData(data []byte) {
b.mutex.Lock()
defer b.mutex.Unlock()
b.extraData = data
}
// VideoTrack 视频轨道接口
type VideoTrack interface {
Track
GetVideoWidth() int
GetVideoHeight() int
GetVideoFps() float32
GetConfigFrames() []Frame
}
// VideoTrackImp 视频轨道具体实现
type VideoTrackImp struct {
BaseTrack
width int
height int
fps float32
}
// NewVideoTrackImp 创建视频轨道实例
func NewVideoTrackImp(codecId CodecId, width, height, fps int) *VideoTrackImp {
return &VideoTrackImp{
BaseTrack: BaseTrack{codecId: codecId},
width: width,
height: height,
fps: float32(fps),
}
}
func (v *VideoTrackImp) Ready() bool {
return true
}
func (v *VideoTrackImp) Clone() Track {
v.mutex.Lock()
defer v.mutex.Unlock()
return &VideoTrackImp{
BaseTrack: BaseTrack{
bitRate: v.bitRate,
codecId: v.codecId,
extraData: v.extraData,
},
width: v.width,
height: v.height,
fps: v.fps,
}
}
func (v *VideoTrackImp) GetSdp(payloadType uint8) *Sdp {
// 实际实现应生成SDP描述
return NewDefaultSdp(payloadType, v)
}
func (v *VideoTrackImp) GetVideoWidth() int {
return v.width
}
func (v *VideoTrackImp) GetVideoHeight() int {
return v.height
}
func (v *VideoTrackImp) GetVideoFps() float32 {
return v.fps
}
func (v *VideoTrackImp) GetConfigFrames() []Frame {
// 根据编解码器返回sps/pps等配置帧
return nil
}
// AudioTrack 音频轨道接口
type AudioTrack interface {
Track
GetAudioSampleRate() int
GetAudioSampleBit() int
GetAudioChannel() int
}
// AudioTrackImp 音频轨道具体实现
type AudioTrackImp struct {
BaseTrack
sampleRate int
channels int
sampleBit int
}
// NewAudioTrackImp 创建音频轨道实例
func NewAudioTrackImp(codecId CodecId, sampleRate, channels, sampleBit int) *AudioTrackImp {
return &AudioTrackImp{
BaseTrack: BaseTrack{codecId: codecId},
sampleRate: sampleRate,
channels: channels,
sampleBit: sampleBit,
}
}
func (a *AudioTrackImp) Ready() bool {
return true
}
func (a *AudioTrackImp) Clone() Track {
a.mutex.Lock()
defer a.mutex.Unlock()
return &AudioTrackImp{
BaseTrack: BaseTrack{
bitRate: a.bitRate,
codecId: a.codecId,
extraData: a.extraData,
},
sampleRate: a.sampleRate,
channels: a.channels,
sampleBit: a.sampleBit,
}
}
func (a *AudioTrackImp) GetSdp(payloadType uint8) *Sdp {
return NewDefaultSdp(payloadType, a)
}
func (a *AudioTrackImp) GetAudioSampleRate() int {
if a.sampleRate != 0 {
return a.sampleRate
}
return GetClockRateByCodec(a.codecId)
}
func (a *AudioTrackImp) GetAudioSampleBit() int {
if a.sampleBit != 0 {
return a.sampleBit
}
return 16
}
func (a *AudioTrackImp) GetAudioChannel() int {
if a.channels != 0 {
return a.channels
}
return 1
}
// 辅助函数
func GetClockRateByCodec(codecId CodecId) int {
switch codecId {
case CodecAAC:
return 44100
case CodecG711A, CodecG711U:
return 8000
case CodecOpus:
return 48000
default:
return 0
}
}