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)
I’m using ffmpeg to write videos near my house. I’m also using ffmpeg to cut up videos whenever event happens (ffmpeg -ss 5 seconds). But it cuts not 5 seconds but in most cases 5-15 seconds before my event.
Will sc_threshold help me? Is it my case?
Do I need use this option while writing or while cutting videos?
I assume that you are re-encoding the video and not just using the copy command.
Have you tried putting the -ss 5 behind the -i input.file? It makes a big difference, where to put the -ss (before or behind the input).
Putting it behind the input is typically a bit slower but more accurate.
Hi,
Nope, I’ m just cutting it without reencoding:
ffmpeg -copyts -ss ${timepre} -i ${filemain} -vcodec copy -acodec copy …
I had a lot of experiments, I recall smth from stackoverflow forum regarding the -ss option location, but I don’t remember for sure my results, I will try this again and let you know.
Thanks!
It is not possible with vcodec copy to seek exactly.
This is because you can only seek to the next keyframe of the source video. You need to re-encode (e.g. using vcodec x264).
Hi, I tried to put -ss after the input file.
Yes, it cuts more precisely, but my video stream stuck (blanc screen) at the beginning for some reason despite that I hear the sound…