This is a series of articles. Follow the link here to get an overview over all articles.
Previously
on Using FFmpeg as a HLS streaming server (Part 1) – HLS Basics
We have set up our fist livestream that was already playable in safari. But we have seen, that the segmentation is not working as expected.
After a look in the stream.m3u8 we have a big surprise: The given target duration of 4 seconds are not used. Instead a TARGETDURATION of 10 is set and the segment length (value after #EXTINF:) is also not constant. A constant value is required for a good buffering in the player. We don’t want any interruptions.
Cause
The problem here is that the segmenter splits starts a new file only at keyframes (I-Frames). This makes sense, because if you e.g. seek in the stream the player chooses the nearest new stream*.ts file and starts playing it.
How to solve (step 1)
-g 25 sets the group picture size to 25. My video source has 25 FPS (25 pictures per second). So each second will start with a new picture group. This option forces a target size of 25 frames. After that a new group will be created (starting with a new I-Frame).
Well, now it is much closer to what we want. But there are still some glitches above and also below 4 seconds.
How to solve (step 2)
The reason for this is that FFmpeg has a scene detection. This means, that always when a new scene starts an I-Frame will be set. Since it’s FFmpeg we can easily disable this feature.
-sc_threshold 0
And the new playlist looks as we were expecting: Segments with the exact same duration.
The new command so far is:
./ffmpeg -listen 1 -i rtmp://martin-riedl.de/stream01 \ -c:v libx264 -crf 21 -preset veryfast -g 25 -sc_threshold 0 \ -c:a aac -b:a 128k -ac 2 \ -f hls -hls_time 4 -hls_playlist_type event stream.m3u8
Thank you for such useful information! -sc_threshold 0 and the concept that all target durations should be the same and how to achieve it was really useful for my project. Cheers!
Thanks 🙂
I have a question: for c:v both values work: libx264 and h264. Are they identical? If not, what is the difference?
Short:
Both produce a h264 video output.
Long:
FFmpeg supports a lot of h264 codec implementations.
The most commonly used is x264, because it produces high quality video with a lot of settings. But, it’s a software only codec so it uses only the CPU during encoding.
There exists a lot of other h264 codecs like h264_videotoolbox on MacOS. Those use hardware acceleration and are usually faster that software only codecs.
More information about the hardware acceleration can be found on https://trac.ffmpeg.org/wiki/HWAccelIntro
Thank you very much!
Awesome. Thank’s for this hint 🙂
Glad to help ?
Hello, thanks for the information, the same thing happened to me.
I was able to solve it thanks to this post, now I have a question with the command “-g”. Does this have to have the FPS value of the original video?
But if it is used to convert many videos with different FPS, then it is a problem, right? I was reviewing my videos and they are from different FPS, example: 23,976, 24, 25, 30.
So if I want to automate it, to convert whatever the FPS of the original video is, there is some way to detect the amount of FPS of the video and use this to populate the “-g” command.
I hope you can understand me, I only speak Spanish and I use google translator, greetings.
You can try using FFprobe to extract video information like FPS.
See https://stackoverflow.com/questions/27792934/get-video-fps-using-ffprobe
And with this value you can then build the FFmpeg command.
is there any way we can specify a video bitrate of our own instead of using a preset?
Check out part 3 of this series: https://www.martin-riedl.de/2018/08/25/using-ffmpeg-as-a-hls-streaming-server-part-3/
Hi,
Thanks for the tutorial.
Is there any way to probe the fps of an RTMP input? (before setting the gop)