Skip to content

muxer fail then panic "writePacket: can't write 185 bytes of payload: only 184 is available... " on muxer.WriteData(&astits.MuxerData{ ... #50

@ayhangenc

Description

@ayhangenc

Hi,

I'm working on a simple RTSP to SRT/MPEG-TS gateway (X.7). Lately I'm having error messages and panics during my development and tests.
Here is the test flow:

ffmpeg (mimicing a RTSP camera) --> RTSP server ( mediamtx) --> X.7 gateway app --> ffplay (mimicing SRT consumer)

RTSP Source:

ffmpeg -re -f lavfi -i "smptehdbars=rate=15:size=1280x720" -f lavfi -i "sine=frequency=1000:sample_rate=48000" -vf drawtext="text='Test Stream #1 // :timecode=01\:00\:00\:00':rate=25:x=(w-tw)/2:y=(h-lh)/2:fontsize=55:fontcolor=black:box=1:boxcolor=red" -f rtsp -c:v h264 -crf 26 -preset fast -tune zerolatency -c:a aac -b:a 128k "rtsp://127.0.0.1:8554/live1"

mediamtx is the prebuilt binary with default configuration available on github.

X.7 is using the following packages:
"github.com/asticode/go-astits"
"github.com/haivision/srtgo"
"github.com/bluenviron/gortsplib/v3"

X.7 decode H.264 video and MPEG-4 audio from RTSP stream using gortsplib, extract access units then feed them to MPEG-TS/SRT encoder.
the encoder muxes the access units into TS stream withgo- astits with SRT wrapping using srtgo then transmit it to SRT consumer.

and finally ffplay is acting like a SRT consumer
ffplay "srt://127.0.0.1:5808?mode=listener"

This workflow was working fine for several hours without any error or panic. Then last week I faced a panic with the working code.
The panic is not instant, I run the code, have a fine stream on ffplay for a while (several minutes mainly) then start to get error messages on app log

2023/06/13 10:46:23 SRT MPEGTS muxer write SRT Video error: writePacket: can't write 213 bytes of payload: only 182 is available... 

after some point the video on ffplay freeze and stay frozen forever and ffplay log popping the following following messages continously.

...
[mpegts @ 0x7fbf19f16c00] changing packet size to 192    0B f=0/0   
[mpegts @ 0x7fbf19f16c00] changing packet size to 188    0B f=0/0   
[mpegts @ 0x7fbf19f16c00] changing packet size to 192    0B f=0/0   
[mpegts @ 0x7fbf19f16c00] changing packet size to 188    0B f=0/0   
[mpegts @ 0x7fbf19f16c00] changing packet size to 204    0B f=0/0   
[mpegts @ 0x7fbf19f16c00] changing packet size to 188    0B f=0/0   
1906.04 A-V:520.879 fd= 123 aq=    0KB vq=    0KB sq=    0B f=0/0   
...

after a while, I have panic on app:

panic: runtime error: slice bounds out of range [120:0]

goroutine 52 [running]:
bytes.(*Buffer).Write(0x3?, {0xc000280318?, 0xc00004a970?, 0x10039f53b?})
        /usr/local/go/src/bytes/buffer.go:172 +0xd6
github.com/asticode/go-astikit.(*BitsWriter).write(0xc000298320, {0xc000280318, 0x1, 0x1})
        /Users/anyuser/go/pkg/mod/github.com/asticode/[email protected]/binary.go:142 +0x3d
github.com/asticode/go-astikit.(*BitsWriter).flushBsCache(...)
        /Users/anyuser/go/pkg/mod/github.com/asticode/[email protected]/binary.go:169
github.com/asticode/go-astikit.(*BitsWriter).writeFullByte(0x0?, 0x20?)
        /Users/anyuser/go/pkg/mod/github.com/asticode/[email protected]/binary.go:179 +0x7e
github.com/asticode/go-astikit.(*BitsWriter).writeByteSlice(0xc000298320, {0xc000599180, 0xa8, 0xc00004aaa0?})
        /Users/anyuser/go/pkg/mod/github.com/asticode/[email protected]/binary.go:130 +0x89
github.com/asticode/go-astikit.(*BitsWriter).Write(0xc000298320?, {0x1003e5cc0?, 0xc00004aa50?})
        /Users/anyuser/go/pkg/mod/github.com/asticode/[email protected]/binary.go:75 +0xa5
github.com/asticode/go-astits.writePESData(0x100405d00?, 0xc000282570?, {0xc000599180?, 0x1aa?, 0x1aa?}, 0x8?, 0xb6?)
        /Users/anyuser/go/pkg/mod/github.com/asticode/[email protected]/data_pes.go:465 +0xb3
github.com/asticode/go-astits.(*Muxer).WriteData(0xc0002846e0, 0xc00004acb8)
        /Users/anyuser/go/pkg/mod/github.com/asticode/[email protected]/muxer.go:230 +0x4dd
X.7/gateway.(*SRT).Encode(0xc0000e2580, {0xc0003c9aa0, 0x4, 0x10038d28a?}, {0x0?, 0x10005687f?, 0x10004e552?}, 0x7db35b0a00)
        /Users/anyuser/GolandProjects/X.7/gateway/srt.go:175 +0x10cd
X.7/gateway.(*Gateway).RunRTSP.func1(0xc000292140?)
        /Users/anyuser/GolandProjects/X.7/gateway/rtsp.go:127 +0x191
github.com/bluenviron/gortsplib/v3.(*clientFormat).readRTPUDP(0xc0002983c0, 0xc000282870?)
        /Users/anyuser/go/pkg/mod/github.com/bluenviron/gortsplib/[email protected]/client_format.go:117 +0x185
github.com/bluenviron/gortsplib/v3.(*clientMedia).readRTPUDPPlay(0xc000296480, {0xc000176000, 0xc00004af20?, 0x5c1})
        /Users/anyuser/go/pkg/mod/github.com/bluenviron/gortsplib/[email protected]/client_media.go:291 +0xae
github.com/bluenviron/gortsplib/v3.(*clientUDPListener).runReader(0xc0002b80e0)
        /Users/anyuser/go/pkg/mod/github.com/bluenviron/gortsplib/[email protected]/client_udp_listener.go:195 +0x1e5
created by github.com/bluenviron/gortsplib/v3.(*clientUDPListener).start
        /Users/anyuser/go/pkg/mod/github.com/bluenviron/gortsplib/[email protected]/client_udp_listener.go:153 +0xaa
exit status 2

This is how I implemented the encoder:
(error handling removed for brevity)

func (s *SRT) Encode(auv [][]byte, aua []byte, pts time.Duration) error {
	if auv != nil && aua == nil { //Video stream
		filteredNALUs := [][]byte{
			{byte(h264.NALUTypeAccessUnitDelimiter), 240},
		}
		nonIDRPresent := false
		idrPresent := false
		for _, nalu := range auv {
			typ := h264.NALUType(nalu[0] & 0x1F)
			switch typ {
			case h264.NALUTypeSPS:
				s.sps = append([]byte(nil), nalu...)
				continue
			case h264.NALUTypePPS:
				s.pps = append([]byte(nil), nalu...)
				continue
			case h264.NALUTypeAccessUnitDelimiter:
				continue
			case h264.NALUTypeIDR:
				idrPresent = true
			case h264.NALUTypeNonIDR:
				nonIDRPresent = true
			}
			filteredNALUs = append(filteredNALUs, nalu)
		}
		auv = filteredNALUs
		if !nonIDRPresent && !idrPresent {
			log.Println("IDR-nonIDR Not Present Error: ")
			return fmt.Errorf("IDR-nonIDR Not Present Error")
		}
		if idrPresent {
			auv = append([][]byte{s.sps, s.pps}, auv...)
		}
		var dts time.Duration
		if !s.firstIDRReceived {
			// skip samples silently until we find one with a IDR
			if !idrPresent {
				log.Println("IDR Not Present Error: ")
				return fmt.Errorf("IDR Not Present Error")
			}
			s.firstIDRReceived = true
			s.dtsExtractor = h264.NewDTSExtractor()
			dts, err = s.dtsExtractor.Extract(auv, pts)
			s.startDTS = dts
			dts = 0
			pts -= s.startDTS
		} else {
			dts, err = s.dtsExtractor.Extract(auv, pts)
			if err != nil {
				log.Println("DTS Extract Error: ", err)
			}
			dts -= s.startDTS
			pts -= s.startDTS
		}
		oh := &astits.PESOptionalHeader{
			MarkerBits: 2,
		}
		if dts == pts {
			oh.PTSDTSIndicator = astits.PTSDTSIndicatorOnlyPTS
			oh.PTS = &astits.ClockReference{Base: int64(pts.Seconds() * 90000)}
		} else {
			oh.PTSDTSIndicator = astits.PTSDTSIndicatorBothPresent
			oh.DTS = &astits.ClockReference{Base: int64(dts.Seconds() * 90000)}
			oh.PTS = &astits.ClockReference{Base: int64(pts.Seconds() * 90000)}
		}
		// encode into Annex-B
		annexb, err := h264.AnnexBMarshal(auv)
		// write TS packet to srt
		_, err = s.muxSRT.WriteData(&astits.MuxerData{   //////// this is where I get the error message !
			PID: 256,
			AdaptationField: &astits.PacketAdaptationField{
				RandomAccessIndicator: idrPresent,
			},
			PES: &astits.PESData{
				Header: &astits.PESHeader{
					OptionalHeader: oh,
					StreamID:       224, // video
				},
				Data: annexb,
			},
		})
	} else if auv == nil && aua != nil{ //Audio stream
		// wrap access unit inside an ADTS packet
		pkts := mpeg4audio.ADTSPackets{
			{
				Type:         s.config.Type,
				SampleRate:   s.config.SampleRate,
				ChannelCount: s.config.ChannelCount,
				AU:           aua,
			},
		}
		enc, err := pkts.Marshal()
		err = s.muxSRT.WriteData(&astits.MuxerData{  //////// this is where I get the error message !
			PID: 257,
			AdaptationField: &astits.PacketAdaptationField{
				RandomAccessIndicator: true,
			},
			PES: &astits.PESData{
				Header: &astits.PESHeader{
					OptionalHeader: &astits.PESOptionalHeader{
						MarkerBits:      2,
						PTSDTSIndicator: astits.PTSDTSIndicatorOnlyPTS,
						PTS:             &astits.ClockReference{Base: int64(pts.Seconds() * 90000)},
					},
					PacketLength: uint16(len(enc) + 8),
					StreamID:     192, // audio
				},
				Data: enc,
			},
		})
	}
	return nil
}

Thanks...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions