Support

How can I live stream using FFMPEG?

Our online video platform supports live streaming however currently this option is only available in our larger packages. If you would like to use it, please get in touch.

Download FFMPEG

FFMPEG is a free, open-source command-line tool for working with video files.

You are generally fine using a pre-made, static binary file got from their downloads page. However if you are on a Mac, we found that their latest static binary stalls when outputting to rtmps:// (see below). We needed to use the version built by the Homebrew package manager, installed with brew install ffmpeg.

You can check your download/install worked by opening a terminal window and seeing its version. You should see something like this (along with its configuration):

$ ffmpeg -version
ffmpeg version 5.1.2 Copyright (c) 2000-2022 the FFmpeg developers
built with Apple clang version 11.0.3 (clang-1103.0.32.62)

If you instead see a message like:

$ ffmpeg -version
-bash: ffmpeg: command not found

… it may be that the FFMPEG command is present but is not in your PATH. On a Mac/Linux you can check to see where your binary is using the which command:

$ which ffmpeg
/usr/local/bin/ffmpeg

That provides its absolute path which you could either add to your PATH or use directly instead. At this point you should have a working copy of FFMPEG.

Create a live stream

Once live streaming has been enabled for your package/account, you can use either our Video API or our dashboard to create a new live stream. You need to do that in order to get a stream key.

If you used our dashboard to create the stream, there is a blue link below the player to get its details. If you used the API, that will return the stream key’s ID. You can use that ID to also fetch its details using the API.

Either way you should have a stream URL (for example rtmps://example.com/app) and a secret key (for example random_stream_key_example). Anybody that knows that key can stream to your account so please keep it safe!

Most applications (like OBS) will ask for those two values separately. For FFMPEG you will need to concatenate them into a single value. The complete URL you’ll use should look something like this:

rtmps://example.com/app/random_stream_key_example

Example stream

This is an example FFMPEG command that will generate a test pattern in HD (1080p) at 30fps. It will add some simple audio beeps and write the current time as text. We ensure there is a keyframe every two seconds, which results in segments that are two-seconds long. There is a trade-off between segment duration and latency but generally two or four seconds is a good middle-ground.

You can adjust the two 500K values (the bitrate) depending on your internet connection. Higher values look better but use more data.

Make sure to replace the value rtmps://example.com/app/random_stream_key_example with your own value.

ffmpeg -re -f lavfi -i "aevalsrc=if(eq(floor(t)\,ld(2))\,st(0\,random(4)*3000+1000))\;st(2\,floor(t)+1)\;st(1\,mod(t\,1))\;(0.6*sin(1*ld(0)*ld(1))+0.4*sin(2*ld(0)*ld(1)))*exp(-4*ld(1)) [out1]; testsrc=s=1920x1080,drawtext=borderw=3:fontcolor=white:fontsize=60:text='%{localtime}':x=\(w-text_w\)/2:y=\(h-text_h-line_h\)/2 [out0]" -r 30 -acodec aac -ac 2 -ab 128k -ar 44100 -c:v libx264 -profile:v main -force_key_frames "expr:gte(t,n_forced*2)" -sc_threshold 0 -pix_fmt yuv420p -b:v 500K -maxrate 500K -s 1920x1080 -preset veryfast -f flv "rtmps://example.com/app/random_stream_key_example"

Note: You may have seen similar commands which use e.g -g 60 -keyint_min 60 instead of -force_key_frames "expr:gte(t,n_forced*2)". Both are ways to force the transcoder to put a keyframe (I-frame) at a particular point (since each segment in a HLS manifest should start with a keyframe - for normal usage you would ideally leave it up to the transcoder to decide where the keyframes should be). The first flag sets the number of frames. As our sample video is 30fps (frames per second), setting a keyframe every 60 frames means one every two seconds. However the second way of doing is is not only more self-explanatory, it is also more flexible. It specifies the time in seconds (that’s the 2). And so that flag could be used with a source input that was 60fps (unlike the first one, which would need adjusting to use a new absolute value, of 120). That’s why we recommend using that second flag.

If you run that full command shown above, after a second or two you should see FFMPEG start to generate the test video and audio stream. You can ignore most of the output however within it you can see the video stream uses h264, at 1920x1080 (full HD), at 30fps. That’s all fine. The audio uses aac, at a bitrate of 128k. Again, all fine. It will look something like this:

  Metadata:
    encoder         : Lavf59.27.100
  Stream #0:0: Video: h264 ([7][0][0][0] / 0x0007), yuv420p(tv, progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 300 kb/s, 30 fps, 1k tbn
    Metadata:
      encoder         : Lavc59.37.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 300000/0/300000 buffer size: 0 vbv_delay: N/A
  Stream #0:1: Audio: aac (LC) ([10][0][0][0] / 0x000A), 44100 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc59.37.100 aac
frame= 1215 fps= 25 q=23.0 size=    2237kB time=00:00:48.57 bitrate= 377.3kbits/s speed=0.999x

Leave that running and open a web browser. Load the live stream in our dashboard, or using the URL shown on that page (for example https://watch.vidbeo.com/abcdefg123445). After a moment you should see the player has detected the live stream, and show a red live overlay in the corner. If you click play, you should see the test pattern and some beeps of audio.

To stop streaming from FFMPEG, switch back to your open terminal window and simply end the process (usually hold down Ctrl, and press C).

We’ll then wait for a set reconnect window (normally around 30 seconds) before considering the stream ended.

The event will then be archived and a video on-demand should be added within a few minutes. You are then free to edit that new video’s settings, just like any other video (its title, tags, thumbnail image, and so on). Your existing live stream stays in the system, ready to be re-used.

Stream from a webcam

You may be able to use FFFMPG to stream the output directly from a device connected to your computer, such as a webcam or microphone.

First you need to see which devices are available. If you are on Windows, try

ffmpeg -list_devices true -f dshow -i dummy

On a Mac, try

ffmpeg -f avfoundation -list_devices true -i ''

Either way you should see a list of available devices. For example:

[0] HD Camera (Built-in)
[1] Capture screen 0
[2] Capture screen 1

It’s easiest to use the index number of the device rather than the name. For example to use the first video device (that’s index 0) and the first audo device (that’s index 0), you would use 0:0 as the input to your live stream. So you would use -i “0:0”. For example:

ffmpeg -f avfoundation -video_size 1280x720 -framerate 30 -i "0:0" -c:v libx264 -b:v 2000K -maxrate 2000K -pix_fmt yuv420p -r 30 -s 1280x720 -profile:v main -preset veryfast -force_key_frames "expr:gte(t,n_forced*2)" -sc_threshold 0 -acodec aac -ab 128k -ar 44100 -f flv "rtmps://example.com/app/random_stream_key_example"

Important

You may get a security warning pop up asking if the terminal is allowed to access your device (such as your camera and/or microphone). You would need to approve that for FFMPEG to be able to access your device.

You may also get an error saying your chosen size is not supported by the device. If so, the error message should list ones that are available. For example:

Selected video size (1920x1080) is not supported by the device.
Supported modes:
640x480@[30]fps
1280x720@[30]fps
...

In which case you would need to adjust your command accordingly. For example replacing any mention of 1920x1080 with 1280x720 (or the closest size supported by your device).

Errors

If you are not sure what’s happening, it can be helpful to get FFMPEG to output more text about what it’s doing. That is what the -loglevel flag is for. You can add that to your command. For example -loglevel info. For even more information, -loglevel verbose.

We’ve listed some potential issues below. Please feel free to get in touch if you have any other problem.

Stream starts then immediately stalls

As mentioned above, one common issue is FFMPEG being unable to output to a rtmps:// URL. After about ten seconds you may see repeated errors like:

av_interleaved_write_frame(): End of file time=00:00:00.48
Last message repeated 22 times

… or …

[flv @ 0x7fac62605d80] Failed to update header with correct duration.
[flv @ 0x7fac62605d80] Failed to update header with correct filesize.
Error writing trailer of rtmps://example.com/app/random_stream_key_example: End of file

That can be confirmed by switching to output to an rtmp:// URL instead. Many live streaming platforms use rtmps:// however some (like YouTube) default to using rtmp://. If you find you can output to rtmp:// but not to rtmps://, first make sure rtmps is listed in the supported protocols. You can find out by running:

$ ffmpeg -protocols

That should output a long list and if you scroll down you should see rtmps within the Output section:

...
Output:
  rtmp
  rtmps
  rtmpt
...

Even if it does list rtmps, that uses a TLS connection and so relies on other libraries being available to establish that secure connection. On a Mac, we found the static FFMPEG binary available to download can not output to an rtmps URL, however the version installed by the Homebrew package manager can. You can install that using brew install ffmpeg (it takes a while).

Intermittent stalls

If the stream stalls, resumes, and then stalls again, the issue is likely that your internet connection is not fast enough to support the chosen bitrate. Within the FFMPEG command you should see a parameter like -b:v 500K -maxrate 500K. The -b:v is the bitrate for the video stream, the largest part of the data. The -maxrate (as the name suggests) is the maximum bitrate. We recommend using CBR (Constant BitRate) which is why those two values are the same. You should reduce those values. Your stream won’t look as good (as there is less data being sent) however it will be smoother and there will be less pauses for buffering.

Text error

If you get an error about the text file not being found (or some issue mentioning fontconfig), that could be due to the specific FFMPEG command. Our test command writes text (the current time). However it doesn’t need to. The simplest solution for this is to use a test stream which does not output any text. You could instead use a local video file (here we have one called input.mp4 in the same folder we are running this command from - make sure you have permission to stream it). As usual, replace the URL at the end of this command with your own, real one.

We are again using h264 as the video codec, and aac for the audio codec. You can increase the 500k bitrate values based on the speed of your internet connection. As mentioned above, we use the -force_key_frames flag to ensure there is a keyframe every 2 seconds and then force a scenecut using the options flag:

ffmpeg -re -i "input.mp4" -acodec aac -ac 2 -ar 44100 -b:a 128k -pix_fmt yuv420p -vcodec libx264 -profile:v main -s 1920x1080 -b:v 500k -maxrate 500k -preset veryfast -force_key_frames "expr:gte(t,n_forced*2)" -x264opts "nal-hrd=cbr:no-scenecut" -f flv "rtmps://example.com/app/random_stream_key_example"

Unexpected token error

If you see an error like:

-bash: syntax error near unexpected token `('

… make sure any expressions are wrapped in quotation marks for FFMPEG to correctly parse the command. For example -force_key_frames "expr:gte(t,n_forced*2)".

Note: If your command does not seem to have been received (like FFMPEG appears to be waiting for more input, using a >), that is often caused by the quotation marks not being the ones it expects. When you copy a command directly from a web page, the quotation marks can be subtly different. If your command looks the same, but does not work, it is often worth deleting each quotation mark and simply typing one in manually in its place.

Updated: September 25, 2023