添加Track实现
This commit is contained in:
parent
db7e579916
commit
2b3c9ee03a
|
|
@ -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 |
|
||||
| 私有字段 | 首字母小写字段 + 公开访问方法 |
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue