diff --git a/pkg/aac/rtp.go b/pkg/aac/rtp.go new file mode 100644 index 00000000..f5cd9adc --- /dev/null +++ b/pkg/aac/rtp.go @@ -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) + } + } +} diff --git a/pkg/h264/avc.go b/pkg/h264/avc.go index 1e3d2925..069882b4 100644 --- a/pkg/h264/avc.go +++ b/pkg/h264/avc.go @@ -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 diff --git a/pkg/ivideon/client.go b/pkg/ivideon/client.go index 523c6f18..a43e8953 100644 --- a/pkg/ivideon/client.go +++ b/pkg/ivideon/client.go @@ -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 { diff --git a/pkg/mp4/consumer.go b/pkg/mp4/consumer.go index 53915908..d5882a45 100644 --- a/pkg/mp4/consumer.go +++ b/pkg/mp4/consumer.go @@ -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) } diff --git a/pkg/rtmp/client.go b/pkg/rtmp/client.go index f3ea836f..4efe3115 100644 --- a/pkg/rtmp/client.go +++ b/pkg/rtmp/client.go @@ -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{ diff --git a/pkg/rtsp/conn.go b/pkg/rtsp/conn.go index 97543a21..1b91ca21 100644 --- a/pkg/rtsp/conn.go +++ b/pkg/rtsp/conn.go @@ -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) diff --git a/pkg/streamer/media.go b/pkg/streamer/media.go index b4f07a04..5a6be1bb 100644 --- a/pkg/streamer/media.go +++ b/pkg/streamer/media.go @@ -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 diff --git a/pkg/webrtc/consumer.go b/pkg/webrtc/consumer.go index 8625f5ac..7dab2133 100644 --- a/pkg/webrtc/consumer.go +++ b/pkg/webrtc/consumer.go @@ -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)