package buffer import ( "fmt" "sort" "github.com/pion/rtp" dd "github.com/livekit/livekit-server/pkg/sfu/dependencydescriptor" "github.com/livekit/livekit-server/pkg/sfu/utils" "github.com/livekit/protocol/logger" ) type DependencyDescriptorParser struct { structure *dd.FrameDependencyStructure ddExtID uint8 logger logger.Logger onMaxLayerChanged func(int32, int32) decodeTargets []DependencyDescriptorDecodeTarget wrapAround *utils.WrapAround[uint16, uint64] structureExtSeq uint64 activeDecodeTargetsExtSeq uint64 activeDecodeTargetsMask uint32 } func NewDependencyDescriptorParser(ddExtID uint8, logger logger.Logger, onMaxLayerChanged func(int32, int32)) *DependencyDescriptorParser { logger.Infow("creating dependency descriptor parser", "ddExtID", ddExtID) return &DependencyDescriptorParser{ ddExtID: ddExtID, logger: logger, onMaxLayerChanged: onMaxLayerChanged, wrapAround: utils.NewWrapAround[uint16, uint64](), } } type ExtDependencyDescriptor struct { Descriptor *dd.DependencyDescriptor DecodeTargets []DependencyDescriptorDecodeTarget StructureUpdated bool ActiveDecodeTargetsUpdated bool } func (r *DependencyDescriptorParser) Parse(pkt *rtp.Packet) (*ExtDependencyDescriptor, VideoLayer, error) { var videoLayer VideoLayer ddBuf := pkt.GetExtension(r.ddExtID) if ddBuf == nil { return nil, videoLayer, nil } var ddVal dd.DependencyDescriptor ext := &dd.DependencyDescriptorExtension{ Descriptor: &ddVal, Structure: r.structure, } _, err := ext.Unmarshal(ddBuf) if err != nil { // r.logger.Debugw("failed to parse generic dependency descriptor", "err", err, "payload", pkt.PayloadType, "ddbufLen", len(ddBuf)) return nil, videoLayer, err } extSeq := r.wrapAround.Update(pkt.SequenceNumber).ExtendedVal if ddVal.FrameDependencies != nil { videoLayer.Spatial, videoLayer.Temporal = int32(ddVal.FrameDependencies.SpatialId), int32(ddVal.FrameDependencies.TemporalId) } extDD := &ExtDependencyDescriptor{ Descriptor: &ddVal, } if ddVal.AttachedStructure != nil { r.logger.Debugw(fmt.Sprintf("parsed dependency descriptor\n%s", ddVal.String())) if extSeq > r.structureExtSeq { r.structure = ddVal.AttachedStructure r.decodeTargets = ProcessFrameDependencyStructure(ddVal.AttachedStructure) r.structureExtSeq = extSeq extDD.StructureUpdated = true extDD.ActiveDecodeTargetsUpdated = true // The dependency descriptor reader will always set ActiveDecodeTargetsBitmask for TemplateDependencyStructure is present, // so don't need to notify max layer change here. } } if mask := ddVal.ActiveDecodeTargetsBitmask; mask != nil && extSeq > r.activeDecodeTargetsExtSeq { r.activeDecodeTargetsExtSeq = extSeq if *mask != r.activeDecodeTargetsMask { r.activeDecodeTargetsMask = *mask extDD.ActiveDecodeTargetsUpdated = true var maxSpatial, maxTemporal int32 for _, dt := range r.decodeTargets { if *mask&(1<