diff --git a/doc/track.md b/doc/track.md new file mode 100644 index 0000000..2874642 --- /dev/null +++ b/doc/track.md @@ -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 | +| 私有字段 | 首字母小写字段 + 公开访问方法 | \ No newline at end of file diff --git a/extension/track.go b/extension/track.go new file mode 100644 index 0000000..5e3e466 --- /dev/null +++ b/extension/track.go @@ -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 + } +} \ No newline at end of file