Browse Source

update gortsplib, gohlslib (#1637)

pull/1638/head
Alessandro Ros 2 years ago committed by GitHub
parent
commit
2dffccf9c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      README.md
  2. 5
      go.mod
  3. 10
      go.sum
  4. 2
      internal/conf/authmethod.go
  5. 4
      internal/conf/conf.go
  6. 2
      internal/conf/conf_test.go
  7. 2
      internal/conf/path.go
  8. 2
      internal/conf/protocol.go
  9. 2
      internal/conf/sourceprotocol.go
  10. 22
      internal/core/api_test.go
  11. 2
      internal/core/core.go
  12. 28
      internal/core/core_test.go
  13. 65
      internal/core/hls_muxer.go
  14. 76
      internal/core/hls_source.go
  15. 20
      internal/core/hls_source_test.go
  16. 8
      internal/core/metrics_test.go
  17. 6
      internal/core/path.go
  18. 6
      internal/core/rpicamera_source.go
  19. 20
      internal/core/rtmp_conn.go
  20. 16
      internal/core/rtmp_server_test.go
  21. 12
      internal/core/rtmp_source.go
  22. 12
      internal/core/rtmp_source_test.go
  23. 10
      internal/core/rtsp_conn.go
  24. 14
      internal/core/rtsp_server.go
  25. 6
      internal/core/rtsp_server_test.go
  26. 24
      internal/core/rtsp_session.go
  27. 20
      internal/core/rtsp_source.go
  28. 10
      internal/core/rtsp_source_test.go
  29. 2
      internal/core/source.go
  30. 10
      internal/core/stream.go
  31. 6
      internal/core/stream_format.go
  32. 8
      internal/core/stream_media.go
  33. 72
      internal/core/udp_source.go
  34. 354
      internal/core/webrtc_conn.go
  35. 8
      internal/core/webrtc_server_test.go
  36. 4
      internal/formatprocessor/generic.go
  37. 4
      internal/formatprocessor/generic_test.go
  38. 59
      internal/formatprocessor/h264.go
  39. 10
      internal/formatprocessor/h264_test.go
  40. 77
      internal/formatprocessor/h265.go
  41. 10
      internal/formatprocessor/h265_test.go
  42. 8
      internal/formatprocessor/mpeg4audio.go
  43. 8
      internal/formatprocessor/opus.go
  44. 16
      internal/formatprocessor/processor.go
  45. 8
      internal/formatprocessor/vp8.go
  46. 8
      internal/formatprocessor/vp9.go
  47. 2
      internal/rpicamera/rpicamera.go
  48. 67
      internal/rtmp/conn.go
  49. 36
      internal/rtmp/conn_test.go

4
README.md

@ -1181,7 +1181,7 @@ For more advanced options, you can create and serve a custom web page by startin @@ -1181,7 +1181,7 @@ For more advanced options, you can create and serve a custom web page by startin
## Standards
* RTSP/RTP/RTCP standards https://github.com/aler9/gortsplib#standards
* RTSP/RTP/RTCP standards https://github.com/bluenviron/gortsplib#standards
* HLS standards https://github.com/bluenviron/gohlslib#standards
* Golang project layout https://github.com/golang-standards/project-layout
@ -1189,7 +1189,7 @@ For more advanced options, you can create and serve a custom web page by startin @@ -1189,7 +1189,7 @@ For more advanced options, you can create and serve a custom web page by startin
Related projects
* gortsplib (RTSP library used internally) https://github.com/aler9/gortsplib
* gortsplib (RTSP library used internally) https://github.com/bluenviron/gortsplib
* gohlslib (HLS library used internally) https://github.com/bluenviron/gohlslib
* pion/sdp (SDP library used internally) https://github.com/pion/sdp
* pion/rtp (RTP library used internally) https://github.com/pion/rtp

5
go.mod

@ -5,9 +5,10 @@ go 1.20 @@ -5,9 +5,10 @@ go 1.20
require (
code.cloudfoundry.org/bytefmt v0.0.0
github.com/alecthomas/kong v0.7.1
github.com/aler9/gortsplib/v2 v2.2.2
github.com/asticode/go-astits v1.11.0
github.com/bluenviron/gohlslib v0.0.0-20230331102633-868d71cf3d3b
github.com/bluenviron/gohlslib v0.1.1
github.com/bluenviron/gortsplib/v3 v3.0.0
github.com/bluenviron/mediacommon v0.2.0
github.com/fsnotify/fsnotify v1.6.0
github.com/gin-gonic/gin v1.9.0
github.com/google/uuid v1.3.0

10
go.sum

@ -4,16 +4,18 @@ github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2o @@ -4,16 +4,18 @@ github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2o
github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4=
github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/aler9/gortsplib/v2 v2.2.2 h1:tTw8pdKSOEjlZjjE1S4ftXPHJkYOqjNNv3hjQ0Nto9M=
github.com/aler9/gortsplib/v2 v2.2.2/go.mod h1:k6uBVHGwsIc/0L5SLLqWwi6bSJUb4VR0HfvncyHlKQI=
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/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.11.0 h1:GTHUXht0ZXAJXsVbsLIcyfHr1Bchi4QQwMARw2ZWAng=
github.com/asticode/go-astits v1.11.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI=
github.com/bluenviron/gohlslib v0.0.0-20230331102633-868d71cf3d3b h1:eFmp8pdtZ7GdpdLJnPu9XKpxzbTKaOiUc1zFPCaMc00=
github.com/bluenviron/gohlslib v0.0.0-20230331102633-868d71cf3d3b/go.mod h1:6tKammMhZsSSN5copPcn28MehHxqpaCzfeaKLHahhiQ=
github.com/bluenviron/gohlslib v0.1.1 h1:rUwMsILN8Wkxx9NxZYKx3CdDZIIuMpfVNe7IXLxe26A=
github.com/bluenviron/gohlslib v0.1.1/go.mod h1:jPRjSDyELabTOcVXkI/H3U3/sCMQZzpBL+8+GAlquPE=
github.com/bluenviron/gortsplib/v3 v3.0.0 h1:1H1+Z/U5VDgn30XhUO/BjJUbBoVxg/miMwSPs7I3BxI=
github.com/bluenviron/gortsplib/v3 v3.0.0/go.mod h1:hqJ4DffxUbzVj+PM9ilPwr0jlBMwqqoCe58eoLCHG+w=
github.com/bluenviron/mediacommon v0.2.0 h1:XEuIr8FA5bfzjsQhrITd6ILgN9JCl0e0Cu8IVFEp5Hk=
github.com/bluenviron/mediacommon v0.2.0/go.mod h1:t0dqPsWUTchyvib0MhixIwXEgvDX4V9G+I0GzWLQRb8=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA=
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=

2
internal/conf/authmethod.go

@ -6,7 +6,7 @@ import ( @@ -6,7 +6,7 @@ import (
"sort"
"strings"
"github.com/aler9/gortsplib/v2/pkg/headers"
"github.com/bluenviron/gortsplib/v3/pkg/headers"
)
// AuthMethods is the authMethods parameter.

4
internal/conf/conf.go

@ -11,9 +11,9 @@ import ( @@ -11,9 +11,9 @@ import (
"strings"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/headers"
"github.com/bluenviron/gohlslib"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/headers"
"golang.org/x/crypto/nacl/secretbox"
"gopkg.in/yaml.v2"

2
internal/conf/conf_test.go

@ -8,7 +8,7 @@ import ( @@ -8,7 +8,7 @@ import (
"testing"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/bluenviron/gortsplib/v3"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/nacl/secretbox"

2
internal/conf/path.go

@ -10,7 +10,7 @@ import ( @@ -10,7 +10,7 @@ import (
"strings"
"time"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/bluenviron/gortsplib/v3/pkg/url"
)
var rePathName = regexp.MustCompile(`^[0-9a-zA-Z_\-/\.~]+$`)

2
internal/conf/protocol.go

@ -6,7 +6,7 @@ import ( @@ -6,7 +6,7 @@ import (
"sort"
"strings"
"github.com/aler9/gortsplib/v2"
"github.com/bluenviron/gortsplib/v3"
)
// Protocol is a RTSP transport.

2
internal/conf/sourceprotocol.go

@ -4,7 +4,7 @@ import ( @@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"github.com/aler9/gortsplib/v2"
"github.com/bluenviron/gortsplib/v3"
)
// SourceProtocol is the sourceProtocol parameter.

22
internal/core/api_test.go

@ -13,17 +13,17 @@ import ( @@ -13,17 +13,17 @@ import (
"testing"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
"github.com/aler9/rtsp-simple-server/internal/rtmp"
)
var testFormatH264 = &format.H264{
var testFormatH264 = &formats.H264{
PayloadTyp: 96,
SPS: []byte{0x01, 0x02, 0x03, 0x04},
PPS: []byte{0x01, 0x02, 0x03, 0x04},
@ -32,7 +32,7 @@ var testFormatH264 = &format.H264{ @@ -32,7 +32,7 @@ var testFormatH264 = &format.H264{
var testMediaH264 = &media.Media{
Type: media.TypeVideo,
Formats: []format.Format{testFormatH264},
Formats: []formats.Format{testFormatH264},
}
func httpRequest(method string, ur string, in interface{}, out interface{}) error {
@ -211,7 +211,7 @@ func TestAPIPathsList(t *testing.T) { @@ -211,7 +211,7 @@ func TestAPIPathsList(t *testing.T) {
media0,
{
Type: media.TypeAudio,
Formats: []format.Format{&format.MPEG4Audio{
Formats: []formats.Format{&formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
@ -273,11 +273,11 @@ func TestAPIPathsList(t *testing.T) { @@ -273,11 +273,11 @@ func TestAPIPathsList(t *testing.T) {
medias := media.Medias{
{
Type: media.TypeVideo,
Formats: []format.Format{testFormatH264},
Formats: []formats.Format{testFormatH264},
},
{
Type: media.TypeAudio,
Formats: []format.Format{&format.MPEG4Audio{
Formats: []formats.Format{&formats.MPEG4Audio{
PayloadTyp: 97,
Config: &mpeg4audio.Config{
Type: 2,
@ -473,7 +473,7 @@ func TestAPIProtocolSpecificList(t *testing.T) { @@ -473,7 +473,7 @@ func TestAPIProtocolSpecificList(t *testing.T) {
err = conn.InitializeClient(u, true)
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{ // 1920x1080 baseline
0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02,
@ -683,7 +683,7 @@ func TestAPIKick(t *testing.T) { @@ -683,7 +683,7 @@ func TestAPIKick(t *testing.T) {
err = conn.InitializeClient(u, true)
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{ // 1920x1080 baseline
0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02,

2
internal/core/core.go

@ -9,7 +9,7 @@ import ( @@ -9,7 +9,7 @@ import (
"reflect"
"github.com/alecthomas/kong"
"github.com/aler9/gortsplib/v2"
"github.com/bluenviron/gortsplib/v3"
"github.com/gin-gonic/gin"
"github.com/aler9/rtsp-simple-server/internal/conf"

28
internal/core/core_test.go

@ -10,12 +10,12 @@ import ( @@ -10,12 +10,12 @@ import (
"testing"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/base"
"github.com/aler9/gortsplib/v2/pkg/headers"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/sdp"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/base"
"github.com/bluenviron/gortsplib/v3/pkg/headers"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/sdp"
"github.com/bluenviron/gortsplib/v3/pkg/url"
"github.com/stretchr/testify/require"
)
@ -129,7 +129,7 @@ func TestCorePathAutoDeletion(t *testing.T) { @@ -129,7 +129,7 @@ func TestCorePathAutoDeletion(t *testing.T) {
require.NoError(t, err)
var res base.Response
err = res.Read(br)
err = res.Unmarshal(br)
require.NoError(t, err)
require.Equal(t, base.StatusNotFound, res.StatusCode)
} else {
@ -159,7 +159,7 @@ func TestCorePathAutoDeletion(t *testing.T) { @@ -159,7 +159,7 @@ func TestCorePathAutoDeletion(t *testing.T) {
require.NoError(t, err)
var res base.Response
err = res.Read(br)
err = res.Unmarshal(br)
require.NoError(t, err)
require.Equal(t, base.StatusNotFound, res.StatusCode)
}
@ -184,9 +184,9 @@ import ( @@ -184,9 +184,9 @@ import (
"os"
"os/signal"
"syscall"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
)
func main() {
@ -196,7 +196,7 @@ func main() { @@ -196,7 +196,7 @@ func main() {
medi := &media.Media{
Type: media.TypeVideo,
Formats: []format.Format{&format.H264{
Formats: []formats.Format{&formats.H264{
PayloadTyp: 96,
SPS: []byte{0x01, 0x02, 0x03, 0x04},
PPS: []byte{0x01, 0x02, 0x03, 0x04},
@ -273,7 +273,7 @@ func main() { @@ -273,7 +273,7 @@ func main() {
require.NoError(t, err)
var res base.Response
err = res.Read(br)
err = res.Unmarshal(br)
require.NoError(t, err)
require.Equal(t, base.StatusOK, res.StatusCode)
@ -308,7 +308,7 @@ func main() { @@ -308,7 +308,7 @@ func main() {
require.NoError(t, err)
var res base.Response
err = res.Read(br)
err = res.Unmarshal(br)
require.NoError(t, err)
require.Equal(t, base.StatusOK, res.StatusCode)
}

65
internal/core/hls_muxer.go

@ -15,10 +15,11 @@ import ( @@ -15,10 +15,11 @@ import (
"sync/atomic"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/ringbuffer"
"github.com/bluenviron/gohlslib/pkg/codecs"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/ringbuffer"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/gin-gonic/gin"
"github.com/aler9/rtsp-simple-server/internal/conf"
@ -281,12 +282,12 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{}) @@ -281,12 +282,12 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})
var medias media.Medias
videoMedia, videoFormat := m.setupVideoMedia(res.stream)
videoMedia, videoTrack := m.createVideoTrack(res.stream)
if videoMedia != nil {
medias = append(medias, videoMedia)
}
audioMedia, audioFormat := m.setupAudioMedia(res.stream)
audioMedia, audioTrack := m.createAudioTrack(res.stream)
if audioMedia != nil {
medias = append(medias, audioMedia)
}
@ -311,8 +312,8 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{}) @@ -311,8 +312,8 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})
SegmentDuration: time.Duration(m.segmentDuration),
PartDuration: time.Duration(m.partDuration),
SegmentMaxSize: uint64(m.segmentMaxSize),
VideoTrack: videoFormat,
AudioTrack: audioFormat,
VideoTrack: videoTrack,
AudioTrack: audioTrack,
Directory: muxerDirectory,
}
@ -358,8 +359,8 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{}) @@ -358,8 +359,8 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})
}
}
func (m *hlsMuxer) setupVideoMedia(stream *stream) (*media.Media, format.Format) {
var videoFormatH265 *format.H265
func (m *hlsMuxer) createVideoTrack(stream *stream) (*media.Media, *gohlslib.Track) {
var videoFormatH265 *formats.H265
videoMedia := stream.medias().FindFormat(&videoFormatH265)
if videoFormatH265 != nil {
@ -389,10 +390,18 @@ func (m *hlsMuxer) setupVideoMedia(stream *stream) (*media.Media, format.Format) @@ -389,10 +390,18 @@ func (m *hlsMuxer) setupVideoMedia(stream *stream) (*media.Media, format.Format)
})
})
return videoMedia, videoFormatH265
vps, sps, pps := videoFormatH265.SafeParams()
return videoMedia, &gohlslib.Track{
Codec: &codecs.H265{
VPS: vps,
SPS: sps,
PPS: pps,
},
}
}
var videoFormatH264 *format.H264
var videoFormatH264 *formats.H264
videoMedia = stream.medias().FindFormat(&videoFormatH264)
if videoFormatH264 != nil {
@ -422,14 +431,21 @@ func (m *hlsMuxer) setupVideoMedia(stream *stream) (*media.Media, format.Format) @@ -422,14 +431,21 @@ func (m *hlsMuxer) setupVideoMedia(stream *stream) (*media.Media, format.Format)
})
})
return videoMedia, videoFormatH264
sps, pps := videoFormatH264.SafeParams()
return videoMedia, &gohlslib.Track{
Codec: &codecs.H264{
SPS: sps,
PPS: pps,
},
}
}
return nil, nil
}
func (m *hlsMuxer) setupAudioMedia(stream *stream) (*media.Media, format.Format) {
var audioFormatMPEG4Audio *format.MPEG4Audio
func (m *hlsMuxer) createAudioTrack(stream *stream) (*media.Media, *gohlslib.Track) {
var audioFormatMPEG4Audio *formats.MPEG4Audio
audioMedia := stream.medias().FindFormat(&audioFormatMPEG4Audio)
if audioFormatMPEG4Audio != nil {
@ -465,10 +481,14 @@ func (m *hlsMuxer) setupAudioMedia(stream *stream) (*media.Media, format.Format) @@ -465,10 +481,14 @@ func (m *hlsMuxer) setupAudioMedia(stream *stream) (*media.Media, format.Format)
})
})
return audioMedia, audioFormatMPEG4Audio
return audioMedia, &gohlslib.Track{
Codec: &codecs.MPEG4Audio{
Config: *audioFormatMPEG4Audio.Config,
},
}
}
var audioFormatOpus *format.Opus
var audioFormatOpus *formats.Opus
audioMedia = stream.medias().FindFormat(&audioFormatOpus)
if audioFormatOpus != nil {
@ -497,7 +517,16 @@ func (m *hlsMuxer) setupAudioMedia(stream *stream) (*media.Media, format.Format) @@ -497,7 +517,16 @@ func (m *hlsMuxer) setupAudioMedia(stream *stream) (*media.Media, format.Format)
})
})
return audioMedia, audioFormatOpus
return audioMedia, &gohlslib.Track{
Codec: &codecs.Opus{
Channels: func() int {
if audioFormatOpus.IsStereo {
return 2
}
return 1
}(),
},
}
}
return nil, nil

76
internal/core/hls_source.go

@ -4,13 +4,14 @@ import ( @@ -4,13 +4,14 @@ import (
"context"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gohlslib"
"github.com/bluenviron/gohlslib/pkg/codecs"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/formatprocessor"
"github.com/aler9/rtsp-simple-server/internal/logger"
"github.com/bluenviron/gohlslib"
)
type hlsSourceParent interface {
@ -53,22 +54,26 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -53,22 +54,26 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
},
}
c.OnTracks(func(tracks []format.Format) error {
c.OnTracks(func(tracks []*gohlslib.Track) error {
var medias media.Medias
for _, track := range tracks {
medi := &media.Media{
Formats: []format.Format{track},
}
medias = append(medias, medi)
cformat := track
switch track.(type) {
case *format.H264:
medi.Type = media.TypeVideo
var medi *media.Media
switch tcodec := track.Codec.(type) {
case *codecs.H264:
medi = &media.Media{
Type: media.TypeVideo,
Formats: []formats.Format{&formats.H264{
PayloadTyp: 96,
PacketizationMode: 1,
SPS: tcodec.SPS,
PPS: tcodec.PPS,
}},
}
c.OnData(track, func(pts time.Duration, unit interface{}) {
err := stream.writeData(medi, cformat, &formatprocessor.UnitH264{
err := stream.writeData(medi, medi.Formats[0], &formatprocessor.UnitH264{
PTS: pts,
AU: unit.([][]byte),
NTP: time.Now(),
@ -78,11 +83,19 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -78,11 +83,19 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
})
case *format.H265:
medi.Type = media.TypeVideo
case *codecs.H265:
medi = &media.Media{
Type: media.TypeVideo,
Formats: []formats.Format{&formats.H265{
PayloadTyp: 96,
VPS: tcodec.VPS,
SPS: tcodec.SPS,
PPS: tcodec.PPS,
}},
}
c.OnData(track, func(pts time.Duration, unit interface{}) {
err := stream.writeData(medi, cformat, &formatprocessor.UnitH265{
err := stream.writeData(medi, medi.Formats[0], &formatprocessor.UnitH265{
PTS: pts,
AU: unit.([][]byte),
NTP: time.Now(),
@ -92,11 +105,20 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -92,11 +105,20 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
})
case *format.MPEG4Audio:
medi.Type = media.TypeAudio
case *codecs.MPEG4Audio:
medi = &media.Media{
Type: media.TypeAudio,
Formats: []formats.Format{&formats.MPEG4Audio{
PayloadTyp: 96,
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
Config: &tcodec.Config,
}},
}
c.OnData(track, func(pts time.Duration, unit interface{}) {
err := stream.writeData(medi, cformat, &formatprocessor.UnitMPEG4Audio{
err := stream.writeData(medi, medi.Formats[0], &formatprocessor.UnitMPEG4Audio{
PTS: pts,
AUs: [][]byte{unit.([]byte)},
NTP: time.Now(),
@ -106,11 +128,17 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -106,11 +128,17 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
})
case *format.Opus:
medi.Type = media.TypeAudio
case *codecs.Opus:
medi = &media.Media{
Type: media.TypeAudio,
Formats: []formats.Format{&formats.Opus{
PayloadTyp: 96,
IsStereo: (tcodec.Channels == 2),
}},
}
c.OnData(track, func(pts time.Duration, unit interface{}) {
err := stream.writeData(medi, cformat, &formatprocessor.UnitOpus{
err := stream.writeData(medi, medi.Formats[0], &formatprocessor.UnitOpus{
PTS: pts,
Frame: unit.([]byte),
NTP: time.Now(),
@ -120,6 +148,8 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -120,6 +148,8 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
})
}
medias = append(medias, medi)
}
res := s.parent.sourceStaticImplSetReady(pathSourceStaticSetReadyReq{

20
internal/core/hls_source_test.go

@ -8,13 +8,13 @@ import ( @@ -8,13 +8,13 @@ import (
"net/http"
"testing"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/asticode/go-astits"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/url"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/gin-gonic/gin"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
@ -250,8 +250,8 @@ func TestHLSSource(t *testing.T) { @@ -250,8 +250,8 @@ func TestHLSSource(t *testing.T) {
{
Type: media.TypeVideo,
Control: medias[0].Control,
Formats: []format.Format{
&format.H264{
Formats: []formats.Format{
&formats.H264{
PayloadTyp: 96,
PacketizationMode: 1,
},
@ -260,8 +260,8 @@ func TestHLSSource(t *testing.T) { @@ -260,8 +260,8 @@ func TestHLSSource(t *testing.T) {
{
Type: media.TypeAudio,
Control: medias[1].Control,
Formats: []format.Format{
&format.MPEG4Audio{
Formats: []formats.Format{
&formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,

8
internal/core/metrics_test.go

@ -9,9 +9,9 @@ import ( @@ -9,9 +9,9 @@ import (
"os"
"testing"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/stretchr/testify/require"
"github.com/aler9/rtsp-simple-server/internal/rtmp"
@ -62,7 +62,7 @@ func TestMetrics(t *testing.T) { @@ -62,7 +62,7 @@ func TestMetrics(t *testing.T) {
err = conn.InitializeClient(u, true)
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{ // 1920x1080 baseline
0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02,

6
internal/core/path.go

@ -10,9 +10,9 @@ import ( @@ -10,9 +10,9 @@ import (
"sync/atomic"
"time"
"github.com/aler9/gortsplib/v2/pkg/base"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/bluenviron/gortsplib/v3/pkg/base"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/url"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/externalcmd"

6
internal/core/rpicamera_source.go

@ -4,8 +4,8 @@ import ( @@ -4,8 +4,8 @@ import (
"context"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/formatprocessor"
@ -75,7 +75,7 @@ func (s *rpiCameraSource) Log(level logger.Level, format string, args ...interfa @@ -75,7 +75,7 @@ func (s *rpiCameraSource) Log(level logger.Level, format string, args ...interfa
func (s *rpiCameraSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan *conf.PathConf) error {
medi := &media.Media{
Type: media.TypeVideo,
Formats: []format.Format{&format.H264{
Formats: []formats.Format{&formats.H264{
PayloadTyp: 96,
PacketizationMode: 1,
}},

20
internal/core/rtmp_conn.go

@ -10,11 +10,11 @@ import ( @@ -10,11 +10,11 @@ import (
"sync"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/ringbuffer"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/ringbuffer"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/google/uuid"
"github.com/notedit/rtmp/format/flv/flvio"
@ -252,12 +252,12 @@ func (c *rtmpConn) runRead(ctx context.Context, u *url.URL) error { @@ -252,12 +252,12 @@ func (c *rtmpConn) runRead(ctx context.Context, u *url.URL) error {
c.state = rtmpConnStateRead
c.stateMutex.Unlock()
var videoFormat *format.H264
var videoFormat *formats.H264
videoMedia := res.stream.medias().FindFormat(&videoFormat)
videoFirstIDRFound := false
var videoStartDTS time.Duration
var audioFormat *format.MPEG4Audio
var audioFormat *formats.MPEG4Audio
audioMedia := res.stream.medias().FindFormat(&audioFormat)
if videoFormat == nil && audioFormat == nil {
@ -509,7 +509,7 @@ func (c *rtmpConn) runPublish(ctx context.Context, u *url.URL) error { @@ -509,7 +509,7 @@ func (c *rtmpConn) runPublish(ctx context.Context, u *url.URL) error {
if videoFormat != nil {
videoMedia = &media.Media{
Type: media.TypeVideo,
Formats: []format.Format{videoFormat},
Formats: []formats.Format{videoFormat},
}
medias = append(medias, videoMedia)
}
@ -517,7 +517,7 @@ func (c *rtmpConn) runPublish(ctx context.Context, u *url.URL) error { @@ -517,7 +517,7 @@ func (c *rtmpConn) runPublish(ctx context.Context, u *url.URL) error {
if audioFormat != nil {
audioMedia = &media.Media{
Type: media.TypeAudio,
Formats: []format.Format{audioFormat},
Formats: []formats.Format{audioFormat},
}
medias = append(medias, audioMedia)
}
@ -540,7 +540,7 @@ func (c *rtmpConn) runPublish(ctx context.Context, u *url.URL) error { @@ -540,7 +540,7 @@ func (c *rtmpConn) runPublish(ctx context.Context, u *url.URL) error {
var onVideoData func(time.Duration, [][]byte)
if _, ok := videoFormat.(*format.H264); ok {
if _, ok := videoFormat.(*formats.H264); ok {
onVideoData = func(pts time.Duration, au [][]byte) {
err = rres.stream.writeData(videoMedia, videoFormat, &formatprocessor.UnitH264{
PTS: pts,

16
internal/core/rtmp_server_test.go

@ -8,8 +8,8 @@ import ( @@ -8,8 +8,8 @@ import (
"testing"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/notedit/rtmp/format/flv/flvio"
"github.com/stretchr/testify/require"
@ -100,7 +100,7 @@ func TestRTMPServerPublishRead(t *testing.T) { @@ -100,7 +100,7 @@ func TestRTMPServerPublishRead(t *testing.T) {
err = conn1.InitializeClient(u, true)
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{ // 1920x1080 baseline
0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02,
@ -111,7 +111,7 @@ func TestRTMPServerPublishRead(t *testing.T) { @@ -111,7 +111,7 @@ func TestRTMPServerPublishRead(t *testing.T) {
PacketizationMode: 1,
}
audioTrack := &format.MPEG4Audio{
audioTrack := &formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
@ -224,7 +224,7 @@ func TestRTMPServerAuth(t *testing.T) { @@ -224,7 +224,7 @@ func TestRTMPServerAuth(t *testing.T) {
err = conn1.InitializeClient(u1, true)
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
@ -289,7 +289,7 @@ func TestRTMPServerAuthFail(t *testing.T) { @@ -289,7 +289,7 @@ func TestRTMPServerAuthFail(t *testing.T) {
err = conn1.InitializeClient(u1, true)
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
@ -344,7 +344,7 @@ func TestRTMPServerAuthFail(t *testing.T) { @@ -344,7 +344,7 @@ func TestRTMPServerAuthFail(t *testing.T) {
err = conn1.InitializeClient(u1, true)
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
@ -399,7 +399,7 @@ func TestRTMPServerAuthFail(t *testing.T) { @@ -399,7 +399,7 @@ func TestRTMPServerAuthFail(t *testing.T) {
err = conn1.InitializeClient(u1, true)
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,

12
internal/core/rtmp_source.go

@ -11,9 +11,9 @@ import ( @@ -11,9 +11,9 @@ import (
"strings"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/notedit/rtmp/format/flv/flvio"
"github.com/aler9/rtsp-simple-server/internal/conf"
@ -116,7 +116,7 @@ func (s *rtmpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -116,7 +116,7 @@ func (s *rtmpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
return err
}
if _, ok := videoFormat.(*format.H265); ok {
if _, ok := videoFormat.(*formats.H265); ok {
return fmt.Errorf("proxying H265 streams with RTMP is not supported")
}
@ -127,7 +127,7 @@ func (s *rtmpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -127,7 +127,7 @@ func (s *rtmpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
if videoFormat != nil {
videoMedia = &media.Media{
Type: media.TypeVideo,
Formats: []format.Format{videoFormat},
Formats: []formats.Format{videoFormat},
}
medias = append(medias, videoMedia)
}
@ -135,7 +135,7 @@ func (s *rtmpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -135,7 +135,7 @@ func (s *rtmpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
if audioFormat != nil {
audioMedia = &media.Media{
Type: media.TypeAudio,
Formats: []format.Format{audioFormat},
Formats: []formats.Format{audioFormat},
}
medias = append(medias, audioMedia)
}

12
internal/core/rtmp_source_test.go

@ -6,10 +6,10 @@ import ( @@ -6,10 +6,10 @@ import (
"os"
"testing"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/url"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/notedit/rtmp/format/flv/flvio"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
@ -59,7 +59,7 @@ func TestRTMPSource(t *testing.T) { @@ -59,7 +59,7 @@ func TestRTMPSource(t *testing.T) {
_, _, err = conn.InitializeServer()
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{ // 1920x1080 baseline
0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02,
@ -70,7 +70,7 @@ func TestRTMPSource(t *testing.T) { @@ -70,7 +70,7 @@ func TestRTMPSource(t *testing.T) {
PacketizationMode: 1,
}
audioTrack := &format.MPEG4Audio{
audioTrack := &formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,

10
internal/core/rtsp_conn.go

@ -6,11 +6,11 @@ import ( @@ -6,11 +6,11 @@ import (
"net"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/auth"
"github.com/aler9/gortsplib/v2/pkg/base"
"github.com/aler9/gortsplib/v2/pkg/headers"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/auth"
"github.com/bluenviron/gortsplib/v3/pkg/base"
"github.com/bluenviron/gortsplib/v3/pkg/headers"
"github.com/bluenviron/gortsplib/v3/pkg/url"
"github.com/google/uuid"
"github.com/aler9/rtsp-simple-server/internal/conf"

14
internal/core/rtsp_server.go

@ -8,10 +8,10 @@ import ( @@ -8,10 +8,10 @@ import (
"sync"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/base"
"github.com/aler9/gortsplib/v2/pkg/headers"
"github.com/aler9/gortsplib/v2/pkg/liberrors"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/base"
"github.com/bluenviron/gortsplib/v3/pkg/headers"
"github.com/bluenviron/gortsplib/v3/pkg/liberrors"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/externalcmd"
@ -351,10 +351,10 @@ func (s *rtspServer) OnPause(ctx *gortsplib.ServerHandlerOnPauseCtx) (*base.Resp @@ -351,10 +351,10 @@ func (s *rtspServer) OnPause(ctx *gortsplib.ServerHandlerOnPauseCtx) (*base.Resp
return se.onPause(ctx)
}
// OnDecodeError implements gortsplib.ServerHandlerOnOnDecodeError.
func (s *rtspServer) OnDecodeError(ctx *gortsplib.ServerHandlerOnDecodeErrorCtx) {
// OnDecodeError implements gortsplib.ServerHandlerOnWarning.
func (s *rtspServer) OnWarning(ctx *gortsplib.ServerHandlerOnWarningCtx) {
se := ctx.Session.UserData().(*rtspSession)
se.onDecodeError(ctx)
se.onWarning(ctx)
}
// apiConnsList is called by api and metrics.

6
internal/core/rtsp_server_test.go

@ -5,9 +5,9 @@ import ( @@ -5,9 +5,9 @@ import (
"testing"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/url"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
)

24
internal/core/rtsp_session.go

@ -8,10 +8,10 @@ import ( @@ -8,10 +8,10 @@ import (
"sync"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/base"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/base"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/url"
"github.com/google/uuid"
"github.com/pion/rtp"
@ -325,7 +325,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R @@ -325,7 +325,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R
cformat := forma
switch forma.(type) {
case *format.H264:
case *formats.H264:
ctx.Session.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := s.stream.writeData(cmedia, cformat, &formatprocessor.UnitH264{
RTPPackets: []*rtp.Packet{pkt},
@ -336,7 +336,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R @@ -336,7 +336,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R
}
})
case *format.H265:
case *formats.H265:
ctx.Session.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := s.stream.writeData(cmedia, cformat, &formatprocessor.UnitH265{
RTPPackets: []*rtp.Packet{pkt},
@ -347,7 +347,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R @@ -347,7 +347,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R
}
})
case *format.VP8:
case *formats.VP8:
ctx.Session.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := s.stream.writeData(cmedia, cformat, &formatprocessor.UnitVP8{
RTPPackets: []*rtp.Packet{pkt},
@ -358,7 +358,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R @@ -358,7 +358,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R
}
})
case *format.VP9:
case *formats.VP9:
ctx.Session.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := s.stream.writeData(cmedia, cformat, &formatprocessor.UnitVP9{
RTPPackets: []*rtp.Packet{pkt},
@ -369,7 +369,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R @@ -369,7 +369,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R
}
})
case *format.MPEG4Audio:
case *formats.MPEG4Audio:
ctx.Session.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := s.stream.writeData(cmedia, cformat, &formatprocessor.UnitMPEG4Audio{
RTPPackets: []*rtp.Packet{pkt},
@ -380,7 +380,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R @@ -380,7 +380,7 @@ func (s *rtspSession) onRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R
}
})
case *format.Opus:
case *formats.Opus:
ctx.Session.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := s.stream.writeData(cmedia, cformat, &formatprocessor.UnitOpus{
RTPPackets: []*rtp.Packet{pkt},
@ -470,7 +470,7 @@ func (s *rtspSession) apiSourceDescribe() interface{} { @@ -470,7 +470,7 @@ func (s *rtspSession) apiSourceDescribe() interface{} {
}{typ, s.uuid.String()}
}
// onDecodeError is called by rtspServer.
func (s *rtspSession) onDecodeError(ctx *gortsplib.ServerHandlerOnDecodeErrorCtx) {
// onWarning is called by rtspServer.
func (s *rtspSession) onWarning(ctx *gortsplib.ServerHandlerOnWarningCtx) {
s.log(logger.Warn, "%v", ctx.Error)
}

20
internal/core/rtsp_source.go

@ -9,15 +9,15 @@ import ( @@ -9,15 +9,15 @@ import (
"strings"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/base"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/base"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/pion/rtp"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/formatprocessor"
"github.com/aler9/rtsp-simple-server/internal/logger"
"github.com/bluenviron/gortsplib/v3/pkg/url"
)
type rtspSourceParent interface {
@ -137,7 +137,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -137,7 +137,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
cformat := forma
switch forma.(type) {
case *format.H264:
case *formats.H264:
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := res.stream.writeData(cmedia, cformat, &formatprocessor.UnitH264{
RTPPackets: []*rtp.Packet{pkt},
@ -148,7 +148,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -148,7 +148,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
}
})
case *format.H265:
case *formats.H265:
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := res.stream.writeData(cmedia, cformat, &formatprocessor.UnitH265{
RTPPackets: []*rtp.Packet{pkt},
@ -159,7 +159,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -159,7 +159,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
}
})
case *format.VP8:
case *formats.VP8:
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := res.stream.writeData(cmedia, cformat, &formatprocessor.UnitVP8{
RTPPackets: []*rtp.Packet{pkt},
@ -170,7 +170,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -170,7 +170,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
}
})
case *format.VP9:
case *formats.VP9:
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := res.stream.writeData(cmedia, cformat, &formatprocessor.UnitVP9{
RTPPackets: []*rtp.Packet{pkt},
@ -181,7 +181,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -181,7 +181,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
}
})
case *format.MPEG4Audio:
case *formats.MPEG4Audio:
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := res.stream.writeData(cmedia, cformat, &formatprocessor.UnitMPEG4Audio{
RTPPackets: []*rtp.Packet{pkt},
@ -192,7 +192,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha @@ -192,7 +192,7 @@ func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf cha
}
})
case *format.Opus:
case *formats.Opus:
c.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {
err := res.stream.writeData(cmedia, cformat, &formatprocessor.UnitOpus{
RTPPackets: []*rtp.Packet{pkt},

10
internal/core/rtsp_source_test.go

@ -6,11 +6,11 @@ import ( @@ -6,11 +6,11 @@ import (
"testing"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/auth"
"github.com/aler9/gortsplib/v2/pkg/base"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/url"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/auth"
"github.com/bluenviron/gortsplib/v3/pkg/base"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/url"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
)

2
internal/core/source.go

@ -4,7 +4,7 @@ import ( @@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/media"
)
// source is an entity that can provide a stream.

10
internal/core/stream.go

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
package core
import (
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/aler9/rtsp-simple-server/internal/formatprocessor"
)
@ -46,7 +46,7 @@ func (s *stream) medias() media.Medias { @@ -46,7 +46,7 @@ func (s *stream) medias() media.Medias {
return s.rtspStream.Medias()
}
func (s *stream) readerAdd(r reader, medi *media.Media, forma format.Format, cb func(formatprocessor.Unit)) {
func (s *stream) readerAdd(r reader, medi *media.Media, forma formats.Format, cb func(formatprocessor.Unit)) {
sm := s.smedias[medi]
sf := sm.formats[forma]
sf.readerAdd(r, cb)
@ -60,7 +60,7 @@ func (s *stream) readerRemove(r reader) { @@ -60,7 +60,7 @@ func (s *stream) readerRemove(r reader) {
}
}
func (s *stream) writeData(medi *media.Media, forma format.Format, data formatprocessor.Unit) error {
func (s *stream) writeData(medi *media.Media, forma formats.Format, data formatprocessor.Unit) error {
sm := s.smedias[medi]
sf := sm.formats[forma]
return sf.writeData(s, medi, data)

6
internal/core/stream_format.go

@ -4,8 +4,8 @@ import ( @@ -4,8 +4,8 @@ import (
"sync"
"sync/atomic"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/aler9/rtsp-simple-server/internal/formatprocessor"
)
@ -18,7 +18,7 @@ type streamFormat struct { @@ -18,7 +18,7 @@ type streamFormat struct {
func newStreamFormat(
udpMaxPayloadSize int,
forma format.Format,
forma formats.Format,
generateRTPPackets bool,
) (*streamFormat, error) {
proc, err := formatprocessor.New(udpMaxPayloadSize, forma, generateRTPPackets)

8
internal/core/stream_media.go

@ -1,12 +1,12 @@ @@ -1,12 +1,12 @@
package core
import (
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
)
type streamMedia struct {
formats map[format.Format]*streamFormat
formats map[formats.Format]*streamFormat
}
func newStreamMedia(udpMaxPayloadSize int,
@ -14,7 +14,7 @@ func newStreamMedia(udpMaxPayloadSize int, @@ -14,7 +14,7 @@ func newStreamMedia(udpMaxPayloadSize int,
generateRTPPackets bool,
) (*streamMedia, error) {
sm := &streamMedia{
formats: make(map[format.Format]*streamFormat),
formats: make(map[formats.Format]*streamFormat),
}
for _, forma := range medi.Formats {

72
internal/core/udp_source.go

@ -6,12 +6,12 @@ import ( @@ -6,12 +6,12 @@ import (
"net"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/asticode/go-astits"
"github.com/bluenviron/gohlslib/pkg/mpegts"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/bluenviron/mediacommon/pkg/formats/mpegts"
"golang.org/x/net/ipv4"
"github.com/aler9/rtsp-simple-server/internal/conf"
@ -173,15 +173,17 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -173,15 +173,17 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
var stream *stream
for _, track := range tracks {
medi := &media.Media{
Formats: []format.Format{track.Format},
}
medias = append(medias, medi)
cformat := track.Format
switch track.Format.(type) {
case *format.H264:
medi.Type = media.TypeVideo
var medi *media.Media
switch tcodec := track.Codec.(type) {
case *mpegts.CodecH264:
medi = &media.Media{
Type: media.TypeVideo,
Formats: []formats.Format{&formats.H264{
PayloadTyp: 96,
PacketizationMode: 1,
}},
}
mediaCallbacks[track.ES.ElementaryPID] = func(pts time.Duration, data []byte) {
au, err := h264.AnnexBUnmarshal(data)
@ -190,7 +192,7 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -190,7 +192,7 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
return
}
err = stream.writeData(medi, cformat, &formatprocessor.UnitH264{
err = stream.writeData(medi, medi.Formats[0], &formatprocessor.UnitH264{
PTS: pts,
AU: au,
NTP: time.Now(),
@ -200,8 +202,13 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -200,8 +202,13 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
}
case *format.H265:
medi.Type = media.TypeVideo
case *mpegts.CodecH265:
medi = &media.Media{
Type: media.TypeVideo,
Formats: []formats.Format{&formats.H265{
PayloadTyp: 96,
}},
}
mediaCallbacks[track.ES.ElementaryPID] = func(pts time.Duration, data []byte) {
au, err := h264.AnnexBUnmarshal(data)
@ -210,7 +217,7 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -210,7 +217,7 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
return
}
err = stream.writeData(medi, cformat, &formatprocessor.UnitH265{
err = stream.writeData(medi, medi.Formats[0], &formatprocessor.UnitH265{
PTS: pts,
AU: au,
NTP: time.Now(),
@ -220,8 +227,17 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -220,8 +227,17 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
}
case *format.MPEG4Audio:
medi.Type = media.TypeAudio
case *mpegts.CodecMPEG4Audio:
medi = &media.Media{
Type: media.TypeAudio,
Formats: []formats.Format{&formats.MPEG4Audio{
PayloadTyp: 96,
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
Config: &tcodec.Config,
}},
}
mediaCallbacks[track.ES.ElementaryPID] = func(pts time.Duration, data []byte) {
var pkts mpeg4audio.ADTSPackets
@ -236,7 +252,7 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -236,7 +252,7 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
aus[i] = pkt.AU
}
err = stream.writeData(medi, cformat, &formatprocessor.UnitMPEG4Audio{
err = stream.writeData(medi, medi.Formats[0], &formatprocessor.UnitMPEG4Audio{
PTS: pts,
AUs: aus,
NTP: time.Now(),
@ -246,8 +262,14 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -246,8 +262,14 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
}
case *format.Opus:
medi.Type = media.TypeAudio
case *mpegts.CodecOpus:
medi = &media.Media{
Type: media.TypeAudio,
Formats: []formats.Format{&formats.Opus{
PayloadTyp: 96,
IsStereo: (tcodec.Channels == 2),
}},
}
mediaCallbacks[track.ES.ElementaryPID] = func(pts time.Duration, data []byte) {
pos := 0
@ -261,7 +283,7 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -261,7 +283,7 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
pos += n
err = stream.writeData(medi, cformat, &formatprocessor.UnitOpus{
err = stream.writeData(medi, medi.Formats[0], &formatprocessor.UnitOpus{
PTS: pts,
Frame: au.Frame,
NTP: time.Now(),
@ -278,6 +300,8 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -278,6 +300,8 @@ func (s *udpSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
}
}
medias = append(medias, medi)
}
res := s.parent.sourceStaticImplSetReady(pathSourceStaticSetReadyReq{

354
internal/core/webrtc_conn.go

@ -14,12 +14,12 @@ import ( @@ -14,12 +14,12 @@ import (
"sync"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtph264"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtpvp8"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtpvp9"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/aler9/gortsplib/v2/pkg/ringbuffer"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtph264"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpvp8"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpvp9"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/gortsplib/v3/pkg/ringbuffer"
"github.com/google/uuid"
"github.com/pion/ice/v2"
"github.com/pion/interceptor"
@ -64,7 +64,7 @@ func newPeerConnection(configuration webrtc.Configuration, @@ -64,7 +64,7 @@ func newPeerConnection(configuration webrtc.Configuration,
type webRTCTrack struct {
media *media.Media
format format.Format
format formats.Format
webRTCTrack *webrtc.TrackLocalStaticRTP
cb func(formatprocessor.Unit, context.Context, chan error)
}
@ -306,11 +306,31 @@ func (c *webRTCConn) runInner(ctx context.Context) error { @@ -306,11 +306,31 @@ func (c *webRTCConn) runInner(ctx context.Context) error {
path.readerRemove(pathReaderRemoveReq{author: c})
}()
tracks, err := c.allocateTracks(res.stream.medias())
var tracks []*webRTCTrack
videoTrack, err := c.createVideoTrack(res.stream.medias())
if err != nil {
return err
}
if videoTrack != nil {
tracks = append(tracks, videoTrack)
}
audioTrack, err := c.createAudioTrack(res.stream.medias())
if err != nil {
return err
}
if audioTrack != nil {
tracks = append(tracks, audioTrack)
}
if tracks == nil {
return fmt.Errorf(
"the stream doesn't contain any supported codec (which are currently VP9, VP8, H264, Opus, G722, G711)")
}
err = c.wsconn.WriteJSON(c.genICEServers())
if err != nil {
return err
@ -538,10 +558,8 @@ outer: @@ -538,10 +558,8 @@ outer:
}
}
func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error) {
var ret []*webRTCTrack
var vp9Format *format.VP9
func (c *webRTCConn) createVideoTrack(medias media.Medias) (*webRTCTrack, error) {
var vp9Format *formats.VP9
vp9Media := medias.FindFormat(&vp9Format)
if vp9Format != nil {
@ -563,7 +581,7 @@ func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error) @@ -563,7 +581,7 @@ func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error)
}
encoder.Init()
ret = append(ret, &webRTCTrack{
return &webRTCTrack{
media: vp9Media,
format: vp9Format,
webRTCTrack: webRTCTrak,
@ -583,122 +601,121 @@ func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error) @@ -583,122 +601,121 @@ func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error)
webRTCTrak.WriteRTP(pkt)
}
},
})
}, nil
}
var vp8Format *format.VP8
if vp9Format == nil {
vp8Media := medias.FindFormat(&vp8Format)
var vp8Format *formats.VP8
vp8Media := medias.FindFormat(&vp8Format)
if vp8Format != nil {
webRTCTrak, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeVP8,
ClockRate: uint32(vp8Format.ClockRate()),
},
"vp8",
"rtspss",
)
if err != nil {
return nil, err
}
if vp8Format != nil {
webRTCTrak, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeVP8,
ClockRate: uint32(vp8Format.ClockRate()),
},
"vp8",
"rtspss",
)
if err != nil {
return nil, err
}
encoder := &rtpvp8.Encoder{
PayloadType: 96,
PayloadMaxSize: webrtcPayloadMaxSize,
}
encoder.Init()
encoder := &rtpvp8.Encoder{
PayloadType: 96,
PayloadMaxSize: webrtcPayloadMaxSize,
}
encoder.Init()
ret = append(ret, &webRTCTrack{
media: vp8Media,
format: vp8Format,
webRTCTrack: webRTCTrak,
cb: func(unit formatprocessor.Unit, ctx context.Context, writeError chan error) {
tunit := unit.(*formatprocessor.UnitVP8)
return &webRTCTrack{
media: vp8Media,
format: vp8Format,
webRTCTrack: webRTCTrak,
cb: func(unit formatprocessor.Unit, ctx context.Context, writeError chan error) {
tunit := unit.(*formatprocessor.UnitVP8)
if tunit.Frame == nil {
return
}
if tunit.Frame == nil {
return
}
packets, err := encoder.Encode(tunit.Frame, tunit.PTS)
if err != nil {
return
}
packets, err := encoder.Encode(tunit.Frame, tunit.PTS)
if err != nil {
return
}
for _, pkt := range packets {
webRTCTrak.WriteRTP(pkt)
}
},
})
}
for _, pkt := range packets {
webRTCTrak.WriteRTP(pkt)
}
},
}, nil
}
if vp9Format == nil && vp8Format == nil {
var h264Format *format.H264
h264Media := medias.FindFormat(&h264Format)
var h264Format *formats.H264
h264Media := medias.FindFormat(&h264Format)
if h264Format != nil {
webRTCTrak, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeH264,
ClockRate: uint32(h264Format.ClockRate()),
},
"h264",
"rtspss",
)
if err != nil {
return nil, err
}
if h264Format != nil {
webRTCTrak, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeH264,
ClockRate: uint32(h264Format.ClockRate()),
},
"h264",
"rtspss",
)
if err != nil {
return nil, err
}
encoder := &rtph264.Encoder{
PayloadType: 96,
PayloadMaxSize: webrtcPayloadMaxSize,
}
encoder.Init()
encoder := &rtph264.Encoder{
PayloadType: 96,
PayloadMaxSize: webrtcPayloadMaxSize,
}
encoder.Init()
var lastPTS time.Duration
firstNALUReceived := false
var lastPTS time.Duration
firstNALUReceived := false
ret = append(ret, &webRTCTrack{
media: h264Media,
format: h264Format,
webRTCTrack: webRTCTrak,
cb: func(unit formatprocessor.Unit, ctx context.Context, writeError chan error) {
tunit := unit.(*formatprocessor.UnitH264)
return &webRTCTrack{
media: h264Media,
format: h264Format,
webRTCTrack: webRTCTrak,
cb: func(unit formatprocessor.Unit, ctx context.Context, writeError chan error) {
tunit := unit.(*formatprocessor.UnitH264)
if tunit.AU == nil {
return
}
if tunit.AU == nil {
return
}
if !firstNALUReceived {
firstNALUReceived = true
lastPTS = tunit.PTS
} else {
if tunit.PTS < lastPTS {
select {
case writeError <- fmt.Errorf("WebRTC doesn't support H264 streams with B-frames"):
case <-ctx.Done():
}
return
if !firstNALUReceived {
firstNALUReceived = true
lastPTS = tunit.PTS
} else {
if tunit.PTS < lastPTS {
select {
case writeError <- fmt.Errorf("WebRTC doesn't support H264 streams with B-frames"):
case <-ctx.Done():
}
lastPTS = tunit.PTS
}
packets, err := encoder.Encode(tunit.AU, tunit.PTS)
if err != nil {
return
}
lastPTS = tunit.PTS
}
for _, pkt := range packets {
webRTCTrak.WriteRTP(pkt)
}
},
})
}
packets, err := encoder.Encode(tunit.AU, tunit.PTS)
if err != nil {
return
}
for _, pkt := range packets {
webRTCTrak.WriteRTP(pkt)
}
},
}, nil
}
var opusFormat *format.Opus
return nil, nil
}
func (c *webRTCConn) createAudioTrack(medias media.Medias) (*webRTCTrack, error) {
var opusFormat *formats.Opus
opusMedia := medias.FindFormat(&opusFormat)
if opusFormat != nil {
@ -714,7 +731,7 @@ func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error) @@ -714,7 +731,7 @@ func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error)
return nil, err
}
ret = append(ret, &webRTCTrack{
return &webRTCTrack{
media: opusMedia,
format: opusFormat,
webRTCTrack: webRTCTrak,
@ -723,84 +740,73 @@ func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error) @@ -723,84 +740,73 @@ func (c *webRTCConn) allocateTracks(medias media.Medias) ([]*webRTCTrack, error)
webRTCTrak.WriteRTP(pkt)
}
},
})
}, nil
}
var g722Format *format.G722
if opusFormat == nil {
g722Media := medias.FindFormat(&g722Format)
if g722Format != nil {
webRTCTrak, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeG722,
ClockRate: uint32(g722Format.ClockRate()),
},
"g722",
"rtspss",
)
if err != nil {
return nil, err
}
var g722Format *formats.G722
g722Media := medias.FindFormat(&g722Format)
ret = append(ret, &webRTCTrack{
media: g722Media,
format: g722Format,
webRTCTrack: webRTCTrak,
cb: func(unit formatprocessor.Unit, ctx context.Context, writeError chan error) {
for _, pkt := range unit.GetRTPPackets() {
webRTCTrak.WriteRTP(pkt)
}
},
})
if g722Format != nil {
webRTCTrak, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeG722,
ClockRate: uint32(g722Format.ClockRate()),
},
"g722",
"rtspss",
)
if err != nil {
return nil, err
}
}
var g711Format *format.G711
if opusFormat == nil && g722Format == nil {
g711Media := medias.FindFormat(&g711Format)
return &webRTCTrack{
media: g722Media,
format: g722Format,
webRTCTrack: webRTCTrak,
cb: func(unit formatprocessor.Unit, ctx context.Context, writeError chan error) {
for _, pkt := range unit.GetRTPPackets() {
webRTCTrak.WriteRTP(pkt)
}
},
}, nil
}
if g711Format != nil {
var mtyp string
if g711Format.MULaw {
mtyp = webrtc.MimeTypePCMU
} else {
mtyp = webrtc.MimeTypePCMA
}
var g711Format *formats.G711
g711Media := medias.FindFormat(&g711Format)
webRTCTrak, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: mtyp,
ClockRate: uint32(g711Format.ClockRate()),
},
"g711",
"rtspss",
)
if err != nil {
return nil, err
}
if g711Format != nil {
var mtyp string
if g711Format.MULaw {
mtyp = webrtc.MimeTypePCMU
} else {
mtyp = webrtc.MimeTypePCMA
}
ret = append(ret, &webRTCTrack{
media: g711Media,
format: g711Format,
webRTCTrack: webRTCTrak,
cb: func(unit formatprocessor.Unit, ctx context.Context, writeError chan error) {
for _, pkt := range unit.GetRTPPackets() {
webRTCTrak.WriteRTP(pkt)
}
},
})
webRTCTrak, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: mtyp,
ClockRate: uint32(g711Format.ClockRate()),
},
"g711",
"rtspss",
)
if err != nil {
return nil, err
}
}
if ret == nil {
return nil, fmt.Errorf(
"the stream doesn't contain any supported codec (which are currently VP9, VP8, H264, Opus, G722, G711)")
return &webRTCTrack{
media: g711Media,
format: g711Format,
webRTCTrack: webRTCTrak,
cb: func(unit formatprocessor.Unit, ctx context.Context, writeError chan error) {
for _, pkt := range unit.GetRTPPackets() {
webRTCTrak.WriteRTP(pkt)
}
},
}, nil
}
return ret, nil
return nil, nil
}
func (c *webRTCConn) genICEServers() []webrtc.ICEServer {

8
internal/core/webrtc_server_test.go

@ -6,9 +6,9 @@ import ( @@ -6,9 +6,9 @@ import (
"testing"
"time"
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/media"
"github.com/bluenviron/gortsplib/v3"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/gorilla/websocket"
"github.com/pion/rtp"
"github.com/pion/webrtc/v3"
@ -184,7 +184,7 @@ func TestWebRTCServer(t *testing.T) { @@ -184,7 +184,7 @@ func TestWebRTCServer(t *testing.T) {
medi := &media.Media{
Type: media.TypeVideo,
Formats: []format.Format{&format.H264{
Formats: []formats.Format{&formats.H264{
PayloadTyp: 96,
PacketizationMode: 1,
}},

4
internal/formatprocessor/generic.go

@ -4,7 +4,7 @@ import ( @@ -4,7 +4,7 @@ import (
"fmt"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/pion/rtp"
)
@ -30,7 +30,7 @@ type formatProcessorGeneric struct { @@ -30,7 +30,7 @@ type formatProcessorGeneric struct {
func newGeneric(
udpMaxPayloadSize int,
forma format.Format,
forma formats.Format,
generateRTPPackets bool,
) (*formatProcessorGeneric, error) {
if generateRTPPackets {

4
internal/formatprocessor/generic_test.go

@ -3,13 +3,13 @@ package formatprocessor @@ -3,13 +3,13 @@ package formatprocessor
import (
"testing"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
)
func TestGenericRemovePadding(t *testing.T) {
forma := &format.Generic{
forma := &formats.Generic{
PayloadTyp: 96,
RTPMap: "private/90000",
}

59
internal/formatprocessor/h264.go

@ -4,9 +4,9 @@ import ( @@ -4,9 +4,9 @@ import (
"bytes"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtph264"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtph264"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/pion/rtp"
)
@ -87,7 +87,7 @@ func (d *UnitH264) GetNTP() time.Time { @@ -87,7 +87,7 @@ func (d *UnitH264) GetNTP() time.Time {
type formatProcessorH264 struct {
udpMaxPayloadSize int
format *format.H264
format *formats.H264
encoder *rtph264.Encoder
decoder *rtph264.Decoder
@ -95,7 +95,7 @@ type formatProcessorH264 struct { @@ -95,7 +95,7 @@ type formatProcessorH264 struct {
func newH264(
udpMaxPayloadSize int,
forma *format.H264,
forma *formats.H264,
allocateEncoder bool,
) (*formatProcessorH264, error) {
t := &formatProcessorH264{
@ -112,37 +112,56 @@ func newH264( @@ -112,37 +112,56 @@ func newH264(
func (t *formatProcessorH264) updateTrackParametersFromRTPPacket(pkt *rtp.Packet) {
sps, pps := rtpH264ExtractSPSPPS(pkt)
update := false
if sps != nil && !bytes.Equal(sps, t.format.SafeSPS()) {
t.format.SafeSetSPS(sps)
if sps != nil && !bytes.Equal(sps, t.format.SPS) {
update = true
}
if pps != nil && !bytes.Equal(pps, t.format.SafePPS()) {
t.format.SafeSetPPS(pps)
if pps != nil && !bytes.Equal(pps, t.format.PPS) {
update = true
}
if update {
if sps == nil {
sps = t.format.SPS
}
if pps == nil {
pps = t.format.PPS
}
t.format.SafeSetParams(sps, pps)
}
}
func (t *formatProcessorH264) updateTrackParametersFromNALUs(nalus [][]byte) {
sps := t.format.SPS
pps := t.format.PPS
update := false
for _, nalu := range nalus {
typ := h264.NALUType(nalu[0] & 0x1F)
switch typ {
case h264.NALUTypeSPS:
if !bytes.Equal(nalu, t.format.SafeSPS()) {
t.format.SafeSetSPS(nalu)
if !bytes.Equal(nalu, sps) {
sps = nalu
update = true
}
case h264.NALUTypePPS:
if !bytes.Equal(nalu, t.format.SafePPS()) {
t.format.SafeSetPPS(nalu)
if !bytes.Equal(nalu, pps) {
pps = nalu
update = true
}
}
}
if update {
t.format.SafeSetParams(sps, pps)
}
}
func (t *formatProcessorH264) remuxAccessUnit(nalus [][]byte) [][]byte {
var sps []byte
var pps []byte
addParameters := false
n := 0
@ -159,10 +178,8 @@ func (t *formatProcessorH264) remuxAccessUnit(nalus [][]byte) [][]byte { @@ -159,10 +178,8 @@ func (t *formatProcessorH264) remuxAccessUnit(nalus [][]byte) [][]byte {
case h264.NALUTypeIDR: // prepend parameters if there's at least an IDR
if !addParameters {
addParameters = true
sps = t.format.SafeSPS()
pps = t.format.SafePPS()
if sps != nil && pps != nil {
if t.format.SPS != nil && t.format.PPS != nil {
n += 2
}
}
@ -177,9 +194,9 @@ func (t *formatProcessorH264) remuxAccessUnit(nalus [][]byte) [][]byte { @@ -177,9 +194,9 @@ func (t *formatProcessorH264) remuxAccessUnit(nalus [][]byte) [][]byte {
filteredNALUs := make([][]byte, n)
i := 0
if addParameters && sps != nil && pps != nil {
filteredNALUs[0] = sps
filteredNALUs[1] = pps
if addParameters && t.format.SPS != nil && t.format.PPS != nil {
filteredNALUs[0] = t.format.SPS
filteredNALUs[1] = t.format.PPS
i = 2
}

10
internal/formatprocessor/h264_test.go

@ -4,14 +4,14 @@ import ( @@ -4,14 +4,14 @@ import (
"bytes"
"testing"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
)
func TestH264DynamicParams(t *testing.T) {
forma := &format.H264{
forma := &formats.H264{
PayloadTyp: 96,
PacketizationMode: 1,
}
@ -54,7 +54,7 @@ func TestH264DynamicParams(t *testing.T) { @@ -54,7 +54,7 @@ func TestH264DynamicParams(t *testing.T) {
}
func TestH264OversizedPackets(t *testing.T) {
forma := &format.H264{
forma := &formats.H264{
PayloadTyp: 96,
SPS: []byte{0x01, 0x02, 0x03, 0x04},
PPS: []byte{0x01, 0x02, 0x03, 0x04},
@ -153,7 +153,7 @@ func TestH264OversizedPackets(t *testing.T) { @@ -153,7 +153,7 @@ func TestH264OversizedPackets(t *testing.T) {
}
func TestH264EmptyPacket(t *testing.T) {
forma := &format.H264{
forma := &formats.H264{
PayloadTyp: 96,
PacketizationMode: 1,
}

77
internal/formatprocessor/h265.go

@ -4,9 +4,9 @@ import ( @@ -4,9 +4,9 @@ import (
"bytes"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/h265"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtph265"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtph265"
"github.com/bluenviron/mediacommon/pkg/codecs/h265"
"github.com/pion/rtp"
)
@ -94,7 +94,7 @@ func (d *UnitH265) GetNTP() time.Time { @@ -94,7 +94,7 @@ func (d *UnitH265) GetNTP() time.Time {
type formatProcessorH265 struct {
udpMaxPayloadSize int
format *format.H265
format *formats.H265
encoder *rtph265.Encoder
decoder *rtph265.Decoder
@ -102,7 +102,7 @@ type formatProcessorH265 struct { @@ -102,7 +102,7 @@ type formatProcessorH265 struct {
func newH265(
udpMaxPayloadSize int,
forma *format.H265,
forma *formats.H265,
allocateEncoder bool,
) (*formatProcessorH265, error) {
t := &formatProcessorH265{
@ -119,47 +119,70 @@ func newH265( @@ -119,47 +119,70 @@ func newH265(
func (t *formatProcessorH265) updateTrackParametersFromRTPPacket(pkt *rtp.Packet) {
vps, sps, pps := rtpH265ExtractVPSSPSPPS(pkt)
update := false
if vps != nil && !bytes.Equal(vps, t.format.SafeVPS()) {
t.format.SafeSetVPS(vps)
if vps != nil && !bytes.Equal(vps, t.format.VPS) {
update = true
}
if sps != nil && !bytes.Equal(sps, t.format.SafeSPS()) {
t.format.SafeSetSPS(sps)
if sps != nil && !bytes.Equal(sps, t.format.SPS) {
update = true
}
if pps != nil && !bytes.Equal(pps, t.format.SafePPS()) {
t.format.SafeSetPPS(pps)
if pps != nil && !bytes.Equal(pps, t.format.PPS) {
update = true
}
if update {
if vps == nil {
vps = t.format.VPS
}
if sps == nil {
sps = t.format.SPS
}
if pps == nil {
pps = t.format.PPS
}
t.format.SafeSetParams(vps, sps, pps)
}
}
func (t *formatProcessorH265) updateTrackParametersFromNALUs(nalus [][]byte) {
vps := t.format.VPS
sps := t.format.SPS
pps := t.format.PPS
update := false
for _, nalu := range nalus {
typ := h265.NALUType((nalu[0] >> 1) & 0b111111)
switch typ {
case h265.NALUType_VPS_NUT:
if !bytes.Equal(nalu, t.format.SafeVPS()) {
t.format.SafeSetVPS(nalu)
if !bytes.Equal(nalu, t.format.VPS) {
vps = nalu
update = true
}
case h265.NALUType_SPS_NUT:
if !bytes.Equal(nalu, t.format.SafePPS()) {
t.format.SafeSetSPS(nalu)
if !bytes.Equal(nalu, t.format.SPS) {
sps = nalu
update = true
}
case h265.NALUType_PPS_NUT:
if !bytes.Equal(nalu, t.format.SafePPS()) {
t.format.SafeSetPPS(nalu)
if !bytes.Equal(nalu, t.format.PPS) {
pps = nalu
update = true
}
}
}
if update {
t.format.SafeSetParams(vps, sps, pps)
}
}
func (t *formatProcessorH265) remuxAccessUnit(nalus [][]byte) [][]byte {
var vps []byte
var sps []byte
var pps []byte
addParameters := false
n := 0
@ -178,11 +201,7 @@ func (t *formatProcessorH265) remuxAccessUnit(nalus [][]byte) [][]byte { @@ -178,11 +201,7 @@ func (t *formatProcessorH265) remuxAccessUnit(nalus [][]byte) [][]byte {
if !addParameters {
addParameters = true
vps = t.format.SafeVPS()
sps = t.format.SafeSPS()
pps = t.format.SafePPS()
if vps != nil && sps != nil && pps != nil {
if t.format.VPS != nil && t.format.SPS != nil && t.format.PPS != nil {
n += 3
}
}
@ -197,10 +216,10 @@ func (t *formatProcessorH265) remuxAccessUnit(nalus [][]byte) [][]byte { @@ -197,10 +216,10 @@ func (t *formatProcessorH265) remuxAccessUnit(nalus [][]byte) [][]byte {
filteredNALUs := make([][]byte, n)
i := 0
if addParameters && vps != nil && sps != nil && pps != nil {
filteredNALUs[0] = vps
filteredNALUs[1] = sps
filteredNALUs[2] = pps
if addParameters && t.format.VPS != nil && t.format.SPS != nil && t.format.PPS != nil {
filteredNALUs[0] = t.format.VPS
filteredNALUs[1] = t.format.SPS
filteredNALUs[2] = t.format.PPS
i = 3
}

10
internal/formatprocessor/h265_test.go

@ -4,14 +4,14 @@ import ( @@ -4,14 +4,14 @@ import (
"bytes"
"testing"
"github.com/aler9/gortsplib/v2/pkg/codecs/h265"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/mediacommon/pkg/codecs/h265"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
)
func TestH265DynamicParams(t *testing.T) {
forma := &format.H265{
forma := &formats.H265{
PayloadTyp: 96,
}
@ -59,7 +59,7 @@ func TestH265DynamicParams(t *testing.T) { @@ -59,7 +59,7 @@ func TestH265DynamicParams(t *testing.T) {
}
func TestH265OversizedPackets(t *testing.T) {
forma := &format.H265{
forma := &formats.H265{
PayloadTyp: 96,
VPS: []byte{byte(h265.NALUType_VPS_NUT) << 1, 10, 11, 12},
SPS: []byte{byte(h265.NALUType_SPS_NUT) << 1, 13, 14, 15},
@ -146,7 +146,7 @@ func TestH265OversizedPackets(t *testing.T) { @@ -146,7 +146,7 @@ func TestH265OversizedPackets(t *testing.T) {
}
func TestH265EmptyPacket(t *testing.T) {
forma := &format.H265{
forma := &formats.H265{
PayloadTyp: 96,
}

8
internal/formatprocessor/mpeg4audio.go

@ -4,8 +4,8 @@ import ( @@ -4,8 +4,8 @@ import (
"fmt"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtpmpeg4audio"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpmpeg4audio"
"github.com/pion/rtp"
)
@ -29,14 +29,14 @@ func (d *UnitMPEG4Audio) GetNTP() time.Time { @@ -29,14 +29,14 @@ func (d *UnitMPEG4Audio) GetNTP() time.Time {
type formatProcessorMPEG4Audio struct {
udpMaxPayloadSize int
format *format.MPEG4Audio
format *formats.MPEG4Audio
encoder *rtpmpeg4audio.Encoder
decoder *rtpmpeg4audio.Decoder
}
func newMPEG4Audio(
udpMaxPayloadSize int,
forma *format.MPEG4Audio,
forma *formats.MPEG4Audio,
allocateEncoder bool,
) (*formatProcessorMPEG4Audio, error) {
t := &formatProcessorMPEG4Audio{

8
internal/formatprocessor/opus.go

@ -4,8 +4,8 @@ import ( @@ -4,8 +4,8 @@ import (
"fmt"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtpsimpleaudio"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpsimpleaudio"
"github.com/pion/rtp"
)
@ -29,14 +29,14 @@ func (d *UnitOpus) GetNTP() time.Time { @@ -29,14 +29,14 @@ func (d *UnitOpus) GetNTP() time.Time {
type formatProcessorOpus struct {
udpMaxPayloadSize int
format *format.Opus
format *formats.Opus
encoder *rtpsimpleaudio.Encoder
decoder *rtpsimpleaudio.Decoder
}
func newOpus(
udpMaxPayloadSize int,
forma *format.Opus,
forma *formats.Opus,
allocateEncoder bool,
) (*formatProcessorOpus, error) {
t := &formatProcessorOpus{

16
internal/formatprocessor/processor.go

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
package formatprocessor
import (
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
)
// Processor allows to cleanup and normalize streams.
@ -14,26 +14,26 @@ type Processor interface { @@ -14,26 +14,26 @@ type Processor interface {
// New allocates a Processor.
func New(
udpMaxPayloadSize int,
forma format.Format,
forma formats.Format,
generateRTPPackets bool,
) (Processor, error) {
switch forma := forma.(type) {
case *format.H264:
case *formats.H264:
return newH264(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.H265:
case *formats.H265:
return newH265(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.VP8:
case *formats.VP8:
return newVP8(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.VP9:
case *formats.VP9:
return newVP9(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.MPEG4Audio:
case *formats.MPEG4Audio:
return newMPEG4Audio(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.Opus:
case *formats.Opus:
return newOpus(udpMaxPayloadSize, forma, generateRTPPackets)
default:

8
internal/formatprocessor/vp8.go

@ -4,8 +4,8 @@ import ( @@ -4,8 +4,8 @@ import (
"fmt"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtpvp8"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpvp8"
"github.com/pion/rtp"
)
@ -29,14 +29,14 @@ func (d *UnitVP8) GetNTP() time.Time { @@ -29,14 +29,14 @@ func (d *UnitVP8) GetNTP() time.Time {
type formatProcessorVP8 struct {
udpMaxPayloadSize int
format *format.VP8
format *formats.VP8
encoder *rtpvp8.Encoder
decoder *rtpvp8.Decoder
}
func newVP8(
udpMaxPayloadSize int,
forma *format.VP8,
forma *formats.VP8,
allocateEncoder bool,
) (*formatProcessorVP8, error) {
t := &formatProcessorVP8{

8
internal/formatprocessor/vp9.go

@ -4,8 +4,8 @@ import ( @@ -4,8 +4,8 @@ import (
"fmt"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/gortsplib/v2/pkg/formatdecenc/rtpvp9"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpvp9"
"github.com/pion/rtp"
)
@ -29,14 +29,14 @@ func (d *UnitVP9) GetNTP() time.Time { @@ -29,14 +29,14 @@ func (d *UnitVP9) GetNTP() time.Time {
type formatProcessorVP9 struct {
udpMaxPayloadSize int
format *format.VP9
format *formats.VP9
encoder *rtpvp9.Encoder
decoder *rtpvp9.Decoder
}
func newVP9(
udpMaxPayloadSize int,
forma *format.VP9,
forma *formats.VP9,
allocateEncoder bool,
) (*formatProcessorVP9, error) {
t := &formatProcessorVP9{

2
internal/rpicamera/rpicamera.go

@ -16,7 +16,7 @@ import ( @@ -16,7 +16,7 @@ import (
"sync"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
)
const (

67
internal/rtmp/conn.go

@ -9,10 +9,10 @@ import ( @@ -9,10 +9,10 @@ import (
"strings"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/aler9/gortsplib/v2/pkg/codecs/h265"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/pkg/codecs/h265"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/notedit/rtmp/format/flv/flvio"
"github.com/aler9/rtsp-simple-server/internal/rtmp/bytecounter"
@ -584,14 +584,14 @@ func (c *Conn) WriteMessage(msg message.Message) error { @@ -584,14 +584,14 @@ func (c *Conn) WriteMessage(msg message.Message) error {
return c.mrw.Write(msg)
}
func trackFromH264DecoderConfig(data []byte) (format.Format, error) {
func trackFromH264DecoderConfig(data []byte) (formats.Format, error) {
var conf h264conf.Conf
err := conf.Unmarshal(data)
if err != nil {
return nil, fmt.Errorf("unable to parse H264 config: %v", err)
}
return &format.H264{
return &formats.H264{
PayloadTyp: 96,
SPS: conf.SPS,
PPS: conf.PPS,
@ -599,14 +599,14 @@ func trackFromH264DecoderConfig(data []byte) (format.Format, error) { @@ -599,14 +599,14 @@ func trackFromH264DecoderConfig(data []byte) (format.Format, error) {
}, nil
}
func trackFromAACDecoderConfig(data []byte) (*format.MPEG4Audio, error) {
func trackFromAACDecoderConfig(data []byte) (*formats.MPEG4Audio, error) {
var mpegConf mpeg4audio.Config
err := mpegConf.Unmarshal(data)
if err != nil {
return nil, err
}
return &format.MPEG4Audio{
return &formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpegConf,
SizeLength: 13,
@ -617,7 +617,7 @@ func trackFromAACDecoderConfig(data []byte) (*format.MPEG4Audio, error) { @@ -617,7 +617,7 @@ func trackFromAACDecoderConfig(data []byte) (*format.MPEG4Audio, error) {
var errEmptyMetadata = errors.New("metadata is empty")
func (c *Conn) readTracksFromMetadata(payload []interface{}) (format.Format, *format.MPEG4Audio, error) {
func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, *formats.MPEG4Audio, error) {
if len(payload) != 1 {
return nil, nil, fmt.Errorf("invalid metadata")
}
@ -687,8 +687,8 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (format.Format, *fo @@ -687,8 +687,8 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (format.Format, *fo
return nil, nil, errEmptyMetadata
}
var videoTrack format.Format
var audioTrack *format.MPEG4Audio
var videoTrack formats.Format
var audioTrack *formats.MPEG4Audio
for {
msg, err := c.ReadMessage()
@ -734,7 +734,7 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (format.Format, *fo @@ -734,7 +734,7 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (format.Format, *fo
}
if h265VPS != nil && h265SPS != nil && h265PPS != nil {
videoTrack = &format.H265{
videoTrack = &formats.H265{
PayloadTyp: 96,
VPS: h265VPS,
SPS: h265SPS,
@ -766,10 +766,10 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (format.Format, *fo @@ -766,10 +766,10 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (format.Format, *fo
}
}
func (c *Conn) readTracksFromMessages(msg message.Message) (format.Format, *format.MPEG4Audio, error) {
func (c *Conn) readTracksFromMessages(msg message.Message) (formats.Format, *formats.MPEG4Audio, error) {
var startTime *time.Duration
var videoTrack format.Format
var audioTrack *format.MPEG4Audio
var videoTrack formats.Format
var audioTrack *formats.MPEG4Audio
// analyze 1 second of packets
outer:
@ -842,7 +842,7 @@ outer: @@ -842,7 +842,7 @@ outer:
// ReadTracks reads track informations.
// It returns the video track and the audio track.
func (c *Conn) ReadTracks() (format.Format, *format.MPEG4Audio, error) {
func (c *Conn) ReadTracks() (formats.Format, *formats.MPEG4Audio, error) {
msg, err := func() (message.Message, error) {
for {
msg, err := c.ReadMessage()
@ -901,7 +901,7 @@ func (c *Conn) ReadTracks() (format.Format, *format.MPEG4Audio, error) { @@ -901,7 +901,7 @@ func (c *Conn) ReadTracks() (format.Format, *format.MPEG4Audio, error) {
}
// WriteTracks writes track informations.
func (c *Conn) WriteTracks(videoTrack *format.H264, audioTrack *format.MPEG4Audio) error {
func (c *Conn) WriteTracks(videoTrack *formats.H264, audioTrack *formats.MPEG4Audio) error {
err := c.WriteMessage(&message.MsgDataAMF0{
ChunkStreamID: 4,
MessageStreamID: 0x1000000,
@ -944,21 +944,24 @@ func (c *Conn) WriteTracks(videoTrack *format.H264, audioTrack *format.MPEG4Audi @@ -944,21 +944,24 @@ func (c *Conn) WriteTracks(videoTrack *format.H264, audioTrack *format.MPEG4Audi
// write decoder config only if SPS and PPS are available.
// if they're not available yet, they're sent later.
if videoTrack != nil && videoTrack.SafeSPS() != nil && videoTrack.SafePPS() != nil {
buf, _ := h264conf.Conf{
SPS: videoTrack.SafeSPS(),
PPS: videoTrack.SafePPS(),
}.Marshal()
err = c.WriteMessage(&message.MsgVideo{
ChunkStreamID: message.MsgVideoChunkStreamID,
MessageStreamID: 0x1000000,
IsKeyFrame: true,
H264Type: flvio.AVC_SEQHDR,
Payload: buf,
})
if err != nil {
return err
if videoTrack != nil {
sps, pps := videoTrack.SafeParams()
if sps != nil && pps != nil {
buf, _ := h264conf.Conf{
SPS: sps,
PPS: pps,
}.Marshal()
err = c.WriteMessage(&message.MsgVideo{
ChunkStreamID: message.MsgVideoChunkStreamID,
MessageStreamID: 0x1000000,
IsKeyFrame: true,
H264Type: flvio.AVC_SEQHDR,
Payload: buf,
})
if err != nil {
return err
}
}
}

36
internal/rtmp/conn_test.go

@ -7,9 +7,9 @@ import ( @@ -7,9 +7,9 @@ import (
"testing"
"time"
"github.com/aler9/gortsplib/v2/pkg/codecs/h264"
"github.com/aler9/gortsplib/v2/pkg/codecs/mpeg4audio"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/notedit/rtmp/format/flv/flvio"
"github.com/stretchr/testify/require"
@ -484,18 +484,18 @@ func TestReadTracks(t *testing.T) { @@ -484,18 +484,18 @@ func TestReadTracks(t *testing.T) {
for _, ca := range []struct {
name string
videoTrack format.Format
audioTrack format.Format
videoTrack formats.Format
audioTrack formats.Format
}{
{
"video+audio",
&format.H264{
&formats.H264{
PayloadTyp: 96,
SPS: sps,
PPS: pps,
PacketizationMode: 1,
},
&format.MPEG4Audio{
&formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
@ -509,23 +509,23 @@ func TestReadTracks(t *testing.T) { @@ -509,23 +509,23 @@ func TestReadTracks(t *testing.T) {
},
{
"video",
&format.H264{
&formats.H264{
PayloadTyp: 96,
SPS: sps,
PPS: pps,
PacketizationMode: 1,
},
(*format.MPEG4Audio)(nil),
(*formats.MPEG4Audio)(nil),
},
{
"metadata without codec id",
&format.H264{
&formats.H264{
PayloadTyp: 96,
SPS: sps,
PPS: pps,
PacketizationMode: 1,
},
&format.MPEG4Audio{
&formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
@ -539,13 +539,13 @@ func TestReadTracks(t *testing.T) { @@ -539,13 +539,13 @@ func TestReadTracks(t *testing.T) {
},
{
"missing metadata, video+audio",
&format.H264{
&formats.H264{
PayloadTyp: 96,
SPS: sps,
PPS: pps,
PacketizationMode: 1,
},
&format.MPEG4Audio{
&formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
@ -560,7 +560,7 @@ func TestReadTracks(t *testing.T) { @@ -560,7 +560,7 @@ func TestReadTracks(t *testing.T) {
{
"missing metadata, audio",
nil,
&format.MPEG4Audio{
&formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
@ -574,7 +574,7 @@ func TestReadTracks(t *testing.T) { @@ -574,7 +574,7 @@ func TestReadTracks(t *testing.T) {
},
{
"obs studio h265",
&format.H265{
&formats.H265{
PayloadTyp: 96,
VPS: []byte{
0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x40,
@ -595,7 +595,7 @@ func TestReadTracks(t *testing.T) { @@ -595,7 +595,7 @@ func TestReadTracks(t *testing.T) {
0x44, 0x01, 0xc0, 0xf7, 0xc0, 0xcc, 0x90,
},
},
&format.MPEG4Audio{
&formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
@ -1103,7 +1103,7 @@ func TestWriteTracks(t *testing.T) { @@ -1103,7 +1103,7 @@ func TestWriteTracks(t *testing.T) {
_, _, err = rconn.InitializeServer()
require.NoError(t, err)
videoTrack := &format.H264{
videoTrack := &formats.H264{
PayloadTyp: 96,
SPS: []byte{
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
@ -1116,7 +1116,7 @@ func TestWriteTracks(t *testing.T) { @@ -1116,7 +1116,7 @@ func TestWriteTracks(t *testing.T) {
PacketizationMode: 1,
}
audioTrack := &format.MPEG4Audio{
audioTrack := &formats.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,

Loading…
Cancel
Save