mirror of
https://github.com/bluenviron/mediamtx
synced 2025-02-16 19:46:59 +00:00
support G711 tracks with multiple channels and custom sample rates (#2891)
This commit is contained in:
parent
a6c7d287a7
commit
20bb9b90cd
2
go.mod
2
go.mod
@ -8,7 +8,7 @@ require (
|
||||
github.com/alecthomas/kong v0.8.1
|
||||
github.com/aler9/writerseeker v1.1.0
|
||||
github.com/bluenviron/gohlslib v1.2.0
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.3
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.4-0.20240108201647-63a81d0896f5
|
||||
github.com/bluenviron/mediacommon v1.7.1
|
||||
github.com/datarhei/gosrt v0.5.5
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
|
4
go.sum
4
go.sum
@ -22,8 +22,8 @@ github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYh
|
||||
github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI=
|
||||
github.com/bluenviron/gohlslib v1.2.0 h1:Hrx2/n/AcmKKIV+MjZLKs5kmW+O7xCdUSPJQoS39JKw=
|
||||
github.com/bluenviron/gohlslib v1.2.0/go.mod h1:kG/Sjebsxnf5asMGaGcQ0aSvtFGNChJPgctds2wDHOI=
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.3 h1:/FgUhxe/DGFkmwHNGNnw7NhcuZeSwnxCzYHDbyAtMjo=
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.3/go.mod h1:UqdkRR5YvKHP/wHEQQySJFKJm6tIZcftdP7cNszIZ1g=
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.4-0.20240108201647-63a81d0896f5 h1:DU63YvVivfcIq7jcA1KCwi9YO+jEVglYNJCIrOLj8QE=
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.4-0.20240108201647-63a81d0896f5/go.mod h1:UqdkRR5YvKHP/wHEQQySJFKJm6tIZcftdP7cNszIZ1g=
|
||||
github.com/bluenviron/mediacommon v1.7.1 h1:7Lm2b8M9gUk3Ben1w+OPwadAeYseIBscwgdiL+aLtfw=
|
||||
github.com/bluenviron/mediacommon v1.7.1/go.mod h1:Ij/kE1LEucSjryNBVTyPL/gBI0d6/Css3f5PyrM957w=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format/rtpsimpleaudio"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format/rtplpcm"
|
||||
"github.com/pion/rtp"
|
||||
|
||||
"github.com/bluenviron/mediamtx/internal/unit"
|
||||
@ -14,8 +14,8 @@ import (
|
||||
type formatProcessorG711 struct {
|
||||
udpMaxPayloadSize int
|
||||
format *format.G711
|
||||
encoder *rtpsimpleaudio.Encoder
|
||||
decoder *rtpsimpleaudio.Decoder
|
||||
encoder *rtplpcm.Encoder
|
||||
decoder *rtplpcm.Decoder
|
||||
}
|
||||
|
||||
func newG711(
|
||||
@ -39,9 +39,11 @@ func newG711(
|
||||
}
|
||||
|
||||
func (t *formatProcessorG711) createEncoder() error {
|
||||
t.encoder = &rtpsimpleaudio.Encoder{
|
||||
t.encoder = &rtplpcm.Encoder{
|
||||
PayloadMaxSize: t.udpMaxPayloadSize - 12,
|
||||
PayloadType: t.format.PayloadType(),
|
||||
BitDepth: 8,
|
||||
ChannelCount: t.format.ChannelCount,
|
||||
}
|
||||
return t.encoder.Init()
|
||||
}
|
||||
@ -49,14 +51,16 @@ func (t *formatProcessorG711) createEncoder() error {
|
||||
func (t *formatProcessorG711) ProcessUnit(uu unit.Unit) error { //nolint:dupl
|
||||
u := uu.(*unit.G711)
|
||||
|
||||
pkt, err := t.encoder.Encode(u.Samples)
|
||||
pkts, err := t.encoder.Encode(u.Samples)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.RTPPackets = []*rtp.Packet{pkt}
|
||||
u.RTPPackets = pkts
|
||||
|
||||
ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
|
||||
u.RTPPackets[0].Timestamp += ts
|
||||
for _, pkt := range u.RTPPackets {
|
||||
pkt.Timestamp += ts
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -12,7 +12,10 @@ import (
|
||||
func TestG611Encode(t *testing.T) {
|
||||
t.Run("alaw", func(t *testing.T) {
|
||||
forma := &format.G711{
|
||||
MULaw: false,
|
||||
PayloadTyp: 8,
|
||||
MULaw: false,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
}
|
||||
|
||||
p, err := New(1472, forma, true)
|
||||
@ -37,7 +40,10 @@ func TestG611Encode(t *testing.T) {
|
||||
|
||||
t.Run("mulaw", func(t *testing.T) {
|
||||
forma := &format.G711{
|
||||
MULaw: true,
|
||||
PayloadTyp: 0,
|
||||
MULaw: true,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
}
|
||||
|
||||
p, err := New(1472, forma, true)
|
||||
|
@ -95,17 +95,9 @@ func hasAudio(md flvio.AMFMap, audioTrack *format.Format) (bool, error) {
|
||||
return true, nil
|
||||
|
||||
case message.CodecPCMA:
|
||||
v, ok := md.GetV("stereo")
|
||||
if ok && v == true {
|
||||
return false, fmt.Errorf("stereo PCMA is not supported")
|
||||
}
|
||||
return true, nil
|
||||
|
||||
case message.CodecPCMU:
|
||||
v, ok := md.GetV("stereo")
|
||||
if ok && v == true {
|
||||
return false, fmt.Errorf("stereo PCMU is not supported")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@ -336,19 +328,31 @@ func tracksFromMetadata(conn *Conn, payload []interface{}) (format.Format, forma
|
||||
}
|
||||
|
||||
case msg.Codec == message.CodecPCMA:
|
||||
if msg.Channels == message.ChannelsStereo {
|
||||
return nil, nil, fmt.Errorf("stereo PCMA is not supported")
|
||||
audioTrack = &format.G711{
|
||||
PayloadTyp: 8,
|
||||
MULaw: false,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: func() int {
|
||||
if msg.Channels == message.ChannelsStereo {
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}(),
|
||||
}
|
||||
|
||||
audioTrack = &format.G711{MULaw: false}
|
||||
|
||||
case msg.Codec == message.CodecPCMU:
|
||||
if msg.Channels == message.ChannelsStereo {
|
||||
return nil, nil, fmt.Errorf("stereo PCMU is not supported")
|
||||
audioTrack = &format.G711{
|
||||
PayloadTyp: 0,
|
||||
MULaw: true,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: func() int {
|
||||
if msg.Channels == message.ChannelsStereo {
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}(),
|
||||
}
|
||||
|
||||
audioTrack = &format.G711{MULaw: true}
|
||||
|
||||
case msg.Codec == message.CodecLPCM:
|
||||
audioTrack = &format.LPCM{
|
||||
PayloadTyp: 96,
|
||||
|
@ -786,7 +786,12 @@ func TestReadTracks(t *testing.T) {
|
||||
{
|
||||
"pcma",
|
||||
nil,
|
||||
&format.G711{},
|
||||
&format.G711{
|
||||
PayloadTyp: 8,
|
||||
MULaw: false,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
},
|
||||
[]message.Message{
|
||||
&message.DataAMF0{
|
||||
ChunkStreamID: 4,
|
||||
@ -817,7 +822,10 @@ func TestReadTracks(t *testing.T) {
|
||||
"pcmu",
|
||||
nil,
|
||||
&format.G711{
|
||||
MULaw: true,
|
||||
PayloadTyp: 0,
|
||||
MULaw: true,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
},
|
||||
[]message.Message{
|
||||
&message.DataAMF0{
|
||||
|
@ -80,12 +80,18 @@ func newIncomingTrack(
|
||||
|
||||
case strings.ToLower(webrtc.MimeTypePCMU):
|
||||
t.format = &format.G711{
|
||||
MULaw: true,
|
||||
PayloadTyp: 0,
|
||||
MULaw: true,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
}
|
||||
|
||||
case strings.ToLower(webrtc.MimeTypePCMA):
|
||||
t.format = &format.G711{
|
||||
MULaw: false,
|
||||
PayloadTyp: 8,
|
||||
MULaw: false,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -56,13 +56,19 @@ func TestAgent(t *testing.T) {
|
||||
{
|
||||
Type: description.MediaTypeAudio,
|
||||
Formats: []rtspformat.Format{&rtspformat.G711{
|
||||
MULaw: false,
|
||||
PayloadTyp: 8,
|
||||
MULaw: false,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
}},
|
||||
},
|
||||
{
|
||||
Type: description.MediaTypeAudio,
|
||||
Formats: []rtspformat.Format{&rtspformat.G711{
|
||||
MULaw: true,
|
||||
PayloadTyp: 0,
|
||||
MULaw: true,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
}},
|
||||
},
|
||||
}}
|
||||
|
@ -775,8 +775,8 @@ func (f *formatFMP4) initialize() {
|
||||
codec := &fmp4.CodecLPCM{
|
||||
LittleEndian: false,
|
||||
BitDepth: 16,
|
||||
SampleRate: 8000,
|
||||
ChannelCount: 1,
|
||||
SampleRate: forma.SampleRate,
|
||||
ChannelCount: forma.ChannelCount,
|
||||
}
|
||||
track := addTrack(codec)
|
||||
|
||||
|
@ -244,6 +244,14 @@ func findAudioTrack(
|
||||
|
||||
if g711Format != nil {
|
||||
return g711Format, func(track *webrtc.OutgoingTrack) error {
|
||||
if g711Format.SampleRate != 8000 {
|
||||
return fmt.Errorf("unsupported G711 sample rate")
|
||||
}
|
||||
|
||||
if g711Format.ChannelCount != 1 {
|
||||
return fmt.Errorf("unsupported G711 channel count")
|
||||
}
|
||||
|
||||
stream.AddReader(writer, media, g711Format, func(u unit.Unit) error {
|
||||
for _, pkt := range u.GetRTPPackets() {
|
||||
track.WriteRTP(pkt) //nolint:errcheck
|
||||
|
Loading…
Reference in New Issue
Block a user