forked from External/mediamtx
move aac utilities into gortsplib
This commit is contained in:
parent
3b0327233e
commit
68ab5c05f6
8 changed files with 9 additions and 245 deletions
1
Makefile
1
Makefile
|
|
@ -80,7 +80,6 @@ endif
|
||||||
|
|
||||||
test-internal:
|
test-internal:
|
||||||
go test -v $(TEST_INTERNAL_OPTS) \
|
go test -v $(TEST_INTERNAL_OPTS) \
|
||||||
./internal/aac \
|
|
||||||
./internal/conf \
|
./internal/conf \
|
||||||
./internal/confenv \
|
./internal/confenv \
|
||||||
./internal/confwatcher \
|
./internal/confwatcher \
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -5,7 +5,7 @@ go 1.16
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||||
github.com/aler9/gortsplib v0.0.0-20210923180721-13c6b69d302d
|
github.com/aler9/gortsplib v0.0.0-20210923181911-321fe06c6dab
|
||||||
github.com/asticode/go-astits v1.9.0
|
github.com/asticode/go-astits v1.9.0
|
||||||
github.com/fsnotify/fsnotify v1.4.9
|
github.com/fsnotify/fsnotify v1.4.9
|
||||||
github.com/gin-gonic/gin v1.7.2
|
github.com/gin-gonic/gin v1.7.2
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -2,8 +2,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/aler9/gortsplib v0.0.0-20210923180721-13c6b69d302d h1:aiMG2qO6tpLgXYeaWH/o/RT9en/tMNco/KZ9XN+QOt0=
|
github.com/aler9/gortsplib v0.0.0-20210923181911-321fe06c6dab h1:Dp3zUKCN/74UdxYBvHNKJubuYZeesDDCAB4gx6wZYh4=
|
||||||
github.com/aler9/gortsplib v0.0.0-20210923180721-13c6b69d302d/go.mod h1:DKI+t4Wj5YjkpxmiQhmG3qRG5VMOprDQvto62wMO68c=
|
github.com/aler9/gortsplib v0.0.0-20210923181911-321fe06c6dab/go.mod h1:DKI+t4Wj5YjkpxmiQhmG3qRG5VMOprDQvto62wMO68c=
|
||||||
github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927 h1:95mXJ5fUCYpBRdSOnLAQAdJHHKxxxJrVCiaqDi965YQ=
|
github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927 h1:95mXJ5fUCYpBRdSOnLAQAdJHHKxxxJrVCiaqDi965YQ=
|
||||||
github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927/go.mod h1:vzuE21rowz+lT1NGsWbreIvYulgBpCGnQyeTyFblUHc=
|
github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927/go.mod h1:vzuE21rowz+lT1NGsWbreIvYulgBpCGnQyeTyFblUHc=
|
||||||
github.com/asticode/go-astikit v0.20.0 h1:+7N+J4E4lWx2QOkRdOf6DafWJMv6O4RRfgClwQokrH8=
|
github.com/asticode/go-astikit v0.20.0 h1:+7N+J4E4lWx2QOkRdOf6DafWJMv6O4RRfgClwQokrH8=
|
||||||
|
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
package aac
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
mpegAudioTypeAACLLC = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
var sampleRates = []int{
|
|
||||||
96000,
|
|
||||||
88200,
|
|
||||||
64000,
|
|
||||||
48000,
|
|
||||||
44100,
|
|
||||||
32000,
|
|
||||||
24000,
|
|
||||||
22050,
|
|
||||||
16000,
|
|
||||||
12000,
|
|
||||||
11025,
|
|
||||||
8000,
|
|
||||||
7350,
|
|
||||||
}
|
|
||||||
|
|
||||||
var channelCounts = []int{
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4,
|
|
||||||
5,
|
|
||||||
6,
|
|
||||||
8,
|
|
||||||
}
|
|
||||||
|
|
||||||
// ADTSPacket is an ADTS packet
|
|
||||||
type ADTSPacket struct {
|
|
||||||
Type int
|
|
||||||
SampleRate int
|
|
||||||
ChannelCount int
|
|
||||||
AU []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeADTS decodes an ADTS stream into ADTS packets.
|
|
||||||
func DecodeADTS(byts []byte) ([]*ADTSPacket, error) {
|
|
||||||
// refs: https://wiki.multimedia.cx/index.php/ADTS
|
|
||||||
|
|
||||||
var ret []*ADTSPacket
|
|
||||||
|
|
||||||
for len(byts) > 0 {
|
|
||||||
syncWord := (uint16(byts[0]) << 4) | (uint16(byts[1]) >> 4)
|
|
||||||
if syncWord != 0xfff {
|
|
||||||
return nil, fmt.Errorf("invalid syncword")
|
|
||||||
}
|
|
||||||
|
|
||||||
protectionAbsent := byts[1] & 0x01
|
|
||||||
if protectionAbsent != 1 {
|
|
||||||
return nil, fmt.Errorf("CRC is not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt := &ADTSPacket{}
|
|
||||||
|
|
||||||
pkt.Type = int((byts[2] >> 6) + 1)
|
|
||||||
|
|
||||||
switch pkt.Type {
|
|
||||||
case mpegAudioTypeAACLLC:
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported object type: %d", pkt.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
sampleRateIndex := (byts[2] >> 2) & 0x0F
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case sampleRateIndex <= 12:
|
|
||||||
pkt.SampleRate = sampleRates[sampleRateIndex]
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid sample rate index: %d", sampleRateIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
channelConfig := ((byts[2] & 0x01) << 2) | ((byts[3] >> 6) & 0x03)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case channelConfig >= 1 && channelConfig <= 7:
|
|
||||||
pkt.ChannelCount = channelCounts[channelConfig-1]
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid channel configuration: %d", channelConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
frameLen := int(((uint16(byts[3])&0x03)<<11)|
|
|
||||||
(uint16(byts[4])<<3)|
|
|
||||||
((uint16(byts[5])>>5)&0x07)) - 7
|
|
||||||
|
|
||||||
// fullness := ((uint16(byts[5]) & 0x1F) << 6) | ((uint16(byts[6]) >> 2) & 0x3F)
|
|
||||||
|
|
||||||
frameCount := byts[6] & 0x03
|
|
||||||
if frameCount != 0 {
|
|
||||||
return nil, fmt.Errorf("multiple frame count not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(byts[7:]) < frameLen {
|
|
||||||
return nil, fmt.Errorf("invalid frame length")
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt.AU = byts[7 : 7+frameLen]
|
|
||||||
byts = byts[7+frameLen:]
|
|
||||||
|
|
||||||
ret = append(ret, pkt)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeADTS encodes ADTS packets into an ADTS stream.
|
|
||||||
func EncodeADTS(pkts []*ADTSPacket) ([]byte, error) {
|
|
||||||
var ret []byte
|
|
||||||
|
|
||||||
for _, pkt := range pkts {
|
|
||||||
sampleRateIndex := func() int {
|
|
||||||
for i, s := range sampleRates {
|
|
||||||
if s == pkt.SampleRate {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}()
|
|
||||||
|
|
||||||
if sampleRateIndex == -1 {
|
|
||||||
return nil, fmt.Errorf("invalid sample rate: %d", pkt.SampleRate)
|
|
||||||
}
|
|
||||||
|
|
||||||
channelConfig := func() int {
|
|
||||||
for i, co := range channelCounts {
|
|
||||||
if co == pkt.ChannelCount {
|
|
||||||
return i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}()
|
|
||||||
|
|
||||||
if channelConfig == -1 {
|
|
||||||
return nil, fmt.Errorf("invalid channel count: %d", pkt.ChannelCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
frameLen := len(pkt.AU) + 7
|
|
||||||
|
|
||||||
fullness := 0x07FF // like ffmpeg does
|
|
||||||
|
|
||||||
header := make([]byte, 7)
|
|
||||||
header[0] = 0xFF
|
|
||||||
header[1] = 0xF1
|
|
||||||
header[2] = uint8(((pkt.Type - 1) << 6) | (sampleRateIndex << 2) | ((channelConfig >> 2) & 0x01))
|
|
||||||
header[3] = uint8((channelConfig&0x03)<<6 | (frameLen>>11)&0x03)
|
|
||||||
header[4] = uint8((frameLen >> 3) & 0xFF)
|
|
||||||
header[5] = uint8((frameLen&0x07)<<5 | ((fullness >> 6) & 0x1F))
|
|
||||||
header[6] = uint8((fullness & 0x3F) << 2)
|
|
||||||
ret = append(ret, header...)
|
|
||||||
|
|
||||||
ret = append(ret, pkt.AU...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package aac
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
var casesADTS = []struct {
|
|
||||||
name string
|
|
||||||
byts []byte
|
|
||||||
pkts []*ADTSPacket
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"single",
|
|
||||||
[]byte{0xff, 0xf1, 0x4c, 0x80, 0x1, 0x3f, 0xfc, 0xaa, 0xbb},
|
|
||||||
[]*ADTSPacket{
|
|
||||||
{
|
|
||||||
Type: 2,
|
|
||||||
SampleRate: 48000,
|
|
||||||
ChannelCount: 2,
|
|
||||||
AU: []byte{0xaa, 0xbb},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"multiple",
|
|
||||||
[]byte{
|
|
||||||
0xff, 0xf1, 0x50, 0x40, 0x1, 0x3f, 0xfc, 0xaa,
|
|
||||||
0xbb, 0xff, 0xf1, 0x4c, 0x80, 0x1, 0x3f, 0xfc,
|
|
||||||
0xcc, 0xdd,
|
|
||||||
},
|
|
||||||
[]*ADTSPacket{
|
|
||||||
{
|
|
||||||
Type: 2,
|
|
||||||
SampleRate: 44100,
|
|
||||||
ChannelCount: 1,
|
|
||||||
AU: []byte{0xaa, 0xbb},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: 2,
|
|
||||||
SampleRate: 48000,
|
|
||||||
ChannelCount: 2,
|
|
||||||
AU: []byte{0xcc, 0xdd},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecodeADTS(t *testing.T) {
|
|
||||||
for _, ca := range casesADTS {
|
|
||||||
t.Run(ca.name, func(t *testing.T) {
|
|
||||||
pkts, err := DecodeADTS(ca.byts)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, ca.pkts, pkts)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeADTS(t *testing.T) {
|
|
||||||
for _, ca := range casesADTS {
|
|
||||||
t.Run(ca.name, func(t *testing.T) {
|
|
||||||
byts, err := EncodeADTS(ca.pkts)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, ca.byts, byts)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -13,13 +13,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
|
"github.com/aler9/gortsplib/pkg/aac"
|
||||||
"github.com/aler9/gortsplib/pkg/h264"
|
"github.com/aler9/gortsplib/pkg/h264"
|
||||||
"github.com/aler9/gortsplib/pkg/rtpaac"
|
"github.com/aler9/gortsplib/pkg/rtpaac"
|
||||||
"github.com/aler9/gortsplib/pkg/rtph264"
|
"github.com/aler9/gortsplib/pkg/rtph264"
|
||||||
"github.com/asticode/go-astits"
|
"github.com/asticode/go-astits"
|
||||||
"github.com/grafov/m3u8"
|
"github.com/grafov/m3u8"
|
||||||
|
|
||||||
"github.com/aler9/rtsp-simple-server/internal/aac"
|
|
||||||
"github.com/aler9/rtsp-simple-server/internal/logger"
|
"github.com/aler9/rtsp-simple-server/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
|
"github.com/aler9/gortsplib/pkg/aac"
|
||||||
"github.com/aler9/gortsplib/pkg/h264"
|
"github.com/aler9/gortsplib/pkg/h264"
|
||||||
"github.com/asticode/go-astits"
|
"github.com/asticode/go-astits"
|
||||||
|
|
||||||
"github.com/aler9/rtsp-simple-server/internal/aac"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/aler9/gortsplib/pkg/rtpaac"
|
"github.com/aler9/gortsplib/pkg/aac"
|
||||||
"github.com/notedit/rtmp/av"
|
"github.com/notedit/rtmp/av"
|
||||||
nh264 "github.com/notedit/rtmp/codec/h264"
|
nh264 "github.com/notedit/rtmp/codec/h264"
|
||||||
"github.com/notedit/rtmp/format/flv/flvio"
|
"github.com/notedit/rtmp/format/flv/flvio"
|
||||||
|
|
@ -146,7 +146,7 @@ func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) {
|
||||||
return nil, nil, fmt.Errorf("audio track setupped twice")
|
return nil, nil, fmt.Errorf("audio track setupped twice")
|
||||||
}
|
}
|
||||||
|
|
||||||
var mpegConf rtpaac.MPEG4AudioConfig
|
var mpegConf aac.MPEG4AudioConfig
|
||||||
err := mpegConf.Decode(pkt.Data)
|
err := mpegConf.Decode(pkt.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
@ -241,8 +241,8 @@ func (c *Conn) WriteMetadata(videoTrack *gortsplib.Track, audioTrack *gortsplib.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
enc, err := rtpaac.MPEG4AudioConfig{
|
enc, err := aac.MPEG4AudioConfig{
|
||||||
Type: rtpaac.MPEG4AudioType(conf.Type),
|
Type: aac.MPEG4AudioType(conf.Type),
|
||||||
SampleRate: conf.SampleRate,
|
SampleRate: conf.SampleRate,
|
||||||
ChannelCount: conf.ChannelCount,
|
ChannelCount: conf.ChannelCount,
|
||||||
AOTSpecificConfig: conf.AOTSpecificConfig,
|
AOTSpecificConfig: conf.AOTSpecificConfig,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue