mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-09-26 18:51:13 +08:00
241 lines
4.8 KiB
Go
241 lines
4.8 KiB
Go
package pkg
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/bluenviron/mediacommon/pkg/codecs/av1"
|
|
"m7s.live/v5/pkg/codec"
|
|
"m7s.live/v5/pkg/util"
|
|
)
|
|
|
|
type (
|
|
IAudioCodecCtx interface {
|
|
codec.ICodecCtx
|
|
GetSampleRate() int
|
|
GetChannels() int
|
|
GetSampleSize() int
|
|
}
|
|
IVideoCodecCtx interface {
|
|
codec.ICodecCtx
|
|
Width() int
|
|
Height() int
|
|
}
|
|
IDataFrame interface {
|
|
}
|
|
// Source -> Parse -> Demux -> (ConvertCtx) -> Mux(GetAllocator) -> Recycle
|
|
IAVFrame interface {
|
|
GetSample() *Sample
|
|
GetSize() int
|
|
CheckCodecChange() error
|
|
Demux() error // demux to raw format
|
|
Mux(*Sample) error // mux from origin format
|
|
Recycle()
|
|
String() string
|
|
}
|
|
ISequenceCodecCtx[T any] interface {
|
|
GetSequenceFrame() T
|
|
}
|
|
BaseSample struct {
|
|
Raw IRaw // 裸格式用于转换的中间格式
|
|
IDR bool
|
|
TS0, Timestamp, CTS time.Duration // 原始 TS、修正 TS、Composition Time Stamp
|
|
}
|
|
Sample struct {
|
|
codec.ICodecCtx
|
|
util.RecyclableMemory
|
|
*BaseSample
|
|
}
|
|
Nalus = util.ReuseArray[util.Memory]
|
|
|
|
AudioData = util.Memory
|
|
|
|
OBUs AudioData
|
|
|
|
AVFrame struct {
|
|
DataFrame
|
|
*Sample
|
|
Wraps []IAVFrame // 封装格式
|
|
}
|
|
IRaw interface {
|
|
util.Resetter
|
|
Count() int
|
|
}
|
|
AVRing = util.Ring[AVFrame]
|
|
DataFrame struct {
|
|
sync.RWMutex
|
|
discard bool
|
|
Sequence uint32 // 在一个Track中的序号
|
|
WriteTime time.Time // 写入时间,可用于比较两个帧的先后
|
|
}
|
|
)
|
|
|
|
func (sample *Sample) GetSize() int {
|
|
return sample.Size
|
|
}
|
|
|
|
func (sample *Sample) GetSample() *Sample {
|
|
return sample
|
|
}
|
|
|
|
func (sample *Sample) CheckCodecChange() (err error) {
|
|
return
|
|
}
|
|
|
|
func (sample *Sample) Demux() error {
|
|
return nil
|
|
}
|
|
|
|
func (sample *Sample) Mux(from *Sample) error {
|
|
sample.ICodecCtx = from.GetBase()
|
|
return nil
|
|
}
|
|
|
|
func ConvertFrameType(from, to IAVFrame) (err error) {
|
|
fromSampe, toSample := from.GetSample(), to.GetSample()
|
|
if !fromSampe.HasRaw() {
|
|
if err = from.Demux(); err != nil {
|
|
return
|
|
}
|
|
}
|
|
toSample.SetAllocator(fromSampe.GetAllocator())
|
|
toSample.BaseSample = fromSampe.BaseSample
|
|
return to.Mux(fromSampe)
|
|
}
|
|
|
|
func (b *BaseSample) HasRaw() bool {
|
|
return b.Raw != nil && b.Raw.Count() > 0
|
|
}
|
|
|
|
// 90Hz
|
|
func (b *BaseSample) GetDTS() time.Duration {
|
|
return b.Timestamp * 90 / time.Millisecond
|
|
}
|
|
|
|
func (b *BaseSample) GetPTS() time.Duration {
|
|
return (b.Timestamp + b.CTS) * 90 / time.Millisecond
|
|
}
|
|
|
|
func (b *BaseSample) SetDTS(dts time.Duration) {
|
|
b.Timestamp = dts * time.Millisecond / 90
|
|
}
|
|
|
|
func (b *BaseSample) SetPTS(pts time.Duration) {
|
|
b.CTS = pts*time.Millisecond/90 - b.Timestamp
|
|
}
|
|
|
|
func (b *BaseSample) SetTS32(ts uint32) {
|
|
b.Timestamp = time.Duration(ts) * time.Millisecond
|
|
}
|
|
|
|
func (b *BaseSample) GetTS32() uint32 {
|
|
return uint32(b.Timestamp / time.Millisecond)
|
|
}
|
|
|
|
func (b *BaseSample) SetCTS32(ts uint32) {
|
|
b.CTS = time.Duration(ts) * time.Millisecond
|
|
}
|
|
|
|
func (b *BaseSample) GetCTS32() uint32 {
|
|
return uint32(b.CTS / time.Millisecond)
|
|
}
|
|
|
|
func (b *BaseSample) GetNalus() *Nalus {
|
|
if b.Raw == nil {
|
|
b.Raw = &Nalus{}
|
|
}
|
|
return b.Raw.(*Nalus)
|
|
}
|
|
|
|
func (b *BaseSample) GetAudioData() *AudioData {
|
|
if b.Raw == nil {
|
|
b.Raw = &AudioData{}
|
|
}
|
|
return b.Raw.(*AudioData)
|
|
}
|
|
|
|
func (b *BaseSample) ParseAVCC(reader *util.MemoryReader, naluSizeLen int) error {
|
|
array := b.GetNalus()
|
|
for reader.Length > 0 {
|
|
l, err := reader.ReadBE(naluSizeLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
reader.RangeN(int(l), array.GetNextPointer().PushOne)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (frame *AVFrame) Reset() {
|
|
if len(frame.Wraps) > 0 {
|
|
for _, wrap := range frame.Wraps {
|
|
wrap.Recycle()
|
|
}
|
|
frame.BaseSample.IDR = false
|
|
frame.BaseSample.TS0 = 0
|
|
frame.BaseSample.Timestamp = 0
|
|
frame.BaseSample.CTS = 0
|
|
if frame.Raw != nil {
|
|
frame.Raw.Reset()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (frame *AVFrame) Discard() {
|
|
frame.discard = true
|
|
frame.Reset()
|
|
}
|
|
|
|
func (df *DataFrame) StartWrite() (success bool) {
|
|
if df.discard {
|
|
return
|
|
}
|
|
if df.TryLock() {
|
|
return true
|
|
}
|
|
df.discard = true
|
|
return
|
|
}
|
|
|
|
func (df *DataFrame) Ready() {
|
|
df.WriteTime = time.Now()
|
|
df.Unlock()
|
|
}
|
|
|
|
func (obus *OBUs) ParseAVCC(reader *util.MemoryReader) error {
|
|
var obuHeader av1.OBUHeader
|
|
startLen := reader.Length
|
|
for reader.Length > 0 {
|
|
offset := reader.Size - reader.Length
|
|
b, err := reader.ReadByte()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = obuHeader.Unmarshal([]byte{b})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// if log.Trace {
|
|
// vt.Trace("obu", zap.Any("type", obuHeader.Type), zap.Bool("iframe", vt.Value.IFrame))
|
|
// }
|
|
obuSize, _, _ := reader.LEB128Unmarshal()
|
|
end := reader.Size - reader.Length
|
|
size := end - offset + int(obuSize)
|
|
reader = &util.MemoryReader{Memory: reader.Memory, Length: startLen - offset}
|
|
obu, err := reader.ReadBytes(size)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
(*AudioData)(obus).PushOne(obu)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (obus *OBUs) Reset() {
|
|
((*util.Memory)(obus)).Reset()
|
|
}
|
|
|
|
func (obus *OBUs) Count() int {
|
|
return (*util.Memory)(obus).Count()
|
|
}
|