Browse Source

move units into dedicated package (#2245)

needed by #2244
pull/2248/head
Alessandro Ros 2 years ago committed by GitHub
parent
commit
e0fb11040e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      LICENSE
  2. 20
      README.md
  3. 30
      internal/core/hls_muxer.go
  4. 26
      internal/core/hls_source.go
  5. 6
      internal/core/rpicamera_source.go
  6. 42
      internal/core/rtmp_conn.go
  7. 14
      internal/core/rtmp_source.go
  8. 46
      internal/core/srt_conn.go
  9. 22
      internal/core/srt_source.go
  10. 22
      internal/core/udp_source.go
  11. 36
      internal/core/webrtc_outgoing_track.go
  12. 18
      internal/formatprocessor/av1.go
  13. 16
      internal/formatprocessor/generic.go
  14. 6
      internal/formatprocessor/generic_test.go
  15. 18
      internal/formatprocessor/h264.go
  16. 24
      internal/formatprocessor/h264_test.go
  17. 18
      internal/formatprocessor/h265.go
  18. 28
      internal/formatprocessor/h265_test.go
  19. 18
      internal/formatprocessor/mpeg1audio.go
  20. 18
      internal/formatprocessor/mpeg4audio_generic.go
  21. 18
      internal/formatprocessor/mpeg4audio_latm.go
  22. 18
      internal/formatprocessor/opus.go
  23. 5
      internal/formatprocessor/processor.go
  24. 32
      internal/formatprocessor/unit.go
  25. 18
      internal/formatprocessor/vp8.go
  26. 18
      internal/formatprocessor/vp9.go
  27. 6
      internal/stream/stream.go
  28. 9
      internal/stream/stream_format.go
  29. 12
      internal/unit/av1.go
  30. 23
      internal/unit/base.go
  31. 6
      internal/unit/generic.go
  32. 12
      internal/unit/h264.go
  33. 12
      internal/unit/h265.go
  34. 12
      internal/unit/mpeg1audio.go
  35. 12
      internal/unit/mpeg4audio_generic.go
  36. 12
      internal/unit/mpeg4audio_latm.go
  37. 12
      internal/unit/opus.go
  38. 17
      internal/unit/unit.go
  39. 12
      internal/unit/vp8.go
  40. 12
      internal/unit/vp9.go

2
LICENSE

@ -20,7 +20,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
src/internal/hls.min.js is Copyright (c) Dailymotion and is protected by internal/core/hls.min.js is Copyright (c) Dailymotion and is protected by
its own license (Apache License, Version 2.0) available at its own license (Apache License, Version 2.0) available at
https://github.com/video-dev/hls.js/blob/master/LICENSE https://github.com/video-dev/hls.js/blob/master/LICENSE

20
README.md

@ -565,7 +565,7 @@ srt://localhost:8890?streamid=publish:mystream:user:pass&pkt_size=1316
If you want to publish a stream by using a client in listening mode (i.e. with `mode=listener` appended to the URL), read the next section. If you want to publish a stream by using a client in listening mode (i.e. with `mode=listener` appended to the URL), read the next section.
Known clients that can publish with SRT are [FFmpeg](#ffmpeg), [Gstreamer](#gstreamer), [OBS Studio](#obs-studio). Known clients that can publish with SRT are [FFmpeg](#ffmpeg), [GStreamer](#gstreamer), [OBS Studio](#obs-studio).
#### SRT servers #### SRT servers
@ -596,7 +596,7 @@ http://localhost:8889/mystream/whip
Depending on the network it may be difficult to establish a connection between server and clients, see [WebRTC-specific features](#webrtc-specific-features) for remediations. Depending on the network it may be difficult to establish a connection between server and clients, see [WebRTC-specific features](#webrtc-specific-features) for remediations.
Known clients that can publish with WebRTC and WHIP are [FFmpeg](#ffmpeg), [Gstreamer](#gstreamer), [OBS Studio](#obs-studio). Known clients that can publish with WebRTC and WHIP are [FFmpeg](#ffmpeg), [GStreamer](#gstreamer), [OBS Studio](#obs-studio).
#### WebRTC servers #### WebRTC servers
@ -619,7 +619,7 @@ rtsp://localhost:8554/mystream
The resulting stream will be available in path `/mystream`. The resulting stream will be available in path `/mystream`.
Known clients that can publish with RTSP are [FFmpeg](#ffmpeg), [Gstreamer](#gstreamer), [OBS Studio](#obs-studio). Known clients that can publish with RTSP are [FFmpeg](#ffmpeg), [GStreamer](#gstreamer), [OBS Studio](#obs-studio).
#### RTSP cameras and servers #### RTSP cameras and servers
@ -661,7 +661,7 @@ In case authentication is enabled, credentials can be passed to the server by us
rtmp://localhost/mystream?user=myuser&pass=mypass rtmp://localhost/mystream?user=myuser&pass=mypass
``` ```
Known clients that can publish with RTMP are [FFmpeg](#ffmpeg), [Gstreamer](#gstreamer), [OBS Studio](#obs-studio). Known clients that can publish with RTMP are [FFmpeg](#ffmpeg), [GStreamer](#gstreamer), [OBS Studio](#obs-studio).
#### RTMP cameras and servers #### RTMP cameras and servers
@ -717,7 +717,7 @@ paths:
The resulting stream will be available in path `/mypath`. The resulting stream will be available in path `/mypath`.
Known clients that can publish with WebRTC and WHIP are [FFmpeg](#ffmpeg) and [Gstreamer](#gstreamer). Known clients that can publish with WebRTC and WHIP are [FFmpeg](#ffmpeg) and [GStreamer](#gstreamer).
## Read from the server ## Read from the server
@ -842,7 +842,7 @@ If credentials are enabled, append username and password to `streamid`;
srt://localhost:8890?streamid=publish:mystream:user:pass srt://localhost:8890?streamid=publish:mystream:user:pass
``` ```
Known clients that can read with SRT are [FFmpeg](#ffmpeg-1), [Gstreamer](#gstreamer-1) and [VLC](#vlc). Known clients that can read with SRT are [FFmpeg](#ffmpeg-1), [GStreamer](#gstreamer-1) and [VLC](#vlc).
#### WebRTC #### WebRTC
@ -860,7 +860,7 @@ http://localhost:8889/mystream/whep
Depending on the network it may be difficult to establish a connection between server and clients, see [WebRTC-specific features](#webrtc-specific-features) for remediations. Depending on the network it may be difficult to establish a connection between server and clients, see [WebRTC-specific features](#webrtc-specific-features) for remediations.
Known clients that can read with WebRTC and WHEP are [FFmpeg](#ffmpeg-1), [Gstreamer](#gstreamer-1) and [web browsers](#web-browsers-1). Known clients that can read with WebRTC and WHEP are [FFmpeg](#ffmpeg-1), [GStreamer](#gstreamer-1) and [web browsers](#web-browsers-1).
#### RTSP #### RTSP
@ -870,7 +870,7 @@ RTSP is a protocol that allows to publish and read streams. It supports differen
rtsp://localhost:8554/mystream rtsp://localhost:8554/mystream
``` ```
Known clients that can read with RTSP are [FFmpeg](#ffmpeg-1), [Gstreamer](#gstreamer-1) and [VLC](#vlc). Known clients that can read with RTSP are [FFmpeg](#ffmpeg-1), [GStreamer](#gstreamer-1) and [VLC](#vlc).
##### Latency ##### Latency
@ -894,7 +894,7 @@ In case authentication is enabled, credentials can be passed to the server by us
rtmp://localhost/mystream?user=myuser&pass=mypass rtmp://localhost/mystream?user=myuser&pass=mypass
``` ```
Known clients that can read with RTMP are [FFmpeg](#ffmpeg-1), [Gstreamer](#gstreamer-1) and [VLC](#vlc). Known clients that can read with RTMP are [FFmpeg](#ffmpeg-1), [GStreamer](#gstreamer-1) and [VLC](#vlc).
#### HLS #### HLS
@ -923,7 +923,7 @@ ffmpeg -i rtsp://original-source \
-f rtsp rtsp://localhost:8554/mystream -f rtsp rtsp://localhost:8554/mystream
``` ```
Known clients that can read with HLS are [FFmpeg](#ffmpeg-1), [Gstreamer](#gstreamer-1), [VLC](#vlc) and [web browsers](#web-browsers-1). Known clients that can read with HLS are [FFmpeg](#ffmpeg-1), [GStreamer](#gstreamer-1), [VLC](#vlc) and [web browsers](#web-browsers-1).
##### LL-HLS ##### LL-HLS

30
internal/core/hls_muxer.go

@ -19,9 +19,9 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
const ( const (
@ -343,9 +343,9 @@ func (m *hlsMuxer) createVideoTrack(stream *stream.Stream) (*media.Media, *gohls
startPTSFilled := false startPTSFilled := false
var startPTS time.Duration var startPTS time.Duration
stream.AddReader(m, videoMedia, videoFormatAV1, func(unit formatprocessor.Unit) { stream.AddReader(m, videoMedia, videoFormatAV1, func(u unit.Unit) {
m.ringBuffer.Push(func() error { m.ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitAV1) tunit := u.(*unit.AV1)
if tunit.TU == nil { if tunit.TU == nil {
return nil return nil
@ -378,9 +378,9 @@ func (m *hlsMuxer) createVideoTrack(stream *stream.Stream) (*media.Media, *gohls
startPTSFilled := false startPTSFilled := false
var startPTS time.Duration var startPTS time.Duration
stream.AddReader(m, videoMedia, videoFormatVP9, func(unit formatprocessor.Unit) { stream.AddReader(m, videoMedia, videoFormatVP9, func(u unit.Unit) {
m.ringBuffer.Push(func() error { m.ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitVP9) tunit := u.(*unit.VP9)
if tunit.Frame == nil { if tunit.Frame == nil {
return nil return nil
@ -413,9 +413,9 @@ func (m *hlsMuxer) createVideoTrack(stream *stream.Stream) (*media.Media, *gohls
startPTSFilled := false startPTSFilled := false
var startPTS time.Duration var startPTS time.Duration
stream.AddReader(m, videoMedia, videoFormatH265, func(unit formatprocessor.Unit) { stream.AddReader(m, videoMedia, videoFormatH265, func(u unit.Unit) {
m.ringBuffer.Push(func() error { m.ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitH265) tunit := u.(*unit.H265)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil
@ -454,9 +454,9 @@ func (m *hlsMuxer) createVideoTrack(stream *stream.Stream) (*media.Media, *gohls
startPTSFilled := false startPTSFilled := false
var startPTS time.Duration var startPTS time.Duration
stream.AddReader(m, videoMedia, videoFormatH264, func(unit formatprocessor.Unit) { stream.AddReader(m, videoMedia, videoFormatH264, func(u unit.Unit) {
m.ringBuffer.Push(func() error { m.ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitH264) tunit := u.(*unit.H264)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil
@ -498,9 +498,9 @@ func (m *hlsMuxer) createAudioTrack(stream *stream.Stream) (*media.Media, *gohls
audioStartPTSFilled := false audioStartPTSFilled := false
var audioStartPTS time.Duration var audioStartPTS time.Duration
stream.AddReader(m, audioMedia, audioFormatOpus, func(unit formatprocessor.Unit) { stream.AddReader(m, audioMedia, audioFormatOpus, func(u unit.Unit) {
m.ringBuffer.Push(func() error { m.ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitOpus) tunit := u.(*unit.Opus)
if !audioStartPTSFilled { if !audioStartPTSFilled {
audioStartPTSFilled = true audioStartPTSFilled = true
@ -539,9 +539,9 @@ func (m *hlsMuxer) createAudioTrack(stream *stream.Stream) (*media.Media, *gohls
audioStartPTSFilled := false audioStartPTSFilled := false
var audioStartPTS time.Duration var audioStartPTS time.Duration
stream.AddReader(m, audioMedia, audioFormatMPEG4AudioGeneric, func(unit formatprocessor.Unit) { stream.AddReader(m, audioMedia, audioFormatMPEG4AudioGeneric, func(u unit.Unit) {
m.ringBuffer.Push(func() error { m.ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitMPEG4AudioGeneric) tunit := u.(*unit.MPEG4AudioGeneric)
if tunit.AUs == nil { if tunit.AUs == nil {
return nil return nil
@ -582,9 +582,9 @@ func (m *hlsMuxer) createAudioTrack(stream *stream.Stream) (*media.Media, *gohls
audioStartPTSFilled := false audioStartPTSFilled := false
var audioStartPTS time.Duration var audioStartPTS time.Duration
stream.AddReader(m, audioMedia, audioFormatMPEG4AudioLATM, func(unit formatprocessor.Unit) { stream.AddReader(m, audioMedia, audioFormatMPEG4AudioLATM, func(u unit.Unit) {
m.ringBuffer.Push(func() error { m.ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitMPEG4AudioLATM) tunit := u.(*unit.MPEG4AudioLATM)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil

26
internal/core/hls_source.go

@ -11,9 +11,9 @@ import (
"github.com/bluenviron/gortsplib/v3/pkg/media" "github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
type hlsSourceParent interface { type hlsSourceParent interface {
@ -82,8 +82,8 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
} }
c.OnDataAV1(track, func(pts time.Duration, tu [][]byte) { c.OnDataAV1(track, func(pts time.Duration, tu [][]byte) {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitAV1{ stream.WriteUnit(medi, medi.Formats[0], &unit.AV1{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -98,8 +98,8 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
} }
c.OnDataVP9(track, func(pts time.Duration, frame []byte) { c.OnDataVP9(track, func(pts time.Duration, frame []byte) {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitVP9{ stream.WriteUnit(medi, medi.Formats[0], &unit.VP9{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -119,8 +119,8 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
} }
c.OnDataH26x(track, func(pts time.Duration, dts time.Duration, au [][]byte) { c.OnDataH26x(track, func(pts time.Duration, dts time.Duration, au [][]byte) {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH264{ stream.WriteUnit(medi, medi.Formats[0], &unit.H264{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -140,8 +140,8 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
} }
c.OnDataH26x(track, func(pts time.Duration, dts time.Duration, au [][]byte) { c.OnDataH26x(track, func(pts time.Duration, dts time.Duration, au [][]byte) {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH265{ stream.WriteUnit(medi, medi.Formats[0], &unit.H265{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -162,8 +162,8 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
} }
c.OnDataMPEG4Audio(track, func(pts time.Duration, aus [][]byte) { c.OnDataMPEG4Audio(track, func(pts time.Duration, aus [][]byte) {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitMPEG4AudioGeneric{ stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG4AudioGeneric{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -181,8 +181,8 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
} }
c.OnDataOpus(track, func(pts time.Duration, packets [][]byte) { c.OnDataOpus(track, func(pts time.Duration, packets [][]byte) {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitOpus{ stream.WriteUnit(medi, medi.Formats[0], &unit.Opus{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,

6
internal/core/rpicamera_source.go

@ -8,10 +8,10 @@ import (
"github.com/bluenviron/gortsplib/v3/pkg/media" "github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/rpicamera" "github.com/bluenviron/mediamtx/internal/rpicamera"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
func paramsFromConf(cnf *conf.PathConf) rpicamera.Params { func paramsFromConf(cnf *conf.PathConf) rpicamera.Params {
@ -98,8 +98,8 @@ func (s *rpiCameraSource) run(ctx context.Context, cnf *conf.PathConf, reloadCon
stream = res.stream stream = res.stream
} }
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH264{ stream.WriteUnit(medi, medi.Formats[0], &unit.H264{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: dts, PTS: dts,

42
internal/core/rtmp_conn.go

@ -20,10 +20,10 @@ import (
"github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/externalcmd" "github.com/bluenviron/mediamtx/internal/externalcmd"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/rtmp" "github.com/bluenviron/mediamtx/internal/rtmp"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
const ( const (
@ -338,9 +338,9 @@ func (c *rtmpConn) setupVideo(
var startPTS time.Duration var startPTS time.Duration
var videoDTSExtractor *h264.DTSExtractor var videoDTSExtractor *h264.DTSExtractor
stream.AddReader(c, videoMedia, videoFormatH264, func(unit formatprocessor.Unit) { stream.AddReader(c, videoMedia, videoFormatH264, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitH264) tunit := u.(*unit.H264)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil
@ -427,9 +427,9 @@ func (c *rtmpConn) setupAudio(
startPTSFilled := false startPTSFilled := false
var startPTS time.Duration var startPTS time.Duration
stream.AddReader(c, audioMedia, audioFormatMPEG4Generic, func(unit formatprocessor.Unit) { stream.AddReader(c, audioMedia, audioFormatMPEG4Generic, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitMPEG4AudioGeneric) tunit := u.(*unit.MPEG4AudioGeneric)
if tunit.AUs == nil { if tunit.AUs == nil {
return nil return nil
@ -481,9 +481,9 @@ func (c *rtmpConn) setupAudio(
startPTSFilled := false startPTSFilled := false
var startPTS time.Duration var startPTS time.Duration
stream.AddReader(c, audioMedia, audioFormatMPEG4AudioLATM, func(unit formatprocessor.Unit) { stream.AddReader(c, audioMedia, audioFormatMPEG4AudioLATM, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitMPEG4AudioLATM) tunit := u.(*unit.MPEG4AudioLATM)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil
@ -521,9 +521,9 @@ func (c *rtmpConn) setupAudio(
startPTSFilled := false startPTSFilled := false
var startPTS time.Duration var startPTS time.Duration
stream.AddReader(c, audioMedia, audioFormatMPEG1, func(unit formatprocessor.Unit) { stream.AddReader(c, audioMedia, audioFormatMPEG1, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitMPEG1Audio) tunit := u.(*unit.MPEG1Audio)
if !startPTSFilled { if !startPTSFilled {
startPTSFilled = true startPTSFilled = true
@ -624,8 +624,8 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
switch videoFormat.(type) { switch videoFormat.(type) {
case *formats.AV1: case *formats.AV1:
r.OnDataAV1(func(pts time.Duration, tu [][]byte) { r.OnDataAV1(func(pts time.Duration, tu [][]byte) {
stream.WriteUnit(videoMedia, videoFormat, &formatprocessor.UnitAV1{ stream.WriteUnit(videoMedia, videoFormat, &unit.AV1{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -635,8 +635,8 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
case *formats.VP9: case *formats.VP9:
r.OnDataVP9(func(pts time.Duration, frame []byte) { r.OnDataVP9(func(pts time.Duration, frame []byte) {
stream.WriteUnit(videoMedia, videoFormat, &formatprocessor.UnitVP9{ stream.WriteUnit(videoMedia, videoFormat, &unit.VP9{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -646,8 +646,8 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
case *formats.H265: case *formats.H265:
r.OnDataH265(func(pts time.Duration, au [][]byte) { r.OnDataH265(func(pts time.Duration, au [][]byte) {
stream.WriteUnit(videoMedia, videoFormat, &formatprocessor.UnitH265{ stream.WriteUnit(videoMedia, videoFormat, &unit.H265{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -657,8 +657,8 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
case *formats.H264: case *formats.H264:
r.OnDataH264(func(pts time.Duration, au [][]byte) { r.OnDataH264(func(pts time.Duration, au [][]byte) {
stream.WriteUnit(videoMedia, videoFormat, &formatprocessor.UnitH264{ stream.WriteUnit(videoMedia, videoFormat, &unit.H264{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -681,8 +681,8 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
switch audioFormat.(type) { switch audioFormat.(type) {
case *formats.MPEG4AudioGeneric: case *formats.MPEG4AudioGeneric:
r.OnDataMPEG4Audio(func(pts time.Duration, au []byte) { r.OnDataMPEG4Audio(func(pts time.Duration, au []byte) {
stream.WriteUnit(audioMedia, audioFormat, &formatprocessor.UnitMPEG4AudioGeneric{ stream.WriteUnit(audioMedia, audioFormat, &unit.MPEG4AudioGeneric{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -692,8 +692,8 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
case *formats.MPEG1Audio: case *formats.MPEG1Audio:
r.OnDataMPEG1Audio(func(pts time.Duration, frame []byte) { r.OnDataMPEG1Audio(func(pts time.Duration, frame []byte) {
stream.WriteUnit(audioMedia, audioFormat, &formatprocessor.UnitMPEG1Audio{ stream.WriteUnit(audioMedia, audioFormat, &unit.MPEG1Audio{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,

14
internal/core/rtmp_source.go

@ -12,10 +12,10 @@ import (
"github.com/bluenviron/gortsplib/v3/pkg/media" "github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/rtmp" "github.com/bluenviron/mediamtx/internal/rtmp"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
type rtmpSourceParent interface { type rtmpSourceParent interface {
@ -126,8 +126,8 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error {
switch videoFormat.(type) { switch videoFormat.(type) {
case *formats.H264: case *formats.H264:
mc.OnDataH264(func(pts time.Duration, au [][]byte) { mc.OnDataH264(func(pts time.Duration, au [][]byte) {
stream.WriteUnit(videoMedia, videoFormat, &formatprocessor.UnitH264{ stream.WriteUnit(videoMedia, videoFormat, &unit.H264{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -150,8 +150,8 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error {
switch audioFormat.(type) { switch audioFormat.(type) {
case *formats.MPEG4AudioGeneric: case *formats.MPEG4AudioGeneric:
mc.OnDataMPEG4Audio(func(pts time.Duration, au []byte) { mc.OnDataMPEG4Audio(func(pts time.Duration, au []byte) {
stream.WriteUnit(audioMedia, audioFormat, &formatprocessor.UnitMPEG4AudioGeneric{ stream.WriteUnit(audioMedia, audioFormat, &unit.MPEG4AudioGeneric{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,
@ -161,8 +161,8 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error {
case *formats.MPEG1Audio: case *formats.MPEG1Audio:
mc.OnDataMPEG1Audio(func(pts time.Duration, frame []byte) { mc.OnDataMPEG1Audio(func(pts time.Duration, frame []byte) {
stream.WriteUnit(audioMedia, audioFormat, &formatprocessor.UnitMPEG1Audio{ stream.WriteUnit(audioMedia, audioFormat, &unit.MPEG1Audio{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: pts, PTS: pts,

46
internal/core/srt_conn.go

@ -21,9 +21,9 @@ import (
"github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/externalcmd" "github.com/bluenviron/mediamtx/internal/externalcmd"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
func durationGoToMPEGTS(v time.Duration) int64 { func durationGoToMPEGTS(v time.Duration) int64 {
@ -260,8 +260,8 @@ func (c *srtConn) runPublishReader(sconn srt.Conn, path *path) error {
} }
r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error { r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH264{ stream.WriteUnit(medi, medi.Formats[0], &unit.H264{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -279,8 +279,8 @@ func (c *srtConn) runPublishReader(sconn srt.Conn, path *path) error {
} }
r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error { r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH265{ stream.WriteUnit(medi, medi.Formats[0], &unit.H265{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -302,8 +302,8 @@ func (c *srtConn) runPublishReader(sconn srt.Conn, path *path) error {
} }
r.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) error { r.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitMPEG4AudioGeneric{ stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG4AudioGeneric{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -322,8 +322,8 @@ func (c *srtConn) runPublishReader(sconn srt.Conn, path *path) error {
} }
r.OnDataOpus(track, func(pts int64, packets [][]byte) error { r.OnDataOpus(track, func(pts int64, packets [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitOpus{ stream.WriteUnit(medi, medi.Formats[0], &unit.Opus{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -339,8 +339,8 @@ func (c *srtConn) runPublishReader(sconn srt.Conn, path *path) error {
} }
r.OnDataMPEG1Audio(track, func(pts int64, frames [][]byte) error { r.OnDataMPEG1Audio(track, func(pts int64, frames [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitMPEG1Audio{ stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG1Audio{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -459,9 +459,9 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass
randomAccessReceived := false randomAccessReceived := false
dtsExtractor := h265.NewDTSExtractor() dtsExtractor := h265.NewDTSExtractor()
res.stream.AddReader(c, medi, format, func(unit formatprocessor.Unit) { res.stream.AddReader(c, medi, format, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitH265) tunit := u.(*unit.H265)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil
} }
@ -523,9 +523,9 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass
firstIDRReceived := false firstIDRReceived := false
dtsExtractor := h264.NewDTSExtractor() dtsExtractor := h264.NewDTSExtractor()
res.stream.AddReader(c, medi, format, func(unit formatprocessor.Unit) { res.stream.AddReader(c, medi, format, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitH264) tunit := u.(*unit.H264)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil
} }
@ -579,9 +579,9 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass
var startPTS time.Duration var startPTS time.Duration
startPTSFilled := false startPTSFilled := false
res.stream.AddReader(c, medi, format, func(unit formatprocessor.Unit) { res.stream.AddReader(c, medi, format, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitMPEG4AudioGeneric) tunit := u.(*unit.MPEG4AudioGeneric)
if tunit.AUs == nil { if tunit.AUs == nil {
return nil return nil
} }
@ -619,9 +619,9 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass
var startPTS time.Duration var startPTS time.Duration
startPTSFilled := false startPTSFilled := false
res.stream.AddReader(c, medi, format, func(unit formatprocessor.Unit) { res.stream.AddReader(c, medi, format, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitMPEG4AudioLATM) tunit := u.(*unit.MPEG4AudioLATM)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil
} }
@ -662,9 +662,9 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass
var startPTS time.Duration var startPTS time.Duration
startPTSFilled := false startPTSFilled := false
res.stream.AddReader(c, medi, format, func(unit formatprocessor.Unit) { res.stream.AddReader(c, medi, format, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitOpus) tunit := u.(*unit.Opus)
if tunit.Packets == nil { if tunit.Packets == nil {
return nil return nil
} }
@ -697,9 +697,9 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass
var startPTS time.Duration var startPTS time.Duration
startPTSFilled := false startPTSFilled := false
res.stream.AddReader(c, medi, format, func(unit formatprocessor.Unit) { res.stream.AddReader(c, medi, format, func(u unit.Unit) {
ringBuffer.Push(func() error { ringBuffer.Push(func() error {
tunit := unit.(*formatprocessor.UnitMPEG1Audio) tunit := u.(*unit.MPEG1Audio)
if tunit.Frames == nil { if tunit.Frames == nil {
return nil return nil
} }

22
internal/core/srt_source.go

@ -11,9 +11,9 @@ import (
"github.com/datarhei/gosrt" "github.com/datarhei/gosrt"
"github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
type srtSourceParent interface { type srtSourceParent interface {
@ -116,8 +116,8 @@ func (s *srtSource) runReader(sconn srt.Conn) error {
} }
r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error { r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH264{ stream.WriteUnit(medi, medi.Formats[0], &unit.H264{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -135,8 +135,8 @@ func (s *srtSource) runReader(sconn srt.Conn) error {
} }
r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error { r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH265{ stream.WriteUnit(medi, medi.Formats[0], &unit.H265{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -158,8 +158,8 @@ func (s *srtSource) runReader(sconn srt.Conn) error {
} }
r.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) error { r.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitMPEG4AudioGeneric{ stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG4AudioGeneric{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -178,8 +178,8 @@ func (s *srtSource) runReader(sconn srt.Conn) error {
} }
r.OnDataOpus(track, func(pts int64, packets [][]byte) error { r.OnDataOpus(track, func(pts int64, packets [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitOpus{ stream.WriteUnit(medi, medi.Formats[0], &unit.Opus{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -195,8 +195,8 @@ func (s *srtSource) runReader(sconn srt.Conn) error {
} }
r.OnDataMPEG1Audio(track, func(pts int64, frames [][]byte) error { r.OnDataMPEG1Audio(track, func(pts int64, frames [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitMPEG1Audio{ stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG1Audio{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),

22
internal/core/udp_source.go

@ -12,9 +12,9 @@ import (
"golang.org/x/net/ipv4" "golang.org/x/net/ipv4"
"github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
const ( const (
@ -165,8 +165,8 @@ func (s *udpSource) runReader(pc net.PacketConn) error {
} }
r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error { r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH264{ stream.WriteUnit(medi, medi.Formats[0], &unit.H264{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -184,8 +184,8 @@ func (s *udpSource) runReader(pc net.PacketConn) error {
} }
r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error { r.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitH265{ stream.WriteUnit(medi, medi.Formats[0], &unit.H265{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -207,8 +207,8 @@ func (s *udpSource) runReader(pc net.PacketConn) error {
} }
r.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) error { r.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitMPEG4AudioGeneric{ stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG4AudioGeneric{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -227,8 +227,8 @@ func (s *udpSource) runReader(pc net.PacketConn) error {
} }
r.OnDataOpus(track, func(pts int64, packets [][]byte) error { r.OnDataOpus(track, func(pts int64, packets [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitOpus{ stream.WriteUnit(medi, medi.Formats[0], &unit.Opus{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),
@ -244,8 +244,8 @@ func (s *udpSource) runReader(pc net.PacketConn) error {
} }
r.OnDataMPEG1Audio(track, func(pts int64, frames [][]byte) error { r.OnDataMPEG1Audio(track, func(pts int64, frames [][]byte) error {
stream.WriteUnit(medi, medi.Formats[0], &formatprocessor.UnitMPEG1Audio{ stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG1Audio{
BaseUnit: formatprocessor.BaseUnit{ Base: unit.Base{
NTP: time.Now(), NTP: time.Now(),
}, },
PTS: decodeTime(pts), PTS: decodeTime(pts),

36
internal/core/webrtc_outgoing_track.go

@ -14,8 +14,8 @@ import (
"github.com/bluenviron/gortsplib/v3/pkg/ringbuffer" "github.com/bluenviron/gortsplib/v3/pkg/ringbuffer"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/stream"
"github.com/bluenviron/mediamtx/internal/unit"
) )
type webRTCOutgoingTrack struct { type webRTCOutgoingTrack struct {
@ -23,7 +23,7 @@ type webRTCOutgoingTrack struct {
media *media.Media media *media.Media
format formats.Format format formats.Format
track *webrtc.TrackLocalStaticRTP track *webrtc.TrackLocalStaticRTP
cb func(formatprocessor.Unit) error cb func(unit.Unit) error
} }
func newWebRTCOutgoingTrackVideo(medias media.Medias) (*webRTCOutgoingTrack, error) { func newWebRTCOutgoingTrackVideo(medias media.Medias) (*webRTCOutgoingTrack, error) {
@ -56,8 +56,8 @@ func newWebRTCOutgoingTrackVideo(medias media.Medias) (*webRTCOutgoingTrack, err
media: videoMedia, media: videoMedia,
format: av1Format, format: av1Format,
track: webRTCTrak, track: webRTCTrak,
cb: func(unit formatprocessor.Unit) error { cb: func(u unit.Unit) error {
tunit := unit.(*formatprocessor.UnitAV1) tunit := u.(*unit.AV1)
if tunit.TU == nil { if tunit.TU == nil {
return nil return nil
@ -106,8 +106,8 @@ func newWebRTCOutgoingTrackVideo(medias media.Medias) (*webRTCOutgoingTrack, err
media: videoMedia, media: videoMedia,
format: vp9Format, format: vp9Format,
track: webRTCTrak, track: webRTCTrak,
cb: func(unit formatprocessor.Unit) error { cb: func(u unit.Unit) error {
tunit := unit.(*formatprocessor.UnitVP9) tunit := u.(*unit.VP9)
if tunit.Frame == nil { if tunit.Frame == nil {
return nil return nil
@ -156,8 +156,8 @@ func newWebRTCOutgoingTrackVideo(medias media.Medias) (*webRTCOutgoingTrack, err
media: videoMedia, media: videoMedia,
format: vp8Format, format: vp8Format,
track: webRTCTrak, track: webRTCTrak,
cb: func(unit formatprocessor.Unit) error { cb: func(u unit.Unit) error {
tunit := unit.(*formatprocessor.UnitVP8) tunit := u.(*unit.VP8)
if tunit.Frame == nil { if tunit.Frame == nil {
return nil return nil
@ -209,8 +209,8 @@ func newWebRTCOutgoingTrackVideo(medias media.Medias) (*webRTCOutgoingTrack, err
media: videoMedia, media: videoMedia,
format: h264Format, format: h264Format,
track: webRTCTrak, track: webRTCTrak,
cb: func(unit formatprocessor.Unit) error { cb: func(u unit.Unit) error {
tunit := unit.(*formatprocessor.UnitH264) tunit := u.(*unit.H264)
if tunit.AU == nil { if tunit.AU == nil {
return nil return nil
@ -265,8 +265,8 @@ func newWebRTCOutgoingTrackAudio(medias media.Medias) (*webRTCOutgoingTrack, err
media: audioMedia, media: audioMedia,
format: opusFormat, format: opusFormat,
track: webRTCTrak, track: webRTCTrak,
cb: func(unit formatprocessor.Unit) error { cb: func(u unit.Unit) error {
for _, pkt := range unit.GetRTPPackets() { for _, pkt := range u.GetRTPPackets() {
webRTCTrak.WriteRTP(pkt) //nolint:errcheck webRTCTrak.WriteRTP(pkt) //nolint:errcheck
} }
@ -295,8 +295,8 @@ func newWebRTCOutgoingTrackAudio(medias media.Medias) (*webRTCOutgoingTrack, err
media: audioMedia, media: audioMedia,
format: g722Format, format: g722Format,
track: webRTCTrak, track: webRTCTrak,
cb: func(unit formatprocessor.Unit) error { cb: func(u unit.Unit) error {
for _, pkt := range unit.GetRTPPackets() { for _, pkt := range u.GetRTPPackets() {
webRTCTrak.WriteRTP(pkt) //nolint:errcheck webRTCTrak.WriteRTP(pkt) //nolint:errcheck
} }
@ -332,8 +332,8 @@ func newWebRTCOutgoingTrackAudio(medias media.Medias) (*webRTCOutgoingTrack, err
media: audioMedia, media: audioMedia,
format: g711Format, format: g711Format,
track: webRTCTrak, track: webRTCTrak,
cb: func(unit formatprocessor.Unit) error { cb: func(u unit.Unit) error {
for _, pkt := range unit.GetRTPPackets() { for _, pkt := range u.GetRTPPackets() {
webRTCTrak.WriteRTP(pkt) //nolint:errcheck webRTCTrak.WriteRTP(pkt) //nolint:errcheck
} }
@ -363,9 +363,9 @@ func (t *webRTCOutgoingTrack) start(
} }
}() }()
stream.AddReader(r, t.media, t.format, func(unit formatprocessor.Unit) { stream.AddReader(r, t.media, t.format, func(u unit.Unit) {
ringBuffer.Push(func() { ringBuffer.Push(func() {
err := t.cb(unit) err := t.cb(u)
if err != nil { if err != nil {
select { select {
case writeError <- err: case writeError <- err:

18
internal/formatprocessor/av1.go

@ -9,15 +9,9 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// UnitAV1 is an AV1 data unit.
type UnitAV1 struct {
BaseUnit
PTS time.Duration
TU [][]byte
}
type formatProcessorAV1 struct { type formatProcessorAV1 struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.AV1 format *formats.AV1
@ -56,8 +50,8 @@ func (t *formatProcessorAV1) createEncoder() error {
return t.encoder.Init() return t.encoder.Init()
} }
func (t *formatProcessorAV1) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorAV1) Process(u unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitAV1) tunit := u.(*unit.AV1)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -108,9 +102,9 @@ func (t *formatProcessorAV1) Process(unit Unit, hasNonRTSPReaders bool) error {
return nil return nil
} }
func (t *formatProcessorAV1) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorAV1) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitAV1{ return &unit.AV1{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

16
internal/formatprocessor/generic.go

@ -8,13 +8,9 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// UnitGeneric is a generic data unit.
type UnitGeneric struct {
BaseUnit
}
type formatProcessorGeneric struct { type formatProcessorGeneric struct {
udpMaxPayloadSize int udpMaxPayloadSize int
} }
@ -34,8 +30,8 @@ func newGeneric(
}, nil }, nil
} }
func (t *formatProcessorGeneric) Process(unit Unit, _ bool) error { func (t *formatProcessorGeneric) Process(u unit.Unit, _ bool) error {
tunit := unit.(*UnitGeneric) tunit := u.(*unit.Generic)
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -51,9 +47,9 @@ func (t *formatProcessorGeneric) Process(unit Unit, _ bool) error {
return nil return nil
} }
func (t *formatProcessorGeneric) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorGeneric) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitGeneric{ return &unit.Generic{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

6
internal/formatprocessor/generic_test.go

@ -6,6 +6,8 @@ import (
"github.com/bluenviron/gortsplib/v3/pkg/formats" "github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/bluenviron/mediamtx/internal/unit"
) )
func TestGenericRemovePadding(t *testing.T) { func TestGenericRemovePadding(t *testing.T) {
@ -33,8 +35,8 @@ func TestGenericRemovePadding(t *testing.T) {
PaddingSize: 20, PaddingSize: 20,
} }
err = p.Process(&UnitGeneric{ err = p.Process(&unit.Generic{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
}, },
}, false) }, false)

18
internal/formatprocessor/h264.go

@ -10,6 +10,7 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// extract SPS and PPS without decoding RTP packets // extract SPS and PPS without decoding RTP packets
@ -69,13 +70,6 @@ func rtpH264ExtractSPSPPS(pkt *rtp.Packet) ([]byte, []byte) {
} }
} }
// UnitH264 is a H264 data unit.
type UnitH264 struct {
BaseUnit
PTS time.Duration
AU [][]byte
}
type formatProcessorH264 struct { type formatProcessorH264 struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.H264 format *formats.H264
@ -230,8 +224,8 @@ func (t *formatProcessorH264) remuxAccessUnit(au [][]byte) [][]byte {
return filteredNALUs return filteredNALUs
} }
func (t *formatProcessorH264) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorH264) Process(u unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitH264) tunit := u.(*unit.H264)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -304,9 +298,9 @@ func (t *formatProcessorH264) Process(unit Unit, hasNonRTSPReaders bool) error {
return nil return nil
} }
func (t *formatProcessorH264) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorH264) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitH264{ return &unit.H264{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

24
internal/formatprocessor/h264_test.go

@ -8,6 +8,8 @@ import (
"github.com/bluenviron/mediacommon/pkg/codecs/h264" "github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/bluenviron/mediamtx/internal/unit"
) )
func TestH264DynamicParams(t *testing.T) { func TestH264DynamicParams(t *testing.T) {
@ -25,8 +27,8 @@ func TestH264DynamicParams(t *testing.T) {
pkts, err := enc.Encode([][]byte{{byte(h264.NALUTypeIDR)}}, 0) pkts, err := enc.Encode([][]byte{{byte(h264.NALUTypeIDR)}}, 0)
require.NoError(t, err) require.NoError(t, err)
data := &UnitH264{ data := &unit.H264{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
} }
@ -40,8 +42,8 @@ func TestH264DynamicParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{7, 4, 5, 6}}, 0) // SPS pkts, err = enc.Encode([][]byte{{7, 4, 5, 6}}, 0) // SPS
require.NoError(t, err) require.NoError(t, err)
err = p.Process(&UnitH264{ err = p.Process(&unit.H264{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
}, false) }, false)
@ -50,8 +52,8 @@ func TestH264DynamicParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{8, 1}}, 0) // PPS pkts, err = enc.Encode([][]byte{{8, 1}}, 0) // PPS
require.NoError(t, err) require.NoError(t, err)
err = p.Process(&UnitH264{ err = p.Process(&unit.H264{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
}, false) }, false)
@ -63,8 +65,8 @@ func TestH264DynamicParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{byte(h264.NALUTypeIDR)}}, 0) pkts, err = enc.Encode([][]byte{{byte(h264.NALUTypeIDR)}}, 0)
require.NoError(t, err) require.NoError(t, err)
data = &UnitH264{ data = &unit.H264{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
} }
@ -129,8 +131,8 @@ func TestH264OversizedPackets(t *testing.T) {
Payload: []byte{0x1c, 0b01000000, 0x01, 0x02, 0x03, 0x04}, Payload: []byte{0x1c, 0b01000000, 0x01, 0x02, 0x03, 0x04},
}, },
} { } {
data := &UnitH264{ data := &unit.H264{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
}, },
} }
@ -192,7 +194,7 @@ func TestH264EmptyPacket(t *testing.T) {
p, err := New(1472, forma, true, nil) p, err := New(1472, forma, true, nil)
require.NoError(t, err) require.NoError(t, err)
unit := &UnitH264{ unit := &unit.H264{
AU: [][]byte{ AU: [][]byte{
{0x07, 0x01, 0x02, 0x03}, // SPS {0x07, 0x01, 0x02, 0x03}, // SPS
{0x08, 0x01, 0x02}, // PPS {0x08, 0x01, 0x02}, // PPS

18
internal/formatprocessor/h265.go

@ -10,6 +10,7 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// extract VPS, SPS and PPS without decoding RTP packets // extract VPS, SPS and PPS without decoding RTP packets
@ -76,13 +77,6 @@ func rtpH265ExtractVPSSPSPPS(pkt *rtp.Packet) ([]byte, []byte, []byte) {
} }
} }
// UnitH265 is a H265 data unit.
type UnitH265 struct {
BaseUnit
PTS time.Duration
AU [][]byte
}
type formatProcessorH265 struct { type formatProcessorH265 struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.H265 format *formats.H265
@ -252,8 +246,8 @@ func (t *formatProcessorH265) remuxAccessUnit(au [][]byte) [][]byte {
return filteredNALUs return filteredNALUs
} }
func (t *formatProcessorH265) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorH265) Process(u unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitH265) tunit := u.(*unit.H265)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -326,9 +320,9 @@ func (t *formatProcessorH265) Process(unit Unit, hasNonRTSPReaders bool) error {
return nil return nil
} }
func (t *formatProcessorH265) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorH265) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitH265{ return &unit.H265{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

28
internal/formatprocessor/h265_test.go

@ -8,6 +8,8 @@ import (
"github.com/bluenviron/mediacommon/pkg/codecs/h265" "github.com/bluenviron/mediacommon/pkg/codecs/h265"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/bluenviron/mediamtx/internal/unit"
) )
func TestH265DynamicParams(t *testing.T) { func TestH265DynamicParams(t *testing.T) {
@ -24,8 +26,8 @@ func TestH265DynamicParams(t *testing.T) {
pkts, err := enc.Encode([][]byte{{byte(h265.NALUType_CRA_NUT) << 1, 0}}, 0) pkts, err := enc.Encode([][]byte{{byte(h265.NALUType_CRA_NUT) << 1, 0}}, 0)
require.NoError(t, err) require.NoError(t, err)
data := &UnitH265{ data := &unit.H265{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
} }
@ -39,8 +41,8 @@ func TestH265DynamicParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{byte(h265.NALUType_VPS_NUT) << 1, 1, 2, 3}}, 0) pkts, err = enc.Encode([][]byte{{byte(h265.NALUType_VPS_NUT) << 1, 1, 2, 3}}, 0)
require.NoError(t, err) require.NoError(t, err)
err = p.Process(&UnitH265{ err = p.Process(&unit.H265{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
}, false) }, false)
@ -49,8 +51,8 @@ func TestH265DynamicParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{byte(h265.NALUType_SPS_NUT) << 1, 4, 5, 6}}, 0) pkts, err = enc.Encode([][]byte{{byte(h265.NALUType_SPS_NUT) << 1, 4, 5, 6}}, 0)
require.NoError(t, err) require.NoError(t, err)
err = p.Process(&UnitH265{ err = p.Process(&unit.H265{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
}, false) }, false)
@ -59,8 +61,8 @@ func TestH265DynamicParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{byte(h265.NALUType_PPS_NUT) << 1, 7, 8, 9}}, 0) pkts, err = enc.Encode([][]byte{{byte(h265.NALUType_PPS_NUT) << 1, 7, 8, 9}}, 0)
require.NoError(t, err) require.NoError(t, err)
err = p.Process(&UnitH265{ err = p.Process(&unit.H265{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
}, false) }, false)
@ -73,8 +75,8 @@ func TestH265DynamicParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{byte(h265.NALUType_CRA_NUT) << 1, 0}}, 0) pkts, err = enc.Encode([][]byte{{byte(h265.NALUType_CRA_NUT) << 1, 0}}, 0)
require.NoError(t, err) require.NoError(t, err)
data = &UnitH265{ data = &unit.H265{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkts[0]}, RTPPackets: []*rtp.Packet{pkts[0]},
}, },
} }
@ -128,8 +130,8 @@ func TestH265OversizedPackets(t *testing.T) {
Payload: bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 2000/4), Payload: bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 2000/4),
}, },
} { } {
data := &UnitH265{ data := &unit.H265{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
}, },
} }
@ -190,7 +192,7 @@ func TestH265EmptyPacket(t *testing.T) {
p, err := New(1472, forma, true, nil) p, err := New(1472, forma, true, nil)
require.NoError(t, err) require.NoError(t, err)
unit := &UnitH265{ unit := &unit.H265{
AU: [][]byte{ AU: [][]byte{
{byte(h265.NALUType_VPS_NUT) << 1, 10, 11, 12}, // VPS {byte(h265.NALUType_VPS_NUT) << 1, 10, 11, 12}, // VPS
{byte(h265.NALUType_SPS_NUT) << 1, 13, 14, 15}, // SPS {byte(h265.NALUType_SPS_NUT) << 1, 13, 14, 15}, // SPS

18
internal/formatprocessor/mpeg1audio.go

@ -9,15 +9,9 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// UnitMPEG1Audio is a MPEG-1/2 Audio data unit.
type UnitMPEG1Audio struct {
BaseUnit
PTS time.Duration
Frames [][]byte
}
type formatProcessorMPEG1Audio struct { type formatProcessorMPEG1Audio struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.MPEG1Audio format *formats.MPEG1Audio
@ -53,8 +47,8 @@ func (t *formatProcessorMPEG1Audio) createEncoder() error {
return t.encoder.Init() return t.encoder.Init()
} }
func (t *formatProcessorMPEG1Audio) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorMPEG1Audio) Process(u unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitMPEG1Audio) tunit := u.(*unit.MPEG1Audio)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -104,9 +98,9 @@ func (t *formatProcessorMPEG1Audio) Process(unit Unit, hasNonRTSPReaders bool) e
return nil return nil
} }
func (t *formatProcessorMPEG1Audio) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorMPEG1Audio) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitMPEG1Audio{ return &unit.MPEG1Audio{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

18
internal/formatprocessor/mpeg4audio_generic.go

@ -9,15 +9,9 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// UnitMPEG4AudioGeneric is a MPEG-4 Audio data unit.
type UnitMPEG4AudioGeneric struct {
BaseUnit
PTS time.Duration
AUs [][]byte
}
type formatProcessorMPEG4AudioGeneric struct { type formatProcessorMPEG4AudioGeneric struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.MPEG4Audio format *formats.MPEG4Audio
@ -58,8 +52,8 @@ func (t *formatProcessorMPEG4AudioGeneric) createEncoder() error {
return t.encoder.Init() return t.encoder.Init()
} }
func (t *formatProcessorMPEG4AudioGeneric) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorMPEG4AudioGeneric) Process(u unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitMPEG4AudioGeneric) tunit := u.(*unit.MPEG4AudioGeneric)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -109,9 +103,9 @@ func (t *formatProcessorMPEG4AudioGeneric) Process(unit Unit, hasNonRTSPReaders
return nil return nil
} }
func (t *formatProcessorMPEG4AudioGeneric) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorMPEG4AudioGeneric) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitMPEG4AudioGeneric{ return &unit.MPEG4AudioGeneric{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

18
internal/formatprocessor/mpeg4audio_latm.go

@ -9,15 +9,9 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// UnitMPEG4AudioLATM is a MPEG-4 Audio data unit.
type UnitMPEG4AudioLATM struct {
BaseUnit
PTS time.Duration
AU []byte
}
type formatProcessorMPEG4AudioLATM struct { type formatProcessorMPEG4AudioLATM struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.MPEG4AudioLATM format *formats.MPEG4AudioLATM
@ -54,8 +48,8 @@ func (t *formatProcessorMPEG4AudioLATM) createEncoder() error {
return t.encoder.Init() return t.encoder.Init()
} }
func (t *formatProcessorMPEG4AudioLATM) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorMPEG4AudioLATM) Process(u unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitMPEG4AudioLATM) tunit := u.(*unit.MPEG4AudioLATM)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -105,9 +99,9 @@ func (t *formatProcessorMPEG4AudioLATM) Process(unit Unit, hasNonRTSPReaders boo
return nil return nil
} }
func (t *formatProcessorMPEG4AudioLATM) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorMPEG4AudioLATM) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitMPEG4AudioLATM{ return &unit.MPEG4AudioLATM{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

18
internal/formatprocessor/opus.go

@ -10,15 +10,9 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// UnitOpus is a Opus data unit.
type UnitOpus struct {
BaseUnit
PTS time.Duration
Packets [][]byte
}
type formatProcessorOpus struct { type formatProcessorOpus struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.Opus format *formats.Opus
@ -56,8 +50,8 @@ func (t *formatProcessorOpus) createEncoder() error {
return t.encoder.Init() return t.encoder.Init()
} }
func (t *formatProcessorOpus) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorOpus) Process(u unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitOpus) tunit := u.(*unit.Opus)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -111,9 +105,9 @@ func (t *formatProcessorOpus) Process(unit Unit, hasNonRTSPReaders bool) error {
return nil return nil
} }
func (t *formatProcessorOpus) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorOpus) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitOpus{ return &unit.Opus{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

5
internal/formatprocessor/processor.go

@ -8,15 +8,16 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// Processor cleans and normalizes streams. // Processor cleans and normalizes streams.
type Processor interface { type Processor interface {
// cleans and normalizes a data unit. // cleans and normalizes a data unit.
Process(Unit, bool) error Process(unit.Unit, bool) error
// wraps a RTP packet into a Unit. // wraps a RTP packet into a Unit.
UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit
} }
// New allocates a Processor. // New allocates a Processor.

32
internal/formatprocessor/unit.go

@ -1,32 +0,0 @@
package formatprocessor
import (
"time"
"github.com/pion/rtp"
)
// BaseUnit contains fields shared across all units.
type BaseUnit struct {
RTPPackets []*rtp.Packet
NTP time.Time
}
// GetRTPPackets implements Unit.
func (u *BaseUnit) GetRTPPackets() []*rtp.Packet {
return u.RTPPackets
}
// GetNTP implements Unit.
func (u *BaseUnit) GetNTP() time.Time {
return u.NTP
}
// Unit is the elementary data unit routed across the server.
type Unit interface {
// returns RTP packets contained into the unit.
GetRTPPackets() []*rtp.Packet
// returns the NTP timestamp of the unit.
GetNTP() time.Time
}

18
internal/formatprocessor/vp8.go

@ -9,15 +9,9 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// UnitVP8 is a VP8 data unit.
type UnitVP8 struct {
BaseUnit
PTS time.Duration
Frame []byte
}
type formatProcessorVP8 struct { type formatProcessorVP8 struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.VP8 format *formats.VP8
@ -54,8 +48,8 @@ func (t *formatProcessorVP8) createEncoder() error {
return t.encoder.Init() return t.encoder.Init()
} }
func (t *formatProcessorVP8) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorVP8) Process(y unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitVP8) tunit := y.(*unit.VP8)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -105,9 +99,9 @@ func (t *formatProcessorVP8) Process(unit Unit, hasNonRTSPReaders bool) error {
return nil return nil
} }
func (t *formatProcessorVP8) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorVP8) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitVP8{ return &unit.VP8{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

18
internal/formatprocessor/vp9.go

@ -9,15 +9,9 @@ import (
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// UnitVP9 is a VP9 data unit.
type UnitVP9 struct {
BaseUnit
PTS time.Duration
Frame []byte
}
type formatProcessorVP9 struct { type formatProcessorVP9 struct {
udpMaxPayloadSize int udpMaxPayloadSize int
format *formats.VP9 format *formats.VP9
@ -54,8 +48,8 @@ func (t *formatProcessorVP9) createEncoder() error {
return t.encoder.Init() return t.encoder.Init()
} }
func (t *formatProcessorVP9) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl func (t *formatProcessorVP9) Process(u unit.Unit, hasNonRTSPReaders bool) error { //nolint:dupl
tunit := unit.(*UnitVP9) tunit := u.(*unit.VP9)
if tunit.RTPPackets != nil { if tunit.RTPPackets != nil {
pkt := tunit.RTPPackets[0] pkt := tunit.RTPPackets[0]
@ -105,9 +99,9 @@ func (t *formatProcessorVP9) Process(unit Unit, hasNonRTSPReaders bool) error {
return nil return nil
} }
func (t *formatProcessorVP9) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) Unit { func (t *formatProcessorVP9) UnitForRTPPacket(pkt *rtp.Packet, ntp time.Time) unit.Unit {
return &UnitVP9{ return &unit.VP9{
BaseUnit: BaseUnit{ Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt}, RTPPackets: []*rtp.Packet{pkt},
NTP: ntp, NTP: ntp,
}, },

6
internal/stream/stream.go

@ -9,8 +9,8 @@ import (
"github.com/bluenviron/gortsplib/v3/pkg/media" "github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
// Stream is a media stream. // Stream is a media stream.
@ -64,7 +64,7 @@ func (s *Stream) RTSPStream() *gortsplib.ServerStream {
} }
// AddReader adds a reader. // AddReader adds a reader.
func (s *Stream) AddReader(r interface{}, medi *media.Media, forma formats.Format, cb func(formatprocessor.Unit)) { func (s *Stream) AddReader(r interface{}, medi *media.Media, forma formats.Format, cb func(unit.Unit)) {
sm := s.smedias[medi] sm := s.smedias[medi]
sf := sm.formats[forma] sf := sm.formats[forma]
sf.addReader(r, cb) sf.addReader(r, cb)
@ -80,7 +80,7 @@ func (s *Stream) RemoveReader(r interface{}) {
} }
// WriteUnit writes a Unit. // WriteUnit writes a Unit.
func (s *Stream) WriteUnit(medi *media.Media, forma formats.Format, data formatprocessor.Unit) { func (s *Stream) WriteUnit(medi *media.Media, forma formats.Format, data unit.Unit) {
sm := s.smedias[medi] sm := s.smedias[medi]
sf := sm.formats[forma] sf := sm.formats[forma]
sf.writeUnit(s, medi, data) sf.writeUnit(s, medi, data)

9
internal/stream/stream_format.go

@ -11,13 +11,14 @@ import (
"github.com/bluenviron/mediamtx/internal/formatprocessor" "github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
) )
type streamFormat struct { type streamFormat struct {
source logger.Writer source logger.Writer
proc formatprocessor.Processor proc formatprocessor.Processor
mutex sync.RWMutex mutex sync.RWMutex
nonRTSPReaders map[interface{}]func(formatprocessor.Unit) nonRTSPReaders map[interface{}]func(unit.Unit)
} }
func newStreamFormat( func newStreamFormat(
@ -34,13 +35,13 @@ func newStreamFormat(
sf := &streamFormat{ sf := &streamFormat{
source: source, source: source,
proc: proc, proc: proc,
nonRTSPReaders: make(map[interface{}]func(formatprocessor.Unit)), nonRTSPReaders: make(map[interface{}]func(unit.Unit)),
} }
return sf, nil return sf, nil
} }
func (sf *streamFormat) addReader(r interface{}, cb func(formatprocessor.Unit)) { func (sf *streamFormat) addReader(r interface{}, cb func(unit.Unit)) {
sf.mutex.Lock() sf.mutex.Lock()
defer sf.mutex.Unlock() defer sf.mutex.Unlock()
sf.nonRTSPReaders[r] = cb sf.nonRTSPReaders[r] = cb
@ -52,7 +53,7 @@ func (sf *streamFormat) removeReader(r interface{}) {
delete(sf.nonRTSPReaders, r) delete(sf.nonRTSPReaders, r)
} }
func (sf *streamFormat) writeUnit(s *Stream, medi *media.Media, data formatprocessor.Unit) { func (sf *streamFormat) writeUnit(s *Stream, medi *media.Media, data unit.Unit) {
sf.mutex.RLock() sf.mutex.RLock()
defer sf.mutex.RUnlock() defer sf.mutex.RUnlock()

12
internal/unit/av1.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// AV1 is an AV1 data unit.
type AV1 struct {
Base
PTS time.Duration
TU [][]byte
}

23
internal/unit/base.go

@ -0,0 +1,23 @@
package unit
import (
"time"
"github.com/pion/rtp"
)
// Base contains fields shared across all units.
type Base struct {
RTPPackets []*rtp.Packet
NTP time.Time
}
// GetRTPPackets implements Unit.
func (u *Base) GetRTPPackets() []*rtp.Packet {
return u.RTPPackets
}
// GetNTP implements Unit.
func (u *Base) GetNTP() time.Time {
return u.NTP
}

6
internal/unit/generic.go

@ -0,0 +1,6 @@
package unit
// Generic is a generic data unit.
type Generic struct {
Base
}

12
internal/unit/h264.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// H264 is a H264 data unit.
type H264 struct {
Base
PTS time.Duration
AU [][]byte
}

12
internal/unit/h265.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// H265 is a H265 data unit.
type H265 struct {
Base
PTS time.Duration
AU [][]byte
}

12
internal/unit/mpeg1audio.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// MPEG1Audio is a MPEG-1/2 Audio data unit.
type MPEG1Audio struct {
Base
PTS time.Duration
Frames [][]byte
}

12
internal/unit/mpeg4audio_generic.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// MPEG4AudioGeneric is a MPEG-4 Audio data unit.
type MPEG4AudioGeneric struct {
Base
PTS time.Duration
AUs [][]byte
}

12
internal/unit/mpeg4audio_latm.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// MPEG4AudioLATM is a MPEG-4 Audio data unit.
type MPEG4AudioLATM struct {
Base
PTS time.Duration
AU []byte
}

12
internal/unit/opus.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// Opus is a Opus data unit.
type Opus struct {
Base
PTS time.Duration
Packets [][]byte
}

17
internal/unit/unit.go

@ -0,0 +1,17 @@
// Package unit contains the Unit definition.
package unit
import (
"time"
"github.com/pion/rtp"
)
// Unit is the elementary data unit routed across the server.
type Unit interface {
// returns RTP packets contained into the unit.
GetRTPPackets() []*rtp.Packet
// returns the NTP timestamp of the unit.
GetNTP() time.Time
}

12
internal/unit/vp8.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// VP8 is a VP8 data unit.
type VP8 struct {
Base
PTS time.Duration
Frame []byte
}

12
internal/unit/vp9.go

@ -0,0 +1,12 @@
package unit
import (
"time"
)
// VP9 is a VP9 data unit.
type VP9 struct {
Base
PTS time.Duration
Frame []byte
}
Loading…
Cancel
Save