diff --git a/docs/2-features/03-publish.md b/docs/2-features/03-publish.md
index 5d372332..b1f59e62 100644
--- a/docs/2-features/03-publish.md
+++ b/docs/2-features/03-publish.md
@@ -2,19 +2,19 @@
Live streams can be published to the server with the following protocols and codecs:
-| protocol | variants | codecs |
-| ----------------------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| [SRT clients](../3-publish/01-srt-clients.md) | | **Video**: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
**Other**: KLV |
-| [SRT cameras and servers](../3-publish/02-srt-cameras-and-servers.md) | | **Video**: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
**Other**: KLV |
-| [WebRTC clients](../3-publish/03-webrtc-clients.md) | WHIP | **Video**: AV1, VP9, VP8, H265, H264
**Audio**: Opus, G722, G711 (PCMA, PCMU) |
-| [WebRTC servers](../3-publish/04-webrtc-servers.md) | WHEP | **Video**: AV1, VP9, VP8, H265, H264
**Audio**: Opus, G722, G711 (PCMA, PCMU) |
-| [RTSP clients](../3-publish/05-rtsp-clients.md) | UDP, TCP, RTSPS | **Video**: AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, MJPEG
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
**Other**: KLV, MPEG-TS, any RTP-compatible codec |
-| [RTSP cameras and servers](../3-publish/06-rtsp-cameras-and-servers.md) | UDP, UDP-Multicast, TCP, RTSPS | **Video**: AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, MJPEG
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
**Other**: KLV, MPEG-TS, any RTP-compatible codec |
-| [RTMP clients](../3-publish/07-rtmp-clients.md) | RTMP, RTMPS, Enhanced RTMP | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM |
-| [RTMP cameras and servers](../3-publish/08-rtmp-cameras-and-servers.md) | RTMP, RTMPS, Enhanced RTMP | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM |
-| [HLS cameras and servers](../3-publish/09-hls-cameras-and-servers.md) | Low-Latency HLS, MP4-based HLS, legacy HLS | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC) |
-| [MPEG-TS](../3-publish/10-mpeg-ts.md) | MPEG-TS over UDP, MPEG-TS over Unix socket | **Video**: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
**Other**: KLV |
-| [RTP](../3-publish/11-rtp.md) | RTP over UDP | **Video**: AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
**Other**: KLV, MPEG-TS, any RTP-compatible codec |
+| protocol | variants | codecs |
+| ----------------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| [SRT clients](../3-publish/01-srt-clients.md) | | **Video**: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
**Other**: KLV |
+| [SRT cameras and servers](../3-publish/02-srt-cameras-and-servers.md) | | **Video**: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
**Other**: KLV |
+| [WebRTC clients](../3-publish/03-webrtc-clients.md) | WHIP | **Video**: AV1, VP9, VP8, H265, H264
**Audio**: Opus, G722, G711 (PCMA, PCMU) |
+| [WebRTC servers](../3-publish/04-webrtc-servers.md) | WHEP | **Video**: AV1, VP9, VP8, H265, H264
**Audio**: Opus, G722, G711 (PCMA, PCMU) |
+| [RTSP clients](../3-publish/05-rtsp-clients.md) | UDP, TCP, RTSPS | **Video**: AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, MJPEG
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
**Other**: KLV, MPEG-TS, any RTP-compatible codec |
+| [RTSP cameras and servers](../3-publish/06-rtsp-cameras-and-servers.md) | UDP, UDP-Multicast, TCP, RTSPS | **Video**: AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, MJPEG
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
**Other**: KLV, MPEG-TS, any RTP-compatible codec |
+| [RTMP clients](../3-publish/07-rtmp-clients.md) | RTMP, RTMPS, Enhanced RTMP | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM |
+| [RTMP cameras and servers](../3-publish/08-rtmp-cameras-and-servers.md) | RTMP, RTMPS, Enhanced RTMP | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM |
+| [HLS cameras and servers](../3-publish/09-hls-cameras-and-servers.md) | Low-Latency HLS, MP4-based HLS, MPEG-TS-based HLS | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC)
**Other**: KLV (MPEG-TS-based HLS only) |
+| [MPEG-TS](../3-publish/10-mpeg-ts.md) | MPEG-TS over UDP, MPEG-TS over Unix socket | **Video**: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
**Other**: KLV |
+| [RTP](../3-publish/11-rtp.md) | RTP over UDP | **Video**: AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
**Other**: KLV, MPEG-TS, any RTP-compatible codec |
We provide instructions for publishing with the following devices:
diff --git a/docs/2-features/04-read.md b/docs/2-features/04-read.md
index 52371f30..8e03f223 100644
--- a/docs/2-features/04-read.md
+++ b/docs/2-features/04-read.md
@@ -2,13 +2,13 @@
Live streams can be read from the server with the following protocols and codecs:
-| protocol | variants | codecs |
-| ---------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| [SRT clients](../4-read/01-srt.md) | | **Video**: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
**Other**: KLV |
-| [WebRTC clients](../4-read/02-webrtc.md) | WHEP | **Video**: AV1, VP9, VP8, H265, H264
**Audio**: Opus, G722, G711 (PCMA, PCMU)
**Other**: KLV |
-| [RTSP clients](../4-read/03-rtsp.md) | UDP, UDP-Multicast, TCP, RTSPS | **Video**: AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
**Other**: KLV, MPEG-TS, any RTP-compatible codec |
-| [RTMP clients](../4-read/04-rtmp.md) | RTMP, RTMPS, Enhanced RTMP | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM |
-| [HLS](../4-read/05-hls.md) | Low-Latency HLS, MP4-based HLS, legacy HLS | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC) |
+| protocol | variants | codecs |
+| ---------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| [SRT clients](../4-read/01-srt.md) | | **Video**: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
**Other**: KLV |
+| [WebRTC clients](../4-read/02-webrtc.md) | WHEP | **Video**: AV1, VP9, VP8, H265, H264
**Audio**: Opus, G722, G711 (PCMA, PCMU)
**Other**: KLV |
+| [RTSP clients](../4-read/03-rtsp.md) | UDP, UDP-Multicast, TCP, RTSPS | **Video**: AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
**Other**: KLV, MPEG-TS, any RTP-compatible codec |
+| [RTMP clients](../4-read/04-rtmp.md) | RTMP, RTMPS, Enhanced RTMP | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM |
+| [HLS](../4-read/05-hls.md) | Low-Latency HLS, MP4-based HLS, MPEG-TS-based HLS | **Video**: AV1, VP9, H265, H264
**Audio**: Opus, MPEG-4 Audio (AAC)
**Other**: KLV (MPEG-TS-based HLS only) |
We provide instructions for reading with the following software:
diff --git a/internal/protocols/hls/from_stream.go b/internal/protocols/hls/from_stream.go
index f94b3ac4..50ddd813 100644
--- a/internal/protocols/hls/from_stream.go
+++ b/internal/protocols/hls/from_stream.go
@@ -19,7 +19,7 @@ import (
// ErrNoSupportedCodecs is returned by FromStream when there are no supported codecs.
var ErrNoSupportedCodecs = errors.New(
- "the stream doesn't contain any supported codec, which are currently AV1, VP9, H265, H264, Opus, MPEG-4 Audio")
+ "the stream doesn't contain any supported codec, which are currently AV1, VP9, H265, H264, Opus, MPEG-4 Audio, KLV")
func setupVideoTrack(
desc *description.Session,
@@ -287,6 +287,54 @@ func setupAudioTracks(
}
}
+func setupDataTracks(
+ desc *description.Session,
+ r *stream.Reader,
+ muxer *gohlslib.Muxer,
+) {
+ addTrack := func(
+ media *description.Media,
+ forma format.Format,
+ track *gohlslib.Track,
+ onData stream.OnDataFunc,
+ ) {
+ muxer.Tracks = append(muxer.Tracks, track)
+ r.OnData(media, forma, onData)
+ }
+
+ for _, media := range desc.Medias {
+ for _, forma := range media.Formats {
+ if forma, ok := forma.(*format.KLV); ok && muxer.Variant == gohlslib.MuxerVariantMPEGTS {
+ track := &gohlslib.Track{
+ Codec: &codecs.KLV{Synchronous: true},
+ ClockRate: forma.ClockRate(),
+ }
+
+ addTrack(
+ media,
+ forma,
+ track,
+ func(u *unit.Unit) error {
+ if u.NilPayload() {
+ return nil
+ }
+
+ err := muxer.WriteKLV(
+ track,
+ u.NTP,
+ u.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate
+ u.Payload.(unit.PayloadKLV))
+ if err != nil {
+ return fmt.Errorf("muxer error: %w", err)
+ }
+
+ return nil
+ })
+ }
+ }
+ }
+}
+
// FromStream maps a MediaMTX stream to a HLS muxer.
func FromStream(
desc *description.Session,
@@ -305,6 +353,12 @@ func FromStream(
muxer,
)
+ setupDataTracks(
+ desc,
+ r,
+ muxer,
+ )
+
if len(muxer.Tracks) == 0 {
return ErrNoSupportedCodecs
}
diff --git a/internal/protocols/hls/from_stream_test.go b/internal/protocols/hls/from_stream_test.go
index acad4711..6c7a2fe4 100644
--- a/internal/protocols/hls/from_stream_test.go
+++ b/internal/protocols/hls/from_stream_test.go
@@ -69,3 +69,53 @@ func TestFromStreamSkipUnsupportedTracks(t *testing.T) {
require.Equal(t, 2, n)
}
+
+func TestFromStreamKLVRequiresMPEGTSVariant(t *testing.T) {
+ t.Run("klv only, non-mpegts variant", func(t *testing.T) {
+ desc := &description.Session{Medias: []*description.Media{{
+ Type: description.MediaTypeApplication,
+ Formats: []format.Format{&format.KLV{PayloadTyp: 96}},
+ }}}
+
+ r := &stream.Reader{
+ Parent: test.Logger(func(logger.Level, string, ...any) {
+ t.Error("should not happen")
+ }),
+ }
+
+ m := &gohlslib.Muxer{Variant: gohlslib.MuxerVariantFMP4}
+
+ err := FromStream(desc, r, m)
+ require.Equal(t, ErrNoSupportedCodecs, err)
+ })
+
+ t.Run("klv alongside video, non-mpegts variant", func(t *testing.T) {
+ desc := &description.Session{Medias: []*description.Media{
+ {
+ Type: description.MediaTypeVideo,
+ Formats: []format.Format{&format.H264{PayloadTyp: 96, PacketizationMode: 1}},
+ },
+ {
+ Type: description.MediaTypeApplication,
+ Formats: []format.Format{&format.KLV{PayloadTyp: 97}},
+ },
+ }}
+
+ n := 0
+
+ r := &stream.Reader{
+ Parent: test.Logger(func(l logger.Level, f string, args ...any) {
+ require.Equal(t, logger.Warn, l)
+ require.Equal(t, "skipping track 2 (KLV)", fmt.Sprintf(f, args...))
+ n++
+ }),
+ }
+
+ m := &gohlslib.Muxer{Variant: gohlslib.MuxerVariantFMP4}
+
+ err := FromStream(desc, r, m)
+ require.NoError(t, err)
+ require.Equal(t, 1, n)
+ require.Equal(t, 1, len(m.Tracks))
+ })
+}
diff --git a/internal/protocols/hls/to_stream.go b/internal/protocols/hls/to_stream.go
index d84e71e5..cf051a08 100644
--- a/internal/protocols/hls/to_stream.go
+++ b/internal/protocols/hls/to_stream.go
@@ -199,6 +199,23 @@ func ToStream(
})
})
+ case *codecs.KLV:
+ medi = &description.Media{
+ Type: description.MediaTypeApplication,
+ Formats: []format.Format{&format.KLV{
+ PayloadTyp: 96,
+ }},
+ }
+ newClockRate := medi.Formats[0].ClockRate()
+
+ c.OnDataKLV(ctrack, func(pts int64, uni []byte) {
+ (*subStream).WriteUnit(medi, medi.Formats[0], &unit.Unit{
+ NTP: handleNTP(pts),
+ PTS: multiplyAndDivide(pts, int64(newClockRate), int64(ctrack.ClockRate)),
+ Payload: unit.PayloadKLV(uni),
+ })
+ })
+
default:
panic("should not happen")
}
diff --git a/internal/protocols/hls/to_stream_test.go b/internal/protocols/hls/to_stream_test.go
index 103c0d6e..9ead53e3 100644
--- a/internal/protocols/hls/to_stream_test.go
+++ b/internal/protocols/hls/to_stream_test.go
@@ -28,143 +28,195 @@ func TestToStreamNoSupportedCodecs(t *testing.T) {
// func TestToStreamSkipUnsupportedTracks(t *testing.T)
func TestToStream(t *testing.T) {
- track1 := &mpegts.Track{
- Codec: &tscodecs.H264{},
- }
+ for _, ca := range []string{
+ "h264",
+ "klv",
+ } {
+ t.Run(ca, func(t *testing.T) {
+ var track1 *mpegts.Track
- s := &http.Server{
- Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- switch {
- case r.Method == http.MethodGet && r.URL.Path == "/stream.m3u8":
- w.Header().Set("Content-Type", `application/vnd.apple.mpegurl`)
- w.Write([]byte("#EXTM3U\n" +
- "#EXT-X-VERSION:3\n" +
- "#EXT-X-ALLOW-CACHE:NO\n" +
- "#EXT-X-TARGETDURATION:2\n" +
- "#EXT-X-MEDIA-SEQUENCE:0\n" +
- "#EXT-X-PROGRAM-DATE-TIME:2018-05-20T08:17:15Z\n" +
- "#EXTINF:2,\n" +
- "segment1.ts\n" +
- "#EXTINF:2,\n" +
- "segment2.ts\n" +
- "#EXTINF:2,\n" +
- "segment3.ts\n" +
- "#EXT-X-ENDLIST\n"))
-
- case r.Method == http.MethodGet && r.URL.Path == "/segment1.ts":
- w.Header().Set("Content-Type", `video/MP2T`)
-
- w := &mpegts.Writer{W: w, Tracks: []*mpegts.Track{track1}}
- err := w.Initialize()
- require.NoError(t, err)
-
- err = w.WriteH264(track1, 2*90000, 2*90000, [][]byte{
- {7, 1, 2, 3}, // SPS
- {8}, // PPS
- {5, 1},
- })
- require.NoError(t, err)
-
- case r.Method == http.MethodGet && r.URL.Path == "/segment2.ts":
- w.Header().Set("Content-Type", `video/MP2T`)
-
- w := &mpegts.Writer{W: w, Tracks: []*mpegts.Track{track1}}
- err := w.Initialize()
- require.NoError(t, err)
-
- err = w.WriteH264(track1, 2*90000, 2*90000, [][]byte{
- {5, 2},
- })
- require.NoError(t, err)
+ switch ca {
+ case "h264":
+ track1 = &mpegts.Track{
+ Codec: &tscodecs.H264{},
+ }
+ case "klv":
+ track1 = &mpegts.Track{
+ Codec: &tscodecs.KLV{Synchronous: true},
+ }
}
- }),
- }
- ln, err := net.Listen("tcp", "localhost:5781")
- require.NoError(t, err)
+ s := &http.Server{
+ Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ switch {
+ case r.Method == http.MethodGet && r.URL.Path == "/stream.m3u8":
+ w.Header().Set("Content-Type", `application/vnd.apple.mpegurl`)
+ w.Write([]byte("#EXTM3U\n" +
+ "#EXT-X-VERSION:3\n" +
+ "#EXT-X-ALLOW-CACHE:NO\n" +
+ "#EXT-X-TARGETDURATION:2\n" +
+ "#EXT-X-MEDIA-SEQUENCE:0\n" +
+ "#EXT-X-PROGRAM-DATE-TIME:2018-05-20T08:17:15Z\n" +
+ "#EXTINF:2,\n" +
+ "segment1.ts\n" +
+ "#EXTINF:2,\n" +
+ "segment2.ts\n" +
+ "#EXTINF:2,\n" +
+ "segment3.ts\n" +
+ "#EXT-X-ENDLIST\n"))
- go s.Serve(ln)
- defer s.Shutdown(context.Background())
+ case r.Method == http.MethodGet && r.URL.Path == "/segment1.ts":
+ w.Header().Set("Content-Type", `video/MP2T`)
- var strm *stream.Stream
- var subStream *stream.SubStream
- done := make(chan struct{})
+ mw := &mpegts.Writer{W: w, Tracks: []*mpegts.Track{track1}}
+ err := mw.Initialize()
+ require.NoError(t, err)
- r := &stream.Reader{Parent: test.NilLogger}
+ switch ca {
+ case "h264":
+ err = mw.WriteH264(track1, 2*90000, 2*90000, [][]byte{
+ {7, 1, 2, 3}, // SPS
+ {8}, // PPS
+ {5, 1},
+ })
+ case "klv":
+ err = mw.WriteKLV(track1, 2*90000, []byte{0x06, 0x0e, 0x2b, 0x34})
+ }
+ require.NoError(t, err)
- var c *gohlslib.Client
- c = &gohlslib.Client{
- URI: "http://localhost:5781/stream.m3u8",
- OnTracks: func(tracks []*gohlslib.Track) error {
- medias, err2 := ToStream(c, tracks, &conf.Path{
- UseAbsoluteTimestamp: true,
- }, &subStream)
- require.NoError(t, err2)
+ case r.Method == http.MethodGet && r.URL.Path == "/segment2.ts":
+ w.Header().Set("Content-Type", `video/MP2T`)
- require.Equal(t, []*description.Media{{
- Type: description.MediaTypeVideo,
- Formats: []format.Format{&format.H264{
- PayloadTyp: 96,
- PacketizationMode: 1,
- }},
- }}, medias)
+ mw := &mpegts.Writer{W: w, Tracks: []*mpegts.Track{track1}}
+ err := mw.Initialize()
+ require.NoError(t, err)
- strm = &stream.Stream{
- Desc: &description.Session{Medias: medias},
- WriteQueueSize: 512,
- RTPMaxPayloadSize: 1450,
- Parent: test.NilLogger,
- }
- err2 = strm.Initialize()
- require.NoError(t, err2)
-
- subStream = &stream.SubStream{
- Stream: strm,
- UseRTPPackets: false,
- }
- err2 = subStream.Initialize()
- require.NoError(t, err2)
-
- n := 0
-
- r.OnData(
- medias[0],
- medias[0].Formats[0],
- func(u *unit.Unit) error {
- switch n {
- case 0:
- require.Equal(t, unit.PayloadH264{
- {7, 1, 2, 3},
- {8},
- {5, 1},
- }, u.Payload)
- require.Equal(t, time.Date(2018, 0o5, 20, 8, 17, 15, 0, time.UTC), u.NTP)
- case 1:
- require.Equal(t, unit.PayloadH264{
- {7, 1, 2, 3},
- {8},
- {5, 2},
- }, u.Payload)
- require.Equal(t, time.Date(2018, 0o5, 20, 8, 17, 15, 0, time.UTC), u.NTP)
- close(done)
- default:
- t.Error("should not happen")
+ switch ca {
+ case "h264":
+ err = mw.WriteH264(track1, 2*90000, 2*90000, [][]byte{
+ {5, 2},
+ })
+ case "klv":
+ err = mw.WriteKLV(track1, 2*90000, []byte{0x01, 0x02, 0x03, 0x04})
+ }
+ require.NoError(t, err)
}
- n++
+ }),
+ }
+
+ ln, err := net.Listen("tcp", "localhost:0")
+ require.NoError(t, err)
+
+ go s.Serve(ln)
+ defer s.Shutdown(context.Background())
+
+ var strm *stream.Stream
+ var subStream *stream.SubStream
+ done := make(chan struct{})
+
+ r := &stream.Reader{Parent: test.NilLogger}
+
+ var c *gohlslib.Client
+ c = &gohlslib.Client{
+ URI: "http://" + ln.Addr().String() + "/stream.m3u8",
+ OnTracks: func(tracks []*gohlslib.Track) error {
+ medias, err2 := ToStream(c, tracks, &conf.Path{
+ UseAbsoluteTimestamp: true,
+ }, &subStream)
+ require.NoError(t, err2)
+
+ switch ca {
+ case "h264":
+ require.Equal(t, []*description.Media{{
+ Type: description.MediaTypeVideo,
+ Formats: []format.Format{&format.H264{
+ PayloadTyp: 96,
+ PacketizationMode: 1,
+ }},
+ }}, medias)
+ case "klv":
+ require.Equal(t, []*description.Media{{
+ Type: description.MediaTypeApplication,
+ Formats: []format.Format{&format.KLV{
+ PayloadTyp: 96,
+ }},
+ }}, medias)
+ }
+
+ strm = &stream.Stream{
+ Desc: &description.Session{Medias: medias},
+ WriteQueueSize: 512,
+ RTPMaxPayloadSize: 1450,
+ Parent: test.NilLogger,
+ }
+ err2 = strm.Initialize()
+ require.NoError(t, err2)
+
+ subStream = &stream.SubStream{
+ Stream: strm,
+ UseRTPPackets: false,
+ }
+ err2 = subStream.Initialize()
+ require.NoError(t, err2)
+
+ n := 0
+
+ r.OnData(
+ medias[0],
+ medias[0].Formats[0],
+ func(u *unit.Unit) error {
+ switch ca {
+ case "h264":
+ switch n {
+ case 0:
+ require.Equal(t, unit.PayloadH264{
+ {7, 1, 2, 3},
+ {8},
+ {5, 1},
+ }, u.Payload)
+ require.Equal(t, time.Date(2018, 0o5, 20, 8, 17, 15, 0, time.UTC), u.NTP)
+ case 1:
+ require.Equal(t, unit.PayloadH264{
+ {7, 1, 2, 3},
+ {8},
+ {5, 2},
+ }, u.Payload)
+ require.Equal(t, time.Date(2018, 0o5, 20, 8, 17, 15, 0, time.UTC), u.NTP)
+ close(done)
+ default:
+ t.Error("should not happen")
+ }
+
+ case "klv":
+ switch n {
+ case 0:
+ require.Equal(t, unit.PayloadKLV{0x06, 0x0e, 0x2b, 0x34}, u.Payload)
+ require.Equal(t, time.Date(2018, 0o5, 20, 8, 17, 15, 0, time.UTC), u.NTP)
+ case 1:
+ require.Equal(t, unit.PayloadKLV{0x01, 0x02, 0x03, 0x04}, u.Payload)
+ require.Equal(t, time.Date(2018, 0o5, 20, 8, 17, 15, 0, time.UTC), u.NTP)
+ close(done)
+ default:
+ t.Error("should not happen")
+ }
+ }
+ n++
+ return nil
+ })
+
+ strm.AddReader(r)
+
return nil
- })
+ },
+ }
+ err = c.Start()
+ require.NoError(t, err)
+ defer c.Close()
- strm.AddReader(r)
+ <-done
- return nil
- },
+ strm.RemoveReader(r)
+ strm.Close()
+ })
}
- err = c.Start()
- require.NoError(t, err)
- defer c.Close()
-
- <-done
-
- strm.RemoveReader(r)
- strm.Close()
}