添加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