rewrite Unit definition (#5079)
Some checks are pending
code_lint / go (push) Waiting to run
code_lint / go_mod (push) Waiting to run
code_lint / docs (push) Waiting to run
code_lint / api_docs (push) Waiting to run
code_test / test_64 (push) Waiting to run
code_test / test_32 (push) Waiting to run
code_test / test_e2e (push) Waiting to run

Stream units now share the same struct, with a specialized payload.
This commit is contained in:
Alessandro Ros 2025-10-11 12:18:51 +02:00 committed by GitHub
parent e2294836f5
commit f5f03562d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
86 changed files with 1100 additions and 1602 deletions

View file

@ -55,18 +55,16 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.AV1)
if tunit.TU == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
return (*w).WriteAV1(
forma,
timestampToDuration(tunit.PTS, forma.ClockRate()),
tunit.TU)
timestampToDuration(u.PTS, forma.ClockRate()),
u.Payload.(unit.PayloadAV1))
})
tracks = append(tracks, forma)
@ -77,18 +75,16 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.VP9)
if tunit.Frame == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
return (*w).WriteVP9(
forma,
timestampToDuration(tunit.PTS, forma.ClockRate()),
tunit.Frame)
timestampToDuration(u.PTS, forma.ClockRate()),
u.Payload.(unit.PayloadVP9))
})
tracks = append(tracks, forma)
@ -101,22 +97,20 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.H265)
if tunit.AU == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
if videoDTSExtractor == nil {
if !h265.IsRandomAccess(tunit.AU) {
if !h265.IsRandomAccess(u.Payload.(unit.PayloadH265)) {
return nil
}
videoDTSExtractor = &h265.DTSExtractor{}
videoDTSExtractor.Initialize()
}
dts, err := videoDTSExtractor.Extract(tunit.AU, tunit.PTS)
dts, err := videoDTSExtractor.Extract(u.Payload.(unit.PayloadH265), u.PTS)
if err != nil {
return err
}
@ -124,9 +118,9 @@ func FromStream(
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
return (*w).WriteH265(
forma,
timestampToDuration(tunit.PTS, forma.ClockRate()),
timestampToDuration(u.PTS, forma.ClockRate()),
timestampToDuration(dts, forma.ClockRate()),
tunit.AU)
u.Payload.(unit.PayloadH265))
})
tracks = append(tracks, forma)
@ -138,17 +132,15 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.H264)
if tunit.AU == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
idrPresent := false
nonIDRPresent := false
for _, nalu := range tunit.AU {
for _, nalu := range u.Payload.(unit.PayloadH264) {
typ := h264.NALUType(nalu[0] & 0x1F)
switch typ {
case h264.NALUTypeIDR:
@ -171,7 +163,7 @@ func FromStream(
return nil
}
dts, err := videoDTSExtractor.Extract(tunit.AU, tunit.PTS)
dts, err := videoDTSExtractor.Extract(u.Payload.(unit.PayloadH264), u.PTS)
if err != nil {
return err
}
@ -179,9 +171,9 @@ func FromStream(
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
return (*w).WriteH264(
forma,
timestampToDuration(tunit.PTS, forma.ClockRate()),
timestampToDuration(u.PTS, forma.ClockRate()),
timestampToDuration(dts, forma.ClockRate()),
tunit.AU)
u.Payload.(unit.PayloadH264))
})
tracks = append(tracks, forma)
@ -191,16 +183,14 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.Opus)
if tunit.Packets == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
pts := tunit.PTS
pts := u.PTS
for _, pkt := range tunit.Packets {
for _, pkt := range u.Payload.(unit.PayloadOpus) {
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
err := (*w).WriteOpus(
forma,
@ -224,15 +214,13 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.MPEG4Audio)
if tunit.AUs == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
for i, au := range tunit.AUs {
pts := tunit.PTS + int64(i)*mpeg4audio.SamplesPerAccessUnit
for i, au := range u.Payload.(unit.PayloadMPEG4Audio) {
pts := u.PTS + int64(i)*mpeg4audio.SamplesPerAccessUnit
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
err := (*w).WriteMPEG4Audio(
@ -255,16 +243,14 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioLATM)
if tunit.Element == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
var ame mpeg4audio.AudioMuxElement
ame.StreamMuxConfig = forma.StreamMuxConfig
err := ame.Unmarshal(tunit.Element)
err := ame.Unmarshal(u.Payload.(unit.PayloadMPEG4AudioLATM))
if err != nil {
return err
}
@ -272,7 +258,7 @@ func FromStream(
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
return (*w).WriteMPEG4Audio(
forma,
timestampToDuration(tunit.PTS, forma.ClockRate()),
timestampToDuration(u.PTS, forma.ClockRate()),
ame.Payloads[0][0][0],
)
})
@ -286,12 +272,14 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.MPEG1Audio)
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
pts := tunit.PTS
pts := u.PTS
for _, frame := range tunit.Frames {
for _, frame := range u.Payload.(unit.PayloadMPEG1Audio) {
var h mpeg1audio.FrameHeader
err := h.Unmarshal(frame)
if err != nil {
@ -321,11 +309,13 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.AC3)
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
for i, frame := range tunit.Frames {
pts := tunit.PTS + int64(i)*ac3.SamplesPerFrame
for i, frame := range u.Payload.(unit.PayloadAC3) {
pts := u.PTS + int64(i)*ac3.SamplesPerFrame
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
err := (*w).WriteAC3(
@ -348,18 +338,16 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.G711)
if tunit.Samples == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
return (*w).WriteG711(
forma,
timestampToDuration(tunit.PTS, forma.ClockRate()),
tunit.Samples,
timestampToDuration(u.PTS, forma.ClockRate()),
u.Payload.(unit.PayloadG711),
)
})
@ -375,18 +363,16 @@ func FromStream(
r.OnData(
media,
forma,
func(u unit.Unit) error {
tunit := u.(*unit.LPCM)
if tunit.Samples == nil {
func(u *unit.Unit) error {
if u.NilPayload() {
return nil
}
nconn.SetWriteDeadline(time.Now().Add(writeTimeout))
return (*w).WriteLPCM(
forma,
timestampToDuration(tunit.PTS, forma.ClockRate()),
tunit.Samples,
timestampToDuration(u.PTS, forma.ClockRate()),
u.Payload.(unit.PayloadLPCM),
)
})

View file

@ -419,31 +419,25 @@ func TestFromStream(t *testing.T) {
switch ca {
case "h264 + aac":
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.H264{
Base: unit.Base{
PTS: 0,
},
AU: [][]byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 0,
Payload: unit.PayloadH264{
{5, 2}, // IDR
},
})
strm.WriteUnit(medias[1], medias[1].Formats[0], &unit.MPEG4Audio{
Base: unit.Base{
PTS: 90000 * 5,
},
AUs: [][]byte{
strm.WriteUnit(medias[1], medias[1].Formats[0], &unit.Unit{
PTS: 90000 * 5,
Payload: unit.PayloadMPEG4Audio{
{3, 4},
},
})
case "av1":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.AV1{
Base: unit.Base{
PTS: 90000 * 2 * int64(i),
},
TU: [][]byte{{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 2 * int64(i),
Payload: unit.PayloadAV1{{
0x0a, 0x0e, 0x00, 0x00, 0x00, 0x4a, 0xab, 0xbf,
0xc3, 0x77, 0x6b, 0xe4, 0x40, 0x40, 0x40, 0x41,
}},
@ -452,21 +446,17 @@ func TestFromStream(t *testing.T) {
case "vp9":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.VP9{
Base: unit.Base{
PTS: 90000 * 2 * int64(i),
},
Frame: []byte{1, 2},
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 2 * int64(i),
Payload: unit.PayloadVP9{1, 2},
})
}
case "h265":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.H265{
Base: unit.Base{
PTS: 90000 * 2 * int64(i),
},
AU: [][]byte{{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 2 * int64(i),
Payload: unit.PayloadH265{{
0x2a, 0x01, 0xad, 0xe0, 0xf5, 0x34, 0x11, 0x0b,
0x41, 0xe8,
}},
@ -475,11 +465,9 @@ func TestFromStream(t *testing.T) {
case "h264":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.H264{
Base: unit.Base{
PTS: 90000 * 2 * int64(i),
},
AU: [][]byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 2 * int64(i),
Payload: unit.PayloadH264{
{5, 2}, // IDR
},
})
@ -487,11 +475,9 @@ func TestFromStream(t *testing.T) {
case "opus":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Opus{
Base: unit.Base{
PTS: 90000 * 5 * int64(i),
},
Packets: [][]byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 5 * int64(i),
Payload: unit.PayloadOpus{
{3, 4},
},
})
@ -499,11 +485,9 @@ func TestFromStream(t *testing.T) {
case "aac":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.MPEG4Audio{
Base: unit.Base{
PTS: 90000 * 5 * int64(i),
},
AUs: [][]byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 5 * int64(i),
Payload: unit.PayloadMPEG4Audio{
{3, 4},
},
})
@ -511,11 +495,9 @@ func TestFromStream(t *testing.T) {
case "mp3":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.MPEG1Audio{
Base: unit.Base{
PTS: 90000 * 5 * int64(i),
},
Frames: [][]byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 5 * int64(i),
Payload: unit.PayloadMPEG1Audio{
{
0xff, 0xfa, 0x52, 0x04, 0x00,
},
@ -525,11 +507,9 @@ func TestFromStream(t *testing.T) {
case "ac-3":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.AC3{
Base: unit.Base{
PTS: 90000 * 5 * int64(i),
},
Frames: [][]byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 5 * int64(i),
Payload: unit.PayloadAC3{
{
0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84,
0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea,
@ -586,11 +566,9 @@ func TestFromStream(t *testing.T) {
case "pcma", "pcmu":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.G711{
Base: unit.Base{
PTS: 90000 * 5 * int64(i),
},
Samples: []byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 5 * int64(i),
Payload: unit.PayloadG711{
3, 4,
},
})
@ -598,19 +576,17 @@ func TestFromStream(t *testing.T) {
case "lpcm":
for i := range 2 {
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.LPCM{
Base: unit.Base{
PTS: 90000 * 5 * int64(i),
},
Samples: []byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
PTS: 90000 * 5 * int64(i),
Payload: unit.PayloadLPCM{
3, 4, 5, 6,
},
})
}
case "h265 + h264 + vp9 + av1 + opus + aac":
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.H265{
AU: [][]byte{
strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{
Payload: unit.PayloadH265{
{
0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60,
0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03,
@ -634,36 +610,34 @@ func TestFromStream(t *testing.T) {
},
})
strm.WriteUnit(medias[1], medias[1].Formats[0], &unit.H264{
AU: [][]byte{
strm.WriteUnit(medias[1], medias[1].Formats[0], &unit.Unit{
Payload: unit.PayloadH264{
codecprocessor.H264DefaultSPS,
codecprocessor.H264DefaultPPS,
{5, 2}, // IDR
},
})
strm.WriteUnit(medias[2], medias[2].Formats[0], &unit.VP9{
Frame: []byte{1, 2},
strm.WriteUnit(medias[2], medias[2].Formats[0], &unit.Unit{
Payload: unit.PayloadVP9{1, 2},
})
strm.WriteUnit(medias[3], medias[3].Formats[0], &unit.AV1{
TU: [][]byte{{
strm.WriteUnit(medias[3], medias[3].Formats[0], &unit.Unit{
Payload: unit.PayloadAV1{{
0x0a, 0x0e, 0x00, 0x00, 0x00, 0x4a, 0xab, 0xbf,
0xc3, 0x77, 0x6b, 0xe4, 0x40, 0x40, 0x40, 0x41,
}},
})
strm.WriteUnit(medias[4], medias[4].Formats[0], &unit.Opus{
Packets: [][]byte{
strm.WriteUnit(medias[4], medias[4].Formats[0], &unit.Unit{
Payload: unit.PayloadOpus{
{3, 4},
},
})
strm.WriteUnit(medias[5], medias[5].Formats[0], &unit.MPEG4Audio{
Base: unit.Base{
PTS: 90000 * 5,
},
AUs: [][]byte{
strm.WriteUnit(medias[5], medias[5].Formats[0], &unit.Unit{
PTS: 90000 * 5,
Payload: unit.PayloadMPEG4Audio{
{3, 4},
},
})

View file

@ -46,12 +46,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataAV1(ttrack, func(pts time.Duration, tu [][]byte) {
(*stream).WriteUnit(medi, ctrack, &unit.AV1{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
TU: tu,
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadAV1(tu),
})
})
@ -63,12 +61,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataVP9(ttrack, func(pts time.Duration, frame []byte) {
(*stream).WriteUnit(medi, ctrack, &unit.VP9{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
Frame: frame,
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadVP9(frame),
})
})
@ -80,12 +76,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataH265(ttrack, func(pts time.Duration, _ time.Duration, au [][]byte) {
(*stream).WriteUnit(medi, ctrack, &unit.H265{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
AU: au,
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadH265(au),
})
})
@ -97,12 +91,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataH264(ttrack, func(pts time.Duration, _ time.Duration, au [][]byte) {
(*stream).WriteUnit(medi, ctrack, &unit.H264{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
AU: au,
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadH264(au),
})
})
@ -114,12 +106,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataOpus(ttrack, func(pts time.Duration, packet []byte) {
(*stream).WriteUnit(medi, ctrack, &unit.Opus{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
Packets: [][]byte{packet},
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadOpus{packet},
})
})
@ -131,12 +121,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataMPEG4Audio(ttrack, func(pts time.Duration, au []byte) {
(*stream).WriteUnit(medi, ctrack, &unit.MPEG4Audio{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
AUs: [][]byte{au},
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadMPEG4Audio{au},
})
})
@ -148,12 +136,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataMPEG1Audio(ttrack, func(pts time.Duration, frame []byte) {
(*stream).WriteUnit(medi, ctrack, &unit.MPEG1Audio{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
Frames: [][]byte{frame},
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadMPEG1Audio{frame},
})
})
@ -165,12 +151,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataAC3(ttrack, func(pts time.Duration, frame []byte) {
(*stream).WriteUnit(medi, ctrack, &unit.AC3{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
Frames: [][]byte{frame},
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadAC3{frame},
})
})
@ -182,12 +166,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataG711(ttrack, func(pts time.Duration, samples []byte) {
(*stream).WriteUnit(medi, ctrack, &unit.G711{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
Samples: samples,
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadG711(samples),
})
})
@ -199,12 +181,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media
medias = append(medias, medi)
r.OnDataLPCM(ttrack, func(pts time.Duration, samples []byte) {
(*stream).WriteUnit(medi, ctrack, &unit.LPCM{
Base: unit.Base{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
},
Samples: samples,
(*stream).WriteUnit(medi, ctrack, &unit.Unit{
NTP: time.Now(),
PTS: durationToTimestamp(pts, ctrack.ClockRate()),
Payload: unit.PayloadLPCM(samples),
})
})