Supported video formats
| Struct | Codec | Payload type | RFC / spec | Encoder | Decoder |
|---|---|---|---|---|---|
format.H264 | H.264 / AVC | dynamic (96–127) or 35 | RFC 6184 | Yes | Yes |
format.H265 | H.265 / HEVC | dynamic (96–127) | RFC 7798 | Yes | Yes |
format.AV1 | AV1 | dynamic (96–127) | AV1 RTP Payload v1.0 | Yes | Yes |
format.VP9 | VP9 | dynamic (96–127) | RFC 9628 | Yes | Yes |
format.VP8 | VP8 | dynamic (96–127) | RFC 7741 | Yes | Yes |
format.MJPEG | Motion-JPEG | 26 (static) | RFC 2435 | Yes | Yes |
format.MPEG4Video | MPEG-4 Visual | dynamic (96–127) | RFC 6416 | Yes | Yes |
format.MPEG1Video | MPEG-1/2 Video | 32 (static) | RFC 2250 | Yes | Yes |
H264
H264
Package path:
github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 6184Struct fields
type H264 struct {
// RTP payload type (96–127 or 35).
PayloadTyp uint8
// Sequence Parameter Set, parsed from sprop-parameter-sets in SDP.
// May be nil if not present in SDP.
SPS []byte
// Picture Parameter Set, parsed from sprop-parameter-sets in SDP.
// May be nil if not present in SDP.
PPS []byte
// Packetization mode (0, 1, or 2). Use 1 for most cameras and encoders.
PacketizationMode int
}
Recording example
Declare the format when starting a recording session:forma := &format.H264{
PayloadTyp: 96,
PacketizationMode: 1,
}
desc := &description.Session{
Medias: []*description.Media{{
Type: description.MediaTypeVideo,
Formats: []format.Format{forma},
}},
}
c := gortsplib.Client{}
err := c.StartRecording("rtsp://myuser:mypass@localhost:8554/mystream", desc)
if err != nil {
panic(err)
}
defer c.Close()
// create RTP encoder
rtpEnc, err := forma.CreateEncoder()
if err != nil {
panic(err)
}
// encode an H264 access unit into RTP packets
pkts, err := rtpEnc.Encode(accessUnit)
if err != nil {
panic(err)
}
for _, pkt := range pkts {
pkt.Timestamp += uint32(int64(randomStart) + pts)
c.WritePacketRTP(desc.Medias[0], pkt)
}
Playback example
// find the H264 media and format
var forma *format.H264
medi := desc.FindFormat(&forma)
if medi == nil {
panic("media not found")
}
// setup RTP -> H264 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)
}
// if SPS and PPS are present in the SDP, send them to any downstream decoder
if forma.SPS != nil {
// process forma.SPS
}
if forma.PPS != nil {
// process forma.PPS
}
_, err = c.Setup(desc.BaseURL, medi, 0, 0)
if err != nil {
panic(err)
}
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
pts, ok := c.PacketPTS(medi, pkt)
if !ok {
return
}
au, err := rtpDec.Decode(pkt)
if err != nil {
if err != rtph264.ErrNonStartingPacketAndNoPrevious && err != rtph264.ErrMorePacketsNeeded {
log.Printf("ERR: %v", err)
}
return
}
// au is [][]byte — a slice of NAL units
log.Printf("received H264 access unit with PTS %v, %d NAL units", pts, len(au))
})
rtph264.ErrNonStartingPacketAndNoPrevious and rtph264.ErrMorePacketsNeeded are non-fatal: the decoder is waiting for more packets to reassemble a complete access unit.H265
H265
Package path:
github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 7798Struct fields
type H265 struct {
// RTP payload type (96–127).
PayloadTyp uint8
// Video Parameter Set, parsed from sprop-vps in SDP. May be nil.
VPS []byte
// Sequence Parameter Set, parsed from sprop-sps in SDP. May be nil.
SPS []byte
// Picture Parameter Set, parsed from sprop-pps in SDP. May be nil.
PPS []byte
// Maximum Decoding Order Number Difference.
MaxDONDiff int
}
Playback example
// find the H265 media and format
var forma *format.H265
medi := desc.FindFormat(&forma)
if medi == nil {
panic("media not found")
}
// setup RTP -> H265 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)
}
// if VPS, SPS and PPS are present in the SDP, pass them to any downstream decoder
if forma.VPS != nil {
// process forma.VPS
}
if forma.SPS != nil {
// process forma.SPS
}
if forma.PPS != nil {
// process forma.PPS
}
_, err = c.Setup(desc.BaseURL, medi, 0, 0)
if err != nil {
panic(err)
}
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
pts, ok := c.PacketPTS(medi, pkt)
if !ok {
return
}
au, err := rtpDec.Decode(pkt)
if err != nil {
if err != rtph265.ErrNonStartingPacketAndNoPrevious && err != rtph265.ErrMorePacketsNeeded {
log.Printf("ERR: %v", err)
}
return
}
// au is [][]byte — a slice of NAL units
log.Printf("received H265 access unit with PTS %v, %d NAL units", pts, len(au))
})
AV1
AV1
Package path:
github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RTP Payload Format For AV1 (v1.0)Struct fields
type AV1 struct {
// RTP payload type (96–127).
PayloadTyp uint8
// Optional AV1 level index from the fmtp line.
LevelIdx *int
// Optional AV1 profile from the fmtp line.
Profile *int
// Optional AV1 tier from the fmtp line.
Tier *int
}
Playback example
// find the AV1 media and format
var forma *format.AV1
medi := desc.FindFormat(&forma)
if medi == nil {
panic("media not found")
}
// setup RTP -> AV1 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)
}
_, err = c.Setup(desc.BaseURL, medi, 0, 0)
if err != nil {
panic(err)
}
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
pts, ok := c.PacketPTS(medi, pkt)
if !ok {
return
}
// extract AV1 temporal units from RTP packets
tu, err := rtpDec.Decode(pkt)
if err != nil {
if err != rtpav1.ErrNonStartingPacketAndNoPrevious && err != rtpav1.ErrMorePacketsNeeded {
log.Printf("ERR: %v", err)
}
return
}
// tu is [][]byte — a slice of OBUs forming a temporal unit
log.Printf("received AV1 temporal unit with PTS %v, %d OBUs", pts, len(tu))
})
VP9
VP9
Package path:
github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 9628Struct fields
type VP9 struct {
// RTP payload type (96–127).
PayloadTyp uint8
// Optional maximum frame rate from fmtp.
MaxFR *int
// Optional maximum frame size from fmtp.
MaxFS *int
// Optional VP9 profile ID from fmtp.
ProfileID *int
}
Usage
var forma *format.VP9
medi := desc.FindFormat(&forma)
if medi == nil {
panic("media not found")
}
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)
}
_, err = c.Setup(desc.BaseURL, medi, 0, 0)
if err != nil {
panic(err)
}
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
pts, ok := c.PacketPTS(medi, pkt)
if !ok {
return
}
frame, err := rtpDec.Decode(pkt)
if err != nil {
log.Printf("ERR: %v", err)
return
}
log.Printf("received VP9 frame with PTS %v, size %d", pts, len(frame))
})
VP8
VP8
Package path:
github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 7741Struct fields
type VP8 struct {
// RTP payload type (96–127).
PayloadTyp uint8
// Optional maximum frame rate from fmtp.
MaxFR *int
// Optional maximum frame size from fmtp.
MaxFS *int
}
Usage
var forma *format.VP8
medi := desc.FindFormat(&forma)
if medi == nil {
panic("media not found")
}
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)
}
_, err = c.Setup(desc.BaseURL, medi, 0, 0)
if err != nil {
panic(err)
}
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
pts, ok := c.PacketPTS(medi, pkt)
if !ok {
return
}
frame, err := rtpDec.Decode(pkt)
if err != nil {
log.Printf("ERR: %v", err)
return
}
log.Printf("received VP8 frame with PTS %v, size %d", pts, len(frame))
})
M-JPEG
M-JPEG
Package path:
github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 2435Static payload type: 26Struct fields
// MJPEG has no configurable fields — payload type 26 is fixed by RFC 3551.
type MJPEG struct{}
Usage
var forma *format.MJPEG
medi := desc.FindFormat(&forma)
if medi == nil {
panic("media not found")
}
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)
}
_, err = c.Setup(desc.BaseURL, medi, 0, 0)
if err != nil {
panic(err)
}
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
pts, ok := c.PacketPTS(medi, pkt)
if !ok {
return
}
frame, err := rtpDec.Decode(pkt)
if err != nil {
log.Printf("ERR: %v", err)
return
}
// frame is a complete JPEG image
log.Printf("received MJPEG frame with PTS %v, size %d", pts, len(frame))
})
MPEG-4 Video
MPEG-4 Video
Package path:
github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 6416, section 7.1Struct fields
type MPEG4Video struct {
// RTP payload type (96–127).
PayloadTyp uint8
// Profile and level indication. Defaults to 1.
ProfileLevelID int
// Decoder configuration, parsed from the config fmtp parameter.
Config []byte
}
Usage
var forma *format.MPEG4Video
medi := desc.FindFormat(&forma)
if medi == nil {
panic("media not found")
}
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)
}
_, err = c.Setup(desc.BaseURL, medi, 0, 0)
if err != nil {
panic(err)
}
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
pts, ok := c.PacketPTS(medi, pkt)
if !ok {
return
}
frame, err := rtpDec.Decode(pkt)
if err != nil {
log.Printf("ERR: %v", err)
return
}
log.Printf("received MPEG-4 Video frame with PTS %v, size %d", pts, len(frame))
})
MPEG-1/2 Video
MPEG-1/2 Video
Package path:
github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 2250Static payload type: 32Struct fields
// MPEG1Video has no configurable fields — payload type 32 is fixed by RFC 3551.
type MPEG1Video struct{}
Usage
var forma *format.MPEG1Video
medi := desc.FindFormat(&forma)
if medi == nil {
panic("media not found")
}
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)
}
_, err = c.Setup(desc.BaseURL, medi, 0, 0)
if err != nil {
panic(err)
}
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
pts, ok := c.PacketPTS(medi, pkt)
if !ok {
return
}
frame, err := rtpDec.Decode(pkt)
if err != nil {
log.Printf("ERR: %v", err)
return
}
log.Printf("received MPEG-1/2 Video frame with PTS %v, size %d", pts, len(frame))
})