hls: support reading and writing KLV (#5604)

This commit is contained in:
eh
2026-04-30 12:14:00 +02:00
committed by GitHub
parent 9b4531364e
commit fcf5eb092d
6 changed files with 319 additions and 146 deletions
+13 -13
View File
@@ -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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3<br/>**Other**: KLV |
| [WebRTC clients](../3-publish/03-webrtc-clients.md) | WHIP | **Video**: AV1, VP9, VP8, H265, H264<br/>**Audio**: Opus, G722, G711 (PCMA, PCMU) |
| [WebRTC servers](../3-publish/04-webrtc-servers.md) | WHEP | **Video**: AV1, VP9, VP8, H265, H264<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM<br/>**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<br/>**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<br/>**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<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3<br/>**Other**: KLV |
| [WebRTC clients](../3-publish/03-webrtc-clients.md) | WHIP | **Video**: AV1, VP9, VP8, H265, H264<br/>**Audio**: Opus, G722, G711 (PCMA, PCMU) |
| [WebRTC servers](../3-publish/04-webrtc-servers.md) | WHEP | **Video**: AV1, VP9, VP8, H265, H264<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM<br/>**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<br/>**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<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC)<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM<br/>**Other**: KLV, MPEG-TS, any RTP-compatible codec |
We provide instructions for publishing with the following devices:
+7 -7
View File
@@ -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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3<br/>**Other**: KLV |
| [WebRTC clients](../4-read/02-webrtc.md) | WHEP | **Video**: AV1, VP9, VP8, H265, H264<br/>**Audio**: Opus, G722, G711 (PCMA, PCMU)<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM<br/>**Other**: KLV, MPEG-TS, any RTP-compatible codec |
| [RTMP clients](../4-read/04-rtmp.md) | RTMP, RTMPS, Enhanced RTMP | **Video**: AV1, VP9, H265, H264<br/>**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<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3<br/>**Other**: KLV |
| [WebRTC clients](../4-read/02-webrtc.md) | WHEP | **Video**: AV1, VP9, VP8, H265, H264<br/>**Audio**: Opus, G722, G711 (PCMA, PCMU)<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM<br/>**Other**: KLV, MPEG-TS, any RTP-compatible codec |
| [RTMP clients](../4-read/04-rtmp.md) | RTMP, RTMPS, Enhanced RTMP | **Video**: AV1, VP9, H265, H264<br/>**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<br/>**Audio**: Opus, MPEG-4 Audio (AAC)<br/>**Other**: KLV (MPEG-TS-based HLS only) |
We provide instructions for reading with the following software:
+55 -1
View File
@@ -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
}
@@ -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))
})
}
+17
View File
@@ -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")
}
+177 -125
View File
@@ -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()
}