Skip to content

Commit

Permalink
hls: support reading and proxying AV1 tracks
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 committed Aug 6, 2023
1 parent b198cc5 commit 5959d18
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 62 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Live streams can be published to the server with:
|[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 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|H265, H264|Opus, MPEG-4 Audio (AAC)|
|[HLS cameras and servers](#hls-cameras-and-servers)|Low-Latency HLS, MP4-based HLS, legacy HLS|AV1, 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)|
|[Raspberry Pi Cameras](#raspberry-pi-cameras)||H264||

Expand All @@ -40,7 +40,7 @@ And can be read from the server with:
|[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), G726, G722, G711, 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|H265, H264|Opus, MPEG-4 Audio (AAC)|
|[HLS](#hls)|Low-Latency HLS, MP4-based HLS, legacy HLS|AV1, H265, H264|Opus, MPEG-4 Audio (AAC)|

**Features**

Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ require (
code.cloudfoundry.org/bytefmt v0.0.0
github.com/abema/go-mp4 v0.11.0
github.com/alecthomas/kong v0.8.0
github.com/bluenviron/gohlslib v0.3.1-0.20230805121442-9577da1cb068
github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230805122812-17acec3f0dea
github.com/bluenviron/mediacommon v0.7.1-0.20230805114828-bee33f3b286d
github.com/bluenviron/gohlslib v0.3.1-0.20230806000705-4ca609772363
github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230806001215-926a452fb745
github.com/bluenviron/mediacommon v0.7.1-0.20230805234008-34d20294a26b
github.com/datarhei/gosrt v0.5.3
github.com/fsnotify/fsnotify v1.6.0
github.com/gin-gonic/gin v1.9.1
Expand All @@ -31,7 +31,7 @@ require (
)

require (
github.com/aler9/writerseeker v0.0.0-20220601075008-6f0e685b9c82 // indirect
github.com/aler9/writerseeker v1.0.0 // indirect
github.com/asticode/go-astikit v0.30.0 // indirect
github.com/asticode/go-astits v1.12.0 // indirect
github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c // indirect
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqr
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/aler9/gosrt v0.0.0-20230803201410-b26769a3a222 h1:69Oj9CKfxxkTqFtBfBNo7zP4HcxEwjpFnFNHHX2Z06c=
github.com/aler9/gosrt v0.0.0-20230803201410-b26769a3a222/go.mod h1:EryxR+Men7aW67IX2FEo56SU+Pay9OHCw3kZx23qKyQ=
github.com/aler9/writerseeker v0.0.0-20220601075008-6f0e685b9c82 h1:9WgSzBLo3a9ToSVV7sRTBYZ1GGOZUpq4+5H3SN0UZq4=
github.com/aler9/writerseeker v0.0.0-20220601075008-6f0e685b9c82/go.mod h1:qsMrZCbeBf/mCLOeF16KDkPu4gktn/pOWyaq1aYQE7U=
github.com/aler9/writerseeker v1.0.0 h1:3wI/NtI20WqX8iLjrivym5VGXxug3EkRPaLRw6k9f9M=
github.com/aler9/writerseeker v1.0.0/go.mod h1:J5H8yGtvHnTM3DddPusobve1mDTYgdAj7eAwjGj8FXY=
github.com/asticode/go-astikit v0.30.0 h1:DkBkRQRIxYcknlaU7W7ksNfn4gMFsB0tqMJflxkRsZA=
github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0=
github.com/asticode/go-astits v1.12.0 h1:BiefTgVEyPgEB8nT6J+Sys/uxE4H/a04SW/aedpOpPc=
github.com/asticode/go-astits v1.12.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI=
github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYhJeJ2aZxADI2tGADS15AzIF8MQ8XAhT4=
github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI=
github.com/bluenviron/gohlslib v0.3.1-0.20230805121442-9577da1cb068 h1:mNSdk14esA9ggCP0+gDmcG9wLvb7QzHLta071nTLYe4=
github.com/bluenviron/gohlslib v0.3.1-0.20230805121442-9577da1cb068/go.mod h1:DouD/43mEaXgwbeQZdtVhzRnA7RuKFYeaVPz6tj/Rfk=
github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230805122812-17acec3f0dea h1:AK6GuUoXDaGfk3HDe6qMJ/Swmj1hIxVtMuw98sa2VO8=
github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230805122812-17acec3f0dea/go.mod h1:9GOyv9dKyDjMHXcrh7rytIoXWvRk+/DC0Mjq3vqEyCU=
github.com/bluenviron/mediacommon v0.7.1-0.20230805114828-bee33f3b286d h1:ye0ze/XtVq23NwgxV/PWcjtagcZXTKZq+V6ZBT0HoTY=
github.com/bluenviron/mediacommon v0.7.1-0.20230805114828-bee33f3b286d/go.mod h1:8Y0rvMJDUCgqDegYrUxG1rbumB6DV0TZ98Rw9mowIrA=
github.com/bluenviron/gohlslib v0.3.1-0.20230806000705-4ca609772363 h1:ysN/BZSY9Q7Ditvro4zvSLLYyxTPyiiVl0ALeY/rHHQ=
github.com/bluenviron/gohlslib v0.3.1-0.20230806000705-4ca609772363/go.mod h1:2aXz4lSl2pToXk9zYmWhdhR02OiRRZCQiFdrQcIWLBc=
github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230806001215-926a452fb745 h1:LR8F5ng75c9KxWLrPWj8bskXCR7AJXv8gm4duKfzUjc=
github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230806001215-926a452fb745/go.mod h1:7owCGeF8gQfziPCWL9UbL+Yqogl13gKJeRI8jhnpadg=
github.com/bluenviron/mediacommon v0.7.1-0.20230805234008-34d20294a26b h1:/csYQQDmZyXw0CVATJSPBkwT3JYap418W7LLX7mscxw=
github.com/bluenviron/mediacommon v0.7.1-0.20230805234008-34d20294a26b/go.mod h1:LR4w8cpvzo2ZcmBwXcentvBj7ZlyF9g9xP4dDbt8uJw=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
Expand Down
2 changes: 1 addition & 1 deletion internal/core/hls_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<video id="video" muted controls autoplay playsinline></video>

<script src="https://cdn.jsdelivr.net/npm/[email protected].3"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected].10"></script>

<script>

Expand Down
2 changes: 1 addition & 1 deletion internal/core/hls_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func TestHLSRead(t *testing.T) {
"#EXT-X-VERSION:9\n"+
"#EXT-X-INDEPENDENT-SEGMENTS\n"+
"\n"+
"#EXT-X-STREAM-INF:BANDWIDTH=1256,AVERAGE-BANDWIDTH=1256,"+
"#EXT-X-STREAM-INF:BANDWIDTH=1192,AVERAGE-BANDWIDTH=1192,"+
"CODECS=\"avc1.42c028\",RESOLUTION=1920x1080,FRAME-RATE=30.000\n"+
"stream.m3u8\n", string(cnt))

Expand Down
39 changes: 37 additions & 2 deletions internal/core/hls_muxer.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,43 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})
}

func (m *hlsMuxer) createVideoTrack(stream *stream.Stream) (*media.Media, *gohlslib.Track) {
var videoFormatAV1 *formats.AV1
videoMedia := stream.Medias().FindFormat(&videoFormatAV1)

if videoFormatAV1 != nil {
startPTSFilled := false
var startPTS time.Duration

stream.AddReader(m, videoMedia, videoFormatAV1, func(unit formatprocessor.Unit) {
m.ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitAV1)

if tunit.OBUs == nil {
return nil
}

Check warning on line 352 in internal/core/hls_muxer.go

View check run for this annotation

Codecov / codecov/patch

internal/core/hls_muxer.go#L343-L352

Added lines #L343 - L352 were not covered by tests

if !startPTSFilled {
startPTSFilled = true
startPTS = tunit.PTS
}

Check warning on line 357 in internal/core/hls_muxer.go

View check run for this annotation

Codecov / codecov/patch

internal/core/hls_muxer.go#L354-L357

Added lines #L354 - L357 were not covered by tests

pts := tunit.PTS - startPTS
err := m.muxer.WriteAV1(tunit.NTP, pts, tunit.OBUs)
if err != nil {
return fmt.Errorf("muxer error: %v", err)
}

Check warning on line 363 in internal/core/hls_muxer.go

View check run for this annotation

Codecov / codecov/patch

internal/core/hls_muxer.go#L359-L363

Added lines #L359 - L363 were not covered by tests

return nil

Check warning on line 365 in internal/core/hls_muxer.go

View check run for this annotation

Codecov / codecov/patch

internal/core/hls_muxer.go#L365

Added line #L365 was not covered by tests
})
})

return videoMedia, &gohlslib.Track{
Codec: &codecs.AV1{},
}

Check warning on line 371 in internal/core/hls_muxer.go

View check run for this annotation

Codecov / codecov/patch

internal/core/hls_muxer.go#L369-L371

Added lines #L369 - L371 were not covered by tests
}

var videoFormatH265 *formats.H265
videoMedia := stream.Medias().FindFormat(&videoFormatH265)
videoMedia = stream.Medias().FindFormat(&videoFormatH265)

if videoFormatH265 != nil {
startPTSFilled := false
Expand Down Expand Up @@ -535,7 +570,7 @@ func (m *hlsMuxer) createAudioTrack(stream *stream.Stream) (*media.Media, *gohls

return audioMedia, &gohlslib.Track{
Codec: &codecs.Opus{
Channels: func() int {
ChannelCount: func() int {

Check warning on line 573 in internal/core/hls_muxer.go

View check run for this annotation

Codecov / codecov/patch

internal/core/hls_muxer.go#L573

Added line #L573 was not covered by tests
if audioFormatOpus.IsStereo {
return 2
}
Expand Down
2 changes: 1 addition & 1 deletion internal/core/hls_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
Type: media.TypeAudio,
Formats: []formats.Format{&formats.Opus{
PayloadTyp: 96,
IsStereo: (tcodec.Channels == 2),
IsStereo: (tcodec.ChannelCount == 2),

Check warning on line 148 in internal/core/hls_source.go

View check run for this annotation

Codecov / codecov/patch

internal/core/hls_source.go#L148

Added line #L148 was not covered by tests
}},
}

Expand Down
37 changes: 0 additions & 37 deletions internal/rtmp/boxes_av1.go

This file was deleted.

13 changes: 7 additions & 6 deletions internal/rtmp/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import (
"fmt"
"time"

gomp4 "github.com/abema/go-mp4"
"github.com/abema/go-mp4"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/mediacommon/pkg/codecs/av1"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/pkg/codecs/h265"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/bluenviron/mediacommon/pkg/formats/fmp4"
"github.com/notedit/rtmp/format/flv/flvio"

"github.com/bluenviron/mediamtx/internal/rtmp/h264conf"
Expand All @@ -30,7 +31,7 @@ type OnDataMPEG4AudioFunc func(pts time.Duration, au []byte)
// OnDataMPEG1AudioFunc is the prototype of the callback passed to OnDataMPEG1Audio().
type OnDataMPEG1AudioFunc func(pts time.Duration, frame []byte)

func h265FindNALU(array []gomp4.HEVCNaluArray, typ h265.NALUType) []byte {
func h265FindNALU(array []mp4.HEVCNaluArray, typ h265.NALUType) []byte {

Check warning on line 34 in internal/rtmp/reader.go

View check run for this annotation

Codecov / codecov/patch

internal/rtmp/reader.go#L34

Added line #L34 was not covered by tests
for _, entry := range array {
if entry.NaluType == byte(typ) && entry.NumNalus == 1 &&
h265.NALUType((entry.Nalus[0].NALUnit[0]>>1)&0b111111) == typ {
Expand Down Expand Up @@ -215,8 +216,8 @@ func tracksFromMetadata(conn *Conn, payload []interface{}) (formats.Format, form
if videoTrack == nil {
switch tmsg.FourCC {
case message.FourCCHEVC:
var hvcc gomp4.HvcC
_, err := gomp4.Unmarshal(bytes.NewReader(tmsg.Config), uint64(len(tmsg.Config)), &hvcc, gomp4.Context{})
var hvcc mp4.HvcC
_, err := mp4.Unmarshal(bytes.NewReader(tmsg.Config), uint64(len(tmsg.Config)), &hvcc, mp4.Context{})

Check warning on line 220 in internal/rtmp/reader.go

View check run for this annotation

Codecov / codecov/patch

internal/rtmp/reader.go#L219-L220

Added lines #L219 - L220 were not covered by tests
if err != nil {
return nil, nil, fmt.Errorf("invalid H265 configuration: %v", err)
}
Expand All @@ -236,8 +237,8 @@ func tracksFromMetadata(conn *Conn, payload []interface{}) (formats.Format, form
}

case message.FourCCAV1:
var av1c Av1C
_, err := gomp4.Unmarshal(bytes.NewReader(tmsg.Config), uint64(len(tmsg.Config)), &av1c, gomp4.Context{})
var av1c fmp4.Av1C
_, err := mp4.Unmarshal(bytes.NewReader(tmsg.Config), uint64(len(tmsg.Config)), &av1c, mp4.Context{})

Check warning on line 241 in internal/rtmp/reader.go

View check run for this annotation

Codecov / codecov/patch

internal/rtmp/reader.go#L240-L241

Added lines #L240 - L241 were not covered by tests
if err != nil {
return nil, nil, fmt.Errorf("invalid AV1 configuration: %v", err)
}
Expand Down

0 comments on commit 5959d18

Please sign in to comment.