Add support AAC for RTSP
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
package aac
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/pion/rtp"
|
||||
)
|
||||
|
||||
const RTPPacketVersionAAC = 0
|
||||
|
||||
func RTPDepay(track *streamer.Track) streamer.WrapperFunc {
|
||||
return func(push streamer.WriterFunc) streamer.WriterFunc {
|
||||
return func(packet *rtp.Packet) error {
|
||||
// support ONLY 2 bytes header size!
|
||||
// streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1408
|
||||
headersSize := binary.BigEndian.Uint16(packet.Payload) >> 3
|
||||
|
||||
//log.Printf("[RTP/AAC] units: %d, size: %4d, ts: %10d, %t", headersSize/2, len(packet.Payload), packet.Timestamp, packet.Marker)
|
||||
|
||||
clone := *packet
|
||||
clone.Version = RTPPacketVersionAAC
|
||||
clone.Payload = packet.Payload[2+headersSize:]
|
||||
return push(&clone)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RTPPay(mtu uint16) streamer.WrapperFunc {
|
||||
sequencer := rtp.NewRandomSequencer()
|
||||
|
||||
return func(push streamer.WriterFunc) streamer.WriterFunc {
|
||||
return func(packet *rtp.Packet) error {
|
||||
if packet.Version != RTPPacketVersionAAC {
|
||||
return push(packet)
|
||||
}
|
||||
|
||||
// support ONLY one unit in payload
|
||||
size := uint16(len(packet.Payload))
|
||||
// 2 bytes header size + 2 bytes first payload size
|
||||
payload := make([]byte, 2+2+size)
|
||||
payload[1] = 16 // header size in bits
|
||||
binary.BigEndian.PutUint16(payload[2:], size<<3)
|
||||
copy(payload[4:], packet.Payload)
|
||||
|
||||
clone := rtp.Packet{
|
||||
Header: rtp.Header{
|
||||
Version: 2,
|
||||
Marker: true,
|
||||
SequenceNumber: sequencer.NextSequenceNumber(),
|
||||
Timestamp: packet.Timestamp,
|
||||
},
|
||||
Payload: payload,
|
||||
}
|
||||
return push(&clone)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,6 @@ import (
|
||||
"github.com/pion/rtp"
|
||||
)
|
||||
|
||||
const PayloadTypeAVC = 255
|
||||
|
||||
func IsAVC(codec *streamer.Codec) bool {
|
||||
return codec.PayloadType == PayloadTypeAVC
|
||||
}
|
||||
|
||||
func EncodeAVC(nals ...[]byte) (avc []byte) {
|
||||
var i, n int
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/fmp4/fmp4io"
|
||||
@@ -162,9 +161,12 @@ func (c *Client) getTracks() error {
|
||||
continue
|
||||
}
|
||||
|
||||
codec := streamer.NewCodec(streamer.CodecH264)
|
||||
codec.FmtpLine = "profile-level-id=" + msg.CodecString[i+1:]
|
||||
codec.PayloadType = h264.PayloadTypeAVC
|
||||
codec := &streamer.Codec{
|
||||
Name: streamer.CodecH264,
|
||||
ClockRate: 90000,
|
||||
FmtpLine: "profile-level-id=" + msg.CodecString[i+1:],
|
||||
PayloadType: streamer.PayloadTypeMP4,
|
||||
}
|
||||
|
||||
i = bytes.Index(msg.Data, []byte("avcC")) - 4
|
||||
if i < 0 {
|
||||
|
||||
+8
-2
@@ -2,6 +2,7 @@ package mp4
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/AlexxIT/go2rtc/pkg/aac"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
@@ -65,7 +66,7 @@ func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *strea
|
||||
}
|
||||
|
||||
var wrapper streamer.WrapperFunc
|
||||
if h264.IsAVC(codec) {
|
||||
if codec.IsMP4() {
|
||||
wrapper = h264.RepairAVC(track)
|
||||
} else {
|
||||
wrapper = h264.RTPDepay(track)
|
||||
@@ -91,7 +92,7 @@ func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *strea
|
||||
return nil
|
||||
}
|
||||
|
||||
if !h264.IsAVC(codec) {
|
||||
if !codec.IsMP4() {
|
||||
wrapper := h265.RTPDepay(track)
|
||||
push = wrapper(push)
|
||||
}
|
||||
@@ -111,6 +112,11 @@ func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *strea
|
||||
return nil
|
||||
}
|
||||
|
||||
if !codec.IsMP4() {
|
||||
wrapper := aac.RTPDepay(track)
|
||||
push = wrapper(push)
|
||||
}
|
||||
|
||||
return track.Bind(push)
|
||||
}
|
||||
|
||||
|
||||
+4
-9
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/httpflv"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/deepch/vdk/av"
|
||||
@@ -74,7 +73,7 @@ func (c *Client) Dial() (err error) {
|
||||
Name: streamer.CodecH264,
|
||||
ClockRate: 90000,
|
||||
FmtpLine: fmtp,
|
||||
PayloadType: h264.PayloadTypeAVC,
|
||||
PayloadType: streamer.PayloadTypeMP4,
|
||||
}
|
||||
|
||||
media := &streamer.Media{
|
||||
@@ -93,17 +92,13 @@ func (c *Client) Dial() (err error) {
|
||||
// TODO: fix support
|
||||
cd := stream.(aacparser.CodecData)
|
||||
|
||||
// a=fmtp:97 streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1588
|
||||
fmtp := fmt.Sprintf(
|
||||
"config=%s",
|
||||
hex.EncodeToString(cd.ConfigBytes),
|
||||
)
|
||||
|
||||
codec := &streamer.Codec{
|
||||
Name: streamer.CodecAAC,
|
||||
ClockRate: uint32(cd.Config.SampleRate),
|
||||
Channels: uint16(cd.Config.ChannelConfig),
|
||||
FmtpLine: fmtp,
|
||||
// a=fmtp:97 streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1588
|
||||
FmtpLine: "streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=" + hex.EncodeToString(cd.ConfigBytes),
|
||||
PayloadType: streamer.PayloadTypeMP4,
|
||||
}
|
||||
|
||||
media := &streamer.Media{
|
||||
|
||||
+10
-3
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/AlexxIT/go2rtc/pkg/aac"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/AlexxIT/go2rtc/pkg/tcp"
|
||||
@@ -764,9 +765,15 @@ func (c *Conn) bindTrack(
|
||||
return nil
|
||||
}
|
||||
|
||||
if h264.IsAVC(track.Codec) {
|
||||
wrapper := h264.RTPPay(1500)
|
||||
push = wrapper(push)
|
||||
if track.Codec.IsMP4() {
|
||||
switch track.Codec.Name {
|
||||
case streamer.CodecH264:
|
||||
wrapper := h264.RTPPay(1500)
|
||||
push = wrapper(push)
|
||||
case streamer.CodecAAC:
|
||||
wrapper := aac.RTPPay(1500)
|
||||
push = wrapper(push)
|
||||
}
|
||||
}
|
||||
|
||||
return track.Bind(push)
|
||||
|
||||
@@ -35,6 +35,8 @@ const (
|
||||
CodecMPA = "MPA" // payload: 14
|
||||
)
|
||||
|
||||
const PayloadTypeMP4 byte = 255
|
||||
|
||||
func GetKind(name string) string {
|
||||
switch name {
|
||||
case CodecH264, CodecH265, CodecVP8, CodecVP9, CodecAV1, CodecJPEG:
|
||||
@@ -151,6 +153,10 @@ func (c *Codec) String() string {
|
||||
return s
|
||||
}
|
||||
|
||||
func (c *Codec) IsMP4() bool {
|
||||
return c.PayloadType == PayloadTypeMP4
|
||||
}
|
||||
|
||||
func (c *Codec) Clone() *Codec {
|
||||
clone := *c
|
||||
return &clone
|
||||
|
||||
@@ -57,7 +57,7 @@ func (c *Conn) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.
|
||||
wrapper := h264.RTPPay(1200)
|
||||
push = wrapper(push)
|
||||
|
||||
if h264.IsAVC(codec) {
|
||||
if codec.IsMP4() {
|
||||
wrapper = h264.RepairAVC(track)
|
||||
} else {
|
||||
wrapper = h264.RTPDepay(track)
|
||||
|
||||
Reference in New Issue
Block a user