Skip to content

Commit

Permalink
rtmp: support publishing G711 and LPCM tracks (#2857) (#2884)
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 committed Jan 7, 2024
1 parent bc7804c commit 27975d8
Show file tree
Hide file tree
Showing 36 changed files with 525 additions and 127 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ Live streams can be published to the server with:
|--------|--------|------------|------------|
|[SRT clients](#srt-clients)||H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3|
|[SRT cameras and servers](#srt-cameras-and-servers)||H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3|
|[WebRTC clients](#webrtc-clients)|Browser-based, WHIP|AV1, VP9, VP8, H264|Opus, G722, G711|
|[WebRTC servers](#webrtc-servers)|WHEP|AV1, VP9, VP8, H264|Opus, G722, G711|
|[RTSP clients](#rtsp-clients)|UDP, TCP, RTSPS|AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG and any RTP-compatible codec|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711, LPCM and any RTP-compatible codec|
|[RTSP cameras and servers](#rtsp-cameras-and-servers)|UDP, UDP-Multicast, TCP, RTSPS|AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG and any RTP-compatible codec|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711, LPCM and any RTP-compatible codec|
|[RTMP clients](#rtmp-clients)|RTMP, RTMPS, Enhanced RTMP|AV1, VP9, H265, H264|MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3)|
|[WebRTC clients](#webrtc-clients)|Browser-based, WHIP|AV1, VP9, VP8, H264|Opus, G722, G711 (PCMA, PCMU)|
|[WebRTC servers](#webrtc-servers)|WHEP|AV1, VP9, VP8, H264|Opus, G722, G711 (PCMA, PCMU)|
|[RTSP clients](#rtsp-clients)|UDP, TCP, RTSPS|AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG and any RTP-compatible codec|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM and any RTP-compatible codec|
|[RTSP cameras and servers](#rtsp-cameras-and-servers)|UDP, UDP-Multicast, TCP, RTSPS|AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG and any RTP-compatible codec|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM and any RTP-compatible codec|
|[RTMP clients](#rtmp-clients)|RTMP, RTMPS, Enhanced RTMP|AV1, VP9, H265, H264|MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), G711 (PCMA, PCMU), LPCM|
|[RTMP cameras and servers](#rtmp-cameras-and-servers)|RTMP, RTMPS, Enhanced RTMP|H264|MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3)|
|[HLS cameras and servers](#hls-cameras-and-servers)|Low-Latency HLS, MP4-based HLS, legacy HLS|AV1, VP9, H265, H264|Opus, MPEG-4 Audio (AAC)|
|[UDP/MPEG-TS](#udpmpeg-ts)|Unicast, broadcast, multicast|H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3|
Expand All @@ -37,16 +37,16 @@ And can be read from the server with:
|protocol|variants|video codecs|audio codecs|
|--------|--------|------------|------------|
|[SRT](#srt)||H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3|
|[WebRTC](#webrtc)|Browser-based, WHEP|AV1, VP9, VP8, H264|Opus, G722, G711|
|[RTSP](#rtsp)|UDP, UDP-Multicast, TCP, RTSPS|AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG and any RTP-compatible codec|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711, LPCM and any RTP-compatible codec|
|[WebRTC](#webrtc)|Browser-based, WHEP|AV1, VP9, VP8, H264|Opus, G722, G711 (PCMA, PCMU)|
|[RTSP](#rtsp)|UDP, UDP-Multicast, TCP, RTSPS|AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG and any RTP-compatible codec|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM and any RTP-compatible codec|
|[RTMP](#rtmp)|RTMP, RTMPS, Enhanced RTMP|H264|MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3)|
|[HLS](#hls)|Low-Latency HLS, MP4-based HLS, legacy HLS|AV1, VP9, H265, H264|Opus, MPEG-4 Audio (AAC)|

And can be recorded with:

|format|video codecs|audio codecs|
|------|------------|------------|
|[fMP4](#record-streams-to-disk)|AV1, VP9, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711, LPCM|
|[fMP4](#record-streams-to-disk)|AV1, VP9, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM|
|[MPEG-TS](#record-streams-to-disk)|H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3|

**Features**
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.2
github.com/bluenviron/gortsplib/v4 v4.6.3-0.20240107120136-f9eb8e573bbe
github.com/bluenviron/mediacommon v1.6.1-0.20231228213201-7bb211dba7e1
github.com/datarhei/gosrt v0.5.5
github.com/fsnotify/fsnotify v1.7.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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.2 h1:CGIsxpnUFvSlIxnSFS0oFSSfwsHMmBCmYcrGAtIcwXc=
github.com/bluenviron/gortsplib/v4 v4.6.2/go.mod h1:dN1YjyPNMfy/NwC17Ga6MiIMiUoQfg5GL7LGsVHa0Jo=
github.com/bluenviron/gortsplib/v4 v4.6.3-0.20240107120136-f9eb8e573bbe h1:eVx4BU4mF26UK/SQlsnIkeCIraQR8AcJf42ymYR3pQE=
github.com/bluenviron/gortsplib/v4 v4.6.3-0.20240107120136-f9eb8e573bbe/go.mod h1:UqdkRR5YvKHP/wHEQQySJFKJm6tIZcftdP7cNszIZ1g=
github.com/bluenviron/mediacommon v1.6.1-0.20231228213201-7bb211dba7e1 h1:f8XDAHvgPbT+n5qf73REdUo9kLmGpP4HNgphKI/8fGE=
github.com/bluenviron/mediacommon v1.6.1-0.20231228213201-7bb211dba7e1/go.mod h1:Ij/kE1LEucSjryNBVTyPL/gBI0d6/Css3f5PyrM957w=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
Expand Down
5 changes: 2 additions & 3 deletions internal/formatprocessor/ac3.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,13 @@ func (t *formatProcessorAC3) ProcessUnit(uu unit.Unit) error { //nolint:dupl
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts

return nil
}

Expand Down
5 changes: 2 additions & 3 deletions internal/formatprocessor/av1.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,13 @@ func (t *formatProcessorAV1) ProcessUnit(uu unit.Unit) error { //nolint:dupl
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts

return nil
}

Expand Down
1 change: 0 additions & 1 deletion internal/formatprocessor/av1_test.go

This file was deleted.

6 changes: 3 additions & 3 deletions internal/formatprocessor/g711.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func newG711(
func (t *formatProcessorG711) createEncoder() error {
t.encoder = &rtpsimpleaudio.Encoder{
PayloadMaxSize: t.udpMaxPayloadSize - 12,
PayloadType: t.format.PayloadType(),
}
return t.encoder.Init()
}
Expand All @@ -52,11 +53,10 @@ func (t *formatProcessorG711) ProcessUnit(uu unit.Unit) error { //nolint:dupl
if err != nil {
return err
}
u.RTPPackets = []*rtp.Packet{pkt}

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
pkt.Timestamp += ts

u.RTPPackets = []*rtp.Packet{pkt}
u.RTPPackets[0].Timestamp += ts

return nil
}
Expand Down
62 changes: 62 additions & 0 deletions internal/formatprocessor/g711_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package formatprocessor

import (
"testing"

"github.com/bluenviron/gortsplib/v4/pkg/format"
"github.com/bluenviron/mediamtx/internal/unit"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
)

func TestG611Encode(t *testing.T) {
t.Run("alaw", func(t *testing.T) {
forma := &format.G711{
MULaw: false,
}

p, err := New(1472, forma, true)
require.NoError(t, err)

unit := &unit.G711{
Samples: []byte{1, 2, 3, 4},
}

err = p.ProcessUnit(unit)
require.NoError(t, err)
require.Equal(t, []*rtp.Packet{{
Header: rtp.Header{
Version: 2,
PayloadType: 8,
SequenceNumber: unit.RTPPackets[0].SequenceNumber,
SSRC: unit.RTPPackets[0].SSRC,
},
Payload: []byte{1, 2, 3, 4},
}}, unit.RTPPackets)
})

t.Run("mulaw", func(t *testing.T) {
forma := &format.G711{
MULaw: true,
}

p, err := New(1472, forma, true)
require.NoError(t, err)

unit := &unit.G711{
Samples: []byte{1, 2, 3, 4},
}

err = p.ProcessUnit(unit)
require.NoError(t, err)
require.Equal(t, []*rtp.Packet{{
Header: rtp.Header{
Version: 2,
PayloadType: 0,
SequenceNumber: unit.RTPPackets[0].SequenceNumber,
SSRC: unit.RTPPackets[0].SSRC,
},
Payload: []byte{1, 2, 3, 4},
}}, unit.RTPPackets)
})
}
10 changes: 4 additions & 6 deletions internal/formatprocessor/h264.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,12 @@ func (t *formatProcessorH264) ProcessUnit(uu unit.Unit) error {
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts
}

return nil
Expand Down Expand Up @@ -306,12 +305,11 @@ func (t *formatProcessorH264) ProcessRTPPacket( //nolint:dupl
if err != nil {
return nil, err
}
u.RTPPackets = pkts

for _, newPKT := range pkts {
for _, newPKT := range u.RTPPackets {
newPKT.Timestamp = pkt.Timestamp
}

u.RTPPackets = pkts
}

return u, nil
Expand Down
10 changes: 4 additions & 6 deletions internal/formatprocessor/h265.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,12 @@ func (t *formatProcessorH265) ProcessUnit(uu unit.Unit) error { //nolint:dupl
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts
}

return nil
Expand Down Expand Up @@ -325,12 +324,11 @@ func (t *formatProcessorH265) ProcessRTPPacket( //nolint:dupl
if err != nil {
return nil, err
}
u.RTPPackets = pkts

for _, newPKT := range pkts {
for _, newPKT := range u.RTPPackets {
newPKT.Timestamp = pkt.Timestamp
}

u.RTPPackets = pkts
}

return u, nil
Expand Down
8 changes: 5 additions & 3 deletions internal/formatprocessor/lpcm.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func newLPCM(
func (t *formatProcessorLPCM) createEncoder() error {
t.encoder = &rtplpcm.Encoder{
PayloadMaxSize: t.udpMaxPayloadSize - 12,
PayloadType: t.format.PayloadTyp,
BitDepth: t.format.BitDepth,
ChannelCount: t.format.ChannelCount,
}
return t.encoder.Init()
}
Expand All @@ -52,14 +55,13 @@ func (t *formatProcessorLPCM) ProcessUnit(uu unit.Unit) error { //nolint:dupl
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts

return nil
}

Expand Down
37 changes: 37 additions & 0 deletions internal/formatprocessor/lpcm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package formatprocessor

import (
"testing"

"github.com/bluenviron/gortsplib/v4/pkg/format"
"github.com/bluenviron/mediamtx/internal/unit"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
)

func TestLPCMEncode(t *testing.T) {
forma := &format.LPCM{
PayloadTyp: 96,
BitDepth: 16,
ChannelCount: 2,
}

p, err := New(1472, forma, true)
require.NoError(t, err)

unit := &unit.LPCM{
Samples: []byte{1, 2, 3, 4},
}

err = p.ProcessUnit(unit)
require.NoError(t, err)
require.Equal(t, []*rtp.Packet{{
Header: rtp.Header{
Version: 2,
PayloadType: 96,
SequenceNumber: unit.RTPPackets[0].SequenceNumber,
SSRC: unit.RTPPackets[0].SSRC,
},
Payload: []byte{1, 2, 3, 4},
}}, unit.RTPPackets)
}
5 changes: 2 additions & 3 deletions internal/formatprocessor/mjpeg.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,13 @@ func (t *formatProcessorMJPEG) ProcessUnit(uu unit.Unit) error { //nolint:dupl
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts

return nil
}

Expand Down
5 changes: 2 additions & 3 deletions internal/formatprocessor/mpeg1_audio.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,13 @@ func (t *formatProcessorMPEG1Audio) ProcessUnit(uu unit.Unit) error { //nolint:d
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts

return nil
}

Expand Down
5 changes: 2 additions & 3 deletions internal/formatprocessor/mpeg1_video.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,13 @@ func (t *formatProcessorMPEG1Video) ProcessUnit(uu unit.Unit) error { //nolint:d
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts

return nil
}

Expand Down
5 changes: 2 additions & 3 deletions internal/formatprocessor/mpeg4_audio.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,13 @@ func (t *formatProcessorMPEG4Audio) ProcessUnit(uu unit.Unit) error { //nolint:d
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/formatprocessor/mpeg4_video.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (t *formatProcessorMPEG4Video) ProcessUnit(uu unit.Unit) error { //nolint:d
}

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

Expand Down
5 changes: 2 additions & 3 deletions internal/formatprocessor/vp8.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,13 @@ func (t *formatProcessorVP8) ProcessUnit(uu unit.Unit) error { //nolint:dupl
if err != nil {
return err
}
u.RTPPackets = pkts

ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ts
}

u.RTPPackets = pkts

return nil
}

Expand Down
Loading

0 comments on commit 27975d8

Please sign in to comment.