From f9eb8e573bbe3a05a7b8a5da4f498637cc858183 Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Sun, 7 Jan 2024 13:01:36 +0100 Subject: [PATCH] support detecting LPCM formats with payload types 10 and 11 (#496) --- README.md | 8 +-- pkg/format/ac3.go | 2 +- pkg/format/av1.go | 2 +- pkg/format/format.go | 106 ++++++++++++++++++++++---------------- pkg/format/format_test.go | 30 +++++++++++ pkg/format/g711.go | 2 +- pkg/format/g722.go | 2 +- pkg/format/g726.go | 2 +- pkg/format/h264.go | 2 +- pkg/format/h265.go | 2 +- pkg/format/lpcm.go | 17 +++++- pkg/format/mjpeg.go | 2 +- pkg/format/mpeg1_audio.go | 2 +- pkg/format/mpeg1_video.go | 2 +- pkg/format/mpeg4_audio.go | 4 +- pkg/format/mpeg4_video.go | 2 +- pkg/format/mpegts.go | 2 +- pkg/format/opus.go | 2 +- pkg/format/speex.go | 2 +- pkg/format/vorbis.go | 2 +- pkg/format/vp8.go | 2 +- pkg/format/vp9.go | 2 +- 22 files changed, 131 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index e448b861..69649bba 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ In RTSP, media streams are routed between server and clients by using RTP packet ### Video -|format|documentation|encoder and decoder available| +|codec|documentation|encoder and decoder available| |------|-------------|-----------------------------| |AV1|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#AV1)|:heavy_check_mark:| |VP9|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#VP9)|:heavy_check_mark:| @@ -116,7 +116,7 @@ In RTSP, media streams are routed between server and clients by using RTP packet ### Audio -|format|documentation|encoder and decoder available| +|codec|documentation|encoder and decoder available| |------|-------------|-----------------------------| |Opus|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#Opus)|:heavy_check_mark:| |Vorbis|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#Vorbis)|| @@ -131,7 +131,7 @@ In RTSP, media streams are routed between server and clients by using RTP packet ### Other -|format|documentation|encoder and decoder available| +|codec|documentation|encoder and decoder available| |------|-------------|-----------------------------| |MPEG-TS|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#MPEGTS)|| @@ -155,7 +155,7 @@ In RTSP, media streams are routed between server and clients by using RTP packet |[RFC4184, RTP Payload Format for AC-3 Audio](https://datatracker.ietf.org/doc/html/rfc4184)|AC-3 payload format| |[RFC6416, RTP Payload Format for MPEG-4 Audio/Visual Streams](https://datatracker.ietf.org/doc/html/rfc6416)|MPEG-4 audio payload format| |[RFC5574, RTP Payload Format for the Speex Codec](https://datatracker.ietf.org/doc/html/rfc5574)|Speex payload format| -|[RFC3551, RTP Profile for Audio and Video Conferences with Minimal Control](https://datatracker.ietf.org/doc/html/rfc3551)|G726, G722, G711 payload formats| +|[RFC3551, RTP Profile for Audio and Video Conferences with Minimal Control](https://datatracker.ietf.org/doc/html/rfc3551)|G726, G722, G711, LPCM payload formats| |[RFC3190, RTP Payload Format for 12-bit DAT Audio and 20- and 24-bit Linear Sampled Audio](https://datatracker.ietf.org/doc/html/rfc3190)|LPCM payload format| |[Codec specifications](https://github.com/bluenviron/mediacommon#specifications)|codecs| |[Golang project layout](https://github.com/golang-standards/project-layout)|project layout| diff --git a/pkg/format/ac3.go b/pkg/format/ac3.go index 99f42f3d..3253202a 100644 --- a/pkg/format/ac3.go +++ b/pkg/format/ac3.go @@ -9,7 +9,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpac3" ) -// AC3 is a RTP format for the AC-3 codec. +// AC3 is the RTP format for the AC-3 codec. // Specification: https://datatracker.ietf.org/doc/html/rfc4184 type AC3 struct { PayloadTyp uint8 diff --git a/pkg/format/av1.go b/pkg/format/av1.go index 7f1083c7..7b311b1e 100644 --- a/pkg/format/av1.go +++ b/pkg/format/av1.go @@ -9,7 +9,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpav1" ) -// AV1 is a RTP format for the AV1 codec. +// AV1 is the RTP format for the AV1 codec. // Specification: https://aomediacodec.github.io/av1-rtp-spec/ type AV1 struct { PayloadTyp uint8 diff --git a/pkg/format/format.go b/pkg/format/format.go index b0c67d90..0938ceb5 100644 --- a/pkg/format/format.go +++ b/pkg/format/format.go @@ -55,26 +55,12 @@ func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[stri format := func() Format { switch { + /* + * static payload types + **/ + // video - case codec == "av1" && clock == "90000": - return &AV1{} - - case codec == "vp9" && clock == "90000": - return &VP9{} - - case codec == "vp8" && clock == "90000": - return &VP8{} - - case codec == "h265" && clock == "90000": - return &H265{} - - case codec == "h264" && clock == "90000": - return &H264{} - - case codec == "mp4v-es" && clock == "90000": - return &MPEG4Video{} - case payloadType == 32: return &MPEG1Video{} @@ -86,42 +72,74 @@ func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[stri // audio - case codec == "opus": - return &Opus{} - - case codec == "vorbis": - return &Vorbis{} - - case codec == "mpeg4-generic", codec == "mp4a-latm": - return &MPEG4Audio{} - case payloadType == 14: return &MPEG1Audio{} - case codec == "ac3": - return &AC3{} - - case codec == "speex": - return &Speex{} - - case (codec == "g726-16" || - codec == "g726-24" || - codec == "g726-32" || - codec == "g726-40" || - codec == "aal2-g726-16" || - codec == "aal2-g726-24" || - codec == "aal2-g726-32" || - codec == "aal2-g726-40") && clock == "8000": - return &G726{} - case payloadType == 9: return &G722{} case payloadType == 0, payloadType == 8: return &G711{} - case codec == "l8", codec == "l16", codec == "l24": + case payloadType == 10, payloadType == 11: return &LPCM{} + + /* + * dynamic payload types + **/ + + case payloadType >= 96 && payloadType <= 127: + switch { + // video + + case codec == "av1" && clock == "90000": + return &AV1{} + + case codec == "vp9" && clock == "90000": + return &VP9{} + + case codec == "vp8" && clock == "90000": + return &VP8{} + + case codec == "h265" && clock == "90000": + return &H265{} + + case codec == "h264" && clock == "90000": + return &H264{} + + case codec == "mp4v-es" && clock == "90000": + return &MPEG4Video{} + + // audio + + case codec == "opus": + return &Opus{} + + case codec == "vorbis": + return &Vorbis{} + + case codec == "mpeg4-generic", codec == "mp4a-latm": + return &MPEG4Audio{} + + case codec == "ac3": + return &AC3{} + + case codec == "speex": + return &Speex{} + + case (codec == "g726-16" || + codec == "g726-24" || + codec == "g726-32" || + codec == "g726-40" || + codec == "aal2-g726-16" || + codec == "aal2-g726-24" || + codec == "aal2-g726-32" || + codec == "aal2-g726-40") && clock == "8000": + return &G726{} + + case codec == "l8", codec == "l16", codec == "l24": + return &LPCM{} + } } return &Generic{} diff --git a/pkg/format/format_test.go b/pkg/format/format_test.go index d0d114ec..aeafb6ab 100644 --- a/pkg/format/format_test.go +++ b/pkg/format/format_test.go @@ -154,6 +154,36 @@ var casesFormat = []struct { "L16/96000/2", nil, }, + { + "audio lpcm 16 rfc3551 stereo", + "audio", + 10, + "", + nil, + &LPCM{ + PayloadTyp: 10, + BitDepth: 16, + SampleRate: 44100, + ChannelCount: 2, + }, + "L16/44100/2", + nil, + }, + { + "audio lpcm 16 rfc3551 mono", + "audio", + 11, + "", + nil, + &LPCM{ + PayloadTyp: 11, + BitDepth: 16, + SampleRate: 44100, + ChannelCount: 1, + }, + "L16/44100/1", + nil, + }, { "audio lpcm 16 with no explicit channel", "audio", diff --git a/pkg/format/g711.go b/pkg/format/g711.go index 23abf4c0..5ba858c6 100644 --- a/pkg/format/g711.go +++ b/pkg/format/g711.go @@ -6,7 +6,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpsimpleaudio" ) -// G711 is a RTP format for the G711 codec, encoded with mu-law or A-law. +// G711 is the RTP format for the G711 codec, encoded with mu-law or A-law. // Specification: https://datatracker.ietf.org/doc/html/rfc3551 type G711 struct { // whether to use mu-law. Otherwise, A-law is used. diff --git a/pkg/format/g722.go b/pkg/format/g722.go index 53f17cbc..9acfcae7 100644 --- a/pkg/format/g722.go +++ b/pkg/format/g722.go @@ -6,7 +6,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpsimpleaudio" ) -// G722 is a RTP format for the G722 codec. +// G722 is the RTP format for the G722 codec. // Specification: https://datatracker.ietf.org/doc/html/rfc3551 type G722 struct{} diff --git a/pkg/format/g726.go b/pkg/format/g726.go index a602d4f8..1c41725a 100644 --- a/pkg/format/g726.go +++ b/pkg/format/g726.go @@ -7,7 +7,7 @@ import ( "github.com/pion/rtp" ) -// G726 is a RTP format for the G726 codec. +// G726 is the RTP format for the G726 codec. // Specification: https://datatracker.ietf.org/doc/html/rfc3551 type G726 struct { PayloadTyp uint8 diff --git a/pkg/format/h264.go b/pkg/format/h264.go index 44028ea3..72316863 100644 --- a/pkg/format/h264.go +++ b/pkg/format/h264.go @@ -15,7 +15,7 @@ import ( "github.com/bluenviron/mediacommon/pkg/codecs/h264" ) -// H264 is a RTP format for the H264 codec. +// H264 is the RTP format for the H264 codec. // Specification: https://datatracker.ietf.org/doc/html/rfc6184 type H264 struct { PayloadTyp uint8 diff --git a/pkg/format/h265.go b/pkg/format/h265.go index 17bfa932..80674869 100644 --- a/pkg/format/h265.go +++ b/pkg/format/h265.go @@ -13,7 +13,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtph265" ) -// H265 is a RTP format for the H265 codec. +// H265 is the RTP format for the H265 codec. // Specification: https://datatracker.ietf.org/doc/html/rfc7798 type H265 struct { PayloadTyp uint8 diff --git a/pkg/format/lpcm.go b/pkg/format/lpcm.go index c461cb8a..a83d96a3 100644 --- a/pkg/format/lpcm.go +++ b/pkg/format/lpcm.go @@ -9,8 +9,9 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtplpcm" ) -// LPCM is a RTP format for the uncompressed, Linear PCM codec. +// LPCM is the RTP format for the LPCM codec. // Specification: https://datatracker.ietf.org/doc/html/rfc3190 +// Specification: https://datatracker.ietf.org/doc/html/rfc3551 type LPCM struct { PayloadTyp uint8 BitDepth int @@ -21,6 +22,20 @@ type LPCM struct { func (f *LPCM) unmarshal(ctx *unmarshalContext) error { f.PayloadTyp = ctx.payloadType + if ctx.payloadType == 10 { + f.BitDepth = 16 + f.SampleRate = 44100 + f.ChannelCount = 2 + return nil + } + + if ctx.payloadType == 11 { + f.BitDepth = 16 + f.SampleRate = 44100 + f.ChannelCount = 1 + return nil + } + switch ctx.codec { case "l8": f.BitDepth = 8 diff --git a/pkg/format/mjpeg.go b/pkg/format/mjpeg.go index 1097f2f8..c5b48c49 100644 --- a/pkg/format/mjpeg.go +++ b/pkg/format/mjpeg.go @@ -6,7 +6,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpmjpeg" ) -// MJPEG is a RTP format for the Motion-JPEG codec. +// MJPEG is the RTP format for the Motion-JPEG codec. // Specification: https://datatracker.ietf.org/doc/html/rfc2435 type MJPEG struct{} diff --git a/pkg/format/mpeg1_audio.go b/pkg/format/mpeg1_audio.go index 5daacca5..e37c1db4 100644 --- a/pkg/format/mpeg1_audio.go +++ b/pkg/format/mpeg1_audio.go @@ -6,7 +6,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpmpeg1audio" ) -// MPEG1Audio is a RTP format for a MPEG-1/2 Audio codec. +// MPEG1Audio is the RTP format for a MPEG-1/2 Audio codec. // Specification: https://datatracker.ietf.org/doc/html/rfc2250 type MPEG1Audio struct{} diff --git a/pkg/format/mpeg1_video.go b/pkg/format/mpeg1_video.go index 0b900d48..04aac53d 100644 --- a/pkg/format/mpeg1_video.go +++ b/pkg/format/mpeg1_video.go @@ -6,7 +6,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpmpeg1video" ) -// MPEG1Video is a RTP format for a MPEG-1/2 Video codec. +// MPEG1Video is the RTP format for a MPEG-1/2 Video codec. // Specification: https://datatracker.ietf.org/doc/html/rfc2250 type MPEG1Video struct{} diff --git a/pkg/format/mpeg4_audio.go b/pkg/format/mpeg4_audio.go index eb7b0e6b..295d6c92 100644 --- a/pkg/format/mpeg4_audio.go +++ b/pkg/format/mpeg4_audio.go @@ -12,14 +12,14 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpmpeg4audio" ) -// MPEG4Audio is a RTP format for a MPEG-4 Audio codec. +// MPEG4Audio is the RTP format for a MPEG-4 Audio codec. // Specification: https://datatracker.ietf.org/doc/html/rfc3640 // Specification: https://datatracker.ietf.org/doc/html/rfc6416#section-7.3 type MPEG4Audio struct { // payload type of packets. PayloadTyp uint8 - // use RFC6416 (LATM) instead of RFC3640 (generic). + // use LATM format (RFC6416) instead of generic format (RFC3640). LATM bool // profile level ID. diff --git a/pkg/format/mpeg4_video.go b/pkg/format/mpeg4_video.go index ba638de5..9874220c 100644 --- a/pkg/format/mpeg4_video.go +++ b/pkg/format/mpeg4_video.go @@ -13,7 +13,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpmpeg4video" ) -// MPEG4Video is a RTP format for a MPEG-4 Video codec. +// MPEG4Video is the RTP format for a MPEG-4 Video codec. // Specification: https://datatracker.ietf.org/doc/html/rfc6416#section-7.1 type MPEG4Video struct { PayloadTyp uint8 diff --git a/pkg/format/mpegts.go b/pkg/format/mpegts.go index 272446fe..2913cafd 100644 --- a/pkg/format/mpegts.go +++ b/pkg/format/mpegts.go @@ -4,7 +4,7 @@ import ( "github.com/pion/rtp" ) -// MPEGTS is a RTP format for MPEG-TS. +// MPEGTS is the RTP format for MPEG-TS. // Specification: https://datatracker.ietf.org/doc/html/rfc2250 type MPEGTS struct{} diff --git a/pkg/format/opus.go b/pkg/format/opus.go index 0ec2e318..77bbb770 100644 --- a/pkg/format/opus.go +++ b/pkg/format/opus.go @@ -10,7 +10,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpsimpleaudio" ) -// Opus is a RTP format for the Opus codec. +// Opus is the RTP format for the Opus codec. // Specification: https://datatracker.ietf.org/doc/html/rfc7587 type Opus struct { PayloadTyp uint8 diff --git a/pkg/format/speex.go b/pkg/format/speex.go index 08c74d77..9dab74b2 100644 --- a/pkg/format/speex.go +++ b/pkg/format/speex.go @@ -7,7 +7,7 @@ import ( "github.com/pion/rtp" ) -// Speex is a RTP format for the Speex codec. +// Speex is the RTP format for the Speex codec. // Specification: https://datatracker.ietf.org/doc/html/rfc5574 type Speex struct { PayloadTyp uint8 diff --git a/pkg/format/vorbis.go b/pkg/format/vorbis.go index 61fab87b..9d5d8017 100644 --- a/pkg/format/vorbis.go +++ b/pkg/format/vorbis.go @@ -9,7 +9,7 @@ import ( "github.com/pion/rtp" ) -// Vorbis is a RTP format for the Vorbis codec. +// Vorbis is the RTP format for the Vorbis codec. // Specification: https://datatracker.ietf.org/doc/html/rfc5215 type Vorbis struct { PayloadTyp uint8 diff --git a/pkg/format/vp8.go b/pkg/format/vp8.go index c699445d..cf933797 100644 --- a/pkg/format/vp8.go +++ b/pkg/format/vp8.go @@ -9,7 +9,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpvp8" ) -// VP8 is a RTP format for the VP8 codec. +// VP8 is the RTP format for the VP8 codec. // Specification: https://datatracker.ietf.org/doc/html/rfc7741 type VP8 struct { PayloadTyp uint8 diff --git a/pkg/format/vp9.go b/pkg/format/vp9.go index 9b6f7605..bc42443d 100644 --- a/pkg/format/vp9.go +++ b/pkg/format/vp9.go @@ -9,7 +9,7 @@ import ( "github.com/bluenviron/gortsplib/v4/pkg/format/rtpvp9" ) -// VP9 is a RTP format for the VP9 codec. +// VP9 is the RTP format for the VP9 codec. // Specification: https://datatracker.ietf.org/doc/html/draft-ietf-payload-vp9-16 type VP9 struct { PayloadTyp uint8