mirror of
https://github.com/aler9/rtsp-simple-server
synced 2025-10-05 07:36:57 +08:00
move units into dedicated package (#2245)
Some checks reported warnings
lint / code (push) Has been cancelled
lint / mod-tidy (push) Has been cancelled
lint / apidocs (push) Has been cancelled
test / test64 (push) Has been cancelled
test / test32 (push) Has been cancelled
test / test_highlevel (push) Has been cancelled
Some checks reported warnings
lint / code (push) Has been cancelled
lint / mod-tidy (push) Has been cancelled
lint / apidocs (push) Has been cancelled
test / test64 (push) Has been cancelled
test / test32 (push) Has been cancelled
test / test_highlevel (push) Has been cancelled
needed by #2244
This commit is contained in:
2
LICENSE
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
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
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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,
|
||||||
|
@@ -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,
|
||||||
|
@@ -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,
|
||||||
|
@@ -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,
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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),
|
||||||
|
@@ -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),
|
||||||
|
@@ -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:
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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,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)
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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.
|
||||||
|
@@ -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
|
|
||||||
}
|
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
Normal file
12
internal/unit/av1.go
Normal file
@@ -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
Normal file
23
internal/unit/base.go
Normal file
@@ -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
Normal file
6
internal/unit/generic.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package unit
|
||||||
|
|
||||||
|
// Generic is a generic data unit.
|
||||||
|
type Generic struct {
|
||||||
|
Base
|
||||||
|
}
|
12
internal/unit/h264.go
Normal file
12
internal/unit/h264.go
Normal file
@@ -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
Normal file
12
internal/unit/h265.go
Normal file
@@ -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
Normal file
12
internal/unit/mpeg1audio.go
Normal file
@@ -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
Normal file
12
internal/unit/mpeg4audio_generic.go
Normal file
@@ -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
Normal file
12
internal/unit/mpeg4audio_latm.go
Normal file
@@ -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
Normal file
12
internal/unit/opus.go
Normal file
@@ -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
Normal file
17
internal/unit/unit.go
Normal file
@@ -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
Normal file
12
internal/unit/vp8.go
Normal file
@@ -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
Normal file
12
internal/unit/vp9.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package unit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VP9 is a VP9 data unit.
|
||||||
|
type VP9 struct {
|
||||||
|
Base
|
||||||
|
PTS time.Duration
|
||||||
|
Frame []byte
|
||||||
|
}
|
Reference in New Issue
Block a user