package buffer import ( "fmt" "sort" "github.com/pion/rtp" dd "github.com/livekit/livekit-server/pkg/sfu/dependencydescriptor" "github.com/livekit/protocol/logger" ) type DependencyDescriptorParser struct { structure *dd.FrameDependencyStructure ddExtID uint8 logger logger.Logger onMaxLayerChanged func(int32, int32) decodeTargets []DependencyDescriptorDecodeTarget } 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, } } type DependencyDescriptorWithDecodeTarget struct { Descriptor *dd.DependencyDescriptor DecodeTargets []DependencyDescriptorDecodeTarget } func (r *DependencyDescriptorParser) Parse(pkt *rtp.Packet) (*DependencyDescriptorWithDecodeTarget, VideoLayer, error) { // DD-TODO: make sure out-of-order RTP packets do not update decode targets 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 } if ddVal.FrameDependencies != nil { videoLayer.Spatial, videoLayer.Temporal = int32(ddVal.FrameDependencies.SpatialId), int32(ddVal.FrameDependencies.TemporalId) } if ddVal.AttachedStructure != nil && !ddVal.FirstPacketInFrame { // r.logger.Debugw("ignoring non-first packet in frame with attached structure") return nil, videoLayer, nil } if ddVal.AttachedStructure != nil { r.structure = ddVal.AttachedStructure r.decodeTargets = ProcessFrameDependencyStructure(ddVal.AttachedStructure) if len(r.decodeTargets) != 0 { r.logger.Debugw(fmt.Sprintf("update decode targets: %v", r.decodeTargets)) r.onMaxLayerChanged(r.decodeTargets[0].Layer.Spatial, r.decodeTargets[0].Layer.Temporal) } } if ddVal.AttachedStructure != nil && ddVal.FirstPacketInFrame { r.logger.Debugw(fmt.Sprintf("parsed dependency descriptor\n%s", ddVal.String())) } if mask := ddVal.ActiveDecodeTargetsBitmask; mask != nil { var maxSpatial, maxTemporal int32 for _, dt := range r.decodeTargets { if *mask&(1<