Setting up hardware acceleration (vaapi) for webrtc

I was able to integrate gstreamer webrtc into my test app. But it was dropping a lot of frames. So I decided to use hardware accelerating by swapping autovideosink with vaapisink.
But it kept failing and I wasn’t able to trace why it was failing as the program was giving me no clue.

So I tried running the example in the main repo with vaapisink instead of autovideosink. I got a segmentation fault this time.
I ran it with GST_DEBUG=5 and I got the following logs:

0:00:04.614956839 74162 0x7f0aa8006760 DEBUG               GST_PADS gstpad.c:4115:check_sticky:<rtpfunnel0:src> pushing all sticky events
0:00:04.614980679 74162 0x7f0a54002300 DEBUG                    bin gstbin.c:4029:gst_bin_handle_message_func:<pipeline0> posting message upward
0:00:04.615068959 74162 0x7f0a54002300 DEBUG                GST_BUS gstbus.c:338:gst_bus_post:<bus3> [msg 0x7f0a50001e20] posting on bus element message: 0x7f0a50001e20, time 99:99:99.999999999, seq-num 710, element 'vaapisink0', prepare-window-handle;
0:00:04.615069191 74162 0x7f0aa8006760 DEBUG               GST_PADS gstpad.c:4039:push_sticky:<rtpfunnel0:src> event stream-start was already received
0:00:04.615102018 74162 0x7f0aa8006760 DEBUG               GST_PADS gstpad.c:4039:push_sticky:<rtpfunnel0:src> event caps was already received
0:00:04.615112439 74162 0x7f0a54002300 DEBUG                GST_BUS gstbus.c:377:gst_bus_post:<bus3> [msg 0x7f0a50001e20] dropped
0:00:04.615126570 74162 0x7f0a54002300 DEBUG                GST_BUS gstbus.c:377:gst_bus_post:<bus2> [msg 0x7f0a50001e20] dropped
0:00:04.615138371 74162 0x7f0a54002300 DEBUG                GST_BUS gstbus.c:377:gst_bus_post:<bus18> [msg 0x7f0a50001e20] dropped
0:00:04.615145763 74162 0x7f0aa8006760 DEBUG              GST_EVENT gstpad.c:5860:gst_pad_send_event_unchecked:<rtpbin:send_rtp_sink_0> have event type segment event: 0x7f0a8c005190, time 99:99:99.999999999, seq-num 47, GstEventSegment, segment=(GstSegment)"segment, flags=(GstSegmentFlags)GST_SEGMENT_FLAG_NONE, rate=(double)1, applied-rate=(double)1, format=(GstFormat)time, base=(guint64)0, offset=(guint64)0, start=(guint64)0, stop=(guint64)18446744073709551615, time=(guint64)0, position=(guint64)0, duration=(guint64)18446744073709551615;";
0:00:04.615168119 74162 0x7f0aa8006760 DEBUG               GST_PADS gstpad.c:4115:check_sticky:<send_rtp_sink_0:proxypad21> pushing all sticky events
0:00:04.615180966 74162 0x7f0aa8006760 DEBUG               GST_PADS gstpad.c:4039:push_sticky:<send_rtp_sink_0:proxypad21> event stream-start was already received
0:00:04.615193475 74162 0x7f0aa8006760 DEBUG               GST_PADS gstpad.c:4039:push_sticky:<send_rtp_sink_0:proxypad21> event caps was already received
Segmentation fault

How do I tweak it to work with hardware acceleration?

I was reading about hardware acceleration here. It says that plugin with a higher rank will be used. But I noticed that when I tried to play a 4k 60 FPS video with playbin it was struggling to do so. But when I explicitly set the video-sink property to vaapisink, it started to play smoothly. So I kept autovideosink in the pipeline. But set the rank to PRIMARY + 1. I got error:

** (webrtc-app:79790): CRITICAL **: 00:53:07.862: gst_vaapi_window_wayland_new: assertion 'GST_VAAPI_IS_DISPLAY_WAYLAND (display)' failed

** (webrtc-app:79790): CRITICAL **: 00:53:07.863: gst_vaapi_window_wayland_new: assertion 'GST_VAAPI_IS_DISPLAY_WAYLAND (display)' failed

** (webrtc-app:79790): CRITICAL **: 00:53:07.866: gst_vaapi_window_wayland_new: assertion 'GST_VAAPI_IS_DISPLAY_WAYLAND (display)' failed

** (webrtc-app:79790): CRITICAL **: 00:53:07.866: gst_vaapi_window_wayland_new: assertion 'GST_VAAPI_IS_DISPLAY_WAYLAND (display)' failed

** (webrtc-app:79790): CRITICAL **: 00:53:07.866: gst_vaapi_window_wayland_new: assertion 'GST_VAAPI_IS_DISPLAY_WAYLAND (display)' failed

** (webrtc-app:79790): CRITICAL **: 00:53:07.866: gst_vaapi_window_wayland_new: assertion 'GST_VAAPI_IS_DISPLAY_WAYLAND (display)' failed
Error: Error from element /GstPipeline:pipeline0/GstWebRTCBin:webrtcbin/TransportReceiveBin:transportreceivebin0/GstNiceSrc:nicesrc0: Internal data stream error. (../libs/gst/base/gstbasesrc.c(3132): gst_base_src_loop (): /GstPipeline:pipeline0/GstWebRTCBin:webrtcbin/TransportReceiveBin:transportreceivebin0/GstNiceSrc:nicesrc0:
streaming stopped, reason not-negotiated (-4))

Also, if I use elements for example like decodebin, will it use vaapidecodebin if it has a higher rank?

vaapisink is no longer supported sink. Use platform specific sinks that fits your use case, one with acceleration on Linux would be glimagesink, gtk4paintablesink, waylandsink (though require very recent compositors), etc.

Oh I see. Thanks! What about hardware encoders and decoders like vaapidecodebin. Are they supported? Or is it better to use decodebin and does decodebin support hardware decoders?

The whole vaapi plugin is in life-support mode and receiving very little maintenance. Nowadays decodebin3 should be able to auto-plug the va decoders.

1 Like

And everything you need should be available in libgstva, except the video sink, which is based on deprecated API on Intel side.

Oh ok, so if I understood correctly, if I’m using vp9enc and decodebin in my pipeline for WebRTC, then will the encoding and decoding be done by the hardware?

No. vp9enc is a software encoder. If you want hardware encoding with vaapi, you should use vavp9enc. For hardware decoding using decodebin the details depend on what’s available on your system and the format of the incoming stream. decodebin may or may not use a hardware decoder. You can check by looking at a pipeline dump.

Got it. So decodebin is using the ranking system right?

Correct, each GstElement has a rank, we rank HW accelerated decoder higher, so as an example vavp9dec will be picked over vp9dec. You can use gst-inspect-1.0 to see what rank installed elements have.

1 Like

Is there a reason why there is no vavp9enc but vavp9dec? I’m basically trying to maximize my performance for webrtc (preventing stuttering).

Since there is no vavp9enc, should I try to use an encoder that is listed in gst-inspect-1.0 va like vah264lpenc? Would there be any benefit or should I just stick with software encoding

Thanks a lot for answering my questions and sorry for asking too many!

That entirely depends on your hardware capabilities. As an example, I got an AMD laptop here that do not have vp9 encoding capability, but the same version of gstreamer offer vavp9enc on an Intel desktop. You can use “vainfo” tool to inspect the VA capabilities.

The benefit of using a hardware encoder is pretty clear, but at the same time it is relative to what hardware you are running at. With current progress in software encoding, an expensive server CPU can often compete with dedicated hardware.

Here is the output of vainfo

libva info: VA-API version 1.17.0
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_17
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.17 (libva 2.12.0)
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 23.1.1 ()
vainfo: Supported profile and entrypoints
      VAProfileNone                   :	VAEntrypointVideoProc
      VAProfileNone                   :	VAEntrypointStats
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointEncSliceLP
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointEncSliceLP
      VAProfileJPEGBaseline           :	VAEntrypointVLD
      VAProfileJPEGBaseline           :	VAEntrypointEncPicture
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointEncSliceLP
      VAProfileVP8Version0_3          :	VAEntrypointVLD
      VAProfileHEVCMain               :	VAEntrypointVLD
      VAProfileHEVCMain               :	VAEntrypointEncSliceLP
      VAProfileHEVCMain10             :	VAEntrypointVLD
      VAProfileHEVCMain10             :	VAEntrypointEncSliceLP
      VAProfileVP9Profile0            :	VAEntrypointVLD
      VAProfileVP9Profile0            :	VAEntrypointEncSliceLP
      VAProfileVP9Profile1            :	VAEntrypointVLD
      VAProfileVP9Profile1            :	VAEntrypointEncSliceLP
      VAProfileVP9Profile2            :	VAEntrypointVLD
      VAProfileVP9Profile2            :	VAEntrypointEncSliceLP
      VAProfileVP9Profile3            :	VAEntrypointVLD
      VAProfileVP9Profile3            :	VAEntrypointEncSliceLP
      VAProfileHEVCMain12             :	VAEntrypointVLD
      VAProfileHEVCMain422_10         :	VAEntrypointVLD
      VAProfileHEVCMain422_12         :	VAEntrypointVLD
      VAProfileHEVCMain444            :	VAEntrypointVLD
      VAProfileHEVCMain444            :	VAEntrypointEncSliceLP
      VAProfileHEVCMain444_10         :	VAEntrypointVLD
      VAProfileHEVCMain444_10         :	VAEntrypointEncSliceLP
      VAProfileHEVCMain444_12         :	VAEntrypointVLD
      VAProfileHEVCSccMain            :	VAEntrypointVLD
      VAProfileHEVCSccMain            :	VAEntrypointEncSliceLP
      VAProfileHEVCSccMain10          :	VAEntrypointVLD
      VAProfileHEVCSccMain10          :	VAEntrypointEncSliceLP
      VAProfileHEVCSccMain444         :	VAEntrypointVLD
      VAProfileHEVCSccMain444         :	VAEntrypointEncSliceLP
      VAProfileAV1Profile0            :	VAEntrypointVLD
      VAProfileHEVCSccMain444_10      :	VAEntrypointVLD
      VAProfileHEVCSccMain444_10      :	VAEntrypointEncSliceLP

So vp9 is indeed supported. And it can also be confirmed by the existence of vaapivp9enc.

But I checked out this link, and I saw that there is no mention of vavp9enc which led me to ask this

The doc needs an update, mind filling an issue?

I wouldn’t mind but the other thing is gst-inspect-1.0 va is giving me the following output:

  vaav1dec: VA-API AV1 Decoder
  vacompositor: VA-API Video Compositor
  vadeinterlace: VA-API Deinterlacer
  vah264dec: VA-API H.264 Decoder
  vah264lpenc: VA-API H.264 Low Power Encoder
  vah265dec: VA-API H.265 Decoder
  vah265lpenc: VA-API H.265 Low Power Encoder
  vajpegdec: VA-API JPEG Decoder
  vampeg2dec: VA-API Mpeg2 Decoder
  vapostproc: VA-API Video Postprocessor
  vavp8dec: VA-API VP8 Decoder
  vavp9dec: VA-API VP9 Decoder

But on the other hand, gst-inspect-1.0 vaapi is giving

  vaapiav1dec: VA-API AV1 decoder
  vaapidecodebin: VA-API Decode Bin
  vaapih264dec: VA-API H264 decoder
  vaapih264enc: VA-API H264 encoder
  vaapih265dec: VA-API H265 decoder
  vaapih265enc: VA-API H265 encoder
  vaapijpegdec: VA-API JPEG decoder
  vaapijpegenc: VA-API JPEG encoder
  vaapimpeg2dec: VA-API MPEG2 decoder
  vaapioverlay: VA-API overlay
  vaapipostproc: VA-API video postprocessing
  vaapisink: VA-API sink
  vaapivp8dec: VA-API VP8 decoder
  vaapivp9dec: VA-API VP9 decoder
  vaapivp9enc: VA-API VP9 encoder

And gst-inspect-1.0 vavp9enc give me: No such element or plugin.
Something else is going on right?

Ah, VP9 encoder is in main branch, and not yet released, sorry about that, you’ll have to be patient, or build your own.

Ah I see :slightly_frowning_face:
I’m guessing it’s the same with av1 too right even though my hardware supports it? Although av1 hardware encoder is not present with vaapi too.
Screenshot taken from about:support from firefox

Screenshot from 2024-12-07 00-54-55

The vainfo trace does not agree with that tool. The AV1 encoder is only in the new VA plugin, and was released as part of GStreamr 1.24.0.

This is the change the introduced VP9 Encoder, and to be released in 1.26.0.

1 Like

Yup you’re right. I verified with ffmpeg.
Google VP9 (decoders: vp9 vp9_v4l2m2m libvpx-vp9 vp9_cuvid vp9_qsv ) (encoders: libvpx-vp9 vp9_vaapi vp9_qsv )
However, I noticed that vp9 has Quick Sync Video support.

However gst-inspect-1.0 qsv shows that there are 0 features. Why are there 0 features?
And also, would you recommend this?

QSV is only supported on Windows in GStreamer. This is a bit pointless since its based on VA on Linux anyway.

Is not vaapi replaced by va-api? I guess vaapi is not maintained anymore.