// Copyright 2020, Chef. All rights reserved. // https://github.com/q191201771/lal // // Use of this source code is governed by a MIT-style license // that can be found in the License file. // // Author: Chef (191201771@qq.com) package sdp import ( "fmt" "strings" "github.com/q191201771/lal/pkg/base" ) type LogicContext struct { RawSdp []byte AudioClockRate int VideoClockRate int Asc []byte Vps []byte Sps []byte Pps []byte audioPayloadTypeBase base.AvPacketPt // lal内部定义的类型 videoPayloadTypeBase base.AvPacketPt audioPayloadTypeOrigin int // 原始类型,sdp或rtp中的类型 videoPayloadTypeOrigin int audioAControl string videoAControl string // 没有用上的 hasAudio bool hasVideo bool } func (lc *LogicContext) IsAudioPayloadTypeOrigin(t int) bool { return lc.audioPayloadTypeOrigin == t } func (lc *LogicContext) IsVideoPayloadTypeOrigin(t int) bool { return lc.videoPayloadTypeOrigin == t } func (lc *LogicContext) IsPayloadTypeOrigin(t int) bool { return lc.audioPayloadTypeOrigin == t || lc.videoPayloadTypeOrigin == t } func (lc *LogicContext) IsAudioUnpackable() bool { return lc.audioPayloadTypeBase == base.AvPacketPtAac && lc.Asc != nil } func (lc *LogicContext) IsVideoUnpackable() bool { return lc.videoPayloadTypeBase == base.AvPacketPtAvc || lc.videoPayloadTypeBase == base.AvPacketPtHevc } func (lc *LogicContext) IsAudioUri(uri string) bool { return lc.audioAControl != "" && strings.HasSuffix(uri, lc.audioAControl) } func (lc *LogicContext) IsVideoUri(uri string) bool { return lc.videoAControl != "" && strings.HasSuffix(uri, lc.videoAControl) } func (lc *LogicContext) HasAudioAControl() bool { return lc.audioAControl != "" } func (lc *LogicContext) HasVideoAControl() bool { return lc.videoAControl != "" } func (lc *LogicContext) MakeAudioSetupUri(uri string) string { return lc.makeSetupUri(uri, lc.audioAControl) } func (lc *LogicContext) MakeVideoSetupUri(uri string) string { return lc.makeSetupUri(uri, lc.videoAControl) } func (lc *LogicContext) GetAudioPayloadTypeBase() base.AvPacketPt { return lc.audioPayloadTypeBase } func (lc *LogicContext) GetVideoPayloadTypeBase() base.AvPacketPt { return lc.videoPayloadTypeBase } func (lc *LogicContext) makeSetupUri(uri string, aControl string) string { if strings.HasPrefix(aControl, "rtsp://") { return aControl } return fmt.Sprintf("%s/%s", uri, aControl) } func ParseSdp2LogicContext(b []byte) (LogicContext, error) { var ret LogicContext c, err := ParseSdp2RawContext(b) if err != nil { return ret, err } for _, md := range c.MediaDescList { switch md.M.Media { case "audio": ret.hasAudio = true ret.AudioClockRate = md.ARtpMap.ClockRate ret.audioAControl = md.AControl.Value ret.audioPayloadTypeOrigin = md.ARtpMap.PayloadType if md.ARtpMap.EncodingName == ARtpMapEncodingNameAac { ret.audioPayloadTypeBase = base.AvPacketPtAac if md.AFmtPBase != nil { ret.Asc, err = ParseAsc(md.AFmtPBase) if err != nil { Log.Warnf("parse asc from afmtp failed. err=%+v", err) } } else { Log.Warnf("aac afmtp not exist.") } } else { ret.audioPayloadTypeBase = base.AvPacketPtUnknown } case "video": ret.hasVideo = true ret.VideoClockRate = md.ARtpMap.ClockRate ret.videoAControl = md.AControl.Value ret.videoPayloadTypeOrigin = md.ARtpMap.PayloadType switch md.ARtpMap.EncodingName { case ARtpMapEncodingNameH264: ret.videoPayloadTypeBase = base.AvPacketPtAvc if md.AFmtPBase != nil { ret.Sps, ret.Pps, err = ParseSpsPps(md.AFmtPBase) if err != nil { Log.Warnf("parse sps pps from afmtp failed. err=%+v", err) } } else { Log.Warnf("avc afmtp not exist.") } case ARtpMapEncodingNameH265: ret.videoPayloadTypeBase = base.AvPacketPtHevc if md.AFmtPBase != nil { ret.Vps, ret.Sps, ret.Pps, err = ParseVpsSpsPps(md.AFmtPBase) if err != nil { Log.Warnf("parse vps sps pps from afmtp failed. err=%+v", err) } } else { Log.Warnf("hevc afmtp not exist.") } default: ret.videoPayloadTypeBase = base.AvPacketPtUnknown } } } ret.RawSdp = b return ret, nil }