Streaming your Linux desktop to Youtube and Twitch via Nvidia’s NVENC and VAAPI

It is possible to use FFmpeg as a live streaming tool with any hardware-based encoder, such as Nvidia’s NVENC and Intel’s VAAPI as demonstrated below:

Without scaling the output:

If you want the output video frame size to be the same as the input for Twitch:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
    -c:v h264_nvenc -preset:v llhq  \
    -rc:v vbr_minqp -qmin:v 19  \
    -f flv rtmp://live.twitch.tv/app/<stream key>

To do the same for Youtube, do:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
    -c:v h264_nvenc -preset:v llhq  \
    -rc:v vbr_minqp -qmin:v 19  \
    -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

Note: Ensure that the size specified above (-s ) does match your screen’s resolution. Also, ensure that the stream key used is correct, otherwise your live broadcast will fail.

Scaling the output:

If you want the output video frame size to be smaller than the input then you can insert the appropriate scale video filter for NVENC:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-filter:v hwupload_cuda,scale_npp=w=1280:h=720:format=nv12:interp_algo=lanczos,hwdownload,format=nv12 \
    -c:v h264_nvenc -preset:v llhq  \
    -rc:v vbr_minqp -qmin:v 19  \
    -f flv rtmp://live.twitch.tv/app/<stream key>

And for Youtube:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-filter:v hwupload_cuda,scale_npp=w=1280:h=720:format=nv12:interp_algo=lanczos,hwdownload,format=nv12 \
    -c:v h264_nvenc -preset:v llhq  \
    -rc:v vbr_minqp -qmin:v 19  \
    -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

Note that the examples above will use CUVID’s NPP-based hardware scaler in the GPU to rescale the output to a perfect 720p (HD-ready) video stream on broadcast.

With webcam overlay:

This will place your webcam overlay in the top right:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
    -f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-filter:v hwupload_cuda,scale_npp=w=1280:h=720:format=nv12:interp_algo=lanczos,hwdownload,format=nv12 \
    -c:v h264_nvenc -preset:v llhq  \
    -rc:v vbr_minqp -qmin:v 19  \
    -f flv rtmp://live.twitch.tv/app/<stream key>

And for Youtube:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
    -f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-filter:v hwupload_cuda,scale_npp=w=1280:h=720:format=nv12:interp_algo=lanczos,hwdownload,format=nv12 \
    -c:v h264_nvenc -preset:v llhq  \
    -rc:v vbr_minqp -qmin:v 19  \
    -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

You can see additional details your webcam with something like:

 ffmpeg -f v4l2 -list_formats all -i /dev/video0 or with v4l2-ctl --list-formats-ext

See the documentation on the ​video4linux2 (v4l2) input device for more info.

Note: Your webcam may natively support whatever frame size you want to overlay onto the main video, so scaling the webcam video as shown in this example can be omitted (just set the appropriate v4l2 -video_size and remove the scale=120:-1,).

With webcam overlay and logo:

This will place your webcam overlay in the top right, and a logo in the bottom left:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
    -f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
    -i logo.png -filter_complex \
     "[0:v]scale=1024:-1,setpts=PTS-STARTPTS[bg]; \
    [1:v]scale=120:-1,setpts=PTS-STARTPTS[fg]; \
    [bg][fg]overlay=W-w-10:10[bg2]; \
    [bg2][3:v]overlay=W-w-10:H-h-10,format=yuv420p[out]"
   -map "[out]" -map 2:a 
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-filter:v hwupload_cuda,scale_npp=w=1280:h=720:format=nv12:interp_algo=lanczos,hwdownload,format=nv12 \
    -c:v h264_nvenc -preset:v llhq  \
    -rc:v vbr_minqp -qmin:v 19  \
    -f flv rtmp://live.twitch.tv/app/<stream key>

And for Youtube:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
    -f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
    -i logo.png -filter_complex \
     "[0:v]scale=1024:-1,setpts=PTS-STARTPTS[bg]; \
    [1:v]scale=120:-1,setpts=PTS-STARTPTS[fg]; \
    [bg][fg]overlay=W-w-10:10[bg2]; \
    [bg2][3:v]overlay=W-w-10:H-h-10,format=yuv420p[out]"
   -map "[out]" -map 2:a 
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-filter:v hwupload_cuda,scale_npp=w=1280:h=720:format=nv12:interp_algo=lanczos,hwdownload,format=nv12 \
    -c:v h264_nvenc -preset:v llhq  \
    -rc:v vbr_minqp -qmin:v 19  \
    -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

Streaming a file to Youtube:

$ ffmpeg -re -i input.mkv -c:v h264_nvenc -preset:v llhq -maxrate 3000k \
-bufsize 6000k -g 50 -c:a aac -b:a 160k -ac 2 \
-ar 44100 -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

Outputting to multiple streaming services & local file:

You can use the tee muxer to efficiently stream to multiple sites and save a local copy if desired. Using tee will allow you to encode only once and send the same data to multiple outputs. Using the onfail option will allow the other streams to continue if one fails.

$ ffmpeg -i input -map 0 -c:v h264_nvenc -preset:v llhq -c:a aac -muxrate 2500k -bufsize 3500k -g 50 -f tee \
"[f=flv:onfail=ignore]rtmp://live.twitch.tv/app/<stream key>|[f=flv:onfail=ignore]rtmp://a.rtmp.youtube.com/live2/<stream key>|local_file.mkv"

The example above will stream to both Youtube and twitch TV and at the same time, store a copy of the video stream on the local filesystem. Modify paths as needed.

Notes:

You can use xwininfo | grep geometry to select the target window and get placement coordinates. For example, an output of -geometry 800x600+284+175 would result in using -video_size 800x600 -i :0.0+284,175. You can also use it to automatically enter the input screen size: -video_size $(xwininfo -root | awk '/-geo/{print $2}').

The ​pulse input device (requires --enable-libpulse) can be an alternative to the ​ALSA input device, as in: -f pulse -i default, as per your preference.

Part 2: Using Intel’s VAAPI to achieve the same:

Without scaling the output:

If you want the output video frame size to be the same as the input for Twitch:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-vaapi_device /dev/dri/renderD129 -vf  'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \
    -f flv rtmp://live.twitch.tv/app/<stream key>

To do the same for Youtube, do:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-vaapi_device /dev/dri/renderD129 -vf  'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \
    -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

Note: Ensure that the size specified above (-s ) does match your screen’s resolution. Also, ensure that the stream key used is correct, otherwise your live broadcast will fail.

Scaling the output:

If you want the output video frame size to be smaller than the input then you can insert the appropriate scale video filter for VAAPI:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-vaapi_device /dev/dri/renderD129 -vf  'format=nv12,hwupload,scale_vaapi=w=1280:h=720' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \
    -f flv rtmp://live.twitch.tv/app/<stream key>

And for Youtube:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-vaapi_device /dev/dri/renderD129 -vf  'format=nv12,hwupload,scale_vaapi=w=1280:h=720' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \
    -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

Note that the examples above will use Intel’s QuickSync hardware scaler engines (available since Snadybridge) in the GPU to re-scale the output to a perfect 720p (HD-ready) video stream on broadcast.

With webcam overlay:

This will place your webcam overlay in the top right:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
    -f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-vaapi_device /dev/dri/renderD129 -vf  'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \
    -f flv rtmp://live.twitch.tv/app/<stream key>

And for Youtube:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
    -f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-vaapi_device /dev/dri/renderD129 -vf  'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \
    -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

You can see additional details your webcam with something like:

 ffmpeg -f v4l2 -list_formats all -i /dev/video0 or with v4l2-ctl --list-formats-ext

See the documentation on the ​video4linux2 (v4l2) input device for more info.

Note: Your webcam may natively support whatever frame size you want to overlay onto the main video, so scaling the webcam video as shown in this example can be omitted (just set the appropriate v4l2 -video_size and remove the scale=120:-1,).

With webcam overlay and logo:

This will place your webcam overlay in the top right, and a logo in the bottom left:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
    -f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
    -i logo.png -filter_complex \
     "[0:v]scale=1024:-1,setpts=PTS-STARTPTS[bg]; \
    [1:v]scale=120:-1,setpts=PTS-STARTPTS[fg]; \
    [bg][fg]overlay=W-w-10:10[bg2]; \
    [bg2][3:v]overlay=W-w-10:H-h-10,format=yuv420p[out]"
   -map "[out]" -map 2:a 
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-vaapi_device /dev/dri/renderD129 -vf  'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \
    -f flv rtmp://live.twitch.tv/app/<stream key>

And for Youtube:

ffmpeg -loglevel debug \
    -f x11grab -s 1920x1080 -framerate 60 -i :0.0 \
    -f v4l2 -video_size 320x240 -framerate 30 -i /dev/video0 \
    -i logo.png -filter_complex \
     "[0:v]scale=1024:-1,setpts=PTS-STARTPTS[bg]; \
    [1:v]scale=120:-1,setpts=PTS-STARTPTS[fg]; \
    [bg][fg]overlay=W-w-10:10[bg2]; \
    [bg2][3:v]overlay=W-w-10:H-h-10,format=yuv420p[out]"
   -map "[out]" -map 2:a 
-thread_queue_size 1024 -f alsa -ac 2 -i hw:0,0 \
-vaapi_device /dev/dri/renderD129 -vf  'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \
    -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

Streaming a file to Youtube:

$ ffmpeg -re -i input.mkv -vaapi_device /dev/dri/renderD129 \
 -vf 'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \ 
-maxrate 3000k \
-bufsize 6000k -g 50 -c:a aac -b:a 160k -ac 2 \
-ar 44100 -f flv rtmp://a.rtmp.youtube.com/live2/<stream key>

Outputting to multiple streaming services & local file:

You can use the tee muxer to efficiently stream to multiple sites and save a local copy if desired. Using tee will allow you to encode only once and send the same data to multiple outputs. Using the onfail option will allow the other streams to continue if one fails.

$ ffmpeg -re -i input.mkv -vaapi_device /dev/dri/renderD129 \
 -vf 'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
-c:v h264_vaapi -qp:v 19 -bf 4 -threads 4 -aspect 16:9 \ 
-maxrate 3000k \
-bufsize 6000k -g 50 -c:a aac -b:a 160k -ac 2 \
-ar 44100 -f tee \
"[f=flv:onfail=ignore]rtmp://live.twitch.tv/app/<stream key>|[f=flv:onfail=ignore]rtmp://a.rtmp.youtube.com/live2/<stream key>|local_file.mkv"

The example above will stream to both Youtube and twitch TV and at the same time, store a copy of the video stream on the local filesystem. Modify paths as needed.

Note: For VAAPI, use the scaler on local file encodes if, and only if, you need to use it, and for best results, stick to the original video stream dimensions, or downscale if needed (scale_vaapi=w=x:h=y) as upscaling can introduce artifacting.

To determine the video stream’s properties, you can run:

ffprobe path-to-video.ext

Where path-to-video-ext refers to the absolute path and name of the file.

Categories Linux, Video Encoding articlesTags , , , , , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this:
search previous next tag category expand menu location phone mail time cart zoom edit close