-
-
Notifications
You must be signed in to change notification settings - Fork 898
Open
Description
Environment
- Client Library: RootEncoder (Pedro's library)
- Server: ZLMediaKit (latest
masterbranch, Docker) - Docker Image:
zlmediakit/zlmediakit:master - Protocol: SRT with MPEG-TS muxing
- Codec: H.264 (also tested with H.265)
- Platform: Android (tested Android 11+)
Issue Description
SRT streaming using MPEG-TS causes ZLMediaKit to crash after approximately 4–5 minutes of streaming.
The server terminates due to an assertion failure inside the TS demuxer.
Assertion failed: (0), function ts_demuxer_input,
file /opt/media/ZLMediaKit/3rdpart/media-server/libmpeg/source/mpeg-ts-dec.c,
line 261
Error Details
ZLMediaKit Log
2026-01-20 17:28:52.692 T [MediaServer] [1-event poller 5] SrtTransport.cpp:776 handleDataPacket | pkt lost 1770381322->1770382164
2026-01-20 17:28:52.692 W [MediaServer] [1-event poller 5] TSDecoder.cpp:69 operator() | ts packet lost, dts:25771715 pts:25771715 bytes:14465
2026-01-20 17:28:55.275 T [MediaServer] [1-event poller 5] UdpServer.cpp:342 operator() | 60-57(192.168.1.36:59624) SRT::SrtSession on err: 6(Assertion failed: (0), function ts_demuxer_input, file /opt/media/ZLMediaKit/3rdpart/media-server/libmpeg/source/mpeg-ts-dec.c, line 261.)
- Stream duration before crash: ~291 seconds
Configuration
Video Encoder (Android)
- Resolution: 720p (1280×720)
- FPS: 30
- Bitrate: 2.5 Mbps
- GOP: 2 seconds (60 frames)
- Codec: H.264 (also tested H.265)
- Audio: Disabled (video-only stream)
SRT Client
- Latency: 300ms
- Cache: 1200 frames
- CheckServerAlive:
true
Code Implementation
SrtSender.kt (video-only TS)
private fun setTrackConfig(videoEnabled: Boolean, audioEnabled: Boolean) {
Pid.reset()
service.clearTracks()
if (videoEnabled) service.addTrack(commandsManager.videoCodec.toCodec())
service.generatePmt()
psiManager.updateService(service)
Log.i(TAG, "Track config: video=$videoEnabled, audio=false (forced video-only for SRT)")
}
override suspend fun sendAudioFrame(mediaFrame: MediaFrame) {
Log.d(TAG, "Skipping audio packet for video-only SRT stream")
return
}Reproduction Steps
- Configure
GenericStreamwith H.264 encoder (720p @ 30fps, 2.5Mbps) - Set SRT URL:
srt://server:9000?streamid=publish:app/stream - Start streaming
- Stream runs normally for 4–5 minutes
- ZLMediaKit crashes with TS demuxer assertion failure
Observations
- RTMP streaming with identical encoder settings is stable for 1–5 hours
- SRT streaming crashes consistently after 4–5 minutes
- Issue reproduces with:
- H.264 and H.265
- Bitrates from 1.5 Mbps to 5 Mbps
- Resolutions from 360p to 720p
Analysis / Suspected Causes
PCR Timing Issues
val pcr = if (isAudio && !mpegTsPayload.isKeyFrame)
null
else
TimeUtils.getCurrentTimeMicro()For video-only streams, PCR may not be continuous or frequent enough for strict TS demuxers.
Adaptation Field Flags
randomAccessIndicatoris only set for keyframes
Continuity Counter
- Potential overflow or reset issues during long streams
PTS / DTS Drift
- Timestamp drift may accumulate over time
Potential Fixes
Fix 1: Always Include PCR for Video-Only Streams
val pcr = TimeUtils.getCurrentTimeMicro()Fix 2: Enforce PCR Interval (e.g. every 100ms)
private var lastPcrTime = 0L
private val pcrInterval = 100_000L
val currentTime = TimeUtils.getCurrentTimeMicro()
val pcr = if (currentTime - lastPcrTime >= pcrInterval) {
lastPcrTime = currentTime
currentTime
} else nullFix 3: Validate Continuity Counter Wrap
pesContinuity = (pesContinuity + 1) and 0xF
if (pesContinuity == 0) {
Log.w(TAG, "PES continuity counter wrapped")
}Workarounds
- Use RTMP instead of SRT (stable for hours)
- Patch ZLMediaKit TS demuxer to skip invalid packets instead of asserting
Expected Behavior
SRT streaming should remain stable for hours without TS demuxer crashes.
Questions
- Is this a known compatibility issue with ZLMediaKit’s TS demuxer?
- Does ZLMediaKit expect stricter PCR / continuity rules for MPEG-TS over SRT?
- Should TS packet generation be adjusted to be more conservative?
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels