Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/bluenviron/gortsplib/llms.txt

Use this file to discover all available pages before exploring further.

Supported video formats

StructCodecPayload typeRFC / specEncoderDecoder
format.H264H.264 / AVCdynamic (96–127) or 35RFC 6184YesYes
format.H265H.265 / HEVCdynamic (96–127)RFC 7798YesYes
format.AV1AV1dynamic (96–127)AV1 RTP Payload v1.0YesYes
format.VP9VP9dynamic (96–127)RFC 9628YesYes
format.VP8VP8dynamic (96–127)RFC 7741YesYes
format.MJPEGMotion-JPEG26 (static)RFC 2435YesYes
format.MPEG4VideoMPEG-4 Visualdynamic (96–127)RFC 6416YesYes
format.MPEG1VideoMPEG-1/2 Video32 (static)RFC 2250YesYes

Package path: github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 6184

Struct 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.
Package path: github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 7798

Struct 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))
})
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))
})
Package path: github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 9628

Struct 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))
})
Package path: github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 7741

Struct 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))
})
Package path: github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 2435Static payload type: 26

Struct 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))
})
Package path: github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 6416, section 7.1

Struct 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))
})
Package path: github.com/bluenviron/gortsplib/v5/pkg/formatSpecification: RFC 2250Static payload type: 32

Struct 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))
})

Build docs developers (and LLMs) love