Skip to content

Commit

Permalink
support publishing VP9 tracks with RTMP (#2247)
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 authored Aug 25, 2023
1 parent 482266a commit 23ddaac
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 14 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Live streams can be published to the server with:
|[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), 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), G726, G722, G711, LPCM and any RTP-compatible codec|
|[RTMP clients](#rtmp-clients)|RTMP, RTMPS, Enhanced RTMP|AV1, H265, H264|MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3)|
|[RTMP clients](#rtmp-clients)|RTMP, RTMPS, Enhanced RTMP|AV1, VP9, H265, H264|MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3)|
|[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|Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3)|
Expand All @@ -46,7 +46,6 @@ And can be read from the server with:

* Publish live streams to the server
* Read live streams from the server
* Proxy streams from other servers or cameras, always or on-demand
* Streams are automatically converted from a protocol to another. For instance, it's possible to publish a stream with RTSP and read it with HLS
* Serve multiple streams at once in separate paths
* Authenticate users; use internal or external authentication
Expand Down Expand Up @@ -102,7 +101,7 @@ _rtsp-simple-server_ has been rebranded as _MediaMTX_. The reason is pretty obvi
* [RTSP](#rtsp)
* [RTMP](#rtmp)
* [HLS](#hls)
* [Features](#features)
* [Other features](#other-features)
* [Configuration](#configuration)
* [Authentication](#authentication)
* [Encrypt the configuration](#encrypt-the-configuration)
Expand Down Expand Up @@ -977,7 +976,7 @@ To decrease the latency, you can:
ffmpeg -i rtsp://original-stream -pix_fmt yuv420p -c:v libx264 -preset ultrafast -b:v 600k -max_muxing_queue_size 1024 -g 30 -f rtsp rtsp://localhost:$RTSP_PORT/compressed
```
## Features
## Other features
### Configuration
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.20

require (
code.cloudfoundry.org/bytefmt v0.0.0
github.com/abema/go-mp4 v0.12.0
github.com/abema/go-mp4 v0.13.0
github.com/alecthomas/kong v0.8.0
github.com/bluenviron/gohlslib v1.0.0
github.com/bluenviron/gortsplib/v3 v3.10.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/abema/go-mp4 v0.12.0 h1:XI9PPt1BpjB3wFl18oFiX6C99uesx7F/X13Z+ga8bYY=
github.com/abema/go-mp4 v0.12.0/go.mod h1:vPl9t5ZK7K0x68jh12/+ECWBCXoWuIDtNgPtU2f04ws=
github.com/abema/go-mp4 v0.13.0 h1:gjEZLt7g0ePpYA5sUDrI2r8X+WuI8o+USkgG5wMgmkI=
github.com/abema/go-mp4 v0.13.0/go.mod h1:vPl9t5ZK7K0x68jh12/+ECWBCXoWuIDtNgPtU2f04ws=
github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0=
github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s=
github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
Expand Down
17 changes: 17 additions & 0 deletions internal/core/rtmp_conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,17 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
})
})

case *formats.VP9:
r.OnDataVP9(func(pts time.Duration, frame []byte) {
stream.WriteUnit(videoMedia, videoFormat, &formatprocessor.UnitVP9{
BaseUnit: formatprocessor.BaseUnit{
NTP: time.Now(),
},
PTS: pts,
Frame: frame,
})
})

case *formats.H265:
r.OnDataH265(func(pts time.Duration, au [][]byte) {
stream.WriteUnit(videoMedia, videoFormat, &formatprocessor.UnitH265{
Expand All @@ -654,6 +665,9 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
AU: au,
})
})

default:
return fmt.Errorf("unsupported video codec: %T", videoFormat)
}
}

Expand Down Expand Up @@ -686,6 +700,9 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
Frames: [][]byte{frame},
})
})

default:
return fmt.Errorf("unsupported audio codec: %T", audioFormat)
}
}

Expand Down
14 changes: 8 additions & 6 deletions internal/core/rtmp_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,6 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error {

videoFormat, audioFormat := mc.Tracks()

switch videoFormat.(type) {
case *formats.H265, *formats.AV1:
return fmt.Errorf("proxying H265 or AV1 tracks with RTMP is not supported")
}

var medias media.Medias
var stream *stream.Stream

Expand All @@ -128,7 +123,8 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error {
}
medias = append(medias, videoMedia)

if _, ok := videoFormat.(*formats.H264); ok {
switch videoFormat.(type) {
case *formats.H264:
mc.OnDataH264(func(pts time.Duration, au [][]byte) {
stream.WriteUnit(videoMedia, videoFormat, &formatprocessor.UnitH264{
BaseUnit: formatprocessor.BaseUnit{
Expand All @@ -138,6 +134,9 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error {
AU: au,
})
})

default:
return fmt.Errorf("unsupported video codec: %T", videoFormat)
}
}

Expand Down Expand Up @@ -170,6 +169,9 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error {
Frames: [][]byte{frame},
})
})

default:
return fmt.Errorf("unsupported audio codec: %T", audioFormat)
}
}

Expand Down
21 changes: 20 additions & 1 deletion internal/rtmp/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import (
// OnDataAV1Func is the prototype of the callback passed to OnDataAV1().
type OnDataAV1Func func(pts time.Duration, tu [][]byte)

// OnDataVP9Func is the prototype of the callback passed to OnDataVP9().
type OnDataVP9Func func(pts time.Duration, frame []byte)

// OnDataH26xFunc is the prototype of the callback passed to OnDataH26x().
type OnDataH26xFunc func(pts time.Duration, au [][]byte)

Expand Down Expand Up @@ -252,7 +255,13 @@ func tracksFromMetadata(conn *Conn, payload []interface{}) (formats.Format, form
videoTrack = &formats.AV1{}

default: // VP9
return nil, nil, fmt.Errorf("VP9 is not supported yet")
var vpcc mp4.VpcC
_, err := mp4.Unmarshal(bytes.NewReader(tmsg.Config), uint64(len(tmsg.Config)), &vpcc, mp4.Context{})
if err != nil {
return nil, nil, fmt.Errorf("invalid VP9 configuration: %v", err)
}

videoTrack = &formats.VP9{}
}
}

Expand Down Expand Up @@ -449,6 +458,16 @@ func (r *Reader) OnDataAV1(cb OnDataAV1Func) {
}
}

// OnDataVP9 sets a callback that is called when VP9 data is received.
func (r *Reader) OnDataVP9(cb OnDataVP9Func) {
r.onDataVideo = func(msg message.Message) error {
if msg, ok := msg.(*message.ExtendedCodedFrames); ok {
cb(msg.DTS, msg.Payload)
}
return nil
}
}

// OnDataH265 sets a callback that is called when H265 data is received.
func (r *Reader) OnDataH265(cb OnDataH26xFunc) {
r.onDataVideo = func(msg message.Message) error {
Expand Down

0 comments on commit 23ddaac

Please sign in to comment.