I am using ffmpeg to live stream video from a Decklink SDI card, and audio with DShow (Dante Virtual Soundcard), and packaging it into an fMP4 HLS livestream. My sources are genlocked to a single SPG clock source (Tri-level ref into an ATEM switcher, and Wordclock into a Dante Rednet interface which is set to be the leader), so in theory they shouldn’t drift.
The livestream is stable for about ~4 hours until suddenly:
[mp4 @ 000001ec63a02300] Packet duration: -441 / dts: 695109876 in stream 0 is out of range
“Stream 0” is the H.265 stream, but it’s unclear to me how or if it is the cause.
After this, the A/V lip sync is noticeably off by half a second or so. I’m not sure how a packet duration can become negative like this, or why it only occurs 4 hours in. Perhaps even with genlock, timestamps from Decklink or DShow are unreliable, some value is rolling over, or some misaligned item builds up over time?
From what I understand about multi-variant HLS/CMAF/fMP4 live streaming, video & audio segments aren’t guaranteed to slice to the exact same duration, but successful A/V sync is achieved on the client side through a combination of: “#EXT-X-PROGRAM-DATE-TIME”, the “tfdt” box, and traditional PTS, but I’m not sure how far upstream this desync problem is occurring.
I’ve tried so many combinations of “genpts”, “wallclock timestamps”, but hopefully someone will have a clue. I can FFprobe some m4s segments if it’s helpful.
My next steps are to try:
- a macOS machine (swapping DirectShow with CoreAudio)
- eliminating each encoder one by one
- removing “-r” rate parameters
- a different muxer besides fMP4 HLS
Each time leaving it running over night. Will update this ticket if I find anything.
FFmpeg command below. I know it’s a chonker, but I didn’t want to leave anything out since I figure every encoder parameter could be important. A key goal of this was to stream in HDR, SDR, and with lossless audio for concerts & DJ mix shows. It works great… for 4 hours at least. :p
ffmpeg -y `
-f decklink -raw_format yuv422p10 -rtbufsize 1G -signal_loss_action 3 -i "DeckLink Mini Recorder 4K" `
-f dshow -i audio="DVS Receive 1-2 (Dante Virtual Soundcard)" `
`
-filter_complex '[0:v]split=2[vhdr][vsdr];[vhdr]null[vhdrout];[vsdr]lut3d=lut.cube:interp=tetrahedral[sdrout];[1:a]asplit=2[aud1][aud2];[aud1]adelay=14800S|14800S[audio1out];[aud2]adelay=13000S|13000S[audio2out]' `
`
-map "[vhdrout]" `
-c:v:0 libx265 -r:v:0 30000/1001 `
-pix_fmt:v:0 yuv420p10le -profile:v:0 main10 -preset:v:0 veryfast `
-force_key_frames:v:0 "expr:eq(mod(n,60),0)" `
-x265-params:v:0 "colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc:range=limited:repeat-headers=1:master-display=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1):max-cll=1000,300:open-gop=0:hdr10-opt=1:hdr10=1:crf=14:vbv-maxrate=8000:vbv-bufsize=14000:keyint=120:min-keyint=60" `
-color_primaries:v:0 bt2020 -color_trc:v:0 smpte2084 -colorspace:v:0 bt2020nc `
-tag:v:0 hvc1 `
`
-map "[sdrout]" -r:v:1 30000/1001 `
-c:v:1 libx264 -pix_fmt:v:1 yuv420p -profile:v:1 high -preset:v:1 veryfast `
-force_key_frames:v:1 "expr:eq(mod(n,60),0)" `
-x264-params:v:1 "colorprim=bt709:transfer=bt709:colormatrix=bt709:crf=22:vbv-maxrate=5000:vbv-bufsize=8000:keyint=120:min-keyint=60:rc-lookahead=60" `
`
-map "[audio1out]" -c:a:0 flac -frame_size:a:0 4096 `
-map "[audio2out]" -c:a:1 libfdk_aac -b:a:1 256k `
`
-max_interleave_delta 0 `
-f hls -hls_segment_type fmp4 -hls_time 6 -hls_delete_threshold 5 -hls_list_size 6 `
-hls_flags independent_segments+delete_segments+program_date_time `
-var_stream_map "v:0,name:live-1080-hdr v:1,name:live-1080-sdr a:0,name:live-audio-flac a:1,name:live-audio-aac" `
-hls_start_number_source datetime -hls_segment_filename "%v/segment_%03d.m4s" "%v/track.m3u8"