The main problem you are facing is probably that your video file does not have key frames in the fit positions . This is especially a problem if you just copy the streams from the input.
FFmpeg depends on key frames to calculate when to "cut" a segment. It makes sense when you think about it. You cannot just make a cut between two keyframes, since each segment must be fully functional in itself. Now it can be argued that FFmpeg should just insert new keyframes on its own, but that would be too friendly, right?)
Fortunately, you can pin keyframes with FFmpeg. Either use the parameter, or set the flag in the code yourself. You said you already tried to force keyframes, but I assume that you did not do it right.
This my test gives good results. This is just a command line, sorry, but you already know how to apply command line parameters in your code, so everything should be fine. Also note that I do not use the "hls_XXX" parameters, because: a) I honestly do not trust them, and b) in this way, I suppose, it should also work for non-HLS streams.
ffmpeg -i inputFile.mov -force_key_frames "expr:gte(t,n_forced*10)" -strict -2 -c:a aac -c:v libx264 -f segment -segment_list_type m3u8 -segment_list_size 0 -segment_time 10.0 -segment_time_delta 0.1 -segment_list stream/test.m3u8 stream/test%02d.ts
You can see exactly how the force_key_frames command works here .
So far, I have implemented the above C ++ command with some additions. But without "force_key_frames", when I set keyframes manually during the transcoding process. Here is what I did:
AVDictionary* headerOptions(0); av_dict_set(&headerOptions, "segment_format", "mpegts", 0); av_dict_set(&headerOptions, "segment_list_type", "m3u8", 0); av_dict_set(&headerOptions, "segment_list", _playlistFileName.c_str(), 0); av_dict_set_int(&headerOptions, "segment_list_size", 0, 0); av_dict_set(&headerOptions, "segment_time_delta", TO_STRING(1.00).c_str(), 0); av_dict_set(&headerOptions, "segment_time", TO_STRING(_segmentDuration).c_str(), 0); av_dict_set_int(&headerOptions, "reference_stream", _videoStream->index, 0); av_dict_set(&headerOptions, "segment_list_flags", "cache+live", 0); avformat_write_header(_formatContext, &headerOptions);
And here is the result of m3u8:
#EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-ALLOW-CACHE:YES #EXT-X-TARGETDURATION:11 #EXTINF:10.083333, test00.ts #EXTINF:10.000000, test01.ts #EXTINF:10.000000, test02.ts #EXTINF:10.000000, test03.ts #EXTINF:10.000000, test04.ts #EXTINF:10.000000, test05.ts #EXTINF:0.083333, test06.ts #EXT-X-ENDLIST
This is not ideal (the first part is somewhat in some way), but I am convinced that you will not get better results than this.
Of course, the best option would be to make sure that your input files always have the correct key frames when copying streams simply, but sometimes you have no control over what files you get.
Side note
When you use FFmpeg in code, always try to do what you do in code using the cli ffmpeg command. If you can get it to work this way, you at least know what parameters to set in the code. And if it works with the command line tool, you know that this should be possible in the code in some way;)