You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/pkg/sdp/pack.go

116 lines
2.8 KiB
Go

// Copyright 2021, 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 (
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/lal/pkg/aac"
"github.com/q191201771/lal/pkg/base"
)
// Pack
//
// @param samplingFrequency: 音频采样率注意当前G711U使用这个参数传递AAC的采样率通过 asc 参数传递 TODO(chef): 考虑 AAC 采样率通过 samplingFrequency 传递 202303
func Pack(vps, sps, pps, asc []byte, audioPt base.AvPacketPt, samplingFrequency int) (ctx LogicContext, err error) {
// 判断音频、视频是否存在以及视频是H264还是H265
var hasAudio, hasVideo, isHevc, isAac bool
if sps != nil && pps != nil {
hasVideo = true
if vps != nil {
isHevc = true
}
}
if audioPt != base.AvPacketPtUnknown {
switch audioPt {
case base.AvPacketPtG711U:
hasAudio = true
case base.AvPacketPtAac:
if asc != nil {
isAac = true
hasAudio = true
// 判断AAC的采样率
var ascCtx *aac.AscContext
ascCtx, err = aac.NewAscContext(asc)
if err != nil {
return
}
samplingFrequency, err = ascCtx.GetSamplingFrequency()
if err != nil {
return
}
}
}
}
if !hasAudio && !hasVideo {
err = nazaerrors.Wrap(base.ErrSdp)
return
}
sdpStr := fmt.Sprintf(`v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:%s
`, base.LalPackSdp)
streamid := 0
if hasVideo {
if isHevc {
tmpl := `m=video 0 RTP/AVP 98
a=rtpmap:98 H265/90000
a=fmtp:98 profile-id=1;sprop-sps=%s;sprop-pps=%s;sprop-vps=%s
a=control:streamid=%d
`
sdpStr += fmt.Sprintf(tmpl, base64.StdEncoding.EncodeToString(sps), base64.StdEncoding.EncodeToString(pps), base64.StdEncoding.EncodeToString(vps), streamid)
} else {
tmpl := `m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=%s,%s; profile-level-id=640016
a=control:streamid=%d
`
sdpStr += fmt.Sprintf(tmpl, base64.StdEncoding.EncodeToString(sps), base64.StdEncoding.EncodeToString(pps), streamid)
}
streamid++
}
if hasAudio {
if isAac {
tmpl := `m=audio 0 RTP/AVP 97
b=AS:128
a=rtpmap:97 MPEG4-GENERIC/%d/2
a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=%s
a=control:streamid=%d
`
sdpStr += fmt.Sprintf(tmpl, samplingFrequency, hex.EncodeToString(asc), streamid)
} else {
tmpl := `m=audio 0 RTP/AVP 0
a=rtpmap:0 PCMU/%d
a=control:streamid=%d
`
sdpStr += fmt.Sprintf(tmpl, samplingFrequency, streamid)
}
}
raw := []byte(strings.ReplaceAll(sdpStr, "\n", "\r\n"))
ctx, err = ParseSdp2LogicContext(raw)
return
}